diff --git a/.gitignore b/.gitignore
index f1650504b7282b0b04bb93ee8e905cc353d7f65d..b57ed74ab225239f4c21de167f26f6f1ed7f2aff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,9 @@ coverage
 # PyCharm project settings
 .idea
 
+# VSCode project settings
+.vscode
+
 # Local data
 secrets.py
 *.log
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index bceb5f51c36ffc38495a45859c5e3083f55144af..291ed49016fc76224378fe52dbea4bb5de0beca1 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,20 +2,25 @@ image: python:3.6
 
 stages:
   - test
+  - quality-assurance
 
 before_script:
   - pip install tox
 
-python36:
+py36-django22:
   image: python:3.6
   stage: test
-  script: tox -e py36
+  script: tox -e py36-django22
 
-python37:
+py37-django22:
   image: python:3.7
   stage: test
-  script: tox -e py37
+  script: tox -e py37-django22
 
 linters:
-  stage: test
+  image: python:3.6
+  stage: quality-assurance
   script: tox -e linters
+
+  # Be nice to new contributors, but please use `tox`
+  allow_failure: true
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index 6ddf1f3ccfdf1d0f28617c5eb811e610c548d900..0000000000000000000000000000000000000000
--- a/.pylintrc
+++ /dev/null
@@ -1,379 +0,0 @@
-[MASTER]
-
-# Specify a configuration file.
-#rcfile=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS,.git
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-# Use multiple processes to speed up Pylint.
-jobs=4
-
-# Allow loading of arbitrary C extensions. Extensions are imported into the
-# active Python interpreter and may run arbitrary code.
-unsafe-load-any-extension=no
-
-# A comma-separated list of package or module names from where C extensions may
-# be loaded. Extensions are loading into the active Python interpreter and may
-# run arbitrary code
-extension-pkg-whitelist=
-
-# Allow optimization of some AST trees. This will activate a peephole AST
-# optimizer, which will apply various small optimizations. For instance, it can
-# be used to obtain the result of joining multiple strings with the addition
-# operator. Joining a lot of strings can lead to a maximum recursion error in
-# Pylint and this flag can prevent that. It has one side effect, the resulting
-# AST will be different than the one from reality.
-optimize-ast=no
-
-
-[MESSAGES CONTROL]
-
-# Only show warnings with the listed confidence levels. Leave empty to show
-# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
-confidence=INFERENCE_FAILURE
-
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time. See also the "--disable" option for examples.
-#enable=
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifiers separated by comma (,) or put this
-# option multiple times (only on the command line, not in the configuration
-# file where it should appear only once).You can also use "--disable=all" to
-# disable everything first and then reenable specific checks. For example, if
-# you want to run only the similarities checker, you can use "--disable=all
-# --enable=similarities". If you want to run only the classes checker, but have
-# no Warning level messages displayed, use"--disable=all --enable=classes
-# --disable=W"
-disable=intern-builtin,nonzero-method,parameter-unpacking,backtick,raw_input-builtin,dict-view-method,filter-builtin-not-iterating,long-builtin,unichr-builtin,input-builtin,unicode-builtin,file-builtin,map-builtin-not-iterating,delslice-method,apply-builtin,cmp-method,setslice-method,coerce-method,long-suffix,raising-string,import-star-module-level,buffer-builtin,reload-builtin,unpacking-in-except,print-statement,hex-method,old-octal-literal,metaclass-assignment,dict-iter-method,range-builtin-not-iterating,using-cmp-argument,indexing-exception,no-absolute-import,coerce-builtin,getslice-method,suppressed-message,execfile-builtin,round-builtin,useless-suppression,reduce-builtin,old-raise-syntax,zip-builtin-not-iterating,cmp-builtin,xrange-builtin,standarderror-builtin,old-division,oct-method,next-method-called,old-ne-operator,basestring-builtin
-
-
-[REPORTS]
-
-# Set the output format. Available formats are text, parseable, colorized, msvs
-# (visual studio) and html. You can also give a reporter class, eg
-# mypackage.mymodule.MyReporterClass.
-output-format=text
-
-# Put messages in a separate file for each module / package specified on the
-# command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
-files-output=no
-
-# Tells whether to display a full report or only the messages
-reports=no
-
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Template used to display messages. This is a python new-style format string
-# used to format the message information. See doc for all details
-#msg-template=
-
-
-[BASIC]
-
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=map,filter
-
-# Good variable names which should always be accepted, separated by a comma
-good-names=i,j,k,ex,Run,_
-
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
-
-# Colon-delimited sets of names that determine each other's naming style when
-# the name regexes allow several styles.
-name-group=
-
-# Include a hint for the correct naming format with invalid-name
-include-naming-hint=yes
-
-# Regular expression matching correct argument names
-argument-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Naming hint for argument names
-argument-name-hint=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression matching correct attribute names
-attr-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Naming hint for attribute names
-attr-name-hint=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression matching correct constant names
-const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
-# Naming hint for constant names
-const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
-# Regular expression matching correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
-
-# Naming hint for class names
-class-name-hint=[A-Z_][a-zA-Z0-9]+$
-
-# Regular expression matching correct inline iteration names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-
-# Naming hint for inline iteration names
-inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
-
-# Regular expression matching correct class attribute names
-class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-
-# Naming hint for class attribute names
-class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-
-# Regular expression matching correct function names
-function-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Naming hint for function names
-function-name-hint=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression matching correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Naming hint for module names
-module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Regular expression matching correct method names
-method-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Naming hint for method names
-method-name-hint=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression matching correct variable names
-variable-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Naming hint for variable names
-variable-name-hint=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=^_
-
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=-1
-
-
-[ELIF]
-
-# Maximum number of nested blocks for function / method body
-max-nested-blocks=5
-
-
-[FORMAT]
-
-# Maximum number of characters on a single line.
-max-line-length=100
-
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=^\s*(# )?<?https?://\S+>?$
-
-# Allow the body of an if to be on the same line as the test if there is no
-# else.
-single-line-if-stmt=no
-
-# List of optional constructs for which whitespace checking is disabled. `dict-
-# separator` is used to allow tabulation in dicts, etc.: {1  : 1,\n222: 2}.
-# `trailing-comma` allows a space between comma and closing bracket: (a, ).
-# `empty-line` allows space-only lines.
-no-space-check=trailing-comma,dict-separator
-
-# Maximum number of lines in a module
-max-module-lines=1000
-
-# String used as indentation unit. This is usually "    " (4 spaces) or "\t" (1
-# tab).
-indent-string='    '
-
-# Number of spaces of indent required inside a hanging  or continued line.
-indent-after-paren=4
-
-# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
-expected-line-ending-format=
-
-
-[LOGGING]
-
-# Logging modules to check that the string format arguments are in logging
-# function parameter format
-logging-modules=logging
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
-
-
-[SIMILARITIES]
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-# Ignore imports when computing similarities.
-ignore-imports=no
-
-
-[SPELLING]
-
-# Spelling dictionary name. Available dictionaries: none. To make it working
-# install python-enchant package.
-spelling-dict=
-
-# List of comma separated words that should not be checked.
-spelling-ignore-words=
-
-# A path to a file that contains private dictionary; one word per line.
-spelling-private-dict-file=
-
-# Tells whether to store unknown words to indicated private dictionary in
-# --spelling-private-dict-file option instead of raising a message.
-spelling-store-unknown-words=no
-
-
-[TYPECHECK]
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# List of module names for which member attributes should not be checked
-# (useful for modules/projects where namespaces are manipulated during runtime
-# and thus existing member attributes cannot be deduced by static analysis. It
-# supports qualified module names, as well as Unix pattern matching.
-ignored-modules=
-
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set). This supports can work
-# with qualified names.
-ignored-classes=
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E1101 when accessed. Python regular
-# expressions are accepted.
-generated-members=
-
-
-[VARIABLES]
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# A regular expression matching the name of dummy variables (i.e. expectedly
-# not used).
-dummy-variables-rgx=_$|dummy
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-# List of strings which can identify a callback function by name. A callback
-# name must start or end with one of those strings.
-callbacks=cb_,_cb
-
-
-[CLASSES]
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-# List of valid names for the first argument in a metaclass class method.
-valid-metaclass-classmethod-first-arg=mcs
-
-# List of member names, which should be excluded from the protected access
-# warning.
-exclude-protected=_asdict,_fields,_replace,_source,_make
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=20
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*
-
-# Maximum number of locals for function / method body
-max-locals=20
-
-# Maximum number of return / yield for function / method body
-max-returns=6
-
-# Maximum number of branch for function / method body
-max-branches=12
-
-# Maximum number of statements in function / method body
-max-statements=50
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=10
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-# Maximum number of boolean expressions in an if statement
-max-bool-expr=5
-
-
-[IMPORTS]
-
-# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=optparse
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled)
-import-graph=
-
-# Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled)
-ext-import-graph=
-
-# Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled)
-int-import-graph=
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "Exception"
-overgeneral-exceptions=Exception
-
diff --git a/apps/activity/__init__.py b/apps/activity/__init__.py
index 75df9e1f408b34c35e9138d12fc2c6b3ac479724..195d53023dbb2e82edfce87166c8373532cd3e77 100644
--- a/apps/activity/__init__.py
+++ b/apps/activity/__init__.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 default_app_config = 'activity.apps.ActivityConfig'
diff --git a/apps/activity/admin.py b/apps/activity/admin.py
index 1efe272c50beac2b537936063b489d656aac1d16..5ceb4e8146bcf1c1392059117c34e2497d04c73a 100644
--- a/apps/activity/admin.py
+++ b/apps/activity/admin.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.contrib import admin
@@ -12,7 +11,7 @@ class ActivityAdmin(admin.ModelAdmin):
     Admin customisation for Activity
     """
     list_display = ('name', 'activity_type', 'organizer')
-    list_filter = ('activity_type',)
+    list_filter = ('activity_type', )
     search_fields = ['name', 'organizer__name']
 
     # Organize activities by start date
diff --git a/apps/activity/api/__init__.py b/apps/activity/api/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/activity/api/serializers.py b/apps/activity/api/serializers.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b9302f17aa24b961be3f792a7afb7a87c6b5e8a
--- /dev/null
+++ b/apps/activity/api/serializers.py
@@ -0,0 +1,36 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from rest_framework import serializers
+
+from ..models import ActivityType, Activity, Guest
+
+
+class ActivityTypeSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Activity types.
+    The djangorestframework plugin will analyse the model `ActivityType` and parse all fields in the API.
+    """
+    class Meta:
+        model = ActivityType
+        fields = '__all__'
+
+
+class ActivitySerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Activities.
+    The djangorestframework plugin will analyse the model `Activity` and parse all fields in the API.
+    """
+    class Meta:
+        model = Activity
+        fields = '__all__'
+
+
+class GuestSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Guests.
+    The djangorestframework plugin will analyse the model `Guest` and parse all fields in the API.
+    """
+    class Meta:
+        model = Guest
+        fields = '__all__'
diff --git a/apps/activity/api/urls.py b/apps/activity/api/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..79e0ba30db826b856170a54e5561674fc06c7037
--- /dev/null
+++ b/apps/activity/api/urls.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from .views import ActivityTypeViewSet, ActivityViewSet, GuestViewSet
+
+
+def register_activity_urls(router, path):
+    """
+    Configure router for Activity REST API.
+    """
+    router.register(path + '/activity', ActivityViewSet)
+    router.register(path + '/type', ActivityTypeViewSet)
+    router.register(path + '/guest', GuestViewSet)
diff --git a/apps/activity/api/views.py b/apps/activity/api/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..5683d458011f3acba0e06bda1b0e6dc575ea513b
--- /dev/null
+++ b/apps/activity/api/views.py
@@ -0,0 +1,37 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from rest_framework import viewsets
+
+from ..models import ActivityType, Activity, Guest
+from .serializers import ActivityTypeSerializer, ActivitySerializer, GuestSerializer
+
+
+class ActivityTypeViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `ActivityType` objects, serialize it to JSON with the given serializer,
+    then render it on /api/activity/type/
+    """
+    queryset = ActivityType.objects.all()
+    serializer_class = ActivityTypeSerializer
+
+
+class ActivityViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Activity` objects, serialize it to JSON with the given serializer,
+    then render it on /api/activity/activity/
+    """
+    queryset = Activity.objects.all()
+    serializer_class = ActivitySerializer
+
+
+class GuestViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Guest` objects, serialize it to JSON with the given serializer,
+    then render it on /api/activity/guest/
+    """
+    queryset = Guest.objects.all()
+    serializer_class = GuestSerializer
diff --git a/apps/activity/apps.py b/apps/activity/apps.py
index 29990f1b6338a186ded3d9dbbef20ef78fa3586f..bb72947f861f74172ecba66202f39e6eef6e5057 100644
--- a/apps/activity/apps.py
+++ b/apps/activity/apps.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.apps import AppConfig
diff --git a/apps/activity/models.py b/apps/activity/models.py
index 4dbc5522bcc09168eab2d1c34bdeea50be6dc33e..8f23060cddd71543003821bf3d27e0366fcb89c2 100644
--- a/apps/activity/models.py
+++ b/apps/activity/models.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.conf import settings
diff --git a/apps/api/urls.py b/apps/api/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e59a8c0acfc87ff928d4392fd06f46be41ac769
--- /dev/null
+++ b/apps/api/urls.py
@@ -0,0 +1,51 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django.conf.urls import url, include
+from django.contrib.auth.models import User
+from rest_framework import routers, serializers, viewsets
+from activity.api.urls import register_activity_urls
+from member.api.urls import register_members_urls
+from note.api.urls import register_note_urls
+
+
+class UserSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Users.
+    The djangorestframework plugin will analyse the model `User` and parse all fields in the API.
+    """
+    class Meta:
+        model = User
+        exclude = (
+            'password',
+            'groups',
+            'user_permissions',
+        )
+
+
+class UserViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `User` objects, serialize it to JSON with the given serializer,
+    then render it on /api/users/
+    """
+    queryset = User.objects.all()
+    serializer_class = UserSerializer
+
+
+# Routers provide an easy way of automatically determining the URL conf.
+# Register each app API router and user viewset
+router = routers.DefaultRouter()
+router.register('user', UserViewSet)
+register_members_urls(router, 'members')
+register_activity_urls(router, 'activity')
+register_note_urls(router, 'note')
+
+app_name = 'api'
+
+# Wire up our API using automatic URL routing.
+# Additionally, we include login URLs for the browsable API.
+urlpatterns = [
+    url('^', include(router.urls)),
+    url('^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
+]
diff --git a/apps/member/__init__.py b/apps/member/__init__.py
index ec189d6f8ca59293a2695d7749e9ba0c6062700e..298d1dda62f47f954a4df4922cf24ed6f16598e8 100644
--- a/apps/member/__init__.py
+++ b/apps/member/__init__.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 default_app_config = 'member.apps.MemberConfig'
diff --git a/apps/member/admin.py b/apps/member/admin.py
index f45d5f55741ff0f665ef632cfc20bc31999e5014..fb1073778fdae66126cf01bd6d3011d704a7e59a 100644
--- a/apps/member/admin.py
+++ b/apps/member/admin.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.contrib import admin
@@ -19,9 +18,9 @@ class ProfileInline(admin.StackedInline):
 
 
 class CustomUserAdmin(UserAdmin):
-    inlines = (ProfileInline,)
+    inlines = (ProfileInline, )
     list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
-    list_select_related = ('profile',)
+    list_select_related = ('profile', )
     form = ProfileForm
 
     def get_inline_instances(self, request, obj=None):
diff --git a/apps/member/api/__init__.py b/apps/member/api/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/member/api/serializers.py b/apps/member/api/serializers.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4df67993dcfd3b4728d02d240d0e59aeb853a12
--- /dev/null
+++ b/apps/member/api/serializers.py
@@ -0,0 +1,46 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from rest_framework import serializers
+
+from ..models import Profile, Club, Role, Membership
+
+
+class ProfileSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Profiles.
+    The djangorestframework plugin will analyse the model `Profile` and parse all fields in the API.
+    """
+    class Meta:
+        model = Profile
+        fields = '__all__'
+
+
+class ClubSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Clubs.
+    The djangorestframework plugin will analyse the model `Club` and parse all fields in the API.
+    """
+    class Meta:
+        model = Club
+        fields = '__all__'
+
+
+class RoleSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Roles.
+    The djangorestframework plugin will analyse the model `Role` and parse all fields in the API.
+    """
+    class Meta:
+        model = Role
+        fields = '__all__'
+
+
+class MembershipSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Memberships.
+    The djangorestframework plugin will analyse the model `Memberships` and parse all fields in the API.
+    """
+    class Meta:
+        model = Membership
+        fields = '__all__'
diff --git a/apps/member/api/urls.py b/apps/member/api/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..15bb83cac1204ddd45aef151887f878ccbd70b5d
--- /dev/null
+++ b/apps/member/api/urls.py
@@ -0,0 +1,14 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from .views import ProfileViewSet, ClubViewSet, RoleViewSet, MembershipViewSet
+
+
+def register_members_urls(router, path):
+    """
+    Configure router for Member REST API.
+    """
+    router.register(path + '/profile', ProfileViewSet)
+    router.register(path + '/club', ClubViewSet)
+    router.register(path + '/role', RoleViewSet)
+    router.register(path + '/membership', MembershipViewSet)
diff --git a/apps/member/api/views.py b/apps/member/api/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..79ba4c12afca3dee2c00445bd280d33b46934101
--- /dev/null
+++ b/apps/member/api/views.py
@@ -0,0 +1,47 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from rest_framework import viewsets
+
+from ..models import Profile, Club, Role, Membership
+from .serializers import ProfileSerializer, ClubSerializer, RoleSerializer, MembershipSerializer
+
+
+class ProfileViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Profile` objects, serialize it to JSON with the given serializer,
+    then render it on /api/members/profile/
+    """
+    queryset = Profile.objects.all()
+    serializer_class = ProfileSerializer
+
+
+class ClubViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Club` objects, serialize it to JSON with the given serializer,
+    then render it on /api/members/club/
+    """
+    queryset = Club.objects.all()
+    serializer_class = ClubSerializer
+
+
+class RoleViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Role` objects, serialize it to JSON with the given serializer,
+    then render it on /api/members/role/
+    """
+    queryset = Role.objects.all()
+    serializer_class = RoleSerializer
+
+
+class MembershipViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Membership` objects, serialize it to JSON with the given serializer,
+    then render it on /api/members/membership/
+    """
+    queryset = Membership.objects.all()
+    serializer_class = MembershipSerializer
diff --git a/apps/member/apps.py b/apps/member/apps.py
index 928c00e4a10c5b00db44ab7428941944b8414c45..2d7f4ab7daf5701bd0c54e4714b87d245a79c5f7 100644
--- a/apps/member/apps.py
+++ b/apps/member/apps.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.apps import AppConfig
diff --git a/apps/member/filters.py b/apps/member/filters.py
index fb1a212871254cb3717b044184f5334d20009b18..418e52fc680fb7888574924eb06623176a03680c 100644
--- a/apps/member/filters.py
+++ b/apps/member/filters.py
@@ -1,31 +1,33 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
-from django_filters import FilterSet, CharFilter,NumberFilter
+from django_filters import FilterSet, CharFilter
 from django.contrib.auth.models import User
 from django.db.models import CharField
 from crispy_forms.helper import FormHelper
 from crispy_forms.layout import Layout, Submit
 
-from .models import  Club
 
 class UserFilter(FilterSet):
     class Meta:
         model = User
-        fields = ['last_name','first_name','username','profile__section']
-        filter_overrides={
-            CharField:{
-                'filter_class':CharFilter,
-                'extra': lambda f:{
-                    'lookup_expr':'icontains'
+        fields = ['last_name', 'first_name', 'username', 'profile__section']
+        filter_overrides = {
+            CharField: {
+                'filter_class': CharFilter,
+                'extra': lambda f: {
+                    'lookup_expr': 'icontains'
                 }
             }
         }
 
+
 class UserFilterFormHelper(FormHelper):
     form_method = 'GET'
     layout = Layout(
-        'last_name','first_name','username','profile__section',
-        Submit('Submit','Apply Filter'),
+        'last_name',
+        'first_name',
+        'username',
+        'profile__section',
+        Submit('Submit', 'Apply Filter'),
     )
diff --git a/apps/member/forms.py b/apps/member/forms.py
index 59d3fec2c78a4a18d54a56ead1481fed077d59fe..66844cf4f37b3c0ebedc9625ea9beb9158dd714c 100644
--- a/apps/member/forms.py
+++ b/apps/member/forms.py
@@ -1,26 +1,23 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
-from django.contrib.auth.forms import UserChangeForm, UserCreationForm
+from dal import autocomplete
+from django.contrib.auth.forms import UserCreationForm
 from django.contrib.auth.models import User
 from django import forms
 
 from .models import Profile, Club, Membership
 
-from django.utils.translation import gettext_lazy as _
-
 from crispy_forms.helper import FormHelper
-from crispy_forms import layout, bootstrap
-from crispy_forms.bootstrap import InlineField, FormActions, StrictButton, Div, Field
+from crispy_forms.bootstrap import Div
 from crispy_forms.layout import Layout
 
 
-
 class SignUpForm(UserCreationForm):
     class Meta:
         model = User
-        fields = ['first_name','last_name','username','email']
+        fields = ['first_name', 'last_name', 'username', 'email']
+
 
 class ProfileForm(forms.ModelForm):
     """
@@ -31,37 +28,56 @@ class ProfileForm(forms.ModelForm):
         fields = '__all__'
         exclude = ['user']
 
+
 class ClubForm(forms.ModelForm):
     class Meta:
         model = Club
-        fields ='__all__'
+        fields = '__all__'
+
 
 class AddMembersForm(forms.Form):
     class Meta:
-        fields = ('',)
+        fields = ('', )
+
 
 class MembershipForm(forms.ModelForm):
     class Meta:
         model = Membership
-        fields = ('user','roles','date_start')
+        fields = ('user', 'roles', 'date_start')
+        # Le champ d'utilisateur est remplacé par un champ d'auto-complétion.
+        # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion
+        # et récupère les noms d'utilisateur valides
+        widgets = {
+            'user':
+            autocomplete.ModelSelect2(
+                url='member:user_autocomplete',
+                attrs={
+                    'data-placeholder': 'Nom ...',
+                    'data-minimum-input-length': 1,
+                },
+            ),
+        }
+
+
+MemberFormSet = forms.modelformset_factory(
+    Membership,
+    form=MembershipForm,
+    extra=2,
+    can_delete=True,
+)
 
-MemberFormSet = forms.modelformset_factory(Membership,
-                                           form=MembershipForm,
-                                           extra=2,
-                                           can_delete=True)
 
 class FormSetHelper(FormHelper):
-    def __init__(self,*args,**kwargs):
-        super().__init__(*args,**kwargs)
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
         self.form_tag = False
         self.form_method = 'POST'
-        self.form_class='form-inline'
+        self.form_class = 'form-inline'
         # self.template = 'bootstrap/table_inline_formset.html'
         self.layout = Layout(
             Div(
-                Div('user',css_class='col-sm-2'),
-                Div('roles',css_class='col-sm-2'),
-                Div('date_start',css_class='col-sm-2'),
+                Div('user', css_class='col-sm-2'),
+                Div('roles', css_class='col-sm-2'),
+                Div('date_start', css_class='col-sm-2'),
                 css_class="row formset-row",
-            )
-        )
+            ))
diff --git a/apps/member/models.py b/apps/member/models.py
index 883f9b4956ab78b31a3d8cb4b628efe465b9d8b6..cd754bd8d90eb648f1366a0de9505021fa35030d 100644
--- a/apps/member/models.py
+++ b/apps/member/models.py
@@ -1,14 +1,12 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.conf import settings
 from django.db import models
-from django.db.models.signals import post_save
-from django.dispatch import receiver
 from django.utils.translation import gettext_lazy as _
 from django.urls import reverse, reverse_lazy
 
+
 class Profile(models.Model):
     """
     An user profile
@@ -50,7 +48,8 @@ class Profile(models.Model):
         verbose_name_plural = _('user profile')
 
     def get_absolute_url(self):
-        return reverse('user_detail',args=(self.pk,))
+        return reverse('user_detail', args=(self.pk, ))
+
 
 class Club(models.Model):
     """
@@ -98,7 +97,7 @@ class Club(models.Model):
         return self.name
 
     def get_absolute_url(self):
-        return reverse_lazy('member:club_detail', args=(self.pk,))
+        return reverse_lazy('member:club_detail', args=(self.pk, ))
 
 
 class Role(models.Model):
@@ -118,6 +117,9 @@ class Role(models.Model):
         verbose_name = _('role')
         verbose_name_plural = _('roles')
 
