From 95d57219ee18cfeb88dffb4fdcd323f0b841b0c1 Mon Sep 17 00:00:00 2001 From: shinedday <shinedday@gmail.com> Date: Fri, 13 May 2022 08:45:40 +0200 Subject: [PATCH] Add Newtwork and experiment menu --- db.sqlite3 | Bin 139264 -> 147456 bytes iotamak_ihm/settings.py | 3 +- iotamak_ihm/urls.py | 2 +- ping/admin.py | 6 +- ping/migrations/0001_initial.py | 11 +- ping/migrations/0002_experiment.py | 23 ++++ ping/models.py | 24 +++- ping/static/ping/index.css | 41 +++++++ ping/templates/ping/entry.html | 35 ++++++ ping/templates/ping/experiment.html | 46 ++++++++ ping/templates/ping/index.html | 81 +++++++++++--- ping/urls.py | 9 +- ping/views.py | 164 +++++++++++++++++++++++++++- uploads/media/config.json | 25 +++++ uploads/media/env.py | 67 ++++++++++++ uploads/media/philosophers.zip | Bin 0 -> 3191 bytes 16 files changed, 508 insertions(+), 29 deletions(-) create mode 100644 ping/migrations/0002_experiment.py create mode 100644 ping/static/ping/index.css create mode 100644 ping/templates/ping/entry.html create mode 100644 ping/templates/ping/experiment.html create mode 100644 uploads/media/config.json create mode 100644 uploads/media/env.py create mode 100644 uploads/media/philosophers.zip diff --git a/db.sqlite3 b/db.sqlite3 index 432f204be352251f792e0f91a1b7377303918b43..e33654f60a42bd1bdaf59e30dc8587fc89bd53be 100644 GIT binary patch delta 7218 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 delta 1829 zcmZo@;A}X+F+o~Tje&tdi2(teC+Zk8s%=b|&(9&u%fP@O%q>5eT|j+f<43N^^3n=| z1`39zR>qcA29|ne7M6yV#*+i2RrnyH=2oWWdd8;albfV%pb8;EMiyokhLg`r8={CB zSXdYuO%{|fK^8T#G&M9dn;a%%fg);dWM*PGdA^J}il~XHrIG36=Q1d^85vm^n;K0v zku^e5YiMe2W-+;3))+<9z{t?ZX!34Z6qgyAn;ILMPyQ>5;xa>1b3;?3$xd>X$R-$? z7+Dw_P3}PxH8L|ZGnsr%&I(1Xfsui+*<?j|BUz*XGq5l-GBPz_W@Qjpbxcgj&CHv; zP+k;SpMj}`k(ue_Y4Wh(2ZySGv4w@9<>ce?8tTZV85)}yne+0mU|{1fW8i<ue}#WH ze;I!_|1AEBjg1NXqQY#<+Kh>%B^mJrsYSV&#l@NVc`}o`^%X>g5vc&o5@%&LW}N=f ziBZ^@U6`3!mop_RF)uwo9_+^WocwfAMrM6Rs9<hpdQoCYW`16=Fc$*@13P~;1OGez z)BLyi_wp~`ujcRG*qF-C!_Oir$ykt?m!6!HIl0}wR*0Ryih=(v|4sf={CoK4^LO!A zZEQ^8=jCH(VGxysEA+2rmf^iJnLWUWosahy?=#*j8ylzax(l)}Dl@W|Wu}(LC+B3Q z=9S0@voNYNvZtixq?V*Y#iSu($r*`x=`b-V0TxC@M)t&%6p*6L(sAK}F&0jNUS6g_ zslMgGY30f0j^!2k#zh$_sbzj1##QE_VQDVmfkhr+7Lg`d<{`ytE+K(V9$t<H77=Ob zF7DZ>rum_^Mg~Skx(24YhT!-xF#u%}19LMIi^=Em6`>JoX=Q4pXKrR_W^S^n;IUqP zadxF)R#IhlnNdzrN?vwBj&V_DMM-&*g^59lX+fT;UaD6`SeA>ce|eUpZ&0dkuzP5@ zf2eMuYj%`DRggziX0W5XVQ7h;f2L1~OF^Jnd3;$~YMN=DtC^ush*4gUe_)kso{2?O zMoLA1ze|OIaj3tEg>hzLQh~91l#_YAds1XxTB5moXrXRaRhfB-rITq`V!U63i<6Oa zc8IG<XtAqLk*>36R=%e}Qc$6jr-f&HUVczYwpVe6bD*PtP*H@LV_uMMlBHvckE5TF ztCeA1eo&>URe*nBS&^5AVR@-nkawDQRgiy0p_i9wWO1=Ygr9|JMrveUVqUO(x|wOB z2`u1@OhBazB;X7!jLghTHZ6F-uRth_Hf>;0V3y&Joy>m0a$}<`|K`~H%M+BiSf(=Y ztMFaoyvlZnx16VoO@uX^Wh(b~7-agpUCn`UA>+mg=a{$}?S<IIvvnC8i>EXCFv@M; z>%wTo%*6O$W8)ph?N>b+Ll_w^PHa58{ku0Kmxuua1A{0-00Vy(Ujgq{o)=utxokLB za@^$*Vtd6V!kWwUow=L&0Mil1b4=}w<_rOh6C35Z8g<Rt#g&yAn-r(p<TFY$Do&5c zXY6FwG_{!SpTKCssI*-_kuij6dv`Kp4Ey%uj*RD-rrUZm?%wX^!Pw8p$hDdA0kZ)M zBmZxPjRk%D6DOqdvoJGqvV$@kBmW-;{y&=q8{YE^GB7YOGjno+if%^!X$<_+HVYQ? z@Ec?>axyq-Mr$*2a>4=|no3QrOfB@xEKLnT$Vku7%tFu5*m8QqF-9?MLt{%lLkoq_ z;?$zN#N1Q`D}{p0=xU|Jl$6vIB`byM+S*ulkWDh&m!`8{U^HTP;F03~!hLCD<0Nh^ z1sPTbMrCc}{OO#SrvS>X3XtroBF)OcsIJdGz3eulJi8Q>Gv_v=yo@9(1EZoQEQhA% zm4LJ+rlf#$ZjZggI7wL=Bdvg3!pQ%Sf&bxV!Gi1jnzD>6nu79%mT*t$8Cn!%79|!J dB&8M=RYF4U9RvTn&4L9__=N<SH91ig0|4gj?{5GA diff --git a/iotamak_ihm/settings.py b/iotamak_ihm/settings.py index fd177df..3f506ac 100644 --- a/iotamak_ihm/settings.py +++ b/iotamak_ihm/settings.py @@ -9,7 +9,7 @@ https://docs.djangoproject.com/en/4.0/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.0/ref/settings/ """ - +import os from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -27,6 +27,7 @@ DEBUG = True ALLOWED_HOSTS = [] +MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads/') # Application definition diff --git a/iotamak_ihm/urls.py b/iotamak_ihm/urls.py index d502811..a05677f 100644 --- a/iotamak_ihm/urls.py +++ b/iotamak_ihm/urls.py @@ -17,6 +17,6 @@ from django.contrib import admin from django.urls import path, include urlpatterns = [ - path('ping/', include('ping.urls')), + path('', include('ping.urls')), path('admin/', admin.site.urls), ] diff --git a/ping/admin.py b/ping/admin.py index 7e490c7..f8dd658 100644 --- a/ping/admin.py +++ b/ping/admin.py @@ -1,5 +1,7 @@ from django.contrib import admin -from .models import Client +from .models import Client, Agent, Experiment -admin.site.register(Client) \ No newline at end of file +admin.site.register(Client) +admin.site.register(Agent) +admin.site.register(Experiment) \ No newline at end of file diff --git a/ping/migrations/0001_initial.py b/ping/migrations/0001_initial.py index 7eda40b..ae0c37f 100644 --- a/ping/migrations/0001_initial.py +++ b/ping/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.0.4 on 2022-05-10 15:39 +# Generated by Django 4.0.4 on 2022-05-12 08:50 from django.db import migrations, models @@ -11,12 +11,21 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name='Agent', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ip', models.CharField(max_length=16)), + ('command', models.CharField(max_length=256)), + ], + ), migrations.CreateModel( name='Client', fields=[ ('hostname', models.CharField(max_length=16, primary_key=True, serialize=False, unique=True)), ('username', models.CharField(max_length=16)), ('password', models.CharField(max_length=16)), + ('status', models.CharField(default='Offline', max_length=8)), ], ), ] diff --git a/ping/migrations/0002_experiment.py b/ping/migrations/0002_experiment.py new file mode 100644 index 0000000..c06c6d6 --- /dev/null +++ b/ping/migrations/0002_experiment.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.4 on 2022-05-12 12:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ping', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Experiment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=60)), + ('status', models.CharField(default='Not checked', max_length=60)), + ('description', models.TextField()), + ('media', models.FileField(blank=True, null=True, upload_to='')), + ], + ), + ] diff --git a/ping/models.py b/ping/models.py index 7a1725a..c6a47a1 100644 --- a/ping/models.py +++ b/ping/models.py @@ -1,10 +1,32 @@ from django.db import models +from django.forms import ModelForm class Client(models.Model): hostname = models.CharField(max_length=16, primary_key=True, unique=True) username = models.CharField(max_length=16) password = models.CharField(max_length=16) + status = models.CharField(max_length=8, default="Offline") def __str__(self): - return "Hostname : " + self.hostname + " Username : " + self.username \ No newline at end of file + return "Hostname : " + self.hostname + " Username : " + self.username + " Status : " + self.status + + +class Agent(models.Model): + ip = models.CharField(max_length=16) + command = models.CharField(max_length=256) + + def __str__(self): + return self.command + +class Experiment(models.Model): + name = models.CharField(max_length=60) + status = models.CharField(max_length=60, default="Not checked") + description = models.TextField() + media = models.FileField(upload_to="media", null=True, blank=True) + + +class ExperimentForm(ModelForm): + class Meta: + model = Experiment + fields = ["name", "description", "media"] diff --git a/ping/static/ping/index.css b/ping/static/ping/index.css new file mode 100644 index 0000000..3e4d206 --- /dev/null +++ b/ping/static/ping/index.css @@ -0,0 +1,41 @@ +body { + margin: 0px; + font-family: Arial, Helvetica, sans-serif; +} + +.topnav { + overflow: hidden; + background-color: #333; +} + +.topnav a { + float: left; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; + font-size: 17px; +} + +.topnav a:hover { + background-color: #ddd; + color: black; +} + +.topnav a.active { + background-color: #0486aa; + color: white; +} + +th { + text-align: center; +} +tr:nth-child(even) {background-color: #f2f2f2;} +td { + height: 25px; + vertical-align: bottom; +} + +th, td { + border-bottom: thin solid #ddd; +} \ No newline at end of file diff --git a/ping/templates/ping/entry.html b/ping/templates/ping/entry.html new file mode 100644 index 0000000..b718dd6 --- /dev/null +++ b/ping/templates/ping/entry.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + {% load static %} + <link rel="stylesheet" type="text/css" href="{% static 'ping/index.css' %}"> + + <title>Experiment - IOTAMAK</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + +</head> + +<body> + + <div class="topnav"> + <a href="/network">Network</a> + <a class="active" href="/experiment">Experiment</a> + </div> + <form action="/experiment/new/" method="POST" enctype="multipart/form-data"> + {% csrf_token %} + {% for entry in form %} + <div> + {{ entry.label_tag }} + </div> + <div> + {{entry}} + </div> + {% endfor %} + <button> + Save! + </button> + </form> +</body> +</html> \ No newline at end of file diff --git a/ping/templates/ping/experiment.html b/ping/templates/ping/experiment.html new file mode 100644 index 0000000..86454db --- /dev/null +++ b/ping/templates/ping/experiment.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + {% load static %} + <link rel="stylesheet" type="text/css" href="{% static 'ping/index.css' %}"> + + <title>Experiment - IOTAMAK</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + +</head> + +<body> + + <div class="topnav"> + <a href="/network">Network</a> + <a class="active" href="/experiment">Experiment</a> + </div> + + <form action='new' method='GET'> + <button type='submit'> Add experiment</button> + </form> + + {% if experiments %} + <table> + <tr> + <th>Name</th> + <th>Status</th> + <th>Check</th> + </tr> + {% for experiment in experiments %} + <tr> + <td>{{ experiment.name }}</td> + <td>{{ experiment.status }}</td> + <td><a href="/experiment/{{ experiment.id }}/check">Check</td> + </tr> + {% endfor %} + </table> + {% else %} + <p>No agents are available.</p> + {% endif %} + +</body> + +</html> \ No newline at end of file diff --git a/ping/templates/ping/index.html b/ping/templates/ping/index.html index 02097b4..e39a748 100644 --- a/ping/templates/ping/index.html +++ b/ping/templates/ping/index.html @@ -1,19 +1,68 @@ <!DOCTYPE html> <html> - <head> - <meta charset="utf-8"> - <title>Main menu</title> - </head> - <body> - <form action='pressed' method='GET'> - <button type='submit'> Ping clients</button> - </form> - - <ul> - {% for client in host_list %} - <li>{{client}}</li> - {% endfor %} - </ul> - - </body> + +<head> + <meta charset="utf-8"> + {% load static %} + <link rel="stylesheet" type="text/css" href="{% static 'ping/index.css' %}"> + + <title>Network - IOTAMAK</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + +</head> + +<body> + <div class="topnav"> + <a class="active" href="/network">Network</a> + <a href="/experiment">Experiment</a> + </div> + + + + <form action='pressed' method='GET'> + <button type='submit'> Ping clients</button> + </form> + + <form action='update' method='GET'> + <button type='submit'> Update clients</button> + </form> + + <form action='agents' method='GET'> + <button type='submit'> agents</button> + </form> + + <table> + <tr> + <th>Hostname</th> + <th>Username</th> + <th>Status</th> + </tr> + {% for client in host_list %} + <tr> + <td>{{ client.hostname }}</td> + <td>{{ client.username }}</td> + <td>{{ client.status }}</td> + </tr> + {% endfor %} + </table> + + {% if agents %} + <table> + <tr> + <th>Hostname</th> + <th>Agent</th> + </tr> + {% for agent in agents %} + <tr> + <td>{{ agent.ip }}</td> + <td>{{ agent.command }}</td> + </tr> + {% endfor %} + </table> + {% else %} + <p>No agents are available.</p> + {% endif %} + +</body> + </html> \ No newline at end of file diff --git a/ping/urls.py b/ping/urls.py index de7ace3..f7f3002 100644 --- a/ping/urls.py +++ b/ping/urls.py @@ -4,6 +4,11 @@ from . import views app_name = 'ping' urlpatterns = [ - path('', views.index, name='index'), - path('pressed/', views.pressed, name='pressed'), + path('network/', views.index, name='index'), + path('network/pressed/', views.pressed, name='pressed'), + path('network/update/', views.update, name='update'), + path('network/agents/', views.agents, name='agents'), + path('experiment/new/', views.entry, name='entry'), + path('experiment/', views.experiment, name='experiment'), + path('experiment/<int:experiment_id>/check/', views.check, name='check'), ] \ No newline at end of file diff --git a/ping/views.py b/ping/views.py index 948a0fa..9cd9305 100644 --- a/ping/views.py +++ b/ping/views.py @@ -1,21 +1,97 @@ +import os import platform +import shutil import subprocess +import re +import zipfile + +from django.conf import settings from django.http import HttpResponse, HttpResponseRedirect from django.template import loader from django.urls import reverse +from iotAmak.tool.remote_client import RemoteClient +from iotAmak.tool.ssh_client import SSHClient, Cmd + +from .models import Client, Agent, Experiment, ExperimentForm + + +def get_remote_client(): + res = [] + for client in Client.objects.all(): + if client.status == "Online": + res.append(RemoteClient(client.hostname, client.username, client.password)) + + return res + + +def get_ssh_client(): + return SSHClient(get_remote_client()) + -from .models import Client +def update(request): + ssh = get_ssh_client() + version = "0.0.1" + commands = [ + Cmd( + cmd="cd Desktop/mqtt_goyon/iotamak-core" + ), + Cmd( + cmd="git pull" + ), + Cmd( + cmd="git checkout main" + ), + Cmd( + cmd="git pull" + ), + Cmd( + cmd="python3 -m pip install --force-reinstall dist/iotAmak-" + version + "-py3-none-any.whl" + ), + Cmd( + cmd="cd ../../../" + ) # , + # Cmd( + # cmd="rm -r Desktop/mqtt_goyon/example/" + self.experiment_name + # ) + + ] + for i_client in range(len(ssh.clients)): + print("Hostname :", ssh.clients[i_client].hostname, " User :", ssh.clients[i_client].user) + ssh.run_cmd(i_client, commands) + + return HttpResponseRedirect(reverse('ping:index')) + + +def agents(request): + ssh = get_ssh_client() + Agent.objects.all().delete() + commands = [ + Cmd( + cmd="ps -ef | tr -s ' ' | cut -d ' ' -f 8-", + do_print=False + )] + ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') + + for i_client in range(len(ssh.clients)): + raw_string = ssh.run_cmd(i_client, commands)[0].split("\r\n") + raw_string = [i for i in raw_string if "python D" in i] + for line in raw_string: + new_entry = Agent(ip=ssh.clients[i_client].hostname, command=ansi_escape.sub('', line)) + new_entry.save() + + return HttpResponseRedirect(reverse('ping:index')) def index(request): template = loader.get_template('ping/index.html') - host_list = Client.objects.all() context = { - "host_list": host_list, + "host_list": Client.objects.all(), + "agents": Agent.objects.all() } return HttpResponse(template.render(context, request)) + def pressed(request): for client in Client.objects.all(): param = '-n' if platform.system().lower() == 'windows' else '-c' @@ -23,6 +99,84 @@ def pressed(request): response = subprocess.call(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 - print(response) + c = Client.objects.get(hostname=client.hostname) + if response: + c.status = "Online" + else: + c.status = "Offline" + c.save() + + return HttpResponseRedirect(reverse('ping:index')) - return HttpResponseRedirect(reverse('ping:index')) \ No newline at end of file + +def entry(request): + if request.method == 'POST': + form = ExperimentForm(request.POST, request.FILES) + + if form.is_valid(): + form.save() + return HttpResponseRedirect(reverse('ping:experiment')) + + else: + form = ExperimentForm() + template = loader.get_template('ping/entry.html') + context = {"form": form} + return HttpResponse(template.render(context, request)) + +def empty_tmp(): + folder = str(settings.MEDIA_ROOT) + "/tmp" + for filename in os.listdir(folder): + file_path = os.path.join(folder, filename) + try: + if os.path.isfile(file_path) or os.path.islink(file_path): + os.unlink(file_path) + elif os.path.isdir(file_path): + shutil.rmtree(file_path) + except Exception as e: + print('Failed to delete %s. Reason: %s' % (file_path, e)) + +def check(request, experiment_id): + # get the path + print(experiment_id) + exp = Experiment.objects.get(pk=experiment_id) + print(str(exp.media)) + print(str(settings.MEDIA_ROOT) + str(exp.media)) + # check if it's a zip -> wrong format : not zip + print() + + if not zipfile.is_zipfile(str(settings.MEDIA_ROOT) + str(exp.media)): + exp.status = "Wrong format : zip file expected" + exp.save() + return HttpResponseRedirect(reverse('ping:experiment')) + + with zipfile.ZipFile(str(settings.MEDIA_ROOT) + str(exp.media), 'r') as zip_ref: + zip_ref.extractall(str(settings.MEDIA_ROOT) + "/tmp") + + folder_path = str(settings.MEDIA_ROOT) + "/tmp/" + exp.name + + if not os.path.isdir(folder_path): + exp.status = "Wrong format : zip should contain a folder" + exp.save() + empty_tmp() + return HttpResponseRedirect(reverse('ping:experiment')) + + required_files = ["amas.py", "agent.py", "env.py", "scheduler.py"] + for required_file in required_files: + if not os.path.exists(folder_path + "/" + required_file): + exp.status = "Wrong format : " + required_file + " file is expected" + exp.save() + empty_tmp() + return HttpResponseRedirect(reverse('ping:experiment')) + + exp.status = "Checked" + exp.save() + empty_tmp() + return HttpResponseRedirect(reverse('ping:experiment')) + + +def experiment(request): + template = loader.get_template('ping/experiment.html') + context = { + "experiments": Experiment.objects.all(), + } + return HttpResponse(template.render(context, request)) diff --git a/uploads/media/config.json b/uploads/media/config.json new file mode 100644 index 0000000..56c5b0c --- /dev/null +++ b/uploads/media/config.json @@ -0,0 +1,25 @@ +{ + "broker" : "192.168.30.209", + "clients_ssh" : [ + { + "hostname" : "192.168.30.18", + "user" : "pi", + "password" : "raspberry" + }, + { + "hostname" : "192.168.30.227", + "user" : "pi", + "password" : "raspberry" + }, + { + "hostname" : "192.168.30.61", + "user" : "pi", + "password" : "raspberry" + }, + { + "hostname" : "192.168.30.75", + "user" : "pi", + "password" : "raspberry" + } + ] +} \ No newline at end of file diff --git a/uploads/media/env.py b/uploads/media/env.py new file mode 100644 index 0000000..c8a767f --- /dev/null +++ b/uploads/media/env.py @@ -0,0 +1,67 @@ + +import sys + + +from iotAmak.environment import Environment +from fork import Fork + + +class PhiEnv(Environment): + + def __init__(self, broker_ip, nbr_phil): + self.nbr_phil = nbr_phil + super().__init__(broker_ip) + + def on_initialization(self): + self.forks = [] + for i in range(self.nbr_phil): + self.forks.append(Fork(i)) + self.subscribe("agent/" + str(i) + "/ask_spoon", self.ask_spoon) + self.subscribe("agent/" + str(i) + "/done_eating", self.done_eating) + + def ask_spoon(self, client, userdata, message): + res = str(message.payload.decode("utf-8")) + agent_id = int(str(message.topic).split("/")[1]) + + if res == "left": + fork_id = agent_id + else: + fork_id = (agent_id - 1) % self.nbr_phil + + if self.forks[fork_id].state == 1: + message = { + "response": "False" + } + elif self.forks[fork_id].taken_by == -1: + message = { + "response": "True", + "side": res, + "state": 0 + } + self.forks[fork_id].taken_by = agent_id + else: + message = { + "response": "True", + "side": res, + "state": 1 + } + self.forks[fork_id].taken_by = agent_id + self.forks[fork_id].state = 1 + + self.client.publish("env/agent/" + str(agent_id) + "/ask_spoon", str(message)) + + def done_eating(self, client, userdata, message): + agent_id = int(str(message.topic).split("/")[1]) + + for fork_id in [agent_id, (agent_id - 1) % self.nbr_phil]: + self.forks[fork_id].state = 0 + + def on_cycle_begin(self) -> None: + for fork in self.forks: + self.client.publish("env/fork/" + str(fork.identifier), str(fork.to_msg())) + print("Fork : ", fork.identifier," taken by ", fork.taken_by, " and is :", fork.state) + + +if __name__ == '__main__': + s = PhiEnv(str(sys.argv[1]), 5) + s.run() \ No newline at end of file diff --git a/uploads/media/philosophers.zip b/uploads/media/philosophers.zip new file mode 100644 index 0000000000000000000000000000000000000000..7c2deb36c8adeb6b9c9f9e60519c28d58b2724f3 GIT binary patch literal 3191 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 Z069Shc(byBlyWd|Fvu`5Ft~DocmQ*rAXoqZ literal 0 HcmV?d00001 -- GitLab