diff --git a/reaction-master/#reaction.py# b/reaction-master/#reaction.py#
deleted file mode 100755
index dacff98c7dc461a31ca032ab31d9f3a2828425e0..0000000000000000000000000000000000000000
--- a/reaction-master/#reaction.py#
+++ /dev/null
@@ -1,269 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# reaction
-# Copyright (C) 2021  EGI-IRTF
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-
-from datetime import datetime, timedelta
-try:
-    from jinja2 import Template
-    jinja2 = True
-except:
-    jinja2 = False
-import glob
-import io
-import os
-try:
-    import matplotlib.pyplot as plot
-    matplotlib = True
-except:
-    matplotlib = False
-
-BASEDIR = 'stats/'
-
-if jinja2:
-    LATEXTEMPLATE = Template(r'''
-<pre>
-\documentclass{article}
-
-\usepackage{tikz}
-\usepackage{pgfplots}
-\pgfplotsset{width=\textwidth,compat=1.16}
-
-\begin{document}
-
-  \begin{tikzpicture}
-    \begin{axis}[
-      title={Communication Challenge -- {{title}}},
-      xlabel={Time [hours]},
-      ylabel={Reactions [number of participants]},
-      xmin=0, xmax={{xmax}},
-      ymin=0, ymax={{ymax}},
-      legend pos=south east,
-      ymajorgrids=true,
-      grid style=dashed,
-    ]
-      \addplot[color=blue, mark=square]
-        coordinates { {{coordinates}} };
-      \addlegendentry{ {{responses}} participants ({{percentageResponses}}\,\%) have reacted}
- 
-      \addplot[color=red]
-        coordinates { (0, {{sitesNumber}})({{xmax}}, {{sitesNumber}}) };
-      \addlegendentry{ {{sitesNumber}} participants have been challenged}
- 
-      \addplot[color=green]
-        coordinates { (24, 0)(24, {{ymax}}) };
-      \addlegendentry{ {{quickSitesNumber}} participants ({{percentageQuick}}\,\%) have reacted within 24 h}
-    \end{axis}
-  \end{tikzpicture}
-
-\end{document}
-</pre>
-''')
-
-def floatPart(string):
-    return(float(string.split('/')[-1].split('-', 1)[0]))
-
-def hashtagPart(string):
-    return(string.split('/')[-1].split('-', 1)[-1])
-
-class ReactionApp(object):
-    def __init__(self, environ, start_response):
-        self.environ = environ
-        self.start = start_response
-
-    def format(self, code, msg):
-        self.start(code, [('Content-type', 'text/html; charset=UTF-8')])
-        return '<html><body><p>{msg}</p></body></html>'.format(msg=msg).encode('UTF-8')
-
-    def image(self, code, type, image):
-        self.start(code, [('Content-type', 'image/{}'.format(type))])
-        return image
-
-    def updatefile(self, folder, hashtag):
-        with open(folder + hashtag, 'a') as tagfile:
-            tagfile.write(str((datetime.now()-datetime(1970, 1, 1)).total_seconds()) + '\n')
-
-    def checkresults(self, folder, hashtag):
-        if os.path.isfile(folder + '.LOCKED'):
-            return self.format('200 OK', 'This campaign has been closed!')
-        with open(folder + hashtag, 'r') as tagfile:
-            lines = tagfile.read().splitlines()
-        if len(lines) < 2:
-            return self.format('500 Internal Server Error', 'Unfortunately, this campaign is broken!')
-        elapsedtime = datetime.fromtimestamp(float(lines[1])) - datetime.fromtimestamp(float(lines[0]))
-        if not os.path.isfile(folder + str(elapsedtime.total_seconds()) + '-' + hashtag):
-            open(folder + str(elapsedtime.total_seconds()) + '-' + hashtag, 'a').close()
-        responses = glob.glob(folder + '*-*')
-        responses.sort(key=floatPart)
-        responses = list(map(hashtagPart, responses))
-        message = '<p>Reaction time: ' + str(elapsedtime) + '</p>'
-        return self.format('200 OK', message)
-
-    def gatherdata(self, folder):
-        if not os.path.isdir(folder):
-            return False
-        responseFiles = glob.glob(folder + '*-*')
-        data = {}
-        data['title'] = folder.split('/')[-2]
-        data['sites'] = set([hashtagPart(x) for x in glob.glob(folder + '*')])
-        data['sitesNumber'] = len(data['sites'])
-        data['responses'] = len(responseFiles)
-        data['responseTimes'] = {hashtagPart(x): floatPart(x) for x in responseFiles}
-        data['responsePoints'] = {hashtagPart(x): os.path.getctime(x) for x in responseFiles}
-        data['missingSites'] = list(filter(lambda x: x not in data['responseTimes'], data['sites']))
-        data['missingSitesNumber'] = len(data['missingSites'])
-        data['quickSites'] = list(filter(lambda x: x<(24*3600), data['responseTimes'].values()))
-        data['quickSitesNumber'] = len(data['quickSites'])
-        data['percentageResponses'] = round(100*data['responses']/len(data['sites']))
-        data['percentageQuick'] = round(100*len(data['quickSites'])/len(data['sites']))
-        return data
-
-    def getresults(self, folder):
-        ReactionApp.getresults.rank = 0
-        def steprank():
-            ReactionApp.getresults.rank += 1
-            return(ReactionApp.getresults.rank)
-        if not os.path.isdir(folder):
-            return self.format('404 Not Found', 'This campaign does not exist!')
-        data = self.gatherdata(folder)
-        message = '<h1>Communication Challenge — {title}'.format_map(data)
-        message += ' — {status} Results</h1>'
-        message += '{responses} participants ({percentageResponses} %) have reacted<br>'.format_map(data)
-        message += '{sitesNumber} participants have been challenged<br>'.format_map(data)
-        message += '{quickSitesNumber} participants ({percentageQuick} %) have reacted within 24 h<br>'.format_map(data)
-        message += '<h2>Reaction Times</h2>'
-        message += '<table cellspacing="2" cellpadding="5" bgcolor="#000000"><tr bgcolor="#ffffff"><th align="left">Sequence #</th><th align="left">Timestamp</th><th align="left">Participant</th><th align="left">Reaction Time</th></tr>'
-        message += '<tr bgcolor="#ffffff">' + '</tr><tr bgcolor="#ffffff">'.join(map(lambda x: '<td align="right">'+str(steprank())+'</td><td>'+datetime.fromtimestamp(data['responsePoints'][x], tz=datetime.now().astimezone().tzinfo).isoformat()+'</td><td><code>'+x+'</code></td><td align="right">'+str(timedelta(seconds=data['responseTimes'][x]))+'</td>', sorted(data['responseTimes'].keys(), key=lambda x: data['responseTimes'][x]))) + '</tr></table>'
-        if (data['missingSitesNumber'] > 0):
-            message += '<h2>Missing Reactions</h2>'
-            message += '<ul><li><code>' + '...</code></li><li><code>'.join(map(lambda x: x[0:48], sorted(data['missingSites']))) + '...</code></li></ul>'
-            status = 'Preliminary'
-        else:
-            status = 'Final'
-        if os.path.isfile(folder + '.LOCKED'):
-            status = 'Final'
-        return self.format('200 OK', message.format(status=status))
-
-usa    def getlatex(self, folder):
-        if not os.path.isdir(folder):
-            return self.format('404 Not Found', 'This campaign does not exist!')
-        data = self.gatherdata(folder)
-        responseTimes = [round(x/3600, 3) for x in data['responseTimes'].values()]
-        responseTimes.sort()
-        data['coordinates'] = '(0, 0)'
-        data['coordinates'] += ''.join(['('+str(responseTimes[x])+', '+str(x+1)+')' for x in range(data['responses'])])
-        data['xmax'] = round(max(responseTimes) * 1.2, -1)
-        data['ymax'] = round(data['sitesNumber'] * 1.2, -1)
-        return self.format('200 OK', LATEXTEMPLATE.render(data))
-
-    def getgraph(self, folder, format):
-        if not os.path.isdir(folder):
-            return self.format('404 Not Found', 'This campaign does not exist!')
-        data = self.gatherdata(folder)
-        responseTimes = [round(x/3600, 3) for x in data['responseTimes'].values()]
-        responseTimes.append(0)
-        responseTimes.sort()
-        xmax = round(max(responseTimes) * 1.2, -1)
-        ymax = round(data['sitesNumber'] * 1.2, -1)
-        plot.figure()
-        plot.plot(responseTimes, range(data['responses']+1), marker='.', color='blue', label='{responses} participants ({percentageResponses} %) have reacted'.format_map(data), zorder=3)
-        plot.axhline(y=data['sitesNumber'], color='red', label='{sitesNumber} participants have been challenged'.format_map(data), zorder=2)
-        plot.axvline(x=24, color='lightgreen', label='{quickSitesNumber} participants ({percentageQuick} %) have reacted within 24 h'.format_map(data), zorder=1)
-        plot.title('Communication Challenge — {title}'.format_map(data))
-        plot.xlabel('Time [hours]')
-        plot.ylabel('Reactions [number of participants]')
-        plot.legend(loc='lower right')
-        plot.plot
-        with io.BytesIO() as buffer:
-            plot.savefig(buffer, format=format)
-            buffer.seek(0)
-            return self.image('200 OK', format, buffer.read())
-
-    def process(self):
-        path = self.environ['PATH_INFO'].split('/')[1:]
-        try:
-            prefix, hashtag = path[0].rsplit('-', 1)
-        except ValueError:
-            prefix = ''
-            hashtag = path[0]
-        try:
-            int(hashtag, 16)
-        except (KeyError, ValueError):
-            return self.format('400 Bad Request', 'This is not a valid link!')
-
-        if prefix:
-            folder = os.path.abspath(BASEDIR + prefix) + '/'
-            if not folder.startswith(BASEDIR):
-                self.format('400 Bad Request', 'Good try!')
-        else:
-            folder = BASEDIR
-
-        if not os.path.isfile(folder + hashtag):
-            if len(path) == 2 and path[1] == 'create':
-                if not os.path.isdir(folder):
-                    os.makedirs(folder)
-                self.updatefile(folder, hashtag)
-                return self.format('200 OK', 'File {tag} created'.format(tag=hashtag))
-            elif len(path) != 1:
-                return self.format('400 Bad Request', 'What are you trying to do?')
-            elif not os.path.isdir(folder):
-                return self.format('404 Not Found', 'This campaign does not exist!')
-            else:
-                return self.format('404 Not Found', 'This id does not exist!')
-
-        if 'HTTP_REFERER' in self.environ:
-            referer = self.environ['HTTP_REFERER']
-        else:
-            referer = ''
-        if 'HTTPS' in self.environ and self.environ['HTTPS']:
-            url = 'https://'
-        else:
-            url = 'http://'
-        url += '{host}{URI}'.format(host=self.environ['HTTP_HOST'],
-                                    URI=self.environ['REQUEST_URI'])
-        if referer == url:
-            self.updatefile(folder, hashtag)
-            return self.checkresults(folder, hashtag)
-        elif len(path) == 2:
-            if path[1] == 'results':
-                return self.getresults(folder)
-            elif path[1] == 'graph' and matplotlib:
-                return self.getgraph(folder, 'png')
-            elif path[1] == 'latex' and jinja2:
-                return self.getlatex(folder)
-            else:
-                return self.format('400 Bad Request', 'Nice try!')
-        elif len(path) == 3 and path[1] == 'graph' and matplotlib:
-            if path[2] == 'jpg':
-                return self.getgraph(folder, 'jpg')
-            elif path[2] == 'pdf':
-                return self.getgraph(folder, 'pdf')
-            elif path[2] == 'png':
-                return self.getgraph(folder, 'png')
-            elif path[2] == 'svg':
-                return self.getgraph(folder, 'svg')
-            else:
-                return self.format('400 Bad Request', 'Nice try!')
-        elif os.path.isfile(folder + '.LOCKED'):
-            return self.format('200 OK', 'This campaign has been closed!')
-        else:
-            return self.format('200 OK', 'Please click <a href="{URL}">here</a> to confirm your submission!'.format(URL=url))
-
-
-    def __iter__(self):
-        yield self.process()