+    def __str__(self):
+        return str(self.name)
+
 
 class Membership(models.Model):
     """
@@ -126,15 +128,15 @@ class Membership(models.Model):
     """
     user = models.ForeignKey(
         settings.AUTH_USER_MODEL,
-        on_delete=models.PROTECT
+        on_delete=models.PROTECT,
     )
     club = models.ForeignKey(
         Club,
-        on_delete=models.PROTECT
+        on_delete=models.PROTECT,
     )
     roles = models.ForeignKey(
         Role,
-        on_delete=models.PROTECT
+        on_delete=models.PROTECT,
     )
     date_start = models.DateField(
         verbose_name=_('membership starts on'),
diff --git a/apps/member/signals.py b/apps/member/signals.py
index 6688516b615a89c7ca57f80e6b6706841b546b55..4e945ad504ec4889419b9064e021183f6bc5aaaa 100644
--- a/apps/member/signals.py
+++ b/apps/member/signals.py
@@ -1,6 +1,2 @@
-#!/usr/bin/env python
-
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
-
diff --git a/apps/member/tables.py b/apps/member/tables.py
index 4218948c11aa5e516a12057e12594cde95bb5abd..a6de17d2f3a0cc3406f928ee8eb4376cd5f13e66 100644
--- a/apps/member/tables.py
+++ b/apps/member/tables.py
@@ -1,19 +1,24 @@
-#!/usr/bin/env python
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
 
 import django_tables2 as tables
-from .models import Club
-from django.conf import settings
 from django.contrib.auth.models import User
 
+from .models import Club
+
+
 class ClubTable(tables.Table):
     class Meta:
-        attrs = {'class':'table table-bordered table-condensed table-striped table-hover'}
+        attrs = {
+            'class': 'table table-condensed table-striped table-hover'
+        }
         model = Club
-        template_name = 'django_tables2/bootstrap.html'
-        fields = ('id','name','email')
-        row_attrs = {'class':'table-row',
-                     'data-href': lambda record: record.pk }
-
+        template_name = 'django_tables2/bootstrap4.html'
+        fields = ('id', 'name', 'email')
+        row_attrs = {
+            'class': 'table-row',
+            'data-href': lambda record: record.pk
+        }
 
 
 class UserTable(tables.Table):
@@ -21,7 +26,9 @@ class UserTable(tables.Table):
     solde = tables.Column(accessor='note.balance')
 
     class Meta:
-        attrs = {'class':'table table-bordered table-condensed table-striped table-hover'}
-        template_name = 'django_tables2/bootstrap.html'
-        fields = ('last_name','first_name','username','email')
+        attrs = {
+            'class': 'table table-condensed table-striped table-hover'
+        }
+        template_name = 'django_tables2/bootstrap4.html'
+        fields = ('last_name', 'first_name', 'username', 'email')
         model = User
diff --git a/apps/member/urls.py b/apps/member/urls.py
index 9bcc10959180f9da8eb5757f8ebbfd5e888ec38a..6a7ed5ce4004879805378e7645ebb78a2e374684 100644
--- a/apps/member/urls.py
+++ b/apps/member/urls.py
@@ -1,7 +1,4 @@
-#!/usr/bin/env python
-
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.urls import path
@@ -10,12 +7,16 @@ from . import views
 
 app_name = 'member'
 urlpatterns = [
-    path('signup/',views.UserCreateView.as_view(),name="signup"),
-    path('club/',views.ClubListView.as_view(),name="club_list"),
-    path('club/<int:pk>/',views.ClubDetailView.as_view(),name="club_detail"),
-    path('club/<int:pk>/add_member/',views.ClubAddMemberView.as_view(),name="club_add_member"),
-    path('club/create/',views.ClubCreateView.as_view(),name="club_create"),
-    path('user/',views.UserListView.as_view(),name="user_list"),
-    path('user/<int:pk>',views.UserDetailView.as_view(),name="user_detail"),
-    path('user/<int:pk>/update',views.UserUpdateView.as_view(),name="user_update_profile"),
+    path('signup/', views.UserCreateView.as_view(), name="signup"),
+    path('club/', views.ClubListView.as_view(), name="club_list"),
+    path('club/<int:pk>/', views.ClubDetailView.as_view(), name="club_detail"),
+    path('club/<int:pk>/add_member/', views.ClubAddMemberView.as_view(), name="club_add_member"),
+    path('club/create/', views.ClubCreateView.as_view(), name="club_create"),
+    path('user/', views.UserListView.as_view(), name="user_list"),
+    path('user/<int:pk>', views.UserDetailView.as_view(), name="user_detail"),
+    path('user/<int:pk>/update', views.UserUpdateView.as_view(), name="user_update_profile"),
+    path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
+
+    # API for the user autocompleter
+    path('user/user-autocomplete', views.UserAutocomplete.as_view(), name="user_autocomplete"),
 ]
diff --git a/apps/member/views.py b/apps/member/views.py
index 90ea5ec351311902db2243a5771809cea1973e6f..6f982c64f6463a954de664c04640ee20dd7fd9db 100644
--- a/apps/member/views.py
+++ b/apps/member/views.py
@@ -1,29 +1,26 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
+from dal import autocomplete
 from django.contrib.auth.mixins import LoginRequiredMixin
+from django.shortcuts import redirect
 from django.utils.translation import gettext_lazy as _
-from django.views.generic import CreateView, ListView, DetailView, UpdateView
-from django.http import HttpResponseRedirect
-from django.contrib.auth.forms import UserCreationForm
+from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
 from django.contrib.auth.models import User
 from django.urls import reverse_lazy
 from django.db.models import Q
-
 from django_tables2.views import SingleTableView
-
+from rest_framework.authtoken.models import Token
+from note.models import Alias, NoteUser
+from note.models.transactions import Transaction
+from note.tables import HistoryTable
 
 from .models import Profile, Club, Membership
-from .forms import  SignUpForm, ProfileForm, ClubForm,MembershipForm, MemberFormSet,FormSetHelper
-from .tables import ClubTable,UserTable
+from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, MemberFormSet, FormSetHelper
+from .tables import ClubTable, UserTable
 from .filters import UserFilter, UserFilterFormHelper
 
 
-from note.models.transactions import Transaction
-from note.tables import HistoryTable
-
 class UserCreateView(CreateView):
     """
     Une vue pour inscrire un utilisateur et lui créer un profile
@@ -31,10 +28,10 @@ class UserCreateView(CreateView):
 
     form_class = SignUpForm
     success_url = reverse_lazy('login')
-    template_name ='member/signup.html'
+    template_name = 'member/signup.html'
     second_form = ProfileForm
 
-    def get_context_data(self,**kwargs):
+    def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         context["profile_form"] = self.second_form()
 
@@ -49,40 +46,78 @@ class UserCreateView(CreateView):
             profile.save()
         return super().form_valid(form)
 
-class UserUpdateView(LoginRequiredMixin,UpdateView):
+
+class UserUpdateView(LoginRequiredMixin, UpdateView):
     model = User
-    fields = ['first_name','last_name','username','email']
+    fields = ['first_name', 'last_name', 'username', 'email']
     template_name = 'member/profile_update.html'
 
     second_form = ProfileForm
-    def get_context_data(self,**kwargs):
+
+    def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
-        context["profile_form"] = self.second_form(instance=context['user'].profile)
+        context['user_modified'] = context['user']
+        context['user'] = self.request.user
+        context["profile_form"] = self.second_form(
+            instance=context['user_modified'].profile)
+        context['title'] = _("Update Profile")
 
         return context
 
+    def get_form(self, form_class=None):
+        form = super().get_form(form_class)
+        if 'username' not in form.data:
+            return form
+
+        new_username = form.data['username']
+
+        # Si l'utilisateur cherche à modifier son pseudo, le nouveau pseudo ne doit pas être proche d'un alias existant
+        note = NoteUser.objects.filter(
+            alias__normalized_name=Alias.normalize(new_username))
+        if note.exists() and note.get().user != self.request.user:
+            form.add_error('username',
+                           _("An alias with a similar name already exists."))
+
+        return form
+
     def form_valid(self, form):
-        profile_form = ProfileForm(data=self.request.POST,instance=self.request.user.profile)
+        profile_form = ProfileForm(
+            data=self.request.POST,
+            instance=self.request.user.profile,
+        )
         if form.is_valid() and profile_form.is_valid():
-            user = form.save()
-            profile  = profile_form.save(commit=False)
+            new_username = form.data['username']
+            alias = Alias.objects.filter(name=new_username)
+            # Si le nouveau pseudo n'est pas un de nos alias, on supprime éventuellement un alias similaire pour le remplacer
+            if not alias.exists():
+                similar = Alias.objects.filter(
+                    normalized_name=Alias.normalize(new_username))
+                if similar.exists():
+                    similar.delete()
+
+            user = form.save(commit=False)
+            profile = profile_form.save(commit=False)
             profile.user = user
             profile.save()
+            user.save()
         return super().form_valid(form)
 
     def get_success_url(self, **kwargs):
-        if  kwargs:
-            return reverse_lazy('member:user_detail', kwargs = {'pk': kwargs['id']})
+        if kwargs:
+            return reverse_lazy('member:user_detail',
+                                kwargs={'pk': kwargs['id']})
         else:
-            return reverse_lazy('member:user_detail', args = (self.object.id,))
+            return reverse_lazy('member:user_detail', args=(self.object.id, ))
+
 
-class UserDetailView(LoginRequiredMixin,DetailView):
+class UserDetailView(LoginRequiredMixin, DetailView):
     """
-    Affiche les informations sur un utilisateur, sa note, ses clubs ...
+    Affiche les informations sur un utilisateur, sa note, ses clubs...
     """
     model = Profile
     context_object_name = "profile"
-    def get_context_data(slef,**kwargs):
+
+    def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         user = context['profile'].user
         history_list = \
@@ -91,9 +126,14 @@ class UserDetailView(LoginRequiredMixin,DetailView):
         club_list = \
             Membership.objects.all().filter(user=user).only("club")
         context['club_list'] = ClubTable(club_list)
+        context['title'] = _("Account #%(id)s: %(username)s") % {
+            'id': user.pk,
+            'username': user.username,
+        }
         return context
 
-class UserListView(LoginRequiredMixin,SingleTableView):
+
+class UserListView(LoginRequiredMixin, SingleTableView):
     """
     Affiche la liste des utilisateurs, avec une fonction de recherche statique
     """
@@ -103,44 +143,91 @@ class UserListView(LoginRequiredMixin,SingleTableView):
     filter_class = UserFilter
     formhelper_class = UserFilterFormHelper
 
-    def get_queryset(self,**kwargs):
+    def get_queryset(self, **kwargs):
         qs = super().get_queryset()
-        self.filter = self.filter_class(self.request.GET,queryset=qs)
+        self.filter = self.filter_class(self.request.GET, queryset=qs)
         self.filter.form.helper = self.formhelper_class()
         return self.filter.qs
 
-    def get_context_data(self,**kwargs):
+    def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         context["filter"] = self.filter
         return context
 
 
-###################################
-############## CLUB ###############
-###################################
+class ManageAuthTokens(LoginRequiredMixin, TemplateView):
+    """
+    Affiche le jeton d'authentification, et permet de le regénérer
+    """
+    model = Token
+    template_name = "member/manage_auth_tokens.html"
+
+    def get(self, request, *args, **kwargs):
+        if 'regenerate' in request.GET and Token.objects.filter(
+                user=request.user).exists():
+            Token.objects.get(user=self.request.user).delete()
+            return redirect(reverse_lazy('member:auth_token') + "?show",
+                            permanent=True)
 
-class ClubCreateView(LoginRequiredMixin,CreateView):
+        return super().get(request, *args, **kwargs)
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context['token'] = Token.objects.get_or_create(
+            user=self.request.user)[0]
+        return context
+
+
+class UserAutocomplete(autocomplete.Select2QuerySetView):
+    """
+    Auto complete users by usernames
+    """
+    def get_queryset(self):
+        """
+        Quand une personne cherche un utilisateur par pseudo, une requête est envoyée sur l'API dédiée à l'auto-complétion.
+        Cette fonction récupère la requête, et renvoie la liste filtrée des utilisateurs par pseudos.
+        """
+        #  Un utilisateur non connecté n'a accès à aucune information
+        if not self.request.user.is_authenticated:
+            return User.objects.none()
+
+        qs = User.objects.all()
+
+        if self.q:
+            qs = qs.filter(username__regex=self.q)
+
+        return qs
+
+
+# ******************************* #
+#              CLUB               #
+# ******************************* #
+
+
+class ClubCreateView(LoginRequiredMixin, CreateView):
     """
     Create Club
     """
     model = Club
     form_class = ClubForm
 
-    def form_valid(self,form):
+    def form_valid(self, form):
         return super().form_valid(form)
 
-class ClubListView(LoginRequiredMixin,SingleTableView):
+
+class ClubListView(LoginRequiredMixin, SingleTableView):
     """
     List existing Clubs
     """
     model = Club
     table_class = ClubTable
 
-class ClubDetailView(LoginRequiredMixin,DetailView):
+
+class ClubDetailView(LoginRequiredMixin, DetailView):
     model = Club
-    context_object_name="club"
+    context_object_name = "club"
 
-    def get_context_data(self,**kwargs):
+    def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         club = context["club"]
         club_transactions =  \
@@ -152,23 +239,30 @@ class ClubDetailView(LoginRequiredMixin,DetailView):
         context['member_list'] = club_member
         return context
 
-class ClubAddMemberView(LoginRequiredMixin,CreateView):
+
+class ClubAddMemberView(LoginRequiredMixin, CreateView):
     model = Membership
     form_class = MembershipForm
     template_name = 'member/add_members.html'
-    def get_context_data(self,**kwargs):
+
+    def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         context['formset'] = MemberFormSet()
         context['helper'] = FormSetHelper()
+
+        context['no_cache'] = True
+
         return context
 
-    def post(self,request,*args,**kwargs):
-        formset = MembershipFormset(request.POST)
-        if formset.is_valid():
-            return self.form_valid(formset)
-        else:
-            return self.form_invalid(formset)
+    def post(self, request, *args, **kwargs):
+        return
+        # TODO: Implement POST
+        # formset = MembershipFormset(request.POST)
+        # if formset.is_valid():
+        #     return self.form_valid(formset)
+        # else:
+        #     return self.form_invalid(formset)
 
-    def form_valid(self,formset):
+    def form_valid(self, formset):
         formset.save()
         return super().form_valid(formset)
diff --git a/apps/note/__init__.py b/apps/note/__init__.py
index 4773b310daa1e485c9301f33514e27ef13411a4b..f7c331b2dbe800989aa5662518bfaec1e54dbf81 100644
--- a/apps/note/__init__.py
+++ b/apps/note/__init__.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 default_app_config = 'note.apps.NoteConfig'
diff --git a/apps/note/admin.py b/apps/note/admin.py
index 298b91c052294d5a3a1b7a64d4fc6637adefb631..3a9721aeee3eaa7c30750ee4a31109a97fb6f5cb 100644
--- a/apps/note/admin.py
+++ b/apps/note/admin.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.contrib import admin
@@ -8,7 +7,7 @@ from polymorphic.admin import PolymorphicChildModelAdmin, \
     PolymorphicChildModelFilter, PolymorphicParentModelAdmin
 
 from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
-from .models.transactions import Transaction, TransactionTemplate
+from .models.transactions import Transaction, TransactionCategory, TransactionTemplate
 
 
 class AliasInlines(admin.TabularInline):
@@ -25,7 +24,10 @@ class NoteAdmin(PolymorphicParentModelAdmin):
     Parent regrouping all note types as children
     """
     child_models = (NoteClub, NoteSpecial, NoteUser)
-    list_filter = (PolymorphicChildModelFilter, 'is_active',)
+    list_filter = (
+        PolymorphicChildModelFilter,
+        'is_active',
+    )
 
     # Use a polymorphic list
     list_display = ('pretty', 'balance', 'is_active')
@@ -44,11 +46,12 @@ class NoteClubAdmin(PolymorphicChildModelAdmin):
     """
     Child for a club note, see NoteAdmin
     """
-    inlines = (AliasInlines,)
+    inlines = (AliasInlines, )
 
     # We can't change club after creation or the balance
     readonly_fields = ('club', 'balance')
-    search_fields = ('club',)
+    search_fields = ('club', )
+
     def has_add_permission(self, request):
         """
         A club note should not be manually added
@@ -67,7 +70,7 @@ class NoteSpecialAdmin(PolymorphicChildModelAdmin):
     """
     Child for a special note, see NoteAdmin
     """
-    readonly_fields = ('balance',)
+    readonly_fields = ('balance', )
 
 
 @admin.register(NoteUser)
@@ -75,7 +78,7 @@ class NoteUserAdmin(PolymorphicChildModelAdmin):
     """
     Child for an user note, see NoteAdmin
     """
-    inlines = (AliasInlines,)
+    inlines = (AliasInlines, )
 
     # We can't change user after creation or the balance
     readonly_fields = ('user', 'balance')
@@ -101,7 +104,10 @@ class TransactionAdmin(admin.ModelAdmin):
     list_display = ('created_at', 'poly_source', 'poly_destination',
                     'quantity', 'amount', 'transaction_type', 'valid')
     list_filter = ('transaction_type', 'valid')
-    autocomplete_fields = ('source', 'destination',)
+    autocomplete_fields = (
+        'source',
+        'destination',
+    )
 
     def poly_source(self, obj):
         """
@@ -136,8 +142,8 @@ class TransactionTemplateAdmin(admin.ModelAdmin):
     Admin customisation for TransactionTemplate
     """
     list_display = ('name', 'poly_destination', 'amount', 'template_type')
-    list_filter = ('template_type',)
-    autocomplete_fields = ('destination',)
+    list_filter = ('template_type', )
+    autocomplete_fields = ('destination', )
 
     def poly_destination(self, obj):
         """
@@ -146,3 +152,12 @@ class TransactionTemplateAdmin(admin.ModelAdmin):
         return str(obj.destination)
 
     poly_destination.short_description = _('destination')
+
+
+@admin.register(TransactionCategory)
+class TransactionCategoryAdmin(admin.ModelAdmin):
+    """
+    Admin customisation for TransactionTemplate
+    """
+    list_display = ('name', )
+    list_filter = ('name', )
diff --git a/apps/note/api/__init__.py b/apps/note/api/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py
new file mode 100644
index 0000000000000000000000000000000000000000..db0e35318ac4ca71b5902a22231ba11d098bd790
--- /dev/null
+++ b/apps/note/api/serializers.py
@@ -0,0 +1,103 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from rest_framework import serializers
+from rest_polymorphic.serializers import PolymorphicSerializer
+
+from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
+from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction
+
+
+class NoteSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Notes.
+    The djangorestframework plugin will analyse the model `Note` and parse all fields in the API.
+    """
+    class Meta:
+        model = Note
+        fields = '__all__'
+        extra_kwargs = {
+            'url': {
+                'view_name': 'project-detail',
+                'lookup_field': 'pk'
+            },
+        }
+
+
+class NoteClubSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Club's notes.
+    The djangorestframework plugin will analyse the model `NoteClub` and parse all fields in the API.
+    """
+    class Meta:
+        model = NoteClub
+        fields = '__all__'
+
+
+class NoteSpecialSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for special notes.
+    The djangorestframework plugin will analyse the model `NoteSpecial` and parse all fields in the API.
+    """
+    class Meta:
+        model = NoteSpecial
+        fields = '__all__'
+
+
+class NoteUserSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for User's notes.
+    The djangorestframework plugin will analyse the model `NoteUser` and parse all fields in the API.
+    """
+    class Meta:
+        model = NoteUser
+        fields = '__all__'
+
+
+class AliasSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Aliases.
+    The djangorestframework plugin will analyse the model `Alias` and parse all fields in the API.
+    """
+    class Meta:
+        model = Alias
+        fields = '__all__'
+
+
+class NotePolymorphicSerializer(PolymorphicSerializer):
+    model_serializer_mapping = {
+        Note: NoteSerializer,
+        NoteUser: NoteUserSerializer,
+        NoteClub: NoteClubSerializer,
+        NoteSpecial: NoteSpecialSerializer
+    }
+
+
+class TransactionTemplateSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Transaction templates.
+    The djangorestframework plugin will analyse the model `TransactionTemplate` and parse all fields in the API.
+    """
+    class Meta:
+        model = TransactionTemplate
+        fields = '__all__'
+
+
+class TransactionSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Transactions.
+    The djangorestframework plugin will analyse the model `Transaction` and parse all fields in the API.
+    """
+    class Meta:
+        model = Transaction
+        fields = '__all__'
+
+
+class MembershipTransactionSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Membership transactions.
+    The djangorestframework plugin will analyse the model `MembershipTransaction` and parse all fields in the API.
+    """
+    class Meta:
+        model = MembershipTransaction
+        fields = '__all__'
diff --git a/apps/note/api/urls.py b/apps/note/api/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..54218796211fb21173c9501b38f5cacff85f65dd
--- /dev/null
+++ b/apps/note/api/urls.py
@@ -0,0 +1,17 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from .views import NotePolymorphicViewSet, AliasViewSet, \
+    TransactionViewSet, TransactionTemplateViewSet, MembershipTransactionViewSet
+
+
+def register_note_urls(router, path):
+    """
+    Configure router for Note REST API.
+    """
+    router.register(path + '/note', NotePolymorphicViewSet)
+    router.register(path + '/alias', AliasViewSet)
+
+    router.register(path + '/transaction/transaction', TransactionViewSet)
+    router.register(path + '/transaction/template', TransactionTemplateViewSet)
+    router.register(path + '/transaction/membership', MembershipTransactionViewSet)
diff --git a/apps/note/api/views.py b/apps/note/api/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..94b4a47a287eec3d481ed3f5dc9d48f8a6cbb535
--- /dev/null
+++ b/apps/note/api/views.py
@@ -0,0 +1,161 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django.db.models import Q
+from rest_framework import viewsets
+
+from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
+from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction
+from .serializers import NoteSerializer, NotePolymorphicSerializer, NoteClubSerializer, NoteSpecialSerializer, \
+    NoteUserSerializer, AliasSerializer, \
+    TransactionTemplateSerializer, TransactionSerializer, MembershipTransactionSerializer
+
+
+class NoteViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Note` objects, serialize it to JSON with the given serializer,
+    then render it on /api/note/note/
+    """
+    queryset = Note.objects.all()
+    serializer_class = NoteSerializer
+
+
+class NoteClubViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `NoteClub` objects, serialize it to JSON with the given serializer,
+    then render it on /api/note/club/
+    """
+    queryset = NoteClub.objects.all()
+    serializer_class = NoteClubSerializer
+
+
+class NoteSpecialViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `NoteSpecial` objects, serialize it to JSON with the given serializer,
+    then render it on /api/note/special/
+    """
+    queryset = NoteSpecial.objects.all()
+    serializer_class = NoteSpecialSerializer
+
+
+class NoteUserViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `NoteUser` objects, serialize it to JSON with the given serializer,
+    then render it on /api/note/user/
+    """
+    queryset = NoteUser.objects.all()
+    serializer_class = NoteUserSerializer
+
+
+class NotePolymorphicViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Note` objects (with polymorhism), serialize it to JSON with the given serializer,
+    then render it on /api/note/note/
+    """
+    queryset = Note.objects.all()
+    serializer_class = NotePolymorphicSerializer
+
+    def get_queryset(self):
+        """
+        Parse query and apply filters.
+        :return: The filtered set of requested notes
+        """
+        queryset = Note.objects.all()
+
+        alias = self.request.query_params.get("alias", ".*")
+        queryset = queryset.filter(
+            Q(alias__name__regex=alias)
+            | Q(alias__normalized_name__regex=alias.lower()))
+
+        note_type = self.request.query_params.get("type", None)
+        if note_type:
+            types = str(note_type).lower()
+            if "user" in types:
+                queryset = queryset.filter(polymorphic_ctype__model="noteuser")
+            elif "club" in types:
+                queryset = queryset.filter(polymorphic_ctype__model="noteclub")
+            elif "special" in types:
+                queryset = queryset.filter(
+                    polymorphic_ctype__model="notespecial")
+            else:
+                queryset = queryset.none()
+
+        return queryset
+
+
+class AliasViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Alias` objects, serialize it to JSON with the given serializer,
+    then render it on /api/aliases/
+    """
+    queryset = Alias.objects.all()
+    serializer_class = AliasSerializer
+
+    def get_queryset(self):
+        """
+        Parse query and apply filters.
+        :return: The filtered set of requested aliases
+        """
+
+        queryset = Alias.objects.all()
+
+        alias = self.request.query_params.get("alias", ".*")
+        queryset = queryset.filter(
+            Q(name__regex=alias) | Q(normalized_name__regex=alias.lower()))
+
+        note_id = self.request.query_params.get("note", None)
+        if note_id:
+            queryset = queryset.filter(id=note_id)
+
+        note_type = self.request.query_params.get("type", None)
+        if note_type:
+            types = str(note_type).lower()
+            if "user" in types:
+                queryset = queryset.filter(
+                    note__polymorphic_ctype__model="noteuser")
+            elif "club" in types:
+                queryset = queryset.filter(
+                    note__polymorphic_ctype__model="noteclub")
+            elif "special" in types:
+                queryset = queryset.filter(
+                    note__polymorphic_ctype__model="notespecial")
+            else:
+                queryset = queryset.none()
+
+        return queryset
+
+
+class TransactionTemplateViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `TransactionTemplate` objects, serialize it to JSON with the given serializer,
+    then render it on /api/note/transaction/template/
+    """
+    queryset = TransactionTemplate.objects.all()
+    serializer_class = TransactionTemplateSerializer
+
+
+class TransactionViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Transaction` objects, serialize it to JSON with the given serializer,
+    then render it on /api/note/transaction/transaction/
+    """
+    queryset = Transaction.objects.all()
+    serializer_class = TransactionSerializer
+
+
+class MembershipTransactionViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `MembershipTransaction` objects, serialize it to JSON with the given serializer,
+    then render it on /api/note/transaction/membership/
+    """
+    queryset = MembershipTransaction.objects.all()
+    serializer_class = MembershipTransactionSerializer
diff --git a/apps/note/apps.py b/apps/note/apps.py
index c53f915a6b21a903990476766706249e64558335..4881e3b91b3676db9b123c6a9ce65830d7b905b6 100644
--- a/apps/note/apps.py
+++ b/apps/note/apps.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.apps import AppConfig
@@ -20,9 +19,9 @@ class NoteConfig(AppConfig):
         """
         post_save.connect(
             signals.save_user_note,
-            sender=settings.AUTH_USER_MODEL
+            sender=settings.AUTH_USER_MODEL,
         )
         post_save.connect(
             signals.save_club_note,
-            sender='member.Club'
+            sender='member.Club',
         )
diff --git a/apps/note/forms.py b/apps/note/forms.py
index d74fa5b4db8572da1e29fdad542f4796b8b3acce..e4fd344c1672031f4bf57279de23c6d965c32ffc 100644
--- a/apps/note/forms.py
+++ b/apps/note/forms.py
@@ -1,9 +1,94 @@
-#!/usr/bin/env python
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
 
+from dal import autocomplete
 from django import forms
-from .models import TransactionTemplate
+
+from .models import Transaction, TransactionTemplate
+
 
 class TransactionTemplateForm(forms.ModelForm):
     class Meta:
         model = TransactionTemplate
-        fields ='__all__'
+        fields = '__all__'
+
+        # Le champ de destination est remplacé par un champ d'auto-complétion.
+        # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion
+        # et récupère les aliases valides
+        # Pour force le type d'une note, il faut rajouter le paramètre :
+        # forward=(forward.Const('TYPE', 'note_type') où TYPE est dans {user, club, special}
+        widgets = {
+            'destination':
+            autocomplete.ModelSelect2(
+                url='note:note_autocomplete',
+                attrs={
+                    'data-placeholder': 'Note ...',
+                    'data-minimum-input-length': 1,
+                },
+            ),
+        }
+
+
+class TransactionForm(forms.ModelForm):
+    def save(self, commit=True):
+        self.instance.transaction_type = 'transfert'
+
+        super().save(commit)
+
+    class Meta:
+        model = Transaction
+        fields = (
+            'source',
+            'destination',
+            'reason',
+            'amount',
+        )
+
+        # Voir ci-dessus
+        widgets = {
+            'source':
+            autocomplete.ModelSelect2(
+                url='note:note_autocomplete',
+                attrs={
+                    'data-placeholder': 'Note ...',
+                    'data-minimum-input-length': 1,
+                },
+            ),
+            'destination':
+            autocomplete.ModelSelect2(
+                url='note:note_autocomplete',
+                attrs={
+                    'data-placeholder': 'Note ...',
+                    'data-minimum-input-length': 1,
+                },
+            ),
+        }
+
+
+class ConsoForm(forms.ModelForm):
+    def save(self, commit=True):
+        button: TransactionTemplate = TransactionTemplate.objects.filter(
+            name=self.data['button']).get()
+        self.instance.destination = button.destination
+        self.instance.amount = button.amount
+        self.instance.transaction_type = 'bouton'
+        self.instance.reason = button.name
+        super().save(commit)
+
+    class Meta:
+        model = Transaction
+        fields = ('source', )
+
+        # Le champ d'utilisateur est remplacé par un champ d'auto-complétion.
+        # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion
+        # et récupère les aliases de note valides
+        widgets = {
+            'source':
+            autocomplete.ModelSelect2(
+                url='note:note_autocomplete',
+                attrs={
+                    'data-placeholder': 'Note ...',
+                    'data-minimum-input-length': 1,
+                },
+            ),
+        }
diff --git a/apps/note/models/__init__.py b/apps/note/models/__init__.py
index b00572ce4a83a36d03791895e0a9ca33fc2b6644..7e6cc310e823e28eea3f8d8e40b8e1d98b87ac7c 100644
--- a/apps/note/models/__init__.py
+++ b/apps/note/models/__init__.py
@@ -1,14 +1,13 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
 from .transactions import MembershipTransaction, Transaction, \
-    TransactionTemplate
+    TransactionCategory, TransactionTemplate
 
 __all__ = [
     # Notes
     'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser',
     # Transactions
-    'MembershipTransaction', 'Transaction', 'TransactionTemplate',
+    'MembershipTransaction', 'Transaction', 'TransactionCategory', 'TransactionTemplate',
 ]
diff --git a/apps/note/models/notes.py b/apps/note/models/notes.py
index e3ab7931b8ee88cd2047c5c4d43ec0609bdb226e..3b616f0e754abaee90a917ae0288d0410ce1de77 100644
--- a/apps/note/models/notes.py
+++ b/apps/note/models/notes.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 import unicodedata
@@ -10,7 +9,6 @@ from django.core.validators import RegexValidator
 from django.db import models
 from django.utils.translation import gettext_lazy as _
 from polymorphic.models import PolymorphicModel
-
 """
 Defines each note types
 """
@@ -34,8 +32,7 @@ class Note(PolymorphicModel):
         default=True,
         help_text=_(
             'Designates whether this note should be treated as active. '
-            'Unselect this instead of deleting notes.'
-        ),
+            'Unselect this instead of deleting notes.'),
     )
     display_image = models.ImageField(
         verbose_name=_('display image'),
@@ -85,7 +82,8 @@ class Note(PolymorphicModel):
         """
         Verify alias (simulate save)
         """
-        aliases = Alias.objects.filter(name=str(self))
+        aliases = Alias.objects.filter(
+            normalized_name=Alias.normalize(str(self)))
         if aliases.exists():
             # Alias exists, so check if it is linked to this note
             if aliases.first().note != self:
@@ -181,15 +179,15 @@ class Alias(models.Model):
         validators=[
             RegexValidator(
                 regex=settings.ALIAS_VALIDATOR_REGEX,
-                message=_('Invalid alias')
+                message=_('Invalid alias'),
             )
-        ] if settings.ALIAS_VALIDATOR_REGEX else []
+        ] if settings.ALIAS_VALIDATOR_REGEX else [],
     )
     normalized_name = models.CharField(
         max_length=255,
         unique=True,
         default='',
-        editable=False
+        editable=False,
     )
     note = models.ForeignKey(
         Note,
@@ -209,11 +207,9 @@ class Alias(models.Model):
         Normalizes a string: removes most diacritics and does casefolding
         """
         return ''.join(
-            char
-            for char in unicodedata.normalize('NFKD', string.casefold())
+            char for char in unicodedata.normalize('NFKD', string.casefold())
             if all(not unicodedata.category(char).startswith(cat)
-                   for cat in {'M', 'P', 'Z', 'C'})
-        ).casefold()
+                   for cat in {'M', 'P', 'Z', 'C'})).casefold()
 
     def save(self, *args, **kwargs):
         """
@@ -229,7 +225,13 @@ class Alias(models.Model):
             raise ValidationError(_('Alias too long.'))
         try:
             if self != Alias.objects.get(normalized_name=normalized_name):
-                raise ValidationError(_('An alias with a similar name '
-                                        'already exists.'))
+                raise ValidationError(
+                    _('An alias with a similar name '
+                      'already exists.'))
         except Alias.DoesNotExist:
             pass
+
+    def delete(self, using=None, keep_parents=False):
+        if self.name == str(self.note):
+            raise ValidationError(_("You can't delete your main alias."))
+        return super().delete(using, keep_parents)
diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py
index 7a058607fb0b467f87d87f54fb65221e256ac8f8..4db2eda1aa41a4230db4714d6bbea7a583bf4b63 100644
--- a/apps/note/models/transactions.py
+++ b/apps/note/models/transactions.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.db import models
@@ -7,16 +6,36 @@ from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
 from django.urls import reverse
 
-from .notes import Note,NoteClub
+from .notes import Note, NoteClub
 
 """
 Defines transactions
 """
 
 
+class TransactionCategory(models.Model):
+    """
+    Defined a recurrent transaction category
+
+    Example: food, softs, ...
+    """
+    name = models.CharField(
+        verbose_name=_("name"),
+        max_length=31,
+        unique=True,
+    )
+
+    class Meta:
+        verbose_name = _("transaction category")
+        verbose_name_plural = _("transaction categories")
+
+    def __str__(self):
+        return str(self.name)
+
+
 class TransactionTemplate(models.Model):
     """
-    Defined a reccurent transaction
+    Defined a recurrent transaction
 
     associated to selling something (a burger, a beer, ...)
     """
@@ -35,9 +54,11 @@ class TransactionTemplate(models.Model):
         verbose_name=_('amount'),
         help_text=_('in centimes'),
     )
-    template_type = models.CharField(
+    template_type = models.ForeignKey(
+        TransactionCategory,
+        on_delete=models.PROTECT,
         verbose_name=_('type'),
-        max_length=31
+        max_length=31,
     )
 
     description = models.CharField(
@@ -50,7 +71,7 @@ class TransactionTemplate(models.Model):
         verbose_name_plural = _("transaction templates")
 
     def get_absolute_url(self):
-        return reverse('note:template_update',args=(self.pk,))
+        return reverse('note:template_update', args=(self.pk, ))
 
 
 class Transaction(models.Model):
@@ -83,9 +104,7 @@ class Transaction(models.Model):
         verbose_name=_('quantity'),
         default=1,
     )
-    amount = models.PositiveIntegerField(
-        verbose_name=_('amount'),
-    )
+    amount = models.PositiveIntegerField(verbose_name=_('amount'), )
     transaction_type = models.CharField(
         verbose_name=_('type'),
         max_length=31,
@@ -127,7 +146,7 @@ class Transaction(models.Model):
 
     @property
     def total(self):
-        return self.amount*self.quantity
+        return self.amount * self.quantity
 
 
 class MembershipTransaction(Transaction):
diff --git a/apps/note/signals.py b/apps/note/signals.py
index 6e5d5c9e93312419ee338afc834a0bcc625a3f1d..ad376ee082e43230a7d2fd16be6f6975f982dd22 100644
--- a/apps/note/signals.py
+++ b/apps/note/signals.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 
diff --git a/apps/note/tables.py b/apps/note/tables.py
index 4d4e9608c1236126b5cce3c3490bf882fd418f11..43a1ef7413566ce1c127131d7addf094910efbb0 100644
--- a/apps/note/tables.py
+++ b/apps/note/tables.py
@@ -1,20 +1,26 @@
-#!/usr/bin/env python
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
 import django_tables2 as tables
+from django.db.models import F
+
 from .models.transactions import Transaction
 
 
 class HistoryTable(tables.Table):
     class Meta:
-        attrs = {'class':'table table-bordered table-condensed table-striped table-hover'}
+        attrs = {
+            'class':
+            'table table-condensed table-striped table-hover'
+        }
         model = Transaction
-        template_name = 'django_tables2/bootstrap.html'
-        sequence = ('...','total','valid')
+        template_name = 'django_tables2/bootstrap4.html'
+        sequence = ('...', 'total', 'valid')
 
-    total = tables.Column() #will use Transaction.total() !!
+    total = tables.Column()  # will use Transaction.total() !!
 
-    def order_total(self, QuerySet, is_descending):
+    def order_total(self, queryset, is_descending):
         # needed for rendering
-        QuerySet = QuerySet.annotate(
-            total=F('amount') * F('quantity')
-        ).order_by(('-' if is_descending else '') + 'total')
-        return (QuerySet, True)
+        queryset = queryset.annotate(total=F('amount') * F('quantity')) \
+            .order_by(('-' if is_descending else '') + 'total')
+        return (queryset, True)
diff --git a/apps/note/templatetags/pretty_money.py b/apps/note/templatetags/pretty_money.py
index ec0a0d5b3b9c4325ba1ab4988056606789ba335a..12530c6e22d4ea0eb86b46d018ffbcddb0c44f8c 100644
--- a/apps/note/templatetags/pretty_money.py
+++ b/apps/note/templatetags/pretty_money.py
@@ -1,11 +1,21 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
 from django import template
 
 
 def pretty_money(value):
-    if value%100 == 0:
-        return "{:s}{:d} €".format("- " if value < 0 else "", abs(value) // 100)
+    if value % 100 == 0:
+        return "{:s}{:d} €".format(
+            "- " if value < 0 else "",
+            abs(value) // 100,
+        )
     else:
-        return "{:s}{:d} € {:02d}".format("- " if value < 0 else "", abs(value) // 100, abs(value) % 100)
+        return "{:s}{:d} € {:02d}".format(
+            "- " if value < 0 else "",
+            abs(value) // 100,
+            abs(value) % 100,
+        )
 
 
 register = template.Library()
diff --git a/apps/note/urls.py b/apps/note/urls.py
index 5e423d465b6339124063fe1f59e28e93f96d2f4a..fea911f6ac5ebdeaa871240fe56c764d024db675 100644
--- a/apps/note/urls.py
+++ b/apps/note/urls.py
@@ -1,15 +1,19 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.urls import path
 
 from . import views
+from .models import Note
 
 app_name = 'note'
 urlpatterns = [
     path('transfer/', views.TransactionCreate.as_view(), name='transfer'),
-    path('buttons/create/',views.TransactionTemplateCreateView.as_view(),name='template_create'),
-    path('buttons/update/<int:pk>/',views.TransactionTemplateUpdateView.as_view(),name='template_update'),
-    path('buttons/',views.TransactionTemplateListView.as_view(),name='template_list')
+    path('buttons/create/', views.TransactionTemplateCreateView.as_view(), name='template_create'),
+    path('buttons/update/<int:pk>/', views.TransactionTemplateUpdateView.as_view(), name='template_update'),
+    path('buttons/', views.TransactionTemplateListView.as_view(), name='template_list'),
+    path('consos/', views.ConsoView.as_view(), name='consos'),
+
+    # API for the note autocompleter
+    path('note-autocomplete/', views.NoteAutocomplete.as_view(model=Note), name='note_autocomplete'),
 ]
diff --git a/apps/note/views.py b/apps/note/views.py
index 08f4f63093a89226a6d3548b9ee7e9399449dacc..167ef4f0d4c4c8a45c251e7e60af2ebb622b98b1 100644
--- a/apps/note/views.py
+++ b/apps/note/views.py
@@ -1,13 +1,16 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
+from dal import autocomplete
 from django.contrib.auth.mixins import LoginRequiredMixin
+from django.db.models import Q
+from django.urls import reverse
 from django.utils.translation import gettext_lazy as _
-from django.views.generic import CreateView, ListView, DetailView, UpdateView
+from django.views.generic import CreateView, ListView, UpdateView
+
+from .models import Transaction, TransactionTemplate, Alias
+from .forms import TransactionForm, TransactionTemplateForm, ConsoForm
 
-from .models import Transaction,TransactionTemplate
-from .forms import TransactionTemplateForm
 
 class TransactionCreate(LoginRequiredMixin, CreateView):
     """
@@ -16,7 +19,7 @@ class TransactionCreate(LoginRequiredMixin, CreateView):
     TODO: If user have sufficient rights, they can transfer from an other note
     """
     model = Transaction
-    fields = ('destination', 'amount', 'reason')
+    form_class = TransactionForm
 
     def get_context_data(self, **kwargs):
         """
@@ -25,24 +28,127 @@ class TransactionCreate(LoginRequiredMixin, CreateView):
         context = super().get_context_data(**kwargs)
         context['title'] = _('Transfer money from your account '
                              'to one or others')
+
+        context['no_cache'] = True
+
         return context
 
-class TransactionTemplateCreateView(LoginRequiredMixin,CreateView):
+    def get_form(self, form_class=None):
+        """
+        If the user has no right to transfer funds, then it won't have the choice of the source of the transfer.
+        """
+        form = super().get_form(form_class)
+
+        if False:  # TODO: fix it with "if %user has no right to transfer funds"
+            del form.fields['source']
+
+        return form
+
+    def form_valid(self, form):
+        """
+        If the user has no right to transfer funds, then it will be the source of the transfer by default.
+        """
+        if False:  # TODO: fix it with "if %user has no right to transfer funds"
+            form.instance.source = self.request.user.note
+
+        return super().form_valid(form)
+
+
+class NoteAutocomplete(autocomplete.Select2QuerySetView):
+    """
+    Auto complete note by aliases
+    """
+    def get_queryset(self):
+        """
+        Quand une personne cherche un alias, une requête est envoyée sur l'API dédiée à l'auto-complétion.
+        Cette fonction récupère la requête, et renvoie la liste filtrée des aliases.
+        """
+        #  Un utilisateur non connecté n'a accès à aucune information
+        if not self.request.user.is_authenticated:
+            return Alias.objects.none()
+
+        qs = Alias.objects.all()
+
+        # self.q est le paramètre de la recherche
+        if self.q:
+            qs = qs.filter(Q(name__regex=self.q) | Q(normalized_name__regex=Alias.normalize(self.q)))\
+                .order_by('normalized_name').distinct()
+
+        # Filtrage par type de note (user, club, special)
+        note_type = self.forwarded.get("note_type", None)
+        if note_type:
+            types = str(note_type).lower()
+            if "user" in types:
+                qs = qs.filter(note__polymorphic_ctype__model="noteuser")
+            elif "club" in types:
+                qs = qs.filter(note__polymorphic_ctype__model="noteclub")
+            elif "special" in types:
+                qs = qs.filter(note__polymorphic_ctype__model="notespecial")
+            else:
+                qs = qs.none()
+
+        return qs
+
+    def get_result_label(self, result):
+        # Gère l'affichage de l'alias dans la recherche
+        res = result.name
+        note_name = str(result.note)
+        if res != note_name:
+            res += " (aka. " + note_name + ")"
+        return res
+
+    def get_result_value(self, result):
+        # Le résultat renvoyé doit être l'identifiant de la note, et non de l'alias
+        return str(result.note.pk)
+
+
+class TransactionTemplateCreateView(LoginRequiredMixin, CreateView):
     """
     Create TransactionTemplate
     """
     model = TransactionTemplate
     form_class = TransactionTemplateForm
 
-class TransactionTemplateListView(LoginRequiredMixin,ListView):
+
+class TransactionTemplateListView(LoginRequiredMixin, ListView):
     """
     List TransactionsTemplates
     """
     model = TransactionTemplate
     form_class = TransactionTemplateForm
 
-class TransactionTemplateUpdateView(LoginRequiredMixin,UpdateView):
+
+class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
     """
     """
     model = TransactionTemplate
-    form_class=TransactionTemplateForm
+    form_class = TransactionTemplateForm
+
+
+class ConsoView(LoginRequiredMixin, CreateView):
+    """
+    Consume
+    """
+    model = Transaction
+    template_name = "note/conso_form.html"
+    form_class = ConsoForm
+
+    def get_context_data(self, **kwargs):
+        """
+        Add some context variables in template such as page title
+        """
+        context = super().get_context_data(**kwargs)
+        context['transaction_templates'] = TransactionTemplate.objects.all() \
+            .order_by('template_type')
+        context['title'] = _("Consommations")
+
+        # select2 compatibility
+        context['no_cache'] = True
+
+        return context
+
+    def get_success_url(self):
+        """
+        When clicking a button, reload the same page
+        """
+        return reverse('note:consos')
diff --git a/entrypoint.sh b/entrypoint.sh
index da32571a5e100b30349c044ba3fded737f3777ac..f05e962ae116b4831ea506704b828ab9c5988748 100755
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -1,6 +1,11 @@
 #!/bin/bash
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
 python manage.py compilemessages
 python manage.py makemigrations
+
+# Wait for database
 sleep 5
 python manage.py migrate
 
diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po
new file mode 100644
index 0000000000000000000000000000000000000000..3aadf83e4dca55978262aa6747f4aa56e3de05e8
--- /dev/null
+++ b/locale/de/LC_MESSAGES/django.po
@@ -0,0 +1,517 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-02-21 13:50+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: apps/activity/apps.py:10 apps/activity/models.py:76
+msgid "activity"
+msgstr ""
+
+#: apps/activity/models.py:19 apps/activity/models.py:44
+#: apps/member/models.py:60 apps/member/models.py:111
+#: apps/note/models/notes.py:176 apps/note/models/transactions.py:23
+#: apps/note/models/transactions.py:43 templates/member/profile_detail.html:11
+msgid "name"
+msgstr ""
+
+#: apps/activity/models.py:23
+msgid "can invite"
+msgstr ""
+
+#: apps/activity/models.py:26
+msgid "guest entry fee"
+msgstr ""
+
+#: apps/activity/models.py:30
+msgid "activity type"
+msgstr ""
+
+#: apps/activity/models.py:31
+msgid "activity types"
+msgstr ""
+
+#: apps/activity/models.py:48
+msgid "description"
+msgstr ""
+
+#: apps/activity/models.py:54 apps/note/models/notes.py:152
+#: apps/note/models/transactions.py:60 apps/note/models/transactions.py:104
+msgid "type"
+msgstr ""
+
+#: apps/activity/models.py:60
+msgid "organizer"
+msgstr ""
+
+#: apps/activity/models.py:66
+msgid "attendees club"
+msgstr ""
+
+#: apps/activity/models.py:69
+msgid "start date"
+msgstr ""
+
+#: apps/activity/models.py:72
+msgid "end date"
+msgstr ""
+
+#: apps/activity/models.py:77
+msgid "activities"
+msgstr ""
+
+#: apps/activity/models.py:108
+msgid "guest"
+msgstr ""
+
+#: apps/activity/models.py:109
+msgid "guests"
+msgstr ""
+
+#: apps/member/apps.py:10
+msgid "member"
+msgstr ""
+
+#: apps/member/models.py:23
+msgid "phone number"
+msgstr ""
+
+#: apps/member/models.py:29 templates/member/profile_detail.html:24
+msgid "section"
+msgstr ""
+
+#: apps/member/models.py:30
+msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
+msgstr ""
+
+#: apps/member/models.py:36 templates/member/profile_detail.html:27
+msgid "address"
+msgstr ""
+
+#: apps/member/models.py:42
+msgid "paid"
+msgstr ""
+
+#: apps/member/models.py:47 apps/member/models.py:48
+msgid "user profile"
+msgstr ""
+
+#: apps/member/models.py:65
+msgid "email"
+msgstr ""
+
+#: apps/member/models.py:70
+msgid "membership fee"
+msgstr ""
+
+#: apps/member/models.py:74
+msgid "membership duration"
+msgstr ""
+
+#: apps/member/models.py:75
+msgid "The longest time a membership can last (NULL = infinite)."
+msgstr ""
+
+#: apps/member/models.py:80
+msgid "membership start"
+msgstr ""
+
+#: apps/member/models.py:81
+msgid "How long after January 1st the members can renew their membership."
+msgstr ""
+
+#: apps/member/models.py:86
+msgid "membership end"
+msgstr ""
+
+#: apps/member/models.py:87
+msgid ""
+"How long the membership can last after January 1st of the next year after "
+"members can renew their membership."
+msgstr ""
+
+#: apps/member/models.py:93 apps/note/models/notes.py:127
+msgid "club"
+msgstr ""
+
+#: apps/member/models.py:94
+msgid "clubs"
+msgstr ""
+
+#: apps/member/models.py:117
+msgid "role"
+msgstr ""
+
+#: apps/member/models.py:118
+msgid "roles"
+msgstr ""
+
+#: apps/member/models.py:142
+msgid "membership starts on"
+msgstr ""
+
+#: apps/member/models.py:145
+msgid "membership ends on"
+msgstr ""
+
+#: apps/member/models.py:149
+msgid "fee"
+msgstr ""
+
+#: apps/member/models.py:153
+msgid "membership"
+msgstr ""
+
+#: apps/member/models.py:154
+msgid "memberships"
+msgstr ""
+
+#: apps/member/views.py:63 templates/member/profile_detail.html:42
+msgid "Update Profile"
+msgstr ""
+
+#: apps/member/views.py:79 apps/note/models/notes.py:229
+msgid "An alias with a similar name already exists."
+msgstr ""
+
+#: apps/member/views.py:129
+#, python-format
+msgid "Account #%(id)s: %(username)s"
+msgstr ""
+
+#: apps/note/admin.py:118 apps/note/models/transactions.py:86
+msgid "source"
+msgstr ""
+
+#: apps/note/admin.py:126 apps/note/admin.py:154
+#: apps/note/models/transactions.py:51 apps/note/models/transactions.py:92
+msgid "destination"
+msgstr ""
+
+#: apps/note/apps.py:14 apps/note/models/notes.py:48
+msgid "note"
+msgstr ""
+
+#: apps/note/models/notes.py:26
+msgid "account balance"
+msgstr ""
+
+#: apps/note/models/notes.py:27
+msgid "in centimes, money credited for this instance"
+msgstr ""
+
+#: apps/note/models/notes.py:31
+msgid "active"
+msgstr ""
+
+#: apps/note/models/notes.py:34
+msgid ""
+"Designates whether this note should be treated as active. Unselect this "
+"instead of deleting notes."
+msgstr ""
+
+#: apps/note/models/notes.py:38
+msgid "display image"
+msgstr ""
+
+#: apps/note/models/notes.py:43 apps/note/models/transactions.py:95
+msgid "created at"
+msgstr ""
+
+#: apps/note/models/notes.py:49
+msgid "notes"
+msgstr ""
+
+#: apps/note/models/notes.py:57
+msgid "Note"
+msgstr ""
+
+#: apps/note/models/notes.py:67 apps/note/models/notes.py:90
+msgid "This alias is already taken."
+msgstr ""
+
+#: apps/note/models/notes.py:105
+msgid "user"
+msgstr ""
+
+#: apps/note/models/notes.py:109
+msgid "one's note"
+msgstr ""
+
+#: apps/note/models/notes.py:110
+msgid "users note"
+msgstr ""
+
+#: apps/note/models/notes.py:116
+#, python-format
+msgid "%(user)s's note"
+msgstr ""
+
+#: apps/note/models/notes.py:131
+msgid "club note"
+msgstr ""
+
+#: apps/note/models/notes.py:132
+msgid "clubs notes"
+msgstr ""
+
+#: apps/note/models/notes.py:138
+#, python-format
+msgid "Note of %(club)s club"
+msgstr ""
+
+#: apps/note/models/notes.py:158
+msgid "special note"
+msgstr ""
+
+#: apps/note/models/notes.py:159
+msgid "special notes"
+msgstr ""
+
+#: apps/note/models/notes.py:182
+msgid "Invalid alias"
+msgstr ""
+
+#: apps/note/models/notes.py:198
+msgid "alias"
+msgstr ""
+
+#: apps/note/models/notes.py:199 templates/member/profile_detail.html:33
+msgid "aliases"
+msgstr ""
+
+#: apps/note/models/notes.py:225
+msgid "Alias too long."
+msgstr ""
+
+#: apps/note/models/notes.py:236
+msgid "You can't delete your main alias."
+msgstr ""
+
+#: apps/note/models/transactions.py:29
+msgid "transaction category"
+msgstr ""
+
+#: apps/note/models/transactions.py:30
+msgid "transaction categories"
+msgstr ""
+
+#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:102
+msgid "amount"
+msgstr ""
+
+#: apps/note/models/transactions.py:55
+msgid "in centimes"
+msgstr ""
+
+#: apps/note/models/transactions.py:65
+msgid "transaction template"
+msgstr ""
+
+#: apps/note/models/transactions.py:66
+msgid "transaction templates"
+msgstr ""
+
+#: apps/note/models/transactions.py:99
+msgid "quantity"
+msgstr ""
+
+#: apps/note/models/transactions.py:108
+msgid "reason"
+msgstr ""
+
+#: apps/note/models/transactions.py:112
+msgid "valid"
+msgstr ""
+
+#: apps/note/models/transactions.py:117
+msgid "transaction"
+msgstr ""
+
+#: apps/note/models/transactions.py:118
+msgid "transactions"
+msgstr ""
+
+#: apps/note/models/transactions.py:160
+msgid "membership transaction"
+msgstr ""
+
+#: apps/note/models/transactions.py:161
+msgid "membership transactions"
+msgstr ""
+
+#: apps/note/views.py:29
+msgid "Transfer money from your account to one or others"
+msgstr ""
+
+#: note_kfet/settings/base.py:148
+msgid "German"
+msgstr ""
+
+#: note_kfet/settings/base.py:149
+msgid "English"
+msgstr ""
+
+#: note_kfet/settings/base.py:150
+msgid "French"
+msgstr ""
+
+#: templates/base.html:13
+msgid "The ENS Paris-Saclay BDE note."
+msgstr ""
+
+#: templates/member/club_detail.html:10
+msgid "Membership starts on"
+msgstr ""
+
+#: templates/member/club_detail.html:12
+msgid "Membership ends on"
+msgstr ""
+
+#: templates/member/club_detail.html:14
+msgid "Membership duration"
+msgstr ""
+
+#: templates/member/club_detail.html:18 templates/member/profile_detail.html:30
+msgid "balance"
+msgstr ""
+
+#: templates/member/manage_auth_tokens.html:16
+msgid "Token"
+msgstr ""
+
+#: templates/member/manage_auth_tokens.html:23
+msgid "Created"
+msgstr ""
+
+#: templates/member/manage_auth_tokens.html:31
+msgid "Regenerate token"
+msgstr ""
+
+#: templates/member/profile_detail.html:11
+msgid "first name"
+msgstr ""
+
+#: templates/member/profile_detail.html:14
+msgid "username"
+msgstr ""
+
+#: templates/member/profile_detail.html:17
+msgid "password"
+msgstr ""
+
+#: templates/member/profile_detail.html:20
+msgid "Change password"
+msgstr ""
+
+#: templates/member/profile_detail.html:38
+msgid "Manage auth token"
+msgstr ""
+
+#: templates/member/profile_detail.html:54
+msgid "View my memberships"
+msgstr ""
+
+#: templates/member/profile_update.html:13
+msgid "Save Changes"
+msgstr ""
+
+#: templates/member/signup.html:14
+msgid "Sign Up"
+msgstr ""
+
+#: templates/note/transaction_form.html:35
+msgid "Transfer"
+msgstr ""
+
+#: templates/registration/logged_out.html:8
+msgid "Thanks for spending some quality time with the Web site today."
+msgstr ""
+
+#: templates/registration/logged_out.html:9
+msgid "Log in again"
+msgstr ""
+
+#: templates/registration/login.html:7 templates/registration/login.html:8
+#: templates/registration/login.html:22
+#: templates/registration/password_reset_complete.html:10
+msgid "Log in"
+msgstr ""
+
+#: templates/registration/login.html:13
+#, python-format
+msgid ""
+"You are authenticated as %(username)s, but are not authorized to access this "
+"page. Would you like to login to a different account?"
+msgstr ""
+
+#: templates/registration/login.html:23
+msgid "Forgotten your password or username?"
+msgstr ""
+
+#: templates/registration/password_change_done.html:8
+msgid "Your password was changed."
+msgstr ""
+
+#: templates/registration/password_change_form.html:9
+msgid ""
+"Please enter your old password, for security's sake, and then enter your new "
+"password twice so we can verify you typed it in correctly."
+msgstr ""
+
+#: templates/registration/password_change_form.html:11
+#: templates/registration/password_reset_confirm.html:12
+msgid "Change my password"
+msgstr ""
+
+#: templates/registration/password_reset_complete.html:8
+msgid "Your password has been set.  You may go ahead and log in now."
+msgstr ""
+
+#: templates/registration/password_reset_confirm.html:9
+msgid ""
+"Please enter your new password twice so we can verify you typed it in "
+"correctly."
+msgstr ""
+
+#: templates/registration/password_reset_confirm.html:15
+msgid ""
+"The password reset link was invalid, possibly because it has already been "
+"used.  Please request a new password reset."
+msgstr ""
+
+#: templates/registration/password_reset_done.html:8
+msgid ""
+"We've emailed you instructions for setting your password, if an account "
+"exists with the email you entered. You should receive them shortly."
+msgstr ""
+
+#: templates/registration/password_reset_done.html:9
+msgid ""
+"If you don't receive an email, please make sure you've entered the address "
+"you registered with, and check your spam folder."
+msgstr ""
+
+#: templates/registration/password_reset_form.html:8
+msgid ""
+"Forgotten your password? Enter your email address below, and we'll email "
+"instructions for setting a new one."
+msgstr ""
+
+#: templates/registration/password_reset_form.html:11
+msgid "Reset my password"
+msgstr ""
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 96da86e15f3170a57421012b625a2b5190e67d6f..bdf4fc8ff6512e2386875078be780cef87a506a2 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -3,7 +3,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-08-14 15:14+0200\n"
+"POT-Creation-Date: 2020-02-21 13:50+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -13,356 +13,427 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 
-#: apps/activity/apps.py:11 apps/activity/models.py:70
+#: apps/activity/apps.py:10 apps/activity/models.py:76
 msgid "activity"
 msgstr "activité"
 
-#: apps/activity/models.py:15 apps/activity/models.py:38
-#: apps/member/models.py:59 apps/member/models.py:107
-#: apps/note/models/notes.py:167 apps/note/models/transactions.py:19
-#: templates/member/profile_detail.html:10
+#: apps/activity/models.py:19 apps/activity/models.py:44
+#: apps/member/models.py:60 apps/member/models.py:111
+#: apps/note/models/notes.py:176 apps/note/models/transactions.py:23
+#: apps/note/models/transactions.py:43 templates/member/profile_detail.html:11
 msgid "name"
 msgstr "nom"
 
-#: apps/activity/models.py:19
+#: apps/activity/models.py:23
 msgid "can invite"
 msgstr "peut inviter"
 
-#: apps/activity/models.py:22
+#: apps/activity/models.py:26
 msgid "guest entry fee"
 msgstr "cotisation de l'entrée invité"
 
-#: apps/activity/models.py:26
+#: apps/activity/models.py:30
 msgid "activity type"
 msgstr "type d'activité"
 
-#: apps/activity/models.py:27
+#: apps/activity/models.py:31
 msgid "activity types"
 msgstr "types d'activité"
 
-#: apps/activity/models.py:42
+#: apps/activity/models.py:48
 msgid "description"
 msgstr "description"
 
-#: apps/activity/models.py:48 apps/note/models/notes.py:149
-#: apps/note/models/transactions.py:34 apps/note/models/transactions.py:71
+#: apps/activity/models.py:54 apps/note/models/notes.py:152
+#: apps/note/models/transactions.py:60 apps/note/models/transactions.py:104
 msgid "type"
 msgstr "type"
 
-#: apps/activity/models.py:54
+#: apps/activity/models.py:60
 msgid "organizer"
 msgstr "organisateur"
 
-#: apps/activity/models.py:60
+#: apps/activity/models.py:66
 msgid "attendees club"
 msgstr ""
 
-#: apps/activity/models.py:63
+#: apps/activity/models.py:69
 msgid "start date"
 msgstr "date de début"
 
-#: apps/activity/models.py:66
+#: apps/activity/models.py:72
 msgid "end date"
 msgstr "date de fin"
 
-#: apps/activity/models.py:71
+#: apps/activity/models.py:77
 msgid "activities"
 msgstr "activités"
 
-#: apps/activity/models.py:100
+#: apps/activity/models.py:108
 msgid "guest"
 msgstr "invité"
 
-#: apps/activity/models.py:101
+#: apps/activity/models.py:109
 msgid "guests"
 msgstr "invités"
 
-#: apps/member/apps.py:11
+#: apps/member/apps.py:10
 msgid "member"
 msgstr "adhérent"
 
-#: apps/member/models.py:24
+#: apps/member/models.py:23
 msgid "phone number"
 msgstr "numéro de téléphone"
 
-#: apps/member/models.py:30 templates/member/profile_detail.html:18
+#: apps/member/models.py:29 templates/member/profile_detail.html:24
 msgid "section"
 msgstr "section"
 
-#: apps/member/models.py:31
+#: apps/member/models.py:30
 msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
 msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
 
-#: apps/member/models.py:37 templates/member/profile_detail.html:20
+#: apps/member/models.py:36 templates/member/profile_detail.html:27
 msgid "address"
 msgstr "adresse"
 
-#: apps/member/models.py:43
+#: apps/member/models.py:42
 msgid "paid"
 msgstr "payé"
 
-#: apps/member/models.py:48 apps/member/models.py:49
+#: apps/member/models.py:47 apps/member/models.py:48
 msgid "user profile"
 msgstr "profil utilisateur"
 
-#: apps/member/models.py:64
+#: apps/member/models.py:65
 msgid "email"
 msgstr "courriel"
 
-#: apps/member/models.py:69
+#: apps/member/models.py:70
 msgid "membership fee"
 msgstr "cotisation pour adhérer"
 
-#: apps/member/models.py:73
+#: apps/member/models.py:74
 msgid "membership duration"
 msgstr "durée de l'adhésion"
 
-#: apps/member/models.py:74
+#: apps/member/models.py:75
 msgid "The longest time a membership can last (NULL = infinite)."
 msgstr "La durée maximale d'une adhésion (NULL = infinie)."
 
-#: apps/member/models.py:79
+#: apps/member/models.py:80
 msgid "membership start"
 msgstr "début de l'adhésion"
 
-#: apps/member/models.py:80
+#: apps/member/models.py:81
 msgid "How long after January 1st the members can renew their membership."
 msgstr ""
+"Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur "
+"adhésion."
 
-#: apps/member/models.py:85
+#: apps/member/models.py:86
 msgid "membership end"
 msgstr "fin de l'adhésion"
 
-#: apps/member/models.py:86
+#: apps/member/models.py:87
 msgid ""
 "How long the membership can last after January 1st of the next year after "
 "members can renew their membership."
 msgstr ""
+"Combien de temps l'adhésion peut durer après le 1er Janvier de l'année "
+"suivante avant que les adhérents peuvent renouveler leur adhésion."
 
-#: apps/member/models.py:92 apps/note/models/notes.py:125
+#: apps/member/models.py:93 apps/note/models/notes.py:127
 msgid "club"
 msgstr "club"
 
-#: apps/member/models.py:93
+#: apps/member/models.py:94
 msgid "clubs"
 msgstr "clubs"
 
-#: apps/member/models.py:113
+#: apps/member/models.py:117
 msgid "role"
 msgstr "rôle"
 
-#: apps/member/models.py:114
+#: apps/member/models.py:118
 msgid "roles"
 msgstr "rôles"
 
-#: apps/member/models.py:134
+#: apps/member/models.py:142
 msgid "membership starts on"
 msgstr "l'adhésion commence le"
 
-#: apps/member/models.py:137
+#: apps/member/models.py:145
 msgid "membership ends on"
 msgstr "l'adhésion finie le"
 
-#: apps/member/models.py:141
+#: apps/member/models.py:149
 msgid "fee"
 msgstr "cotisation"
 
-#: apps/member/models.py:145
+#: apps/member/models.py:153
 msgid "membership"
 msgstr "adhésion"
 
-#: apps/member/models.py:146
+#: apps/member/models.py:154
 msgid "memberships"
 msgstr "adhésions"
 
-#: apps/note/admin.py:112 apps/note/models/transactions.py:51
+#: apps/member/views.py:63 templates/member/profile_detail.html:42
+msgid "Update Profile"
+msgstr "Modifier le profil"
+
+#: apps/member/views.py:79 apps/note/models/notes.py:229
+msgid "An alias with a similar name already exists."
+msgstr "Un alias avec un nom similaire existe déjà."
+
+#: apps/member/views.py:129
+#, python-format
+msgid "Account #%(id)s: %(username)s"
+msgstr "Compte n°%(id)s : %(username)s"
+
+#: apps/note/admin.py:118 apps/note/models/transactions.py:86
 msgid "source"
 msgstr "source"
 
-#: apps/note/admin.py:120 apps/note/admin.py:148
-#: apps/note/models/transactions.py:27 apps/note/models/transactions.py:57
+#: apps/note/admin.py:126 apps/note/admin.py:154
+#: apps/note/models/transactions.py:51 apps/note/models/transactions.py:92
 msgid "destination"
 msgstr "destination"
 
-#: apps/note/apps.py:15 apps/note/models/notes.py:47
+#: apps/note/apps.py:14 apps/note/models/notes.py:48
 msgid "note"
 msgstr "note"
 
-#: apps/note/models/notes.py:24
+#: apps/note/models/notes.py:26
 msgid "account balance"
 msgstr "solde du compte"
 
-#: apps/note/models/notes.py:25
+#: apps/note/models/notes.py:27
 msgid "in centimes, money credited for this instance"
 msgstr "en centimes, argent crédité pour cette instance"
 
-#: apps/note/models/notes.py:29
+#: apps/note/models/notes.py:31
 msgid "active"
 msgstr "actif"
 
-#: apps/note/models/notes.py:32
+#: apps/note/models/notes.py:34
 msgid ""
 "Designates whether this note should be treated as active. Unselect this "
 "instead of deleting notes."
 msgstr ""
 "Indique si la note est active. Désactiver cela plutôt que supprimer la note."
 
-#: apps/note/models/notes.py:37
+#: apps/note/models/notes.py:38
 msgid "display image"
 msgstr "image affichée"
 
-#: apps/note/models/notes.py:42 apps/note/models/transactions.py:60
+#: apps/note/models/notes.py:43 apps/note/models/transactions.py:95
 msgid "created at"
 msgstr "créée le"
 
-#: apps/note/models/notes.py:48
+#: apps/note/models/notes.py:49
 msgid "notes"
 msgstr "notes"
 
-#: apps/note/models/notes.py:56
+#: apps/note/models/notes.py:57
 msgid "Note"
 msgstr "Note"
 
-#: apps/note/models/notes.py:66 apps/note/models/notes.py:88
+#: apps/note/models/notes.py:67 apps/note/models/notes.py:90
 msgid "This alias is already taken."
 msgstr "Cet alias est déjà pris."
 
-#: apps/note/models/notes.py:103
+#: apps/note/models/notes.py:105
 msgid "user"
 msgstr "utilisateur"
 
-#: apps/note/models/notes.py:107
+#: apps/note/models/notes.py:109
 msgid "one's note"
 msgstr "note d'un utilisateur"
 
-#: apps/note/models/notes.py:108
+#: apps/note/models/notes.py:110
 msgid "users note"
 msgstr "notes des utilisateurs"
 
-#: apps/note/models/notes.py:114
+#: apps/note/models/notes.py:116
 #, python-format
 msgid "%(user)s's note"
 msgstr "Note de %(user)s"
 
-#: apps/note/models/notes.py:129
+#: apps/note/models/notes.py:131
 msgid "club note"
 msgstr "note d'un club"
 
-#: apps/note/models/notes.py:130
+#: apps/note/models/notes.py:132
 msgid "clubs notes"
 msgstr "notes des clubs"
 
-#: apps/note/models/notes.py:136
+#: apps/note/models/notes.py:138
 #, python-format
-msgid "Note for %(club)s club"
+msgid "Note of %(club)s club"
 msgstr "Note du club %(club)s"
 
-#: apps/note/models/notes.py:155
+#: apps/note/models/notes.py:158
 msgid "special note"
 msgstr "note spéciale"
 
-#: apps/note/models/notes.py:156
+#: apps/note/models/notes.py:159
 msgid "special notes"
 msgstr "notes spéciales"
 
-#: apps/note/models/notes.py:173
+#: apps/note/models/notes.py:182
 msgid "Invalid alias"
 msgstr "Alias invalide"
 
-#: apps/note/models/notes.py:189
+#: apps/note/models/notes.py:198
 msgid "alias"
 msgstr "alias"
 
-#: apps/note/models/notes.py:190
+#: apps/note/models/notes.py:199 templates/member/profile_detail.html:33
 msgid "aliases"
 msgstr "alias"
 
-#: apps/note/models/notes.py:218
+#: apps/note/models/notes.py:225
 msgid "Alias too long."
 msgstr "L'alias est trop long."
 
-#: apps/note/models/notes.py:221
-msgid "An alias with a similar name already exists."
-msgstr "Un alias avec un nom similaire existe déjà."
+#: apps/note/models/notes.py:236
+msgid "You can't delete your main alias."
+msgstr "Vous ne pouvez pas supprimer votre alias principal."
+
+#: apps/note/models/transactions.py:29
+msgid "transaction category"
+msgstr "catégorie de transaction"
 
-#: apps/note/models/transactions.py:30 apps/note/models/transactions.py:68
+#: apps/note/models/transactions.py:30
+msgid "transaction categories"
+msgstr "catégories de transaction"
+
+#: apps/note/models/transactions.py:54 apps/note/models/transactions.py:102
 msgid "amount"
 msgstr "montant"
 
-#: apps/note/models/transactions.py:31
+#: apps/note/models/transactions.py:55
 msgid "in centimes"
 msgstr "en centimes"
 
-#: apps/note/models/transactions.py:39
+#: apps/note/models/transactions.py:65
 msgid "transaction template"
 msgstr "modèle de transaction"
 
-#: apps/note/models/transactions.py:40
+#: apps/note/models/transactions.py:66
 msgid "transaction templates"
 msgstr "modèles de transaction"
 
-#: apps/note/models/transactions.py:64
+#: apps/note/models/transactions.py:99
 msgid "quantity"
 msgstr "quantité"
 
-#: apps/note/models/transactions.py:75
+#: apps/note/models/transactions.py:108
 msgid "reason"
 msgstr "raison"
 
-#: apps/note/models/transactions.py:79
+#: apps/note/models/transactions.py:112
 msgid "valid"
 msgstr "valide"
 
-#: apps/note/models/transactions.py:84
+#: apps/note/models/transactions.py:117
 msgid "transaction"
 msgstr "transaction"
 
-#: apps/note/models/transactions.py:85
+#: apps/note/models/transactions.py:118
 msgid "transactions"
 msgstr "transactions"
 
-#: apps/note/models/transactions.py:118
+#: apps/note/models/transactions.py:160
 msgid "membership transaction"
 msgstr "transaction d'adhésion"
 
-#: apps/note/models/transactions.py:119
+#: apps/note/models/transactions.py:161
 msgid "membership transactions"
 msgstr "transactions d'adhésion"
 
-#: apps/note/views.py:26
+#: apps/note/views.py:29
 msgid "Transfer money from your account to one or others"
 msgstr "Transfert d'argent de ton compte vers un ou plusieurs autres"
 
-#: note_kfet/settings.py:140
+#: note_kfet/settings/base.py:148
+msgid "German"
+msgstr ""
+
+#: note_kfet/settings/base.py:149
 msgid "English"
 msgstr ""
 
-#: note_kfet/settings.py:141
+#: note_kfet/settings/base.py:150
 msgid "French"
 msgstr ""
 
-#: templates/base.html:14
+#: templates/base.html:13
 msgid "The ENS Paris-Saclay BDE note."
-msgstr ""
+msgstr "La note du BDE de l'ENS Paris-Saclay."
+
+#: templates/member/club_detail.html:10
+msgid "Membership starts on"
+msgstr "L'adhésion commence le"
+
+#: templates/member/club_detail.html:12
+msgid "Membership ends on"
+msgstr "L'adhésion finie le"
+
+#: templates/member/club_detail.html:14
+msgid "Membership duration"
+msgstr "Durée de l'adhésion"
+
+#: templates/member/club_detail.html:18 templates/member/profile_detail.html:30
+msgid "balance"
+msgstr "solde du compte"
 
-#: templates/member/profile_detail.html:12
+#: templates/member/manage_auth_tokens.html:16
+msgid "Token"
+msgstr "Jeton"
+
+#: templates/member/manage_auth_tokens.html:23
+msgid "Created"
+msgstr "Créé le"
+
+#: templates/member/manage_auth_tokens.html:31
+msgid "Regenerate token"
+msgstr "Regénérer le jeton"
+
+#: templates/member/profile_detail.html:11
 msgid "first name"
 msgstr ""
 
 #: templates/member/profile_detail.html:14
-#, fuzzy
-#| msgid "name"
 msgid "username"
-msgstr "nom"
+msgstr "nom d'utilisateur"
 
-#: templates/member/profile_detail.html:22
+#: templates/member/profile_detail.html:17
 #, fuzzy
-#| msgid "account balance"
-msgid "balance"
-msgstr "solde du compte"
+#| msgid "Change password"
+msgid "password"
+msgstr "Changer le mot de passe"
 
-#: templates/member/profile_detail.html:26
+#: templates/member/profile_detail.html:20
 msgid "Change password"
+msgstr "Changer le mot de passe"
+
+#: templates/member/profile_detail.html:38
+msgid "Manage auth token"
+msgstr "Gérer les jetons d'authentification"
+
+#: templates/member/profile_detail.html:54
+msgid "View my memberships"
+msgstr "Voir mes adhésions"
+
+#: templates/member/profile_update.html:13
+msgid "Save Changes"
+msgstr "Sauvegarder les changements"
+
+#: templates/member/signup.html:14
+msgid "Sign Up"
 msgstr ""
 
 #: templates/note/transaction_form.html:35
diff --git a/note_kfet/middlewares.py b/note_kfet/middlewares.py
new file mode 100644
index 0000000000000000000000000000000000000000..73b87e363c32faf1d0fa836122fb2a2674347894
--- /dev/null
+++ b/note_kfet/middlewares.py
@@ -0,0 +1,38 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django.http import HttpResponseRedirect
+
+from urllib.parse import urlencode, parse_qs, urlsplit, urlunsplit
+
+
+class TurbolinksMiddleware(object):
+    """
+    Send the `Turbolinks-Location` header in response to a visit that was redirected,
+    and Turbolinks will replace the browser's topmost history entry.
+    """
+
+    def __init__(self, get_response):
+        self.get_response = get_response
+
+    def __call__(self, request):
+        response = self.get_response(request)
+
+        is_turbolinks = request.META.get('HTTP_TURBOLINKS_REFERRER')
+        is_response_redirect = response.has_header('Location')
+
+        if is_turbolinks:
+            if is_response_redirect:
+                location = response['Location']
+                prev_location = request.session.pop('_turbolinks_redirect_to', None)
+                if prev_location is not None:
+                    # relative subsequent redirect
+                    if location.startswith('.'):
+                        location = prev_location.split('?')[0] + location
+                request.session['_turbolinks_redirect_to'] = location
+            else:
+                if request.session.get('_turbolinks_redirect_to'):
+                    location = request.session.pop('_turbolinks_redirect_to')
+                    response['Turbolinks-Location'] = location
+        return response
+
diff --git a/note_kfet/settings/__init__.py b/note_kfet/settings/__init__.py
index 234e70b9dc2d805f6c975155cb61a5bc74f2020a..68a40b887c39d6dde8bd55514cbea624048772e3 100644
--- a/note_kfet/settings/__init__.py
+++ b/note_kfet/settings/__init__.py
@@ -30,12 +30,17 @@ read_env()
 app_stage = os.environ.get('DJANGO_APP_STAGE', 'dev')
 if app_stage == 'prod':
     from .production import *
-    DATABASES["default"]["PASSWORD"] = os.environ.get('DJANGO_DB_PASSWORD','CHANGE_ME_IN_ENV_SETTINGS');
-    SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY','CHANGE_ME_IN_ENV_SETTINGS');
-    ALLOWED_HOSTS.append(os.environ.get('ALLOWED_HOSTS','localhost'));
+    DATABASES["default"]["PASSWORD"] = os.environ.get('DJANGO_DB_PASSWORD','CHANGE_ME_IN_ENV_SETTINGS')
+    SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY','CHANGE_ME_IN_ENV_SETTINGS')
+    ALLOWED_HOSTS.append(os.environ.get('ALLOWED_HOSTS','localhost'))
 else:
     from .development import *
 
+try:
+    from .secrets import *
+except ImportError:
+    pass
+
 # env variables set at the of in /env/bin/activate
 # don't forget to unset in deactivate !
 
diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py
index e583d8a6b0edd7e4105f502d0c5442a857b1e46f..9019b4e07c39a3a0588e91bec7c7b580a4d2d4ba 100644
--- a/note_kfet/settings/base.py
+++ b/note_kfet/settings/base.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 import os
@@ -50,11 +49,18 @@ INSTALLED_APPS = [
     'django.contrib.sites',
     'django.contrib.messages',
     'django.contrib.staticfiles',
+    # API
+    'rest_framework',
+    'rest_framework.authtoken',
+    # Autocomplete
+    'dal',
+    'dal_select2',
 
     # Note apps
     'activity',
     'member',
     'note',
+    'api',
 ]
 LOGIN_REDIRECT_URL = '/note/transfer/'
 
@@ -69,6 +75,7 @@ MIDDLEWARE = [
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.middleware.locale.LocaleMiddleware',
     'django.contrib.sites.middleware.CurrentSiteMiddleware',
+    'note_kfet.middlewares.TurbolinksMiddleware',
 ]
 
 ROOT_URLCONF = 'note_kfet.urls'
@@ -117,6 +124,18 @@ AUTHENTICATION_BACKENDS = (
     'guardian.backends.ObjectPermissionBackend',
 )
 
+REST_FRAMEWORK = {
+    # Use Django's standard `django.contrib.auth` permissions,
+    # or allow read-only access for unauthenticated users.
+    'DEFAULT_PERMISSION_CLASSES': [
+        # TODO Maybe replace it with our custom permissions system
+        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
+    ],
+    'DEFAULT_AUTHENTICATION_CLASSES': [
+        'rest_framework.authentication.TokenAuthentication',
+    ]
+}
+
 ANONYMOUS_USER_NAME = None  # Disable guardian anonymous user
 
 GUARDIAN_GET_CONTENT_TYPE = 'polymorphic.contrib.guardian.get_polymorphic_base_content_type'
@@ -127,6 +146,7 @@ GUARDIAN_GET_CONTENT_TYPE = 'polymorphic.contrib.guardian.get_polymorphic_base_c
 LANGUAGE_CODE = 'en'
 
 LANGUAGES = [
+    ('de', _('German')),
     ('en', _('English')),
     ('fr', _('French')),
 ]
diff --git a/note_kfet/settings/development.py b/note_kfet/settings/development.py
index f6d48776f5a963009fafd26180bb353c8f0befe5..60055ee21d8ff5c43ce09b64a30ecb3a1fd7f374 100644
--- a/note_kfet/settings/development.py
+++ b/note_kfet/settings/development.py
@@ -1,3 +1,6 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
 ########################
 # Development Settings #
 ########################
diff --git a/note_kfet/settings/production.py b/note_kfet/settings/production.py
index 02c46ed21af9d0b02c49acb65f029f132c439a71..296c17a4948f1e48ddcca3eb3ffae39ebdaef2ec 100644
--- a/note_kfet/settings/production.py
+++ b/note_kfet/settings/production.py
@@ -1,3 +1,6 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
 ########################
 # Production  Settings #
 ########################
diff --git a/note_kfet/urls.py b/note_kfet/urls.py
index 88bb6bb9c7b3b73b8528f0bd5162f1f942988205..303e229aaed0ea291620383ce71e7c27fecbf410 100644
--- a/note_kfet/urls.py
+++ b/note_kfet/urls.py
@@ -1,5 +1,4 @@
-# -*- mode: python; coding: utf-8 -*-
-# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.contrib import admin
@@ -19,4 +18,7 @@ urlpatterns = [
     path('accounts/', include('django.contrib.auth.urls')),
     path('admin/doc/', include('django.contrib.admindocs.urls')),
     path('admin/', admin.site.urls),
+
+    # Include Django REST API
+    path('api/', include('api.urls')),
 ]
diff --git a/note_kfet/wsgi.py b/note_kfet/wsgi.py
index 94a8e054fa4ec9bb4d116e5e6fd380065d6a938e..b89430ec723d2522deee1c0f3c93572d4120c5a8 100644
--- a/note_kfet/wsgi.py
+++ b/note_kfet/wsgi.py
@@ -1,4 +1,3 @@
-# -*- mode: python; coding: utf-8 -*-
 # Copyright (C) 2016-2019 by BDE
 # SPDX-License-Identifier: GPL-3.0-or-later
 
diff --git a/requirements.txt b/requirements.txt
index 39b32fdf87288b75dfd9883501f9a1efe73fbae3..21c24808b0f562f2b0f71ea19a1ed1d2193b7b89 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,16 +1,20 @@
 certifi==2019.6.16
 chardet==3.0.4
 defusedxml==0.6.0
-Django==2.2.3
+Django~=2.2
 django-allauth==0.39.1
+django-autocomplete-light==3.5.1
 django-crispy-forms==1.7.2
 django-extensions==2.1.9
 django-filter==2.2.0
 django-guardian==2.1.0
 django-polymorphic==2.0.3
+djangorestframework==3.9.0
+django-rest-polymorphic==0.1.8
 django-reversion==3.0.3
 django-tables2==2.1.0
 docutils==0.14
+psycopg2==2.8.4
 idna==2.8
 oauthlib==3.1.0
 Pillow==6.1.0
diff --git a/static/favicon/android-chrome-192x192.png b/static/favicon/android-chrome-192x192.png
index 5b31f298276637f9997dccc8dad10be846c5d136..38b7efeee89060046077d5b10dd88b9a5df3565f 100644
Binary files a/static/favicon/android-chrome-192x192.png and b/static/favicon/android-chrome-192x192.png differ
diff --git a/static/favicon/android-chrome-512x512.png b/static/favicon/android-chrome-512x512.png
index bb9e4daaed45893728a5cef590d245a38a417138..321f2b5a05cfe5c06db23c0d33201b59c365a0df 100644
Binary files a/static/favicon/android-chrome-512x512.png and b/static/favicon/android-chrome-512x512.png differ
diff --git a/static/favicon/apple-touch-icon.png b/static/favicon/apple-touch-icon.png
index c0b462bde2ab8f89522ebcc9c975878f39a26acf..8f6be04d0145d5d52577564df1e90cf42650e953 100644
Binary files a/static/favicon/apple-touch-icon.png and b/static/favicon/apple-touch-icon.png differ
diff --git a/static/favicon/browserconfig.xml b/static/favicon/browserconfig.xml
index 49604f0ed5d0f3eccff6bc07dc504a3e7f206f8b..c8771dff66fb5a1d6a1f8abc5058da561a89bed6 100644
--- a/static/favicon/browserconfig.xml
+++ b/static/favicon/browserconfig.xml
@@ -3,7 +3,7 @@
     <msapplication>
         <tile>
             <square150x150logo src="/static/favicon/mstile-150x150.png"/>
-            <TileColor>#da532c</TileColor>
+            <TileColor>#00a300</TileColor>
         </tile>
     </msapplication>
 </browserconfig>
diff --git a/static/favicon/favicon-16x16.png b/static/favicon/favicon-16x16.png
index 5db7ed945375943b1950cd0878c568b7f8d60d09..14ff80a4050e9edc31a7120246d5ccae26b8b827 100644
Binary files a/static/favicon/favicon-16x16.png and b/static/favicon/favicon-16x16.png differ
diff --git a/static/favicon/favicon-32x32.png b/static/favicon/favicon-32x32.png
index a3d9263f297fd183b2a402677135c0ddd85cfd60..cb0827345bd0ff74a7c4c24e5ddcc61cc6ebe397 100644
Binary files a/static/favicon/favicon-32x32.png and b/static/favicon/favicon-32x32.png differ
diff --git a/static/favicon/favicon.ico b/static/favicon/favicon.ico
index 53393cda7e0850a26d561567294181c849f5021e..0bf544e051b9061348db04aa2b9c1b9655780860 100644
Binary files a/static/favicon/favicon.ico and b/static/favicon/favicon.ico differ
diff --git a/static/favicon/mstile-150x150.png b/static/favicon/mstile-150x150.png
index 378274c99391b5f2d3524fe3f6e33c0eed5286a2..0c44361b277e35f3759f20054fd4e000861bf0ee 100644
Binary files a/static/favicon/mstile-150x150.png and b/static/favicon/mstile-150x150.png differ
diff --git a/static/favicon/safari-pinned-tab.svg b/static/favicon/safari-pinned-tab.svg
index a8425e8a0f6af47044afaebbd730ff595ac30d68..cb5555d64d6c99079c82f5e380e9b9d42f467313 100644
--- a/static/favicon/safari-pinned-tab.svg
+++ b/static/favicon/safari-pinned-tab.svg
@@ -1 +1 @@
-<svg version="1" xmlns="http://www.w3.org/2000/svg" width="1678.667" height="1678.667" viewBox="0 0 1259.000000 1259.000000"><path d="M652.1 9.6C618 101 575.3 192.4 528 275c-19.3 33.7-21.4 37.1-22.1 35.8-.3-.7-2.6-9.8-4.9-20.1-2.4-10.3-4.7-18.2-5.1-17.5-.9 1.6-5.9 22.3-14.4 59.3-3.7 15.9-9.4 38.3-12.6 49.7-8.4 29.7-10.9 42.4-11.6 60.3-.9 24.1 2.5 37.8 11.9 48.1 2.8 3.1 3.6 4.5 2.3 4-20.1-7.5-38.8-12.5-58-15.3-18-2.6-51.4-2.3-70.4.6-56.9 8.7-106.8 33.5-144.8 72.2-21 21.3-31.3 40.5-31.3 58.3.1 9.2 1.3 11.9 13.8 28.4 5.6 7.3 10.6 14.9 11.2 16.8 1.1 3.2.8 4.1-3 11.7-10.2 19.9-12.8 23.7-45.8 68.4-7.8 10.5-14.2 19.6-14.2 20.1 0 2.4 21.5 4.3 35.4 3.1 13.4-1.1 23.9-3.8 35.8-8.9 5.8-2.5 8.8-3.3 8.4-2.4-.3.8-5.9 15.4-12.6 32.4-6.6 17.1-12 31.5-12 32 0 1.5 3 1.2 12.4-1 18.2-4.2 40.2-12.3 57.9-21.2 4.3-2.1 8.2-3.8 8.6-3.6.4.2-4.5 23.7-11 52.3-6.5 28.6-11.9 52.1-11.9 52.3 0 .6 5-2.5 11.5-7.2 31.5-22.6 60.2-53.4 79.1-84.8 11-18.3 15.9-32.8 17.1-50.9 1.2-18.6-1.2-22.5-22.7-37.3-7.4-5.1-13.6-10-13.8-10.9-.2-.9 1.9-4.9 4.6-9 23.5-34.7 60.1-66.6 99.2-86.2 29.9-15 65.4-25.1 92.7-26.2 11.1-.5 12.5-.4 16.7 1.6 6 3 9 6.7 14.2 17.6 9.1 19.2 16.8 47.5 19.3 70.7 1.3 11.2 1.4 42 .2 49.1-1.5 9.3-4.3 8.9-17.3-2.7-7.5-6.7-10.2-9.9-13.2-15.5-3.7-7.1-5.8-9.1-9.5-9.1-3.4 0-4.2 3.1-2 7.9 1 2.4 1.9 5.8 1.9 7.7 0 3.3 2.8 7.4 5 7.4.6 0 1 1.3 1 2.9 0 1.6 1.3 5.7 2.9 9.1 6.8 14.3 4.2 26.4-7 32-4.6 2.4-11.6 2.6-14.7.5-1.2-.9-3.6-3.6-5.3-6.1-1.7-2.5-5.5-6.1-8.5-8-3-1.9-6.1-4.5-6.9-5.7-.8-1.3-2.2-6.3-3-11.2-.9-4.9-2.6-10.7-3.8-12.9-2.5-4.6-7.8-8.6-11.3-8.6-4.5 0-10.2-6.7-15.9-18.5-2.9-6-6.2-13.1-7.3-15.8-2.4-5.3-5.6-6.4-7.1-2.4-1.1 2.9.2 15.3 2.3 22.2 1.3 4.1 2.2 5.4 5.3 7 4.4 2.3 6.2 6.3 6.2 13.8.1 6.3 2.3 10.2 7.1 12.7 4.9 2.5 5.6 3.8 6.4 12.8l.6 7.3-3 1.7c-1.6.9-3.2 2.5-3.5 3.4-.7 1.9 2.2 10.5 8.9 26.5 6.2 14.7 8.2 24.3 6.6 31.7-1.4 7-4.8 11.5-14.8 20-16.3 13.8-20.2 24.5-18.2 51.3 1.4 19.2 1.2 36-.5 42.5-.8 3.1-3.8 11.4-6.7 18.5-4.6 11.4-5.2 13.6-5.2 20.3-.1 8.8 1.4 12.2 8.1 19.1l4.4 4.6-1 9.6c-2.6 23.5.1 86.1 5.4 123.3 3.2 21.8 4.8 29.8 8.6 43.3 3.7 12.8 15.1 45.6 17.2 49.8 2.1 4 7.9 9 19.2 16.4 23 15.2 51 25.1 86.5 30.6 16.2 2.4 54.7 2.4 71.5 0 23.7-3.5 45.1-9.4 66.2-18.2 26.5-11.1 33.9-20.1 45.1-54.1 11.4-34.3 20.8-78.8 24.7-116.9 3.7-35.8 3.9-81 .5-115.5-2.3-23.5-8.3-60.2-12.1-74.4-.6-2.2-1.2-9-1.3-15.1-.3-13-1.8-17.2-9-25.2-6.3-6.9-8.8-13.1-9.4-22.3-.9-15.4 4.7-28.5 22.3-52 14.2-19 18.5-25.9 18.5-29.7 0-6-7.4-8.4-12.5-4-1.4 1.2-4.5 5.1-6.8 8.6-3.7 5.6-4.8 6.6-8.9 7.8-3.4 1-5.8 2.6-9.4 6.6-7 7.8-11.7 14.2-17.1 23.7-2.6 4.7-5.3 8.5-6 8.5-.6 0-2.7-2.1-4.6-4.6-3.3-4.3-5.5-5.7-17.7-11.3-2.4-1.2-2.5-1.5-2.1-8.9.5-11.2-2.4-14.6-13.3-16.1-9.7-1.2-12.6-5.5-12.6-18.6 0-9.4-1.3-13.1-6.9-19.8-5-6-8.1-12.6-8.1-17.7 0-7.4 2.9-24.5 5.1-29.4 1.6-3.9 1.8-5.3.9-7-1.3-2.5-3.1-2.6-6.9-.7-3.5 1.8-4.8 4.9-6.2 13.9-1.6 11.1-3.8 18.7-7 24.8-3.1 5.7-12.3 15.8-13.5 14.6-1.3-1.3-4.4-16.5-5.5-27.2-1.1-10.4-.6-33.2.7-38.2l.6-2.3 2.5 2c3.9 3 8.8 2.6 12.4-1l3-3 3 3.5c3.1 3.5 10.4 6.5 15.8 6.5 4.4 0 9.9-2 13.1-4.6l3-2.6 1.1 2.9c2 5.4 7.7 9.4 15.1 10.8 3.1.6 4.7.2 9.5-2.6 3.1-1.8 7.4-4.8 9.3-6.5l3.6-3.3 6.5 1.5c3.5.8 10.7 2.8 15.9 4.4 71.8 22.1 151.5 19.6 222.5-7 7.4-2.8 17.1-6.8 21.6-9 4.6-2.2 9.1-4 10-4 1 0 5.8 5.2 11.7 12.7 5.5 7.1 11.5 14.2 13.3 16 8.1 7.6 18.7 6.5 39.5-4 11.2-5.6 30.7-17.3 38.1-22.9 6.4-4.9 23.8-24.7 22.6-25.8-.4-.4-10-1.9-21.3-3.4-23.8-3.1-25-3.3-25-4.6 0-.5 5.3-10.5 11.9-22.3 16.3-29.2 16.5-29.6 14.3-29.1-.9.2-12.3 2.2-25.2 4.4-12.9 2.2-24.5 4.2-25.7 4.5-2 .5-1.6-.7 3.7-11.8 6.1-12.7 10.4-23.7 14.5-36.7 3.4-10.8 5.7-20.1 5.1-20.7-.3-.3-10.8 6.7-23.3 15.4-26.5 18.7-35.1 24.3-36.9 24.3-.7 0-3.2-2.8-5.6-6.2-5.6-8-8.5-10-15.1-10.6-11.5-.9-20.1 3.2-56.6 27-55.6 36.5-94.3 55-135.6 64.8-18.6 4.5-51.8 10-64.1 10.7l-11.2.6-1.6-3.1c-.9-1.8-2.9-3.8-4.4-4.5-3.5-1.8-20.1-2.9-22.6-1.5-1.5.8-3 .2-7.8-3.2-7.9-5.6-15.5-9-20.1-9-2.1 0-6.3.9-9.4 2-6.6 2.3-10.2 2.5-10.9.7-.4-1.1 5.7-19.8 10.5-32l1.1-2.8 7.8 9.3c4.2 5.1 8.6 9.4 9.6 9.6 1.8.4 1.9-.1 1.3-6.4-.4-3.8-1-8-1.3-9.3-.6-2.2-.2-2 4.9 1.8 8.2 6.2 20.7 10.4 20.7 7 0-.6-1.6-3.7-3.5-6.9s-3.5-6-3.5-6.4c0-.3 2.7 1.2 6 3.5 5.4 3.6 19.6 9.6 20.6 8.7.2-.2-2.8-5.1-6.6-10.8-3.8-5.7-6.8-10.6-6.6-10.8.2-.2 2.6 1.2 5.3 3.1 7.3 5.2 16.6 9.6 25.1 11.8 4.1 1 7.6 1.8 7.8 1.6.1-.1-5.5-7.2-12.6-15.7s-12.9-15.8-12.9-16.2c-.1-.4 3.7 2.2 8.3 5.6 4.7 3.5 12.1 8.2 16.5 10.5 7.7 4 19.1 8.5 19.7 7.8.2-.2-4-5.7-9.3-12.3-5.3-6.5-11.2-13.9-13.2-16.4l-3.6-4.4 4 2.3c13.5 8 21.8 12.7 27.9 15.8 9.3 4.7 24.6 11.3 24.6 10.6 0-1.1-19.1-23.1-30.2-34.7-8.6-9.1-10.3-11.3-7.2-9.4 13.3 8.4 40 19.3 52.4 21.3l4.4.7-5.1-5.8c-2.8-3.3-8.6-9.3-12.8-13.4-4.2-4.1-8.5-8.7-9.6-10.2l-2-2.8 6.6 3c13 5.8 35.6 11.7 41.6 10.8 2-.2-1.6-3.3-18.6-16.2-22.6-17.1-24.1-18.4-21-17.1 9 3.8 25.7 8.7 33.5 10 12.4 2 36.1 2.1 34 .2-.8-.8-10.8-7.1-22.3-14.2-11.4-7.1-20.6-12.9-20.5-13.1.2-.1 3.7.5 7.8 1.4 5.4 1.1 13.1 1.6 27.5 1.6 17.1 0 21.5-.3 30.4-2.2 19.7-4.3 20.3-3.7-11-12.7l-27.4-8 12.5-.7c24-1.4 46.8-5.7 63.4-12.1 6.4-2.4 7.6-3.2 6.1-3.8-1.1-.5-16.8-3.8-34.9-7.4-18.1-3.5-33.1-6.7-33.4-7-.3-.3 1.1-.5 3.1-.5 6.3 0 31.8-4.8 45.2-8.5 16.4-4.5 32.4-10.9 48.9-19.4 11.9-6.1 12.7-6.6 9.5-6.9-3-.3-37 1.9-51.4 3.3-4.6.5-4.1.2 5.5-3.3 29.4-10.9 53.1-23.6 71.6-38.4 3.5-2.8 6.2-5.3 5.9-5.6-.4-.4-13 2.8-41.6 10.4-7 1.9-13.1 3.4-13.5 3.4-.5 0 5.4-3.1 13.1-6.9 31.6-15.5 55.9-35.5 76.5-62.9 4.4-5.9 8-11.1 8-11.5 0-.5-1.5.2-3.2 1.5-11.8 8.8-51.5 29.8-56.4 29.8-.3 0 3.6-3 8.5-6.8 34-25.6 61-57.9 80.2-96.2 9.5-18.8 9.5-18.8-6.8-2.9-17.2 16.8-30.9 27.9-48.3 39.4-11.6 7.7-32.6 19.5-34.5 19.5-.5 0 3.1-2.7 8.1-6.1 29.4-20.1 57-48.2 77.8-79.3 10.3-15.4 29.7-55 29.6-60.5-.1-1.5-.2-1.5-1.3 0-4.8 6.3-28.2 31-37.9 39.9-51.4 47.3-107.1 83.6-198.8 129.5-28.8 14.4-70.4 34.5-71.4 34.5-.2 0 .7-3.5 2.1-7.7 2.2-7 4.4-24.3 3.1-24.3-.3 0-10.4 12.6-22.4 28.1l-21.8 28.1-2.7-11c-4.2-17.2-14.4-35.2-25.8-45.5-3.5-3.2-4.5-3.5-12.7-4.2-12.2-1-22.2-3.7-33.1-9-5.1-2.4-9.3-4.2-9.3-3.9 0 .3 2.5 4.8 5.6 10 3.1 5.3 5.4 9.7 5.2 9.9-.2.2-7-1.3-15.1-3.5-8.1-2.1-14.7-3.4-14.7-2.9 0 2.5 3.2 8.2 6.9 12.2l4.1 4.4-11.2.5c-10 .4-12.3.8-20 4-4.9 1.9-8.8 3.3-8.8 3.1 0-.2 2.2-4.6 5-9.6 10.3-19.3 19.9-46.8 24-69.1 1.2-6.1 2.2-11.9 2.4-12.9.2-.9.1-1.7-.3-1.7s-6.5 6.7-13.5 15c-7.1 8.2-13 15-13.1 15-.1 0 2.8-6 6.6-13.3 11.9-23.1 20.3-48.2 24.4-72.7 1.6-9.2 3.4-49 2.2-49-.3 0-4.5 6.9-9.4 15.4-4.8 8.5-8.9 15.3-9.1 15.2-.1-.2 1.3-5.7 3.2-12.2 8.2-28.4 12.2-59.4 11.3-85.9-.3-8.8-1-17.3-1.5-18.9-.8-2.8-1-2.4-4.1 6zm4.5 110.1c-1.3 20.7-4.5 38.6-9.6 54.5-6.3 19.8-30.4 63.9-43.1 79.1-3 3.5-21.5 24.5-41.3 46.6-33.7 37.8-35.9 40.1-37.6 38.6-1.7-1.5-2-1.3-5.4 3.1-4.1 5.4-4.6 4.2-2-4.7 2.5-8.2 4.3-11.3 17.3-28.6 21.3-28.4 49.9-72 70.3-106.8 5.7-9.9 19.6-34.8 30.8-55.3 11.2-20.4 20.6-37.2 20.8-37.2.3 0 .2 4.8-.2 10.7zm414.7 69c-1.5 3.9-9.9 18.3-15.6 26.8-21.5 32.1-53.1 61.1-82.4 75.9-21.7 10.8-65.9 24.9-104.3 33.2-15.6 3.4-43.8 8.4-47 8.4-1.2 0-1.5-1.4-1.5-7.2l.1-7.2 17.9-5.6c32.9-10.3 52.6-18.6 93-39 17.1-8.7 39.8-19.5 50.5-24 34.5-14.5 55-28.2 80.5-53.9 4.9-5 9.1-9.1 9.2-9.1.1 0-.1.8-.4 1.7zM700 266.1c17.4 5.8 22.1 8.6 27.6 16.1l3.9 5.3.5-4 .6-4 3.2 5c4.7 7.2 9.8 21.5 7.6 21.5-1.9-.1-4.9-3.2-8.8-9.1-5.2-8-7.8-9.8-16.2-11.5-4.7-1-8.8-2.8-12.9-5.4-5.1-3.4-6.1-3.7-6.4-2.3-.2 1.1 1.5 3.4 4.8 6.3 4.9 4.3 5.1 4.7 5.1 9.7 0 6.3 1.4 7.6 3.4 2.9 1.2-3 4.1-5.6 6-5.6.4 0-.5 1.7-1.8 3.7-3.2 4.9-4 8.2-2.7 11.6 2.2 5.7 8.5 6 14.6.6 2.2-2 4.1-2.9 5.2-2.5 1.4.6 1.3 1-.7 3.1-3.3 3.5-11.7 7.5-15.7 7.5-1.9 0-5.6-1.1-8.3-2.5-5.8-2.9-6.8-3-9.2-.8-3.9 3.6-1.6 7.7 9.6 16.7l4.8 3.9-6.2 6.1c-5.9 5.8-9.8 11.8-12.5 19.6l-1.3 3.5-1.1-2.9c-.9-2.2-1.4-2.6-2.4-1.7-2.4 1.9-9.8 17.9-13.1 28.1-1.8 5.5-3.6 9.7-3.9 9.3-1.3-1.2-.7-22.1.8-29.9.8-4.3 1.3-7.9 1.1-8.1-.7-.7-5.5 8.8-9 17.6-3.4 8.3-9 26.2-11.7 36.8-2.3 9.5-3.2 6.1-2.5-9.5.7-16 2.7-31.3 5.5-43.5 2.2-9.5 1.9-9.3-8.8 5.2-8.7 11.9-11 15.3-19.4 29.6-6.7 11.3-6.7 11-2-8.5 3.4-14.4 9.3-29.2 15.2-38.1 3.3-5 4.6-7.7 3.9-8.4-1.4-1.5-22.8 21.1-31.3 33.1-7.9 11.1-15.6 19.5-16.2 17.7-1.2-3.4 13.7-29.4 22.6-39.7 4-4.6 4.2-5.1 2.5-6.3-1.7-1.2-1.6-1.6 1.9-5.1 4.2-4.3 4.5-5.2 1.7-5.2-1.1 0-3.1 1.7-4.9 4.3-5.5 8.1-16.6 16.3-21.1 15.5-3.1-.5 30.6-37.8 40.9-45.1 4.4-3.3 8.1-6.3 8.1-6.7 0-1.7-2-2.1-5.5-1.1-3.2.9-3.5.8-3.5-1.2 0-2.9 3.4-8.3 6.1-9.7 1.2-.7 7.4-1.6 13.8-2.2 11.8-.9 16.1-1.9 16.1-3.8 0-.5-3.1-2.6-7-4.5-6.8-3.4-8.8-5.5-5.2-5.5.9 0 7.5.7 14.6 1.5 7.1.9 13.1 1.3 13.4 1.1.2-.3-2.4-3.5-5.8-7.1-3.5-3.6-5.7-6.5-4.9-6.5.8 0 8.4 2.3 16.9 5.1zm-60.1 23.6c-5.3 14.1-18.9 33.7-37.2 54-7 7.7-10.7 11-15.2 13.3-6.5 3.3-62.5 24.3-63.2 23.7-.2-.2.1-1.7.7-3.2 1.1-3 .5-6.5-1.2-6.5-.6 0-2.6 1-4.5 2.1-4.2 2.6-5.3 1.8-2.7-1.9 2.3-3.2 9.1-7.6 26.4-17.4 21.7-12.2 43.3-26.7 70.3-47 14.4-10.9 26.5-19.8 26.9-19.8.4 0 .3 1.2-.3 2.7zm88.1 9.8c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5.7-1.5 1.5-1.5 1.5.7 1.5 1.5zm251.6 41c-5.6 4.9-30.1 16.8-44.1 21.4-21.4 6.9-40.5 9.8-71 10.8-15.8.5-55.1-1-56.3-2.1-.1-.2.2-1.5.7-2.9.6-1.6.7-3.8.1-5.7-1.5-5.3 3-6.5 31.5-8.4 91.4-6.2 112.1-8.5 135-15 7.6-2.2 8.4-1.8 4.1 1.9zm-384.1 54.4c-2.7 2.6-27 17.7-34 21.1-11.6 5.8-18.7 7.3-31.9 6.8-13.6-.4-14.8-1-10.9-5l2.8-3.1-5.7.7c-3.2.3-5.8.2-5.8-.3 0-2 4.3-6 8-7.5 2.3-.9 8.7-2.1 14.3-2.7 12.2-1.2 21.7-2.8 43.7-7.3 17.7-3.7 21-4.1 19.5-2.7zm201 1.5c3.3.9 11.9 2.3 19 3.1 23.3 2.6 28.3 3.5 50.2 9.1 19.5 4.9 40.2 9.1 53.8 10.9 6.7.9 4.7 1.9-10.6 4.9-26.3 5.3-53.4 6.4-72.4 3.2-8.6-1.5-48.4-13.9-53.8-16.8-1.7-.9-1.7-1.1.3-4.2 1.1-1.8 2-4.7 2-6.4 0-1.7.3-3.8.6-4.7.7-1.8 1.1-1.8 10.9.9zm18.2 57.3c48.3 27.7 48.4 27.8 43.9 28.1-5.5.4-18.3-1.9-30.3-5.4-19.4-5.6-36.7-14.5-66.2-33.9-9.6-6.3-10.3-7-8.5-8.2 1-.7 3.9-2.9 6.4-4.7 2.5-1.9 4.9-3.5 5.3-3.5.5-.1 22.7 12.4 49.4 27.6zM519.3 448c14.5 4.2 32.4 7.7 47.9 9.6 7.3.8 13.5 1.7 13.8 2 .9 1-5 5.1-8.9 6.3-6.8 2-27.2 5.1-33.7 5.1-8.4 0-15.6-1.6-23.2-5.2-6.5-3-8.3-5.1-6.3-7.1 2.5-2.5.9-3-7.4-2.4-4.7.3-8.5.3-8.5-.1 0-1.6 11.7-11.1 13.7-11.2 1.3 0 6.9 1.3 12.6 3zm233 18.4c10.6 7.8 24.2 18.7 30.2 24.1 6.1 5.4 16.1 13.9 22.2 18.8 6.2 5 11.1 9.2 10.9 9.5-.2.2-5.2-1.3-11.1-3.2-12.5-4.2-26.5-11.2-39.2-19.6-11.5-7.5-44.7-33.7-45.1-35.6-.2-.7 1.6-3.6 4-6.4 4.1-4.8 4.3-4.9 6.6-3.4 1.3.9 11 8 21.5 15.8zM722.1 498c37.9 39.7 39.4 41.3 38.1 41.8-1.9.6-13.4-5.2-22-11-8.3-5.7-30.6-26.9-43.5-41.2l-8-8.9 3.9-1.2c2.2-.6 4.9-1.7 5.9-2.3 1.1-.6 2.3-1 2.6-.9.3.1 10.7 10.8 23 23.7zM392 482c40.6 3.5 75.2 13.7 111.5 32.9 14.4 7.6 21 11.8 57.5 35.8 52.9 34.7 72.5 45 103.7 54.3 6.5 1.9 7.4 2.6 9 5.8 2.2 4.5 5 5.1 10 2.2l3.6-2.1-.7 5.1c-.7 5.6.3 6 2.4 1 1.3-3.1 2.4-3.7 3.5-2 .9 1.4 4.8 1.2 6.4-.3 1.1-1 1.3-1 .7 0-1 1.9.5 1.6 1.9-.3 1-1.4 1.3-1.3 2.8 1 2.2 3.3 7.1 3.6 8.7.5.7-1.1 1.4-1.8 1.7-1.6.2.3-.3 1.9-1.2 3.7-2.4 4.7-1.2 4.7 2.5 0 2.3-2.9 3.6-3.8 4.3-3.1 1.5 1.5 5 1.4 6.5-.1.9-.9 1.2-.8 1.2.5 0 3.1-4.6 6.7-8.5 6.7-2.3 0-3.8.5-4.2 1.6-1.2 3.3-2.8 2.9 58.4 11.9 28.8 4.3 38.1 5.2 26.1 2.7-23.5-5-41.5-8.4-53.8-10.1-21.5-3.1-21.7-3.1-19.8-4.2.8-.5 10-1.8 20.4-2.9 10.4-1.1 22.3-2.7 26.4-3.5 8.6-1.8 24.4-6.4 23.8-7.1-.3-.2-5.8.7-12.4 2.1-15.7 3.2-30.6 5.3-43 6.1l-10.1.7.5-3.2c.6-4.2 2.2-4.8 20.7-7.2 72.8-9.6 140.7-35.3 200-75.7 7.7-5.3 17.2-11.8 21.2-14.4 13.9-9.4 25.8-12.5 30.8-7.8 3.5 3.3 22.8 38.7 41.5 76 8.3 16.7 8.3 15.6.2 15.2-6.6-.4-6.8-.3-22.2 7.3-46.8 23.2-87.4 36.1-139 44.2-15.9 2.4-55.2 2.4-73 0-26.7-3.7-82.5-16.3-84.5-19-.8-1.1-1.6-1.3-2.6-.6-2 1.3-6.7 1.1-9.2-.3-1.2-.7-7.5-1.5-14.2-1.8l-12-.5-.5-3.3c-.5-3.6-2.7-4.1-2.2-.5.4 3.2-1.6 3.8-4.3 1.3-1.8-1.7-4.3-2.4-10.3-3.1-9.6-1.1-24.5-4.8-35.5-9-4.5-1.7-22.4-10-39.7-18.4-43.2-21-57.4-25.5-80.9-25.5-30.9 0-75.7 13.2-109.5 32.1-48.5 27.3-88.8 68-113.4 114.6-3.7 7.1-7.4 12.9-8.3 13.1-1.9.3-21.2-13.6-36.1-25.9-23.5-19.6-44-41.3-63.8-67.6-13.5-18.1-16.1-22.7-16.2-29.3-.1-13 21.6-45.2 45-67 48-44.5 112.6-66.6 178.2-61zm119.5 7c10.9 6.3 30.1 15.1 40.4 18.5 6.1 2 5.7 2.5-3.4 4.8-9.2 2.3-22.3 3.1-26.6 1.5-5.3-1.9-28.9-17.1-28.9-18.6 0-.7 2-2.1 4.5-3.2 3.2-1.4 4.5-2.5 4.5-4 0-1.8-.6-2-7.5-2-7.8 0-9.5-1.1-4.7-2.9 5.3-2 10.2-.7 21.7 5.9zm557.9 14.6c-2.5 7.1-8.2 21-12.5 30.8-4.3 9.9-7.9 18.8-7.9 19.9 0 1.8.5 1.9 6.8 1.4 7.1-.7 26.7-4.5 37.3-7.2 3.3-.9 6.5-1.5 7-1.3.5.2-4.7 10.1-11.6 22-7 12.1-12.5 22.8-12.5 24.2 0 1.8.9 3 2.8 4 2.9 1.5 24.1 5.2 35.5 6.2l6.9.6-2.4 2.5c-4.8 5.2-20.7 17.9-30 24-15 9.9-40 21.3-46.5 21.3-3.6 0-3.2-1 9.5-24 2.3-4.2 4.8-10.3 5.7-13.8 2.7-10.5 1.7-13.5-17-50.8-12-23.8-16.6-33.9-16.3-35.9.2-2.3 1.9-3.6 10.8-8.7 13-7.5 20.2-12.6 30.5-21.6 4.4-3.8 8.1-6.8 8.3-6.7.2.1-1.8 6.1-4.4 13.1zm-388.4 1c0 .8 3.2 4.9 7.2 9.2 6.6 7.1 29.3 36.5 31.8 41.3 1.1 2 1.1 2-2.2.3-10.4-5.2-33.4-25.8-36.7-32.7-2-4.3-2.5-7.7-2.2-16 0-2.9.5-4.6 1.1-4.2.6.3 1 1.3 1 2.1zm-6.7 41.6c1.4 1.8 3.3 4.9 4.2 6.8 1.9 3.7 4.7 13.2 4 13.8-.4.4-9.5-12.9-11.8-17.5-1.6-3-1.4-6.3.4-6.3.4 0 1.9 1.5 3.2 3.2zm374.2 62c2.4 1.9 2.7 2.6 2.3 6.9-.6 6-7.4 19.9-16.8 33.9-.8 1.2-1.8.6-5.5-3.5-5.8-6.3-18.9-23.4-18.4-23.9.2-.2 3.9-1.8 8.2-3.5 4.3-1.7 11.7-5.1 16.5-7.6 4.8-2.4 9.2-4.5 9.8-4.5.6 0 2.4 1 3.9 2.2zm-328 15.8c.3.5-.1 1-1 1s-1.3-.5-1-1c.3-.6.8-1 1-1 .2 0 .7.4 1 1zm0 14c-.3.5-1.3 1-2.1 1s-1.4-.5-1.4-1c0-.6.9-1 2.1-1 1.1 0 1.7.4 1.4 1zM668 656.7c-1.1 2.1-2 5.6-2 7.8-.1 2.2-.7 6.9-1.5 10.5-1.8 8-1.8 16.4-.2 21 .7 2 3.4 6.1 6 9.3 5.3 6.6 6.6 10.4 7.6 23.6 1.2 15.5 4.3 19.2 16.2 19.7 3.8.1 7.6.8 8.4 1.4 1.1.9 1.4 3.4 1.2 10-.2 10.2 1.1 12.6 7.5 13.6 4.9.8 8.3 3.5 10.9 8.7 1.2 2.3 3 5.2 4.2 6.4l2 2.2-5.4 5.6c-6.4 6.7-12 10.5-15.3 10.5-1.3 0-4.3-1.6-6.6-3.5s-5-3.5-6-3.5c-2.7 0-7.8 4.7-10.1 9.2-2.5 4.8-2.7 4.7-10.7-7-10.5-15.3-20.2-36.5-28.1-61.4-9.8-30.7-9.7-30.1-4.8-32.1 5.7-2.4 15.2-15.7 18.6-26.1 1.2-3.4 2.7-10.2 3.4-15.3 1.3-8.6 3.5-14.3 5.7-14.3.6 0 .1 1.7-1 3.7zm-443.9 33.4c12.9 12.8 26.2 24.2 41.4 35.6 13.8 10.4 16.6 11.7 24.5 11.8 5.9 0 7.3-.4 15.5-4.9 19-10.5 23.2-11.8 29.7-9.6 14.3 5 12.4 27.8-5.2 63.5-7.5 15.1-22.9 39.4-32.7 51.5-6.8 8.4-21.3 22.6-31.8 31.3-7 5.8-19 12.5-20.2 11.4-.3-.4 1.7-9.1 4.5-19.4 9-32.9 19.2-75.4 19.2-79.9 0-1.7-.6-2.4-1.9-2.4-1 0-8.8 3.3-17.2 7.4-8.5 4.1-19.8 9.1-25.3 11.1-10.5 3.9-34.7 10.8-35.3 10.1-.3-.2 2.6-7.3 6.3-15.8 3.7-8.4 9.8-23.4 13.5-33.3 6.7-17.7 6.7-18 4.4-18.3-1.2-.2-7.1 1.7-12.9 4.2-19.3 8.3-35.9 11.3-55.6 10.2-6.3-.4-11.6-.9-11.8-1.1-.2-.2 3.1-4.4 7.4-9.2 21.9-24.4 39.3-49.6 51.6-74.6l4.3-8.9 7.9 8.9c4.4 4.8 13.2 14 19.7 20.4zm233.8 15.2c2.4 2.1 5.1 3.7 6.6 3.7 7.3 0 11.5 6.4 13.9 21.1 1.6 10.1 3.3 13.2 8.6 16.4 1.9 1.1 6 4.8 9.3 8.2 6 6.3 8.5 7.6 16.7 8.8 8.8 1.4 12 4.3 17.4 15.7 5.6 11.8 12 15.3 19.5 10.7 4.7-2.9 7.3-1.5 11 5.9 4.9 9.7 9.3 12.7 44 29.9l31.6 15.7 9.5.1c8.4 0 10.2-.3 15.5-2.8 7.6-3.5 15.1-10.8 22.5-21.8 6.9-10.2 10.6-12.5 14.3-9.1 3.1 2.9 7.5 4.4 11.1 3.7 9.2-1.9 23.8-17.4 38.2-40.7 8.7-14.1 13.5-19.3 18.8-20.3 6.3-1.3 6.8-1.7 10-8.8 4.7-10.2 9-13.3 11.9-8.6 1.7 2.8-.9 7.2-9.5 16.1-10.7 11.1-19.7 23.2-24.6 33.1-6.5 13-7.7 17.8-7.7 29.7 0 9.3.3 11.2 2.6 16 1.4 3 5.3 8.6 8.7 12.3 10.9 12.3 11.6 22.2 4 53-4 16-4.3 18.1-4.2 30.7 0 12.5.4 15.2 5.3 37.5 5.5 25.5 7.2 38.6 5.2 42.3-2.8 5.2-9.7 3.2-14.3-4.2-6.9-11-7.5-21-2.9-51.3 4.3-28.3 4-37.8-1.7-48.8-2.6-5.1-11-13-16.5-15.5-9.9-4.5-25.9-1.6-34.5 6.3-8.2 7.6-10 13.4-11.2 36.2-1.1 19.8-2.6 26.5-12.4 54.8-10.4 30-12 37.5-12.1 54.7 0 19 1.7 24.6 12 40.1 8 12 9 15.2 6 20.9-1.8 3.6-9 6.5-13.7 5.6-7.9-1.5-14.6-9-16.8-18.9-1.8-8.4-2.3-26.4-1.1-38.2.7-6.1 3.2-22 5.7-35.5 7.7-41.6 9.3-57.1 7.5-71.7-2-16.1-5.9-25.6-12.5-30.1-4.3-2.9-10.3-3.9-31.3-5.2-38.7-2.2-72-8.5-112.1-20.9-8.6-2.7-18-5.2-20.8-5.6-10.9-1.4-18.8 3.6-24.2 15.3-7.3 15.8-9 32-5.2 51.4 2.5 12.7 2.5 19.1.1 24.3-2.8 6.2-7.3 9.5-12.8 9.5-3.9 0-5-.5-7.8-3.5-4-4.1-5.6-10.5-4.4-16.9.4-2.5 3.3-9.4 6.3-15.4 8.5-17 9-19.6 8-39.7-1.4-30.5-1.1-42.1 1.3-50 2.9-9.2 7.2-15.8 13-19.8 13-9 17.2-15.6 18-28.9.7-11.2-1.2-18.3-9.3-34.4-7.4-14.8-7.8-17.3-2.5-18.6 3-.8 3.2-1.2 2.6-3.6-.3-1.5-.9-6.3-1.3-10.7-.8-9.3-2.7-13-7.2-14-4.7-1-6.6-4.4-7.3-12.9-.7-9-1.4-10.5-6.4-13.1-4.9-2.6-6.4-5.9-7-15.8l-.4-8.2 7.4 15c5.5 11.2 8.5 16 11.6 18.8zm65.5-5.3c2.2 6 9.4 14.3 19.4 22.2 5.5 4.4 7.2 5.3 10.9 5.3 2.3.1 4.5.3 4.7.6.6.5-1.9 10.9-3.6 15.1-1.2 3.2-2 3.4-5.3 1.2-4.4-2.8-6.7-1.6-9.3 5.1-5.3 13.5-7.4 17.5-9.4 17.5-1 0-2.3-1.1-3-2.4-.9-2.1-.6-3.2 2-7.3 3.8-6 5.2-11.1 5.2-18.9 0-5-.6-7.4-3.6-13.3-2.6-5.2-3.5-8.1-3.2-10.8.3-3.4 0-3.9-3.2-5.4-3.1-1.5-3.6-2.2-4.1-6.5-.3-2.7-.9-5.7-1.4-6.8-.6-1.4-.5-1.8.6-1.4.8.2 2.3 2.8 3.3 5.8zm-205.3 9.7l9.9 7.8-4.9.6c-4.9.7-8.5 2.3-18.7 8.8-5.9 3.7-10.6 4.5-11.2 1.9-.2-1 .7-4.2 2.1-7 2.6-5.7 11.3-19.8 12.3-19.8.3 0 5 3.5 10.5 7.7zm233.2 44.8c-.3 4.1-12.1 27.7-13.6 27.2-.6-.2-1.8-2-2.6-4-1.3-3.6-1.3-4 3.3-13.6 2.5-5.4 4.6-10.1 4.6-10.4 0-.3.5-1.8 1-3.2l1-2.7 3.3 2c2.5 1.5 3.2 2.5 3 4.7zm49.7 11.2c0 6.5 3.5 36.8 5 44.4 1.2 5.6 1.8 10.4 1.5 10.7-.6.7-10.2-3.7-11.5-5.4-.7-.7-.5-3.6.6-8.5.9-4.2 1.8-14.8 2.1-24.7.3-9.4 1-17.2 1.4-17.2.5 0 .9.3.9.7zM571.8 787c-.1 7.7-.7 14-1.2 14-.9 0-2.3-1.5-5.2-5.7-1.4-2-1.3-2.9 2.2-12.2 2-5.6 3.9-10.1 4.1-10.1.2 0 .3 6.3.1 14zm65.3 11.7c3.6 10.4 9.5 21.5 15.9 29.8 2.2 2.8 4 5.6 4 6.2 0 1.4-12 3.7-13.1 2.6-.7-.7-11.9-45.3-11.9-47.6 0-.4.4-.7.9-.7s2.4 4.3 4.2 9.7zM476 888.5c1.5 1.8.6 4.6-2.5 7.5-4.6 4.3-8 .2-4.5-5.5 2.3-3.7 4.9-4.5 7-2zm116.4 30.7c1.4 2.4-1.9 7-4.7 6.6-3-.4-3.4-4.1-.7-6.8 2.3-2.3 3.8-2.3 5.4.2zm38 1.4c4 1.6.3 8.4-4.6 8.4-2.4 0-2.8-.4-2.8-2.9 0-2 .8-3.5 2.2-4.5 2.5-1.8 3-1.9 5.2-1zm142.9 53.5c.7 2.6-.8 7.2-1.6 4.9-1.6-4.5-1.7-7-.3-7 .7 0 1.6.9 1.9 2.1zm-187.9 32.5c3.5 1.3.6 7.4-3.5 7.4-1.5 0-1.9-.7-1.9-3.3 0-4.6 1.4-5.6 5.4-4.1zm44.1 5.8c.8 2.4.6 3.1-1.4 4.7-2.9 2.4-4.3 2-5.5-1.4-.8-2.1-.6-3.1.9-4.7 2.4-2.7 4.7-2.2 6 1.4zm-165.7 110.9c.2 1.8-.2 2.9-1.3 3.4-2 .7-3.5-1.2-3.5-4.5 0-1.9.5-2.3 2.3-2 1.6.2 2.3 1.1 2.5 3.1zm290.6 12.9c-1.3 2.3-3.7 4.8-4.6 4.8-1.2 0-1-3.4.4-4.8 1.6-1.6 5.1-1.6 4.2 0zM585 1154.5c1.1 1.3 1 2.1-.7 4.3-2.8 3.7-5.1 4-5.9.6-.6-2.1-.2-3.1 1.6-4.6 2.7-2.2 3.4-2.2 5-.3zm40.6 5c.8 2.1-2.2 6.5-4.4 6.5s-4.2-1.9-4.2-4c0-.9.5-2.1 1.2-2.8 1.7-1.7 6.7-1.5 7.4.3zm-143.6 42c0 2.8-2.5 4.4-4.2 2.7-1.5-1.5.1-5.2 2.3-5.2 1.4 0 1.9.7 1.9 2.5zm256.8 9.7c.3 2.8-2 5.3-4.3 4.4-2-.7-1.9-3.5.2-5.8 2.1-2.4 3.7-1.8 4.1 1.4zM584 1239.5c0 3.2-2.5 5.1-4.5 3.5-2-1.7-1.9-4.7.2-5.8 2.4-1.4 4.3-.4 4.3 2.3zm38.4-.6c.8 1.3-.3 3.8-2 4.5-1.9.7-4.4-.3-4.4-1.8 0-2.8 5.1-4.9 6.4-2.7z"/><path d="M384 507.4c-5.5 1-6.5 1.5-6.4 3.1.1 1.1 2.2 13.5 4.7 27.5s4.7 27.1 4.9 29c.3 3.4.4 3.5 4.3 3.4 7.8-.1 11.5-1.3 11.5-3.6 0-1.8-.4-2-3.5-1.5-2.7.4-3.7.2-4.4-1.1-1.3-2.5-9.4-50-8.8-51.6.3-.7 2-1.6 3.7-1.9 2.2-.5 3.1-1.2 2.8-2.4-.4-2.1-1.1-2.2-8.8-.9zM407.8 512.7c-4.3.2-7.8.8-7.8 1.3 0 .6 1.1 1 2.5 1s2.8.6 3 1.2c.2.7.9 8.9 1.5 18.2.9 15.3.9 17.1-.6 18.8-1 1-1.5 2-1.3 2.2.6.4 27.9-1.2 29.6-1.8.8-.4 1.3-2.3 1.3-5.6 0-5.9-1.3-6.5-2.6-1.3-1.1 4.4-2.7 5.1-12.5 5.2l-6.7.1-.5-4.3c-.4-2.3-.9-10.6-1.3-18.3l-.6-14.2 3.1-.7c1.7-.4 2.9-1.1 2.5-1.6-.3-.5-.8-.8-1.2-.7-.4.1-4.2.4-8.4.5zM447.2 519.2c.2 1.5 1 2.3 2.3 2.3 1.3 0 2.1-.8 2.3-2.3.3-1.8-.1-2.2-2.3-2.2-2.2 0-2.6.4-2.3 2.2zM446 527.5l-4.5 1.2 2.9 1.2c2.9 1.2 2.9 1.2 2.2 7.9-.3 3.7-.6 7.9-.6 9.4 0 2.1-.5 2.8-2 2.8-1.1 0-2 .4-2 1s2.9 1 6.8.9c5.8 0 6.4-.2 4.3-1.2-2.3-1.1-2.4-1.3-1.9-12.9.3-6.5.2-11.8-.1-11.7-.3.1-2.6.7-5.1 1.4zM469.6 531.1c-4.7 3.7-3.3 8 3.6 11.5 2.7 1.4 5.1 3.1 5.5 4 .8 2.2-1.6 4.4-4.9 4.4-4.3 0-6.8-1.7-6.8-4.5 0-1.4-.4-2.5-1-2.5-.5 0-1 .6-1 1.2 0 .7-.3 2.3-.6 3.4-.5 1.7.1 2.4 2.7 3.3 6.8 2.3 14.3.3 15.5-4.3.9-3.6-.9-5.9-6.6-8.6-4.4-2.1-5.1-2.7-4.8-4.9.2-2 1-2.7 3-2.9 3.6-.4 6.8 1.4 6.8 3.8 0 2.9 1.7 2.4 2.3-.6.4-2.2 0-2.8-2.9-4-4.6-1.9-7.7-1.8-10.8.7z"/><path d="M516 529.9c0 .6.6 1.1 1.4 1.1.8 0 1.6.5 1.8 1.1.2.7-.9 7.7-2.4 15.8-1.5 8-2.7 14.7-2.8 14.8 0 .2-.9.3-2 .3s-2 .4-2 1c0 1.2 6.9 2.5 8 1.4.5-.5 1.8-5.8 2.9-11.8 1.1-6 2.2-11.1 2.5-11.3 1-1.1 28.5 15.3 50.3 29.9 15.2 10.2 20.4 14.3 15.7 12.4-29.2-12-49.8-16.5-78.9-17.3-20.1-.5-33.9.7-53.5 4.7-9.9 2.1-22.4 5.9-21.7 6.6.2.3 4.4-.5 9.2-1.6 15.5-3.6 38.6-7 52-7.6 32.5-1.6 63.6 6.5 123.9 32.3 30.9 13.2 36.8 15.3 43.7 15.3 9.8 0 5.3-2.8-17.2-10.5-26.1-9-37.5-15.1-73.1-38.6-12.8-8.5-27-16.9-35.5-21.1l-14.3-7v-4.3c0-4.8-.1-5-4.7-6-2.1-.4-3.3-.3-3.3.4z"/><path d="M498 532.6c-.6 1.4-1 3-1 3.5s-1 .9-2.2.9c-2 .1-2.1.2-.6 1 1.6 1 1.6 1.4-.3 6.7-2.7 7.9-2.5 11.1.6 11.9 1.4.3 3.3.3 4.2-.1 1.6-.6 1.6-.8-.4-1.6-2.7-1-2.8-2.5-.6-9.6 1.4-4.6 1.9-5.2 3.7-4.7 3.3 1 3.8 1 4.3-.2.2-.6-1-1.4-2.7-1.7l-3-.7 1.5-3.6c1.9-4.6 1.9-4.4-.5-4.4-1.3 0-2.4 1-3 2.6zM994.3 543c-4.8 2.9-6.6 7.2-6 14 .5 6 5.1 17.3 9.4 22.8 5.1 6.8 13.3 7.8 19.2 2.3 5.5-5.2 5.1-14.3-1.3-27.7-5.8-12.2-13.4-16.3-21.3-11.4zm9.7 3.6c4.3 3.7 12 19.8 12.7 26.7.5 4.7.3 5.6-1.8 7.5-5.3 5.1-11.2.7-18-13.3-5.1-10.6-6.2-18.2-3-21.4 2.8-2.8 6.3-2.7 10.1.5zM349.7 545.5c-4.5 1.5-7 3.6-9.8 8.1-1.6 2.6-1.8 3.7-.9 5.4 1.6 3.1 3 2.4 3-1.5 0-3.8 2.3-6 7.7-7.1 2.5-.5 3.7 0 6.3 2.3l3.2 2.9-5.6 4.3c-6.1 4.7-9.6 9.5-9.6 13.2 0 3.6 3.6 8.8 6.5 9.5 5 1.2 8.7-.7 11.9-6.4 3.3-5.7 4.1-6.2 5.1-3.2.8 2.5 1.4 2.5 7-.4 4.5-2.2 4.9-4.5.6-3.1-1.6.5-2.8-1-7.1-9.4-7.5-14.3-11.1-17.2-18.3-14.6zm12.8 17.4c2 4.5 1.6 7.5-1.6 11.4-4 5.2-10.9 2.5-10.9-4.1 0-2.9.8-4.3 4.6-7.9 2.6-2.3 5-4.1 5.3-3.8.4.2 1.6 2.2 2.6 4.4zM963.3 560c-5 3-6.5 5.9-5.2 10.3 1.1 4 3.2 5.1 2.8 1.4-.4-3.5.9-6.3 3.7-7.5 3.7-1.7 6-1.5 8.9 1.1 4.4 3.7 4.3 8.3-.3 22.5-2.2 6.7-3.7 12.4-3.3 12.6.6.4 22-9 23.4-10.3.4-.4.1-1.5-.6-2.5-1.2-1.6-1.8-1.4-10.1 2.3-4.8 2.3-8.6 3.5-8.3 2.8 2.3-6.1 6.7-21.2 6.7-23.3 0-9.1-9.7-14.3-17.7-9.4zM309.2 570.1c-5.1 2.6-6.9 4.9-7.8 10.6-.8 5-1.5 5.3-4.1 1.8l-1.8-2.5-4.2 5.7c-4.5 6.1-4.8 8.3-.6 5.6 2.6-1.7 2.6-1.7 6.2 2.3 2 2.3 6.2 7.6 9.5 11.8l5.9 7.7-2.3 2.4c-1.2 1.3-1.9 2.8-1.6 3.4.5.8 10.8-6.4 16.5-11.5.1-.1 0-.7-.4-1.3-.4-.7-1.4-.5-3 .5-1.3.9-2.9 1.4-3.4 1.2-.5-.1-4.1-4.3-8-9.2-6.1-7.6-7.1-9.4-7.1-12.8 0-7.9 8.9-12.8 15.2-8.4 1 .7 5.2 5.6 9.4 10.9 4.1 5.4 8.1 9.7 8.7 9.7 1.6-.1 10.4-7.7 9.6-8.4-.3-.3-1.9 0-3.7.6-1.7.7-3.3 1-3.5.8-.2-.3-3.8-4.8-8.1-10.1-7.1-9-11.9-12.9-15.8-12.9-.7 0-3.2 1-5.6 2.1zM941.4 573.4c-4.3 1.9-6.4 5.3-6.4 10.3 0 4.8 3.2 14.1 6.7 19.5 4.5 6.7 11.9 7.4 16.9 1.5 2.4-2.8 2.6-3.7 2.1-8.8-.6-7.3-5.1-17.1-9.4-20.9-3.7-3.3-5.3-3.6-9.9-1.6zm6.7 3.7c3 3 8.8 16 9.5 21.1 1.1 8.3-5.5 11.1-10.8 4.7-3.2-3.8-8.8-17.5-8.8-21.5 0-5.8 6-8.4 10.1-4.3zM914.4 585.2c-4.6 1.2-7.3 4.6-6.7 8.5.7 4.2 2.1 4.2 2.5.1.6-6.3 9.7-6.6 11.8-.4 1.2 3.8.1 8-5 18.8-1.6 3.4-2.8 6.4-2.5 6.6.2.2 4.8-1.1 10.3-2.9 8.4-2.7 9.8-3.5 9.4-5.1-.6-2.3-.7-2.3-8.6.7-3.6 1.4-6.6 2.1-6.6 1.6 0-.4 1.6-4.2 3.5-8.4 4-8.6 4.4-13.3 1.5-16.9-2.3-3-5.2-3.8-9.6-2.6zM256.6 588.2c-1.3 1.9-1.4 2.5-.2 4.3 2 3.1 6.3 3.2 7.7.2 2.5-5.4-4.1-9.4-7.5-4.5zM218.7 610.7c-12 11.9-18.4 19-17.8 19.6.6.6 2.1 0 4.1-1.7 1.7-1.4 3.7-2.6 4.3-2.6 1.5 0 44.7 43.2 44.7 44.7 0 .6-1.1 2.5-2.5 4.1-2.5 3-3.2 5.2-1.7 5.2.4 0 5.7-4.8 11.6-10.6 7.4-7.3 10.5-10.9 9.8-11.6-.8-.8-2.1-.3-4.2 1.6-1.7 1.4-3.9 2.6-4.7 2.6-.9 0-6.2-4.5-11.7-10l-10.1-9.9 7.5-7.6c4.2-4.2 8.3-7.5 9.4-7.5 1.1 0 3 1 4.2 2.1 1.5 1.4 2.9 1.9 4 1.5 1.5-.6.2-2.3-6.9-9.4-5.9-5.9-9-8.3-9.7-7.6-.7.7-.2 2.1 1.5 4.3 2.2 3.1 2.3 3.6 1 6-1.2 2.4-4.3 5.5-11.8 12.1l-2.8 2.4-9.4-9.4c-5.2-5.2-9.5-10-9.5-10.6 0-1.9 15.7-16.3 18.5-17 2.1-.5 3.3 0 5.6 2.2 2.1 2 3.2 2.5 4 1.7.8-.8-.2-2.7-3.6-6.9-2.6-3.3-4.8-6-4.9-6.1-.1-.1-8.6 8.2-18.9 18.4zM267.2 601.7c-1.7 2.7-3.7 5.6-4.4 6.5-1.8 2.5-.3 3.3 2.6 1.4 1.4-.9 3-1.6 3.5-1.6 1.2 0 21.1 23.6 21.1 25 0 .6-.9 1.8-2 2.7-1.1 1-2 2.3-2 3 0 2.2 2.5 1.4 5.6-1.8 1.6-1.7 5.3-4.9 8.2-7.1 3.5-2.7 5-4.4 4.3-5.1-.7-.7-1.8-.4-3.5.7-1.4.9-3 1.6-3.5 1.6s-6.6-6.8-13.6-15c-6.9-8.3-12.7-15-12.9-15-.2 0-1.7 2.1-3.4 4.7zM857.5 602.2c-3.2 1.8-4.4 4-4.5 8 0 5 .8 6.6 4.1 8.4 3.5 1.8 7.4 1 9.4-1.9 1.5-2.1 1.5-2 1.5 1.1 0 4.3-2.2 8.4-6.2 11.6-4.2 3.3-2.4 3.4 2.4.1 4.2-2.8 7.8-9.6 7.8-14.6-.1-4.4-3.2-11.4-5.8-12.8-2.6-1.4-6.2-1.4-8.7.1zm7 2.3c2.9 2.9 3.3 7.9.8 10.7-2.2 2.4-3.9 2.3-6.8-.7-3.3-3.2-3.4-8.7-.3-10.9 3-2.1 3.5-2 6.3.9zM838.2 608.4c-2.4 1.2-4 2.5-3.6 2.9.4.4 1.8 0 3-.8 2.1-1.4 2.3-1.3 2.8 1.3.3 1.5.8 6.4 1.2 10.9.6 8 .5 8.3-1.7 9.3-1.9.8-1.4.9 2.5.5 2.7-.3 5.6-.5 6.5-.6.9-.1.5-.4-.9-.8-2.4-.7-2.5-1.2-3.7-12.5-.6-6.5-1.3-11.9-1.5-12.1-.1-.2-2.2.7-4.6 1.9zM892.6 609.4c-4.9 1.1-9.1 2.7-9.4 3.4-.3 1 .4 1.2 3.2.7 8.3-1.6 16.7-4.1 16.7-5 .1-1.5-1-1.4-10.5.9zM818 612.2c-1.6 1.7-2 3.5-2 8.7 0 10.7 4.5 15.6 11 12.1 5-2.7 4.8-18.8-.4-22.2-2.2-1.5-6.6-.8-8.6 1.4zm7.6 1.3c2.1 3.2 3.1 14.4 1.5 17.4-1.7 3-5.2 2.4-7-1.3-1.9-4.1-2-16.4-.1-17.6 2.4-1.6 3.8-1.2 5.6 1.5zM800.8 613.2c-1.8 1.5-3.1 4.8-1.9 4.8.5 0 1.1-.7 1.5-1.5.7-1.9 5-2 6.5-.1 1.8 2.2.3 6.2-4.5 11.5-2.4 2.7-4.4 5.2-4.4 5.5 0 .8 6.9.8 10.9 0 4.8-1 3.7-2.4-2-2.4h-5.1l4.1-5.1c4.7-5.9 5.5-11.1 2.2-12.9-2.6-1.4-5.4-1.3-7.3.2zM647.9 716.9c-1.6 1.6-2.9 3.6-2.9 4.5 0 2.7 2.1 2.8 4.5.2 3.9-4.2 10.1-3.2 12.9 2.2.8 1.6 2 6.5 2.6 11 1.9 14.1 5.4 21.3 11.8 25 2.2 1.2 4.8 2.2 5.9 2.2 1 0 2.9.7 4.2 1.6 2.7 1.9 4.6.7 3.6-2.4-.4-1.4-2.2-2.6-5.8-3.6-9.1-2.7-12.8-8.3-15.2-23.2-2.4-15-6.5-20.4-15-20.4-2.7 0-4.4.8-6.6 2.9zM699.5 777c-1 1.7 1.4 4.9 5.3 6.9 4.2 2.1 6.3 4.3 8.3 8.5 1.8 3.8 3.3 3.8 3.7.1.4-4.3-2.9-8.8-9.3-12.9-5.9-3.8-7-4.2-8-2.6zM477.9 767.2c-.9 2.1-.6 3.6 2 9.5 4.2 9.7 5.4 16.2 4.9 26.3-.3 4.7-.2 9.3.1 10.3.6 1.7.8 1.7 2.5-.2s1.8-3.2 1.3-13.3c-.6-9.9-2.3-20.7-4.3-27.1-.6-1.7-.3-1.9 2.2-1.3 5.5 1.4 9.6 4.9 19.1 16.3 13 15.7 17.6 18.5 33 20.2 10.6 1.1 14.9 3.3 25.8 13.2 4.9 4.4 10.6 8.9 12.7 10 2 1 7.9 2.5 13.1 3.3 5.2.8 11 2.2 12.8 3.1 2.9 1.5 9.8 6.9 17.7 13.9 4.3 3.8 2.4-.8-2.7-6.5-6.3-7.1-14.2-11.3-25-13.3-11.6-2.2-15.2-4.1-26.4-14-12.2-10.7-15.7-12.5-27.5-14.3-14.2-2.1-18.2-4.6-32.4-20.4-10-11-17.7-16.8-23.6-17.6-3.7-.5-4.3-.3-5.3 1.9zM723.6 810.9c-7.6 7.8-11.5 9.1-32.4 11.1-.2 0-4.9 4.7-10.5 10.4-9.2 9.3-11.2 10.8-20.1 15.1-8.9 4.2-9.7 4.8-8.3 6.2 1.4 1.4 2 1.4 5.9-.1 8.7-3.5 18.1-9.9 25.7-17.7l7.8-7.9 8.4-1.4c10.1-1.6 14.9-3.5 20.4-8.1 3.8-3 8.3-10 7.3-11.1-.2-.2-2.1 1.4-4.2 3.5z"/><path d="M539.3 822.6c-.9 2.3 8 10.8 15.7 15.1 3.6 2 7.7 4.7 9.2 6.1 3 2.8 4.3 2.5 3.3-.7-.6-2-5.4-5.5-14.5-10.4-3-1.6-6.3-4.5-8.2-7.2-3.4-4.8-4.5-5.4-5.5-2.9zM503.8 829.6c-.5.4-.8 3-.8 5.8 0 5.6 3.6 13.1 8.4 17.5 3.4 3.2 3.5.7.1-4-4.4-6.1-5.6-8.9-6.3-14.5-.4-3.1-1-5.2-1.4-4.8zM523 830.4c0 .8 3.9 4.2 8.8 7.4 4.8 3.3 11 8 13.8 10.6 5.3 4.7 6.4 5.3 6.4 3.6 0-2.2-8.5-10.1-17-15.9-10.4-7.2-12-7.9-12-5.7zM731.5 833.4c-7.3 2.3-10.7 4.7-21.9 15.5-16.7 16-24.5 20.2-41.9 22.4-8 1-8.8 1.3-8.5 3.2.4 2.9 5.1 3.1 15.1.6 14.5-3.6 23-8.6 36.6-21.5 15.7-14.8 22.5-18.1 32.4-15.3 2.1.6 2.9.4 3.4-.9 1.4-3.8-7.9-6.3-15.2-4z"/><path d="M486.7 836.1c-4.3 6 6.5 21.9 19.3 28.4 14.4 7.3 31.5 7.2 62-.2 18.3-4.4 22.9-4.2 33.9 1.5 9.4 4.9 18.2 8 26.1 9.1 6.8.9 7.8.1 2.3-1.8-2.1-.8-11.2-4.5-20.3-8.4-10.6-4.5-18.3-7.2-21.5-7.4-3.4-.3-10.2.7-21 3-29 6.4-40.7 7-54 2.6-13.8-4.6-23.4-14.9-23.5-25.2 0-4.1-1.2-4.7-3.3-1.6z"/><path d="M516.6 837.9c-.3.5 1.8 2.6 4.7 4.7 2.8 2.2 6.2 5.8 7.5 8.2 2.5 4.4 4.2 5.4 4.2 2.4 0-2.8-5-9.7-9.5-13.1-4.1-3.1-6-3.7-6.9-2.2zM394.6 625.6c-5.2 5.2 2.6 15.2 11 14.2 2.5-.3 2.9-.8 3.2-3.6.4-4-1.7-7.6-6.1-10.2-3.9-2.4-6-2.5-8.1-.4zm7.8 5.7c3 2.4 2.9 5.1-.2 4-2.5-.9-5.2-3.4-5.2-5 0-2 2.1-1.6 5.4 1zM403.8 642.1c-2.7 1.5-2.2 3.7 2.3 11.4 2.3 3.9 5.7 10.3 7.6 14.2 3.6 7.8 5.3 9.3 10.5 9.3 4.8 0 5.8-1.5 5.8-9 0-6.4-.1-6.6-4-10-3.1-2.7-4.4-4.7-5.3-8.5-1-4.2-1.8-5.3-4.7-6.7-3.9-2-9.5-2.3-12.2-.7zm10.6 5.8c.9 1 1.9 4.1 2.2 6.7.2 2.7.8 5 1.4 5.2.5.2 2.4 1.3 4.2 2.5 2.6 1.8 3.4 3.1 3.6 6 .2 2.7-.1 3.9-1.3 4.3-2.3.9-3.9-.9-8-9.4-2-4.2-5.1-9.1-6.7-10.9-1.9-1.9-2.8-3.8-2.5-4.7.9-2.2 5-2 7.1.3zM504.7 643.1c-1.7 2.4-1 6 2.3 11.6 1.1 1.9 2 4.4 2 5.6 0 3.3 2.8 6.7 5.4 6.7 7.3 0 7.6-14.4.4-22.5-3.6-4.1-7.8-4.7-10.1-1.4zm7.7 3.8c2 2.2 4.2 12 3.3 14.5-1 2.4-2.7 1-2.7-2.2 0-1.5-1.2-4.7-2.6-7.1-3.3-6-2-9.6 2-5.2zM390.1 648.6c-2.6 3.4-2.6 4.5.1 7.9 2.4 3 7.4 5.5 11.3 5.5 2.3 0 2.5-.3 2.5-4.6 0-3.9-.5-5.1-3.4-8-4.2-4.2-7.6-4.4-10.5-.8zm8.7 5.6c.4 3.5-2 3.8-4.2.6-1.8-2.6-1.2-4 1.7-3.6 1.6.2 2.3 1.1 2.5 3zM684.3 652.5c-2.8 2-5.7 9.7-4.9 12.9.9 3.6 4.2 5.2 7.3 3.5 3.3-1.7 8.3-9.6 8.3-13 0-4.6-6.2-6.5-10.7-3.4zm6.4 4.1c.1.5-1.1 2.5-2.8 4.4l-3.1 3.5.6-3.9c.5-3.8 2.1-5.9 4-5.3.6.2 1.1.7 1.3 1.3zM834.9 675.3c-1.9 1.2-4.3 3.9-5.3 5.8-2 3.6-2 3.6.3 6.7 2.1 3 2.1 3.3.6 6.2-.8 1.6-3.4 4.2-5.6 5.6-4.3 2.7-7.8 8.8-7.9 13.6 0 2.5.3 2.8 3.6 2.8 2.9 0 4.4-.8 7.3-3.8 2-2.2 5.1-4.5 6.9-5.2 4.1-1.6 8.2-6.4 8.2-9.6 0-1.4-1.2-3.7-2.6-5.1l-2.6-2.6 3.5-3.1c5.6-4.9 7.1-9.1 4.1-12-2.2-2.3-6.5-2-10.5.7zm7.1 3.2c0 2.2-4.9 6.5-7.2 6.5-3 0-1.8-3.1 2.1-5.7 4-2.7 5.1-2.9 5.1-.8zm-4.2 19.2c-.2 2-1.4 3.2-4.8 5-2.5 1.3-6 4-7.7 6.1-2.8 3.1-3.3 3.4-3.3 1.6 0-2.5 2.8-5.6 8-8.9 2.1-1.3 4.1-3.3 4.5-4.5 1-3.1 3.7-2.6 3.3.7zM509.3 675.2c-3.8 4.9-.1 16.8 4.4 14 3.1-2.1 4.6-11.5 2.1-14-1.6-1.6-5.3-1.5-6.5 0zm4.5 6c-.4 5.1-3.1 6.1-3.6 1.5-.4-3.7.4-5.7 2.3-5.7 1.3 0 1.5.9 1.3 4.2zM807.3 706.2c-3.9 4.4-10.3 15.5-10.3 18.1 0 6.1 9.8 4 14.5-3.1 3.6-5.4 4.1-9.9 1.6-14-2.4-3.8-3.1-3.9-5.8-1zm1.8 9.6c-2 3.9-6.7 8.9-7.6 8-.3-.2 1.3-3.3 3.5-6.7 4.3-6.6 7.3-7.6 4.1-1.3z"/></svg>
\ No newline at end of file
+<svg version="1" xmlns="http://www.w3.org/2000/svg" width="933.333" height="933.333" viewBox="0 0 700.000000 700.000000"><path d="M273.1 50.5c-1.6 1.4-3.7 4.7-4.7 7.3-1 2.6-2.3 5.6-3 6.7-.7 1.1-2.4 6.3-3.9 11.5s-3.8 12.1-5.1 15.2c-1.3 3.2-3.1 8.9-4 12.6-.8 3.7-3.5 12.8-5.9 20.2-2.4 7.4-5.1 18.3-5.9 24.1-2 13.5-2.1 29-.2 32.7 4.2 8 16.9 15 53.6 29.7 28.1 11.2 43.9 16.5 49.1 16.5 1.4 0 3.9.4 5.5 1 4.8 1.6 39.4 8.1 46.4 8.7 3.6.3 13.3 0 21.5-.6 8.3-.7 25.6-1.6 38.5-2.1 12.9-.6 26.9-1.7 31-2.5 4.1-.8 9-1.5 10.8-1.5 3.3 0 15.2-4.7 15.2-6.1 0-.4.8-1.5 1.7-2.5 2.5-2.5 3.2-11.3 3.2-41.9 0-32.1-1.2-58.2-2.7-61.1-1.5-2.7-6.5-4.8-9.7-4-5.4 1.4-5.5 2.4-4.8 50.7.7 50.8 1.2 47.9-7.8 47.9-2.7 0-6.6.7-8.6 1.5-4.6 1.9-25.8 3.3-63.3 4.1-27.4.6-30.4.5-42-1.5-6.9-1.2-15-2.8-18-3.6-3-.7-7.7-1.6-10.5-2-10.7-1.4-33.9-8.7-36.5-11.5-.3-.3-5.9-2.4-12.5-4.7-18.7-6.5-27.1-9.8-32.1-12.9-2.5-1.6-6.1-3.7-7.9-4.6-5.1-2.7-6-6.2-4.7-18.1 1.2-11 4.6-26.9 8.2-38.2 6.5-20.9 8.3-26 9.5-27.9.7-1.2 2.5-6.2 4-11.1 1.4-5 3.3-10.9 4.1-13.2l1.6-4.3 3.1 1.6c1.8.9 4.6 2.7 6.3 4 1.7 1.3 3.4 2.1 3.6 1.9.4-.4 9 4 21.3 10.8 1.7.9 8.2 3.7 14.5 6.1 6.3 2.4 12.4 4.7 13.5 5.1 1.1.5 4.9 1.6 8.5 2.5 3.6 1 12.2 3.4 19.2 5.3 7 2 16.9 4.1 22 4.6 5.1.6 14 2 19.8 3.1 16.1 3.2 38.2 4.3 64.5 3.5 21.8-.8 38.2-1.4 39.7-1.5.3 0 2.1-1.2 3.8-2.7 2.8-2.3 3.1-3.1 2.6-6.1-.3-1.9-1.3-4.5-2.2-5.9l-1.6-2.6-13.7.8c-7.5.4-28.8 1-47.4 1.3-27.4.6-34 .4-35.1-.6-1.8-1.8-6.9-2.9-22.6-4.7-7.3-.8-14-2-15-2.5-1-.6-3.4-1-5.4-1-4.7 0-23.6-5.8-41-12.6-13.3-5.3-43.3-20-46.7-23-.8-.8-2.4-1.4-3.5-1.4-1-.1-3-.7-4.4-1.5-4.1-2.4-10.4-1.9-13.9 1z"/><path d="M382.5 117.9c-4.8 1.2-7.5 3-8.5 5.7-2.7 7 1.2 24.6 6.1 27.7 2.7 1.7 6.7-.1 8.6-3.7 1-1.9 4.1-5.2 7-7.5 4-3.1 5.5-5.1 6.3-8.2 2.6-9.6-.7-14.1-10.7-14.5-3.2-.2-7.1.1-8.8.5z"/><path d="M314.3 135.1c-4.3 1.6-6.9 11.1-4.3 15.9 1 1.8 6.8 4 11.4 4.2 1.1.1 2.6.5 3.1.9 2.6 1.9 49.8 9.9 58.6 9.9 2.9 0 5 .7 7.1 2.5 3.9 3.3 15 6.7 22.3 6.8 5.9 0 14.5-3 14.5-5.2 0-.5.9-1.1 1.9-1.4 2.2-.5 8.7-9.1 9.6-12.6.7-2.7-3.5-8.7-7.4-10.7-2.3-1.2-15.3.5-18.8 2.5-1 .6-5.4 2.5-9.8 4.3-7.8 3.2-8.3 3.3-22.5 3.2-22-.1-41.9-5.3-51-13.1-7.8-6.6-11.4-8.4-14.7-7.2zM375.2 172.9c-.7.4-2.5 3.2-3.8 6.2-2.8 6-2.6 8 1.2 14.6 2 3.4 3.4 4.5 8.1 6.3 4.8 1.8 6.1 1.9 8 .9 3.9-2.1 6.6-7.5 6-11.6-1.5-9.3-14.1-19.9-19.5-16.4zM94.5 186.2c-4.1 1.4-7.4 4-19.5 15.3-11.4 10.5-26.9 23.3-34 28.2-7.5 5-11.2 6.6-17.3 7.4-7.2.9-10.7 3.7-10.7 8.6 0 3.6 1.2 6.6 3.7 9.5.8.9 4.1 8.3 7.4 16.3 5.8 14.6 12.7 28.5 19.9 40 2 3.3 5.2 8.7 7.1 12 4.2 7.4 46.3 50 55.6 56.3 3.4 2.3 6.4 5 6.8 6.1.3 1 1.3 2.1 2.3 2.3.9.3 8.1 5.1 16 10.7 7.8 5.6 17 11.8 20.5 13.8 3.4 2 8 4.7 10.2 5.9 6 3.6 30.3 14.4 32.2 14.4.5 0 2.7.9 4.9 1.9 6.3 3 16.5 5.3 20.6 4.7 3-.5 4.2-.2 5.8 1.4 3 3 8.5 2.7 11.7-.8 1.4-1.5 5.7-8.6 9.5-15.7 9.6-17.9 25.4-46.7 29.9-54.5 5.1-9 16.3-31.5 19.2-38.8 1.4-3.3 3.7-7.6 5.1-9.4 1.3-1.8 3-5.6 3.6-8.3.6-2.8 1.6-6.4 2.2-8.1.9-2.4.7-3.7-.6-6.6-1.4-2.9-3.1-4.2-9.4-7.1-12-5.6-17-7.3-27.7-9.7-9.7-2-17.5-4-30-7.4-5.5-1.6-15.2-5.4-20-7.9-3.9-2.1-7.1-3.6-12.6-6.2-3.1-1.4-7-3.5-8.5-4.8-1.6-1.2-5.2-3.1-8.1-4.3-9.3-3.8-32.9-18.2-40.9-25.1-2.8-2.3-5.6-4.3-6.1-4.3-.6 0-2.8-1.9-4.9-4.3-2.1-2.3-3.9-4.1-4.1-4-.1.1-1.6-1.1-3.4-2.8-1.7-1.6-3.5-2.9-3.9-2.9-.5 0-1.2-.9-1.5-2-.3-1.1-1.1-2-1.6-2-1.2 0-15.3-11.4-17.6-14.3-1.7-2.1-6.5-4.8-8.1-4.6-.4 0-2 .5-3.7 1.1zm7 20.8c.4.6 2.3 2.1 4.3 3.4 2.1 1.3 8.7 7 14.7 12.5 6.1 5.6 12.8 11.4 15 12.9 2.2 1.4 5.9 4.2 8.2 6.2 7.2 6.1 9.8 7.8 18.9 12.6 4.9 2.6 10 5.5 11.4 6.4 4.2 2.9 44 22.7 51 25.3 9.9 3.8 29.7 9.5 37.3 10.7 7.5 1.2 23.5 6.5 25.5 8.4 1.1 1.1.8 2.8-2 9.7-5.9 15.1-30.3 63-34.5 68.1-.8.9-1.6 2.2-1.7 3-.3 1.6-3.3 6.8-6.3 11.2-1.2 1.7-4 6.8-6.2 11.4-2.2 4.5-4.9 9.5-6 11-1.1 1.6-2.3 4-2.6 5.5-.8 3-2.6 3.5-4.5 1.2-.7-.8-1.9-1.5-2.6-1.5-.8 0-2.2-.4-3.2-.9-.9-.5-5.7-2.1-10.7-3.6-8.7-2.7-17.4-6.5-35.5-15.4-13.4-6.7-17.3-9.1-27.7-17.1-5.4-4.1-10-7.5-10.3-7.5-2.8-.1-26.3-19.9-43.9-37-14.3-13.9-23-24.3-27.2-32.7-1.6-3.2-3.6-6.1-4.3-6.4-.7-.3-2.2-2.4-3.2-4.7-1-2.3-3.1-6.1-4.7-8.5-4-6-14.7-30.2-14.7-33.3 0-1.8.9-3.2 2.5-4.3 1.4-.9 2.3-2.1 2-2.6-.3-.5 1.6-2.3 4.2-4.1 8-5.5 28-21.6 38.2-30.8 12.3-11.2 13.9-12.3 16.2-11 1 .5 2.1 1.4 2.4 1.9z"/><path d="M134.6 275.6c-.9.8-1.9 2.7-2.2 4.2-.3 1.5-.8 3.3-1 4-.2.7.5 3.1 1.6 5.2 1.1 2.2 2 4.4 2 5 0 .5 1.9 3.8 4.3 7.4 2.3 3.5 5.9 9 8 12.2 3.9 6.2 7.7 11.5 16.8 23.5 4.8 6.3 6.8 8 12.9 11.2 6.1 3.1 8.2 3.7 13.5 3.7 4.4 0 6.6-.5 7.5-1.5 1.5-1.8 1.8-9.3.7-15.3-.9-4.1-.8-4.2 1.7-4.2 4.1 0 9.3-2.5 11.2-5.4 2.1-3.3 1.5-11.4-1.4-17.8-3.1-6.9-8.2-11.2-19.9-16.8-9.1-4.4-12.4-5.4-20.8-6.6-11.9-1.7-25.2-5.6-28.5-8.4-2.8-2.4-4.3-2.5-6.4-.4zM572.3 225.7c-1.8 2.1-7 8-11.5 13.1-8.5 9.7-15.8 15.6-24.2 19.4-6.9 3.2-22.4 11.1-39.6 20.3-23.9 12.8-29.1 15.5-30.5 15.5-.7 0-3.5 1.1-6.2 2.4-5.6 2.8-39.6 12.9-52.8 15.7-4.9 1-12.2 1.9-16.1 1.9-5.8 0-7.7.4-9.8 2.1-2.1 1.6-2.4 2.4-1.5 3 1 .6.9 1.2-.5 2.8-2 2.2-2 2.4-4.5 44.1-1.5 23.3-3 37.9-6.1 58.5-.6 3.8-2.6 13.3-4.6 21-2.6 10.4-4.1 14.4-5.7 15.7-1.7 1.3-1.9 1.9-.9 3 .9 1.1.9 1.7 0 2.6-1.9 1.9 5.7 8.6 8.5 7.7 6.2-1.9 9.7-2.5 14.7-2.5 5.5 0 12.8-1.8 18.5-4.4 1.7-.8 7.5-2.1 13-2.9 27.4-4.3 52-16.4 126.1-62.1 5.5-3.4 12.8-9.4 23.8-19.6 3.9-3.6 12.4-11.2 18.8-16.8 6.4-5.6 14.9-13.8 18.9-18.1 6-6.7 7.8-8.1 11.2-8.6 2.2-.4 5.1-1.8 6.5-3.2 2.2-2.2 2.3-3 1.8-7.7-.6-4.1-.4-5.5.8-6.6 1.8-1.4 2.1-5.3.5-8.1-.6-1.1-3-2.9-5.5-3.9-3.4-1.5-4.4-2.5-4.4-4.2-.1-7.1-2.2-21.5-3.5-23.5-.9-1.3-1.1-2.3-.5-2.3.5 0 1-.8 1-1.8 0-2.2-6.5-15.8-13-27.2-2.7-4.7-5.6-11.2-6.6-14.5-.9-3.3-3-7.9-4.7-10.3-3.9-5.5-6.8-5.6-11.4-.5zm5.8 28.3c.5.3 3 4.9 5.7 10.1 5 9.8 6.4 15.1 9.7 35.9.8 5.2 2.5 12.3 3.7 15.7l2.1 6.1-3.4 5.4c-4.2 6.5-14.5 19-16.7 20.2-2 1.1-5.2 3.9-22.9 19.8-20.1 18.3-30.5 25.8-52.3 38.1-6.3 3.5-15.9 9-21.2 12.1-5.3 3.1-9.9 5.6-10.3 5.6-.4 0-2.5 1.3-4.8 2.8-6.6 4.5-25.8 14-30.4 15.2-2.4.6-4.3 1.4-4.3 1.9 0 .4-1.4.8-3 .9-1.7 0-7 1.2-11.8 2.5-4.8 1.3-11.2 3-14.2 3.7-3 .7-7.1 1.9-9 2.7-1.9.8-6.4 1.6-9.8 1.8-5.7.4-6.3.2-5.7-1.3 1.5-3.6 6.4-24.6 7-30 .4-3.1 1.3-10 2.1-15.2.8-5.2 1.4-13.2 1.4-17.7s.6-13.3 1.4-19.5c1.2-9.5 2.9-30.8 3.1-38.3 0-1.8 1.1-2.2 9-3.3 11.1-1.5 23.8-4.7 42-10.5 14.9-4.8 35.3-12.5 37.6-14.3.8-.6 3-1.7 4.9-2.4 1.9-.8 5.9-2.9 8.8-4.7 2.9-1.8 5.5-3.3 5.9-3.3.3 0 1.4-.6 2.2-1.4 2.5-2.2 25.9-14.2 32.3-16.6 6.4-2.4 16-8.5 26.1-16.9 3.7-3.1 8-6.4 9.5-7.3 2.5-1.7 2.7-1.7 3.6 0 .5.9 1.3 1.9 1.7 2.2z"/><path d="M461.2 337.1c-3.8 6.9-14.6 23.7-17.8 27.6-3.9 4.8-7.3 11.8-7.4 15 0 2.9 2 3.8 10.2 5.1 3.7.6 8.8 2 11.4 3.1 2.5 1.2 5.3 2.1 6 2.1.7 0 2.9.7 4.8 1.7 4.3 2 6 1 8.6-5.2 2.8-6.5 11.1-14.7 23.5-23.1 8.4-5.7 11.7-8.6 12.1-10.4.3-1.4 1-3.5 1.6-4.7.9-1.8.8-2.7-.7-4.3-1.6-1.8-3.1-2-13.4-2-12.7 0-20.1-1.4-28.1-5.5-6.6-3.3-8.7-3.2-10.8.6zM678.2 500.6c-2.1 1.4-6.9 1.8-34.5 2.5-20.8.6-35.7.6-42-.1-5.5-.6-38.1-1-74.2-.9-61.8 0-64.3.1-64.8 1.9-.4 1.5-1.2 1.7-4.4 1.3-5.1-.7-7.9 1.7-16.3 13.4-3.4 4.9-9.7 13.2-13.9 18.5l-7.6 9.7-97.5.3c-73.3.2-98.2.6-100.2 1.5-3.4 1.5-5.8 5.2-7.4 11.4-.7 2.7-2.3 6.3-3.6 8-4.1 5.3-15.1 18.4-22.3 26.5-12.1 13.6-20.8 26.8-24.9 37.6-2 5.3-3.6 10.7-3.6 11.9 0 2.9 6 8.4 10.7 9.9 2.1.7 4.5 1.8 5.3 2.5.8.7 3.3 1.5 5.5 1.8 2.2.2 10.5 1.6 18.5 3 39.3 7.1 67.1 8.7 101 5.9 8.5-.6 37.3-1.7 64-2.2 50.7-1 71.8-2.2 83.4-4.5 8.7-1.8 11.6-3.7 11.6-7.4 0-1.6.9-4 2-5.3 1.9-2.5 5.8-12 8.7-21.3.8-2.8 2.1-6.5 2.9-8.2l1.4-3.3h12.2c6.8 0 16.1-.4 20.8-1 4.7-.5 23.4-1.4 41.5-2 18.2-.6 35.7-1.5 39-2 3.3-.5 13.9-1.5 23.5-2.1 9.6-.5 18.6-1.3 20-1.7 1.6-.5 3.7-2.7 5.7-6.2 5.6-9.6 8.1-13.3 15.3-23 3.8-5.2 7.7-11 8.6-12.8.9-1.9 2.7-5 4.1-7 1.3-2 6.3-11.3 11-20.7 4.7-9.3 9.1-17.7 9.9-18.5 4-4.6 5.7-14.7 2.9-17-2.5-2.1-9.7-2.4-12.3-.4zM654 519.4c2.5 0 6.2-.3 8.2-.8 3.4-.7 3.9-.6 4.8 1.6 1 2 .8 3-1 5.9-1.2 1.9-5.2 8.8-8.9 15.4-8.6 15.4-12 20.8-20.4 32.5-5.2 7.3-6.7 10.1-6.4 12.2.4 3.1.2 3.1-19.3 4.3-5.2.4-11.5 1.1-14 1.6s-18.9 1.3-36.5 1.8c-19.9.6-36.4 1.6-43.5 2.6-13.5 2-38.8 1.7-41.4-.4-1.2-1-3.1-1-9.3-.1-9.1 1.4-28.5.7-38.3-1.4-3.6-.8-9.1-2-12.3-2.6-6.7-1.4-6.7-.8-.4-11.8 3.8-6.7 12.7-18.4 25.8-33.7 2.8-3.3 7.3-9.2 9.9-13.1 3.2-4.7 5.8-7.4 7.4-7.8 1.4-.3 3.7-2.1 5.1-3.9l2.6-3.2 91.7.4c50.4.3 93.7.5 96.2.5zm-247 45.1c0 .2-1.3 1.9-2.9 3.7-1.6 1.8-4.1 5.5-5.6 8.3-1.5 2.7-4.5 7.3-6.6 10.1-5.4 7.1-5.3 12.1.2 16.2 1.9 1.4 14.2 4.7 21.5 5.7 2.7.4 7.2 1.3 10 2s10.2 1.6 16.5 1.9c16.1.9 17.9 1.3 17.9 3.6 0 1.1-.8 2.8-1.7 3.8-3.6 3.8-6.2 10.1-6.9 16.6-.4 3.6-1.2 7-1.8 7.5-1.7 1.4-31.8 3.1-72.1 4-25.2.5-37.7 1.2-39.2 2-2 1-2.2.9-1.6-.5.5-1.5 0-1.6-3.8-1-2.4.3-13.6 1-24.9 1.6-11.3.5-22.5 1.2-25 1.5-2.5.3-14.6.1-27-.4-18.7-.8-25.7-1.6-41.5-4.5-21.3-4-33.5-6.6-33.5-7.1 0-3.7 13.5-25.5 17.4-28 1.4-.9 2.8-2.5 3.1-3.6.4-1.1 4.3-5.8 8.7-10.6 7.9-8.5 15.5-18.2 21.4-27.3l3-4.5 8.9-.6c11-.6 165.5-1.1 165.5-.4z"/><path d="M526 527.9c0 .4-1.6 1.1-3.5 1.4-5.5.9-10.5 4.4-10.5 7.3 0 4 4.2 7.4 9.2 7.4 10.3 0 15.6-3.8 14.4-10.4-.8-4.1-2.8-6-5.6-5.3-1.1.3-2 .1-2-.4s-.4-.9-1-.9c-.5 0-1 .4-1 .9z"/><path d="M492.3 541c-5 1.2-9.7 4.4-10.8 7.4-1.4 4 1.8 9.3 7.5 12.4 5 2.7 11.5 2.6 17.2-.3 1.7-.8 4.6-1.5 6.5-1.5 1.9 0 4.3-.5 5.4-1 2.5-1.4 2.4-.8-.6 3.6s-3.1 6.8-.5 9.4c4.1 4.1 17.8 1.8 20.2-3.4.9-2.1.8-2.9-.5-4.4-1-1-1.7-2.3-1.7-2.9 0-1.4-2.4-2.3-6.3-2.4-3.2 0-3.2 0-.7-1 1.5-.6 6.3-.8 12-.4 5.2.4 11.4.8 13.6 1 2.3.1 4.7.6 5.4 1 .7.4 4.1 1 7.5 1.3 6.4.5 6.4.5 8.5-2.9 1.3-2.1 1.9-4.7 1.8-6.9l-.3-3.5-7 .1c-3.8 0-11.7.2-17.5.4-5.8.2-11.8 0-13.4-.5-1.7-.5-6.8-.3-12.6.5l-9.8 1.3-8.4-4.2c-8.5-4.2-9.9-4.5-15.5-3.1zM311.3 579.1c-2.6.6-4.3 1.6-4.3 2.5 0 .8-1 1.4-2.3 1.4-2.4 0-6.7 3.7-6.7 5.8 0 .7-.4 1.2-1 1.2-1.7 0-1.1 4.1 1.1 6.8l2.1 2.7-4.3.3c-2.3.2-8.4-.4-13.6-1.4-10.7-1.9-11.9-1.5-12.1 4.2-.1 3.7 1.2 7.3 3.2 8.6 2 1.4 16.5.9 20.3-.7 1.9-.8 4.7-1.5 6.1-1.5 2.4 0 2.4.2 1.8 4.6-1 7.7 1.3 9.8 13.1 11.5 5.4.8 6.9.6 13-1.7 20.1-7.6 44.1-23.5 44.3-29.4 0-.8-.5-3.2-1.1-5.3-.9-3.2-1.9-4.2-7.2-7l-6.2-3.2-21-.2c-11.5-.1-22.9.3-25.2.8z"/></svg>
\ No newline at end of file
diff --git a/templates/base.html b/templates/base.html
index 05328d0c12a4badfda097d8a2af0afb802f99e49..4b5f9872d7b52a12eeeabf8ea7500833a522d8f3 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -6,8 +6,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
 <html lang="en" class="position-relative h-100">
 <head>
     <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <title>
         {% block title %}{{ title }}{% endblock title %} - {{ request.site.name }}
     </title>
@@ -23,19 +22,41 @@ SPDX-License-Identifier: GPL-3.0-or-later
     <meta name="msapplication-TileColor" content="#da532c">
     <meta name="msapplication-config" content="{% static "favicon/browserconfig.xml" %}">
     <meta name="theme-color" content="#ffffff">
+    {% if no_cache %}
+        <meta name="turbolinks-cache-control" content="no-cache">
+    {% endif %}
 
     {# Bootstrap CSS #}
     <link rel="stylesheet"
-          href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
-          integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
+          href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
+          integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
           crossorigin="anonymous">
     <link rel="stylesheet"
           href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
+
+    {# JQuery, Bootstrap and Turbolinks JavaScript #}
+    <script src="https://code.jquery.com/jquery-3.4.1.min.js"
+            integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
+            crossorigin="anonymous"></script>
+    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
+            integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
+            crossorigin="anonymous"></script>
+    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
+            integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
+            crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js"
+            crossorigin="anonymous"></script>
+
+    {# Si un formulaire requiert des données supplémentaires (notamment JS), les données sont chargées #}
+    {% if form.media %}
+        {{ form.media }}
+    {% endif %}
+
     {% block extracss %}{% endblock %}
 </head>
-<body>
-<main>
-    <nav class="navbar navbar-expand-md navbar-light bg-light fixed-navbar">
+<body class="d-flex w-100 h-100 flex-column">
+<main class="mb-auto">
+    <nav class="navbar navbar-expand-md navbar-light bg-light fixed-navbar shadow-sm">
         <a class="navbar-brand" href="/">{{ request.site.name }}</a>
         <button class="navbar-toggler" type="button" data-toggle="collapse"
                 data-target="#navbarNavAltMarkup"
@@ -46,7 +67,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
         <div class="collapse navbar-collapse" id="navbarNavDropdown">
             <ul class="navbar-nav">
                 <li class="nav-item active">
-                    <a class="nav-link" href="#"><i class="fa fa-coffee"></i> Consos</a>
+                    <a class="nav-link" href="{% url 'note:consos' %}"><i class="fa fa-coffee"></i> Consos</a>
                 </li>
                 <li class="nav-item active">
                     <a class="nav-link" href="{% url 'member:club_list' %}"><i class="fa fa-users"></i> Clubs</a>
@@ -89,31 +110,23 @@ SPDX-License-Identifier: GPL-3.0-or-later
             </ul>
         </div>
     </nav>
-    <div class="container-fluid mb-5 mt-2">
-        <div class="row">
-            <div class="col-md-1">
-                {% block sidebar %}
-                {% endblock %}
-            </div>
-            <div class="col-md-10 text-justify">
-                {% block contenttitle %}<h1>{{ title }}</h1>{% endblock %}
-                {% block content %}
-                    <p>Default content...</p>
-                {% endblock content %}
-            </div>
-        </div>
+    <div class="container-fluid my-3" style="max-width: 1600px;">
+        {% block contenttitle %}<h1>{{ title }}</h1>{% endblock %}
+        {% block content %}
+            <p>Default content...</p>
+        {% endblock content %}
     </div>
 </main>
-<footer class="bg-light fixed-bottom  py-2">
+<footer class="bg-light mt-auto py-2">
     <div class="container-fluid">
         <div class="row">
             <div class="col-sm">
                 <form action="{% url 'set_language' %}" method="post"
                       class="form-inline">
                     <span class="text-muted mr-1">
-                        NoteKfet2020 -
+                        NoteKfet2020 &mdash;
                         <a href="mailto:tresorie.bde@lists.crans.org"
-                           class="text-muted">Nous contacter</a> -
+                           class="text-muted">Nous contacter</a> &mdash;
                     </span>
                     {% csrf_token %}
                     <select title="language" name="language"
@@ -142,16 +155,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
     </div>
 </footer>
 
-{# Bootstrap JavaScript #}
-<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
-        integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
-        crossorigin="anonymous"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
-        integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
-        crossorigin="anonymous"></script>
-<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
-        integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
-        crossorigin="anonymous"></script>
 {% block extrajavascript %}
 {% endblock extrajavascript %}
 </body>
diff --git a/templates/member/manage_auth_tokens.html b/templates/member/manage_auth_tokens.html
new file mode 100644
index 0000000000000000000000000000000000000000..0103fbbba7ff17d4c9650cd67806b9e556ffeb96
--- /dev/null
+++ b/templates/member/manage_auth_tokens.html
@@ -0,0 +1,33 @@
+{% extends "base.html" %}
+{% load i18n static pretty_money django_tables2 %}
+
+{% block content %}
+    <div class="alert alert-info">
+    <h4>À quoi sert un jeton d'authentification ?</h4>
+
+    Un jeton vous permet de vous connecter à <a href="/api/">l'API de la Note Kfet</a>.<br />
+    Il suffit pour cela d'ajouter en en-tête de vos requêtes <code>Authorization: Token &lt;TOKEN&gt;</code>
+    pour pouvoir vous identifier.<br /><br />
+
+    Une documentation de l'API arrivera ultérieurement.
+    </div>
+
+    <div class="alert alert-info">
+        <strong>{%trans  'Token' %} :</strong>
+        {% if 'show' in request.GET %}
+            {{ token.key }} (<a href="?">cacher</a>)
+        {% else %}
+            <em>caché</em> (<a href="?show">montrer</a>)
+        {% endif %}
+        <br />
+        <strong>{%trans  'Created' %} :</strong> {{ token.created }}
+    </div>
+
+    <div class="alert alert-warning">
+        <strong>Attention :</strong> regénérer le jeton va révoquer tout accès autorisé à l'API via ce jeton !
+    </div>
+
+    <a href="?regenerate">
+        <button class="btn btn-primary">{% trans 'Regenerate token' %}</button>
+    </a>
+{% endblock %}
diff --git a/templates/member/profile_detail.html b/templates/member/profile_detail.html
index 53a0b9a0c3608584f8d7b8136a77f01ecfe0ea12..655f9893271d4c582a087d701b0ad53ae0c1ff62 100644
--- a/templates/member/profile_detail.html
+++ b/templates/member/profile_detail.html
@@ -2,64 +2,76 @@
 {% load i18n static pretty_money django_tables2 %}
 
 {% block content %}
-    <h3>Compte n° {{ object.pk }}</h3>
+<div class="row mt-4">
+    <div class="col-md-3 mb-4">
+        <div class="card bg-light shadow">
+            <img src="{{ object.note.display_image.url }}" class="card-img-top" alt="">
+            <div class="card-body">
+                <dl class="row">
+                    <dt class="col-xl-6">{% trans 'name'|capfirst %}, {% trans 'first name' %}</dt>
+                    <dd class="col-xl-6">{{ object.user.last_name }} {{ object.user.first_name }}</dd>
 
-    <img src="{{ object.note.display_image.url }}" alt=""/>
+                    <dt class="col-xl-6">{% trans 'username'|capfirst %}</dt>
+                    <dd class="col-xl-6">{{ object.user.username }}</dd>
 
-    <dl class="row">
-        <dt class="col-6 col-md-3">{% trans 'name'|capfirst %}</dt>
-        <dd class="col-6 col-md-3">{{ object.user.name }}</dd>
-        <dt class="col-6 col-md-3">{% trans 'first name'|capfirst %}</dt>
-        <dd class="col-6 col-md-3">{{ object.user.first_name }}</dd>
-        <dt class="col-6 col-md-3">{% trans 'username'|capfirst %}</dt>
-        <dd class="col-6 col-md-3">{{ object.user.username }}</dd>
-        <dt class="col-6 col-md-3">Aliases</dt>
-        <dd class="col-6 col-md-3">{{ object.user.note.aliases_set.all }}</dd>
-        <dt class="col-6 col-md-3">{% trans 'section'|capfirst %}</dt>
-        <dd class="col-6 col-md-3">{{ object.section }}</dd>
-        <dt class="col-6 col-md-3">{% trans 'address'|capfirst %}</dt>
-        <dd class="col-6 col-md-3">{{ object.address }}</dd>
-        <dt class="col-6 col-md-3">{% trans 'balance'|capfirst %}</dt>
-        <dd class="col-6 col-md-3">{{ object.user.note.balance | pretty_money }}</dd>
-    </dl>
-    <center>
-        <a class="btn btn-primary" href="{% url 'member:user_update_profile' object.pk %}">{% trans 'Update Profile' %}</a>
-        <a class="btn btn-primary" href="{% url 'password_change' %}">{% trans 'Change password' %}</a>
-    </center>
+                    <dt class="col-xl-6">{% trans 'password'|capfirst %}</dt>
+                    <dd class="col-xl-6">
+                        <a class="small" href="{% url 'password_change' %}">
+                            {% trans 'Change password' %}
+                        </a>
+                    </dd>
 
-<div class="accordion" id="accordionProfile">
-  <div class="card">
-    <div class="card-header" id="headingOne">
-      <h5 class="mb-0">
-        <button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
-            <i class="fa fa-users"></i> {% trans "View my memberships" %}
-        </button>
-      </h5>
-    </div>
+                    <dt class="col-xl-6">{% trans 'section'|capfirst %}</dt>
+                    <dd class="col-xl-6">{{ object.section }}</dd>
 
-    <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionProfile">
-      <div class="card-body">
-        {% render_table club_list %}
-      </div>
-    </div>
-  </div>
-  <div class="card">
-    <div class="card-header" id="headingTwo">
-      <h5 class="mb-0">
-        <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
-            <i class="fa fa-euro"></i> Historique des transactions
-        </button>
-      </h5>
-    </div>
-    <div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionProfile">
-      <div class="card-body">
-          {% render_table history_list %}
-      </div>
-    </div>
-  </div>
-</div>
+                    <dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
+                    <dd class="col-xl-6">{{ object.address }}</dd>
 
+                    <dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
+                    <dd class="col-xl-6">{{ object.user.note.balance | pretty_money }}</dd>
 
+                    <dt class="col-xl-6">{% trans 'aliases'|capfirst %}</dt>
+                    <dd class="col-xl-6">{{ object.user.note.alias_set.all|join:", " }}</dd>
+                </dl>
 
+                {% if object.user.pk == user.pk %}
+                    <a class="small" href="{% url 'member:auth_token' %}">{% trans 'Manage auth token' %}</a>
+                {% endif %}
+            </div>
+            <div class="card-footer">
+                <a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' object.pk %}">{% trans 'Update Profile' %}</a>
+            </div>
+        </div>
+    </div>
+
+    <div class="col-md-9">
+        <div class="accordion shadow" id="accordionProfile">
+            <div class="card">
+                <div class="card-header position-relative" id="clubListHeading">
+                    <a class="btn btn-link stretched-link font-weight-bold"
+                       data-toggle="collapse" data-target="#clubListCollapse"
+                       aria-expanded="true" aria-controls="clubListCollapse">
+                        <i class="fa fa-users"></i> {% trans "View my memberships" %}
+                    </a>
+                </div>
+                <div id="clubListCollapse" class="collapse show" style="overflow:auto hidden" aria-labelledby="clubListHeading" data-parent="#accordionProfile">
+                    {% render_table club_list %}
+                </div>
+            </div>
 
-    {% endblock %}
+            <div class="card">
+                <div class="card-header position-relative" id="historyListHeading">
+                    <a class="btn btn-link stretched-link collapsed font-weight-bold"
+                       data-toggle="collapse" data-target="#historyListCollapse"
+                       aria-expanded="false" aria-controls="historyListCollapse">
+                        <i class="fa fa-euro"></i> Historique des transactions
+                    </a>
+                </div>
+                <div id="historyListCollapse" class="collapse" style="overflow:auto hidden" aria-labelledby="historyListHeading" data-parent="#accordionProfile">
+                    {% render_table history_list %}
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+{% endblock %}
diff --git a/templates/member/profile_update.html b/templates/member/profile_update.html
index 10936cf77edc95a19096d846628647419f8dd657..a47a147bdc9d1c07b62c6a411396bfa68b681f6b 100644
--- a/templates/member/profile_update.html
+++ b/templates/member/profile_update.html
@@ -1,17 +1,16 @@
-<!doctype html>
 {% extends "base.html" %}
-{% load crispy_forms_tags %}
-{% load i18n static pretty_money django_tables2 %}
+{% load i18n crispy_forms_tags %}
+{% comment %}
+SPDX-License-Identifier: GPL-3.0-or-later
+{% endcomment %}
 
 {% block content %}
-
 <form method="post">
-      {% csrf_token %}
-      {{ form|crispy }}
-      {{ profile_form|crispy }}
-      <button class="btn btn-link" type="submit">
-          {% trans "Save Changes" %}
-      </button>
-  </form>
-
+    {% csrf_token %}
+    {{ form|crispy }}
+    {{ profile_form|crispy }}
+    <button class="btn btn-primary" type="submit">
+        {% trans "Save Changes" %}
+    </button>
+</form>
 {% endblock %}
diff --git a/templates/note/conso_form.html b/templates/note/conso_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..b121ad54d12f970a66f9572194d3b45d8a3376c8
--- /dev/null
+++ b/templates/note/conso_form.html
@@ -0,0 +1,97 @@
+{% extends "base.html" %}
+
+{% load i18n static pretty_money %}
+
+{# Remove page title #}
+{% block contenttitle %}{% endblock %}
+
+{% block content %}
+    {# Regroup buttons under categories #}
+    {% regroup transaction_templates by template_type as template_types %}
+
+    <form method="post" onsubmit="window.onbeforeunload=null">
+        {% csrf_token %}
+
+        <div class="row">
+            <div class="col-sm-5 mb-4">
+                {% if form.non_field_errors %}
+                    <p class="errornote">
+                        {% for error in form.non_field_errors %}
+                            {{ error }}
+                        {% endfor %}
+                    </p>
+                {% endif %}
+                {% for field in form %}
+                    <div class="form-row{% if field.errors %} errors{% endif %}">
+                        {{ field.errors }}
+                        <div>
+                            {{ field.label_tag }}
+                            {% if field.is_readonly %}
+                                <div class="readonly">{{ field.contents }}</div>
+                            {% else %}
+                                {{ field }}
+                            {% endif %}
+                            {% if field.field.help_text %}
+                                <div class="help">{{ field.field.help_text|safe }}</div>
+                            {% endif %}
+                        </div>
+                    </div>
+                {% endfor %}
+            </div>
+
+            <div class="col-sm-7">
+                <div class="card text-center shadow">
+                    {# Tabs for button categories #}
+                    <div class="card-header">
+                        <ul class="nav nav-tabs nav-fill card-header-tabs">
+                            {% for template_type in template_types %}
+                                <li class="nav-item">
+                                    <a class="nav-link" data-toggle="tab" href="#{{ template_type.grouper|slugify }}">
+                                        {{ template_type.grouper }}
+                                    </a>
+                                </li>
+                            {% endfor %}
+                        </ul>
+                    </div>
+
+                    {# Tabs content #}
+                    <div class="card-body">
+                        <div class="tab-content">
+                            {% for template_type in template_types %}
+                                <div class="tab-pane" id="{{ template_type.grouper|slugify }}">
+                                    <div class="d-inline-flex flex-wrap justify-content-center">
+                                        {% for button in template_type.list %}
+                                            <button class="btn btn-outline-dark rounded-0 flex-fill"
+                                                    name="button" value="{{ button.name }}">
+                                                {{ button.name }} ({{ button.amount | pretty_money }})
+                                            </button>
+                                        {% endfor %}
+                                    </div>
+                                </div>
+                            {% endfor %}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </form>
+{% endblock %}
+
+{% block extrajavascript %}
+    <script type="text/javascript">
+        $(document).ready(function() {
+            // If hash of a category in the URL, then select this category
+            // else select the first one
+            if (location.hash) {
+                $("a[href='" + location.hash + "']").tab("show");
+            } else {
+                $("a[data-toggle='tab']").first().tab("show");
+            }
+
+            // When selecting a category, change URL
+            $(document.body).on("click", "a[data-toggle='tab']", function(event) {
+                location.hash = this.getAttribute("href");
+            });
+        });
+    </script>
+{% endblock %}
diff --git a/tox.ini b/tox.ini
index c86913729a5e88184c9947fe10a7cee4af2766f1..c4e88c786dc93b3d03e10e9b775644415267a2a1 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,9 +1,13 @@
 [tox]
-envlist = py36,py37,linters
+envlist =
+    py36-django22
+    py37-django22
+    linters
 skipsdist = True
 
 [testenv]
-basepython = python3
+setenv =
+	PYTHONWARNINGS = all
 deps =
     -r{toxinidir}/requirements.txt
     coverage
@@ -12,11 +16,6 @@ commands =
     coverage run ./manage.py test {posargs}
     coverage report -m
 
-[testenv:pre-commit]
-deps = pre-commit
-commands =
-    pre-commit run --all-files --show-diff-on-failure
-
 [testenv:linters]
 deps =
     -r{toxinidir}/requirements.txt
@@ -26,13 +25,12 @@ deps =
     flake8-typing-imports
     pep8-naming
     pyflakes
-    pylint
 commands =
-    flake8 app/activity app/member app/note
-    pylint .
+    flake8 apps/activity apps/api apps/member apps/note
 
 [flake8]
-ignore = D203, W503, E203
+# Ignore too many errors, should be reduced in the future
+ignore = D203, W503, E203, I100, I101
 exclude =
     .tox,
     .git,
@@ -45,7 +43,7 @@ exclude =
     .eggs,
     *migrations*
 max-complexity = 10
+max-line-length = 160
 import-order-style = google
 application-import-names = flake8
 format = ${cyan}%(path)s${reset}:${yellow_bold}%(row)d${reset}:${green_bold}%(col)d${reset}: ${red_bold}%(code)s${reset} %(text)s
-