public interface: rework

This commit is contained in:
nemunaire 2017-03-31 19:47:48 +02:00
parent 23dc467631
commit 37fa6a1955
3 changed files with 377 additions and 157 deletions

View File

@ -29,9 +29,15 @@ body {
.point { .point {
text-shadow: 0 0 20px #0055ff; text-shadow: 0 0 20px #0055ff;
} }
.navbar-inverse .point {
text-shadow: 0 0 12px #0055ff;
}
.end .point { .end .point {
text-shadow: 0 0 20px #ff5500; text-shadow: 0 0 20px #ff5500;
} }
.navbar-inverse .end .point {
text-shadow: 0 0 12px #ff5500;
}
@-webkit-keyframes clockanim { @-webkit-keyframes clockanim {
0% { opacity: 1.0; } 0% { opacity: 1.0; }
50% { opacity: 0; } 50% { opacity: 0; }
@ -107,3 +113,53 @@ h1 small.authors {
transition-delay: 0.7s; transition-delay: 0.7s;
transition-duration: 0s; transition-duration: 0s;
} }
.carousel-indicators {
bottom: -10px;
}
.carousel-caption {
padding: 0;
position: static;
}
.carousel .table {
margin-bottom: 0;
}
.carousel .table-condensed td {
padding: 2px;
}
.table th.frotated {
border: 0;
}
.table th.rotated {
height: 100px;
width: 40px;
min-width: 40px;
max-width: 40px;
position: relative;
vertical-align: bottom;
padding: 0;
font-size: 12px;
line-height: 0.9;
border: 0;
}
th.rotated > div {
position: relative;
top: 0px;
left: -50px;
height: 100%;
transform: skew(45deg,0deg);
overflow: hidden;
border: 1px solid #000;
}
th.rotated div span {
transform: skew(-45deg,0deg) rotate(45deg);
position: absolute;
bottom: 40px;
left: -35px;
display: inline-block;
width: 110px;
text-align: left;
text-overflow: ellipsis;
}

View File

@ -60,29 +60,81 @@ angular.module("FICApp")
} }
updTime(); updTime();
}) })
.controller("DataController", function($scope, $http, $rootScope, $timeout) { .controller("EventsController", function($scope, $http, $interval) {
$rootScope.refresh = function() { $scope.events = [];
$timeout.cancel($scope.cbd); var refreshEvents = function() {
$scope.cbd = $timeout($rootScope.refresh, 4200); $http.get("/events.json").then(function(response) {
$http.get("/demo.json").success(function(demo) { if ($scope.lasteventsetag != undefined && $scope.lasteventsetag == response.headers().etag)
$scope.my = demo; return;
}); $scope.lasteventsetag = response.headers().etag;
$http.get("/events.json").success(function(evts) {
var events = {}; var events = response.data;
var now = new Date(); var now = new Date();
angular.forEach(evts, function(event, key) { var key = 0;
events["e" + event.id] = event; angular.forEach($scope.events, function(event) {
event.since = now.getTime() - now.getTimezoneOffset() * 60000 - Date.parse(event.time); event.keep = 0;
}); });
$scope.events = events; angular.forEach(events, function(event) {
event.time = Date.parse(event.time);
//event.since = now.getTime() - now.getTimezoneOffset() * 60000 - event.time;
event.since = now.getTime() - event.time;
event.keep = 1;
while (key <= $scope.events.length) {
if (key >= $scope.events.length) {
$scope.events.push(event);
break;
} else if (event.id == $scope.events[key].id) {
$scope.events[key].txt = event.txt;
$scope.events[key].time = event.time;
$scope.events[key].kind = event.kind;
$scope.events[key].since = event.since;
$scope.events[key].keep = 1;
break;
} else if (event.time > $scope.events[key].time) {
$scope.events.unshift(event);
break;
} else {
key += 1;
}
}
}); });
$http.get("/public.json").success(function(scene) { angular.forEach($scope.events, function(event, i) {
$scope.scene = scene; if (event.keep == 0) {
$scope.events.splice(i, 1);
}
});
});
}
refreshEvents()
$interval(refreshEvents, 2100);
})
.controller("DataController", function($scope, $http, $rootScope, $interval) {
var refreshScene = function() {
$http.get("/public.json").then(function(response) {
if ($scope.lastpublicetag == response.headers().etag)
return;
$scope.lastpublicetag = response.headers().etag;
$scope.scene = response.data;
});
}
var refreshData = function() {
$http.get("/my.json").then(function(response) {
if ($scope.lastmyetag == response.headers().etag)
return;
$scope.lastmyetag = response.headers().etag;
$scope.my = response.data;
}); });
$http.get("/stats.json").success(function(stats) { $http.get("/stats.json").success(function(stats) {
$scope.stats = stats; $scope.stats = stats;
}); });
$http.get("/themes.json").success(function(themes) { $http.get("/themes.json").then(function(response) {
if ($scope.lastthemeetag == response.headers().etag)
return;
$scope.lastthemeetag = response.headers().etag;
var themes = response.data;
$scope.themes = themes; $scope.themes = themes;
$scope.max_gain = 0; $scope.max_gain = 0;
angular.forEach(themes, function(theme, key) { angular.forEach(themes, function(theme, key) {
@ -94,7 +146,13 @@ angular.module("FICApp")
$scope.max_gain += theme.gain; $scope.max_gain += theme.gain;
}, themes); }, themes);
}); });
$http.get("/teams.json").success(function(teams) { $http.get("/teams.json").then(function(response) {
if ($scope.lastteametag == response.headers().etag)
return;
$scope.lastteametag = response.headers().etag;
var teams = response.data;
$scope.teams_count = Object.keys(teams).length $scope.teams_count = Object.keys(teams).length
$scope.teams = teams; $scope.teams = teams;
@ -106,7 +164,15 @@ angular.module("FICApp")
} }
}, $scope.rank); }, $scope.rank);
}); });
console.log("refresh!");
} }
$rootScope.refresh(); refreshData();
refreshScene();
$interval(refreshData, 4200);
$interval(refreshScene, 900);
})
.controller("TeamController", function($scope, $http, $interval) {
$scope.mystats = null;
$http.get("/api/teams/" + $scope.team.id + "/stats.json").success(function(mstats) {
$scope.mystats = mstats;
});
}); });

View File

@ -20,60 +20,18 @@
<base href="/"> <base href="/">
<script src="/js/angular.min.js"></script> <script src="/js/angular.min.js"></script>
</head> </head>
<body style="overflow: hidden;" ng-controller="DataController"> <body style="overflow: hidden;" class="container-fluid" ng-controller="DataController">
<div class="row" style="margin-top: 10px">
<div class="col-xs-8">
<noscript> <noscript>
<div class="alert alert-danger"> <div class="alert alert-danger">
<strong>Veuillez activer le JavaScript.</strong> Ce site requiert un navigateur interprêtant le JavaScript pour fonctionner. Veuillez l'activer ou en télécharger un supportant cette technologie. <strong>Veuillez activer le JavaScript.</strong> Ce site requiert un navigateur interprêtant le JavaScript pour fonctionner. Veuillez l'activer ou en télécharger un supportant cette technologie.
</div> </div>
</noscript> </noscript>
<div class="navbar navbar-default" ng-controller="TimeController" style="box-shadow: 0px 10px 10px 0px #313539; position:fixed; top:0; width:100vw; z-index:1;">
<div class="container">
<div class="row">
<div class="navbar-header" style="width: 100px">
<a href="/">
<img src="/img/fic.png" alt="Forum International de la Cybersécurité" class="center-block">
</a>
</div>
<div class="navbar-right" style="width: 100px">
<a href="http://www.epita.fr/">
<img src="/img/epita.png" alt="Epita" class="center-block">
</a>
</div>
<div class="text-center" ng-show="time.hours === 0 || time.hours" style="margin-top: -5px; ">
<div id="clock" ng-class="{expired: time.expired, end: time.end}">
<span id="hours">{{ time.hours | time }}</span>
<span class="point">:</span>
<span id="min">{{ time.minutes | time }}</span>
<span class="point">:</span>
<span id="sec">{{ time.seconds | time }}</span>
</div>
<div style="font-size: 18px; margin-top: -15px; text-shadow: 0 0 6px #446688;">
<span ng-show="!time.end && time.duration != time.remaining">Temps restant du challenge forensic</span>
<span ng-show="!time.end && time.duration == time.remaining">Le challenge forensic va bientôt commencer&nbsp;!</span>
<span ng-show="time.end">Le challenge forensic est terminé&nbsp;!</span>
</div>
</div>
<div id="clock" class="col-sm-8" ng-show="!(time.hours === 0 || time.hours)">
{{ time.start | date:"shortDate" }}
</div>
</div>
</div>
</div>
<!--div style="margin: 5px 0;">
Bandeau Twitter catchant #FIC2016
</div-->
<div class="container-fluid text-justify" style="margin-top: 110px; padding: 10px; width: 99%">
<div class="row">
<div class="col-sm-8">
<div ng-repeat="(k,s) in scene" class="repeatedd-item"> <div ng-repeat="(k,s) in scene" class="repeatedd-item">
<div class="well" ng-show="true || s.type == 'welcome' && !s.go"> <div class="well" ng-if="s.type == 'welcome' && !s.params.hide && s.params.kind == 'init'">
<h1>Bienvenue au challenge forensic&nbsp;!</h1> <h1>Bienvenue au challenge forensic&nbsp;!</h1>
<p class="lead text-justify"> <p class="lead text-justify">
Avant de vous installer, venez récupérer votre clef USB auprès Avant de vous installer, venez récupérer votre clef USB auprès
@ -81,22 +39,22 @@
de vous authentifier auprès de notre serveur. de vous authentifier auprès de notre serveur.
</p> </p>
<p class="lead text-justify"> <p class="lead text-justify">
Une fois connecté au réseau, vous pouvez accéder au serveur à&nbsp;: Une fois connecté au réseau, contactez notre serveur sur&nbsp;:
<span style="display: block; font-size: 200%" class="text-center"> <span style="display: block; font-size: 200%" class="text-center">
<a href="https://fic.srs.epita.fr/"><span class="text-info">https://fic.srs.epita.fr/</span></a> <a style="font-family: mono" href="https://fic.srs.epita.fr/"><span class="text-info">https://fic.srs.epita.fr/</span></a>
</span> </span>
</p> </p>
</div> </div>
<div class="panel panel-success" ng-show="true || s.type == 'welcome' && s.go == 1 && startIn"> <div class="panel panel-success" ng-if="s.type == 'welcome' && !s.params.hide && s.params.kind == 'countdown'">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title"><strong>Le challenge forensic 2017 est sur le point de démarrer&nbsp;!</strong></h3> <h3 class="panel-title"><strong>Le challenge forensic 2017 est sur le point de commencer&nbsp;!</strong></h3>
</div> </div>
<div class="panel-body text-center" style="font-size: 450%;" ng-show="startIn">{{ startIn }}</div> <div class="panel-body text-center" style="font-size: 450%;" ng-if="startIn">{{ startIn }}</div>
<div class="panel-body text-center" style="font-size: 450%;" ng-show="!startIn">Go, go, go&nbsp;!</div> <div class="panel-body text-center" style="font-size: 450%;" ng-if="!startIn">Go, go, go&nbsp;!</div>
</div> </div>
<div class="well" ng-show="true || s.type == 'welcome' && s.go == 2"> <div class="well" ng-if="s.type == 'welcome' && !s.params.hide && s.params.kind == 'public'">
<h1>Bienvenue au challenge forensic&nbsp;!</h1> <h1>Bienvenue au challenge forensic&nbsp;!</h1>
<p class="lead text-justify"> <p class="lead text-justify">
Durant ce challenge, les équipes doivent remonter des scénarii Durant ce challenge, les équipes doivent remonter des scénarii
@ -114,56 +72,83 @@
</p> </p>
</div> </div>
<div class="well" ng-show="s.type == 'message'"> <div class="well" ng-if="s.type == 'message' && !s.params.hide">
<h1 ng-show="s.title"><strong>{{ s.title }}</strong></h1> <h1 ng-if="s.params.title"><strong>{{ s.params.title }}</strong></h1>
<p ng-show="s.lead" class="lead text-justify">{{ s.lead }}</p> <p ng-if="s.params.lead" class="lead text-justify">{{ s.params.lead }}</p>
<p ng-bind-html="s.html" ng-show="s.html"></p> <p ng-bind-html="s.params.html" ng-if="s.params.html"></p>
<p ng-show="s.text">{{ s.text }}</p> <p ng-if="s.params.text">{{ s.params.text }}</p>
</div> </div>
<div class="panel {{ s.kind }}" ng-show="s.type == 'panel'"> <div class="panel {{ s.params.kind }}" ng-if="s.type == 'panel' && !s.params.hide">
<div class="panel-heading" ng-show="s.title"> <div class="panel-heading" ng-if="s.params.title">
<h3 class="panel-title">{{ s.title }}</h3> <h3 class="panel-title">{{ s.params.title }}</h3>
</div> </div>
<div class="panel-body" ng-show="s.text">{{ s.text }}</div> <div class="panel-body" ng-if="s.params.text">{{ s.params.text }}</div>
<div class="panel-body" ng-show="s.html" ng-bind-html="s.html"></div> <div class="panel-body" ng-if="s.params.html" ng-bind-html="s.params.html"></div>
</div> </div>
<div class="well" ng-show="s.type == 'exercice'"> <div class="well" ng-if="s.type == 'exercice' && !s.params.hide">
<p class="lead"> <p class="lead">
<strong>{{ themes[my.exercices[s.id].theme_id].exercices[s.id].title }} du challenge {{ themes[my.exercices[s.id].theme_id].name }}</strong> <strong>Challenge <em>{{ themes[my.exercices[s.params.exercice].theme_id].exercices[s.params.exercice].title }}</em> du thème {{ themes[my.exercices[s.params.exercice].theme_id].name }}</strong>
<small class="authors" ng-show="themes[my.exercices[s.id].theme_id].authors">par {{ themes[my.exercices[s.id].theme_id].authors }}</small> <small class="authors" ng-if="themes[my.exercices[s.params.exercice].theme_id].authors">par {{ themes[my.exercices[s.params.exercice].theme_id].authors }}</small>
</p> </p>
<p ng-bind-html="my.exercices[s.id].statement"></p> <p ng-bind-html="my.exercices[s.params.exercice].statement"></p>
<ul class="list-inline"> <ul class="list-inline">
<li>{{ themes[my.exercices[s.id].theme_id].exercices[s.id].gain }} points</li> <li>Rapporte <ng-pluralize count="themes[my.exercices[s.params.exercice].theme_id].exercices[s.params.exercice].gain" when="{'0': 'aucun point', 'one': '{} point', 'other': '{} points'}"></ng-pluralize></li>
<li>{{ my.exercices[s.id].files.length }} fichiers disponibles</li> <li><ng-pluralize count="my.exercices[s.params.exercice].files.length" when="{'0': 'Aucun fichier disponible', 'one': '{} fichier disponible', 'other': '{} fichiers disponibles'}"></ng-pluralize></li>
<li>Tenté par {{ themes[my.exercices[s.id].theme_id].exercices[s.id].tried }} équipes</li> <li ng-if="my.exercices[s.params.exercice].hints.length"><ng-pluralize count="my.exercices[s.params.exercice].hints.length" when="{'0': 'Aucun indice disponible', 'one': '{} indice disponible', 'other': '{} indices disponibles'}"></ng-pluralize></li>
<li>{{ my.exercices[s.id].solved_number }} tentatives</li> <li>Tenté par <ng-pluralize count="themes[my.exercices[s.params.exercice].theme_id].exercices[s.params.exercice].tried" when="{'0': 'aucune équipe', 'one': '{} équipe', 'other': '{} équipes'}"></ng-pluralize></li>
<li>Résolu par {{ themes[my.exercices[s.id].theme_id].exercices[s.id].solved }} équipes</li> <li><ng-pluralize count="my.exercices[s.params.exercice].solved_number" when="{'0': 'aucun tentative', 'one': '{} tentative', 'other': '{} tentatives'}"></ng-pluralize></li>
<li>Résolu par <ng-pluralize count="themes[my.exercices[s.params.exercice].theme_id].exercices[s.params.exercice].solved" when="{'0': 'aucune équipe', 'one': '{} équipe', 'other': '{} équipes'}"></ng-pluralize></li>
</ul> </ul>
</div> </div>
<table class="table table-bordered table-striped" ng-show="s.type == 'table'"> <div class="panel" ng-if="s.type == 'table' && !s.params.hide">
<table class="table table-bordered table-striped table-condensed">
<thead> <thead>
<tr> <tr>
<th></th> <th class="frotated"></th>
<th class="text-center">Niveau 1</th> <th class="rotated" ng-repeat="(tid,th) in themes" ng-if="s.params.themes.indexOf(tid-0) !== -1"><div><span>{{ th.name }}</span></div></th>
<th class="text-center">Niveau 2</th>
<th class="text-center">Niveau 3</th>
<th class="text-center">Niveau 4</th>
<th class="text-center">Niveau 5</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody ng-if="s.params.kind == 'levels'">
<tr ng-repeat="th in s.themes"> <tr ng-repeat="lvl in [1,2,3,4,5]">
<th>{{ themes[th].name }}</th> <th class="text-center"><nobr>Niveau {{ lvl }}</nobr></th>
<td ng-repeat="ex in themes[th].exercices" class="text-center" ng-class="{'text-primary': ex.solved == 0, 'text-success': ex.solved >= 1, 'text-bold': ex.solved >= 1, 'text-warning': ex.solved == 0 && ex.tried}" ng-show="ex.solved || ex.tried || $first"><span ng-show="ex.solved">{{ ex.solved }}</span><span ng-show="!ex.solved">{{ ex.tried }}</span></td> <td ng-repeat="(tid,th) in themes" class="text-center" ng-if="s.params.themes.indexOf(tid-0) !== -1">
<span ng-repeat="exercice in th.exercices" ng-if="$index == lvl-1 && (exercice.tried || lvl == 1)" ng-class="{'text-primary': exercice.solved == 0, 'text-success': exercice.solved >= 1, 'text-bold': exercice.solved >= 1, 'text-warning': exercice.solved == 0 && exercice.tried}">
<span ng-if="exercice.solved">{{ exercice.solved }}</span>
<span ng-if="!exercice.solved">{{ exercice.tried }}</span>
</span>
</td>
</tr> </tr>
</tbody> </tbody>
<tbody ng-if="s.params.kind == 'teams'">
<tr ng-repeat="team in rank | orderBy: 'rank' | limitTo: s.params.limit: s.params.begin" ng-if="s.params.teams.indexOf(team.id-0) !== -1" ng-controller="TeamController">
<th class="text-center">{{ team.rank }}<sup ng-if="team.rank == 1">er</sup><sup ng-if="team.rank > 1">e</sup><br><span style="text-overflow: ellipsis; display: inline-block; width: 82px;overflow: hidden;">{{ team.name }}</span></th>
<td ng-repeat="(tid,th) in themes" class="text-center" ng-if="mystats && s.params.themes.indexOf(tid-0) !== -1">
<span ng-class="{'text-success': mystats.themes[tid].solved}">{{ mystats.themes[tid].solved }}/{{ mystats.themes[tid].total }}</span>
<span ng-class="{'text-warning': mystats.themes[tid].solved < mystats.themes[tid].tried}">({{ mystats.themes[tid].tries }})</span>
</td>
</tr>
</tbody>
<tfoot ng-if="s.params.total" ng-init="team={id:0}">
<tr ng-controller="TeamController">
<td class="text-right">
<span ng-if="s.params.kind == 'levels'">Résolus</span>
<span ng-if="s.params.kind == 'teams'">Total résolus</span><br>
Tentatives
</td>
<td ng-repeat="(tid,th) in themes" class="text-center" ng-if="mystats && s.params.themes.indexOf(tid-0) !== -1">
<strong>{{ mystats.themes[tid].solved }}</strong><br>
{{ mystats.themes[tid].tries }}
</td>
</tr>
</tfoot>
</table> </table>
</div>
<table class="table table-bordered table-striped" ng-show="s.type == 'rank'"> <div class="panel" ng-if="s.type == 'rank' && !s.params.hide">
<table class="table table-bordered table-striped table-condensed">
<thead> <thead>
<tr> <tr>
<th class="text-right">Place</th> <th class="text-right">Place</th>
@ -171,31 +156,139 @@
<th>Score</th> <th>Score</th>
</tr> </tr>
</thead> </thead>
<tbody ng-show="s.which == 'general'"> <tbody ng-if="s.params.which == 'general'">
<tr ng-repeat="r in rank | orderBy: 'rank' | limitTo: 7"> <tr ng-repeat="r in rank | orderBy: 'rank' | limitTo: s.params.limit: s.params.begin">
<th class="text-right">{{ r.rank }}<sup ng-show="r.rank == 1">er</sup><sup ng-show="r.rank > 1">e</sup></th> <th class="text-right">{{ r.rank }}<sup ng-if="r.rank == 1">er</sup><sup ng-if="r.rank > 1">e</sup></th>
<td>{{ r.name }}</td> <td>{{ r.name }}</td>
<td>{{ r.score }}</td> <td>{{ r.score }}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div>
<div class="col-sm-4"> <div class="col-xs-4">
<div ng-repeat="e in events" class="repeated6-item"> <div ng-controller="EventsController">
<div ng-repeat="e in events | limitTo: 7" class="repeated-item">
<div class="alert" ng-class="e.kind"> <div class="alert" ng-class="e.kind">
<div class="heading">{{ e.since | since }}</div> <div class="heading">{{ e.since | since }}</div>
<span ng-bind-html="e.txt"></span> <span ng-bind-html="e.txt"></span>
</div> </div>
</div> </div>
<a href="https://srs.epita.fr/"> <div style="box-shadow: 0px -5px 5px 5px #272b30; position: fixed; bottom: calc(14vh - 1px); right: 0; width: 33vw;" class="navbar navbar-inverse">
<img src="/img/srs.png" class="center-block" alt="Epita"> <div class="text-center" ng-if="time.hours === 0 || time.hours" style="margin-top: -5px;" ng-controller="TimeController">
</a> <div id="clock" ng-class="{expired: time.expired, end: time.end}" style="font-size: 50px" ng-cloak>
<span id="hours">{{ time.hours | time }}</span>
<span class="point">:</span>
<span id="min">{{ time.minutes | time }}</span>
<span class="point">:</span>
<span id="sec">{{ time.seconds | time }}</span>
</div>
<div style="font-size: 18px; margin-top: -15px; text-shadow: 0 0 6px #446688;">
<span ng-if="!time.end && time.duration != time.remaining">Temps restant du challenge forensic</span>
<span ng-if="!time.end && time.duration == time.remaining">Le challenge forensic va bientôt commencer&nbsp;!</span>
<span ng-if="time.end">Le challenge forensic est terminé&nbsp;!</span>
</div>
</div>
<div id="clock" class="col-sm-6" ng-if="!(time.hours === 0 || time.hours)">
{{ time.start | date:"shortDate" }}
</div>
</div>
<div style="position: fixed; bottom: 0; right: 0; width: 33vw; height: 14vh" class="navbar navbar-inverse">
<div class="carousel slide" id="carousel-logos" data-ride="carousel">
<div class="carousel-inner">
<div class="item active">
<div class="carousel-caption">
<a href="http://www.epita.fr/"><img src="/img/epita.png" alt="Epita" style="width:30%"></a>
<a href="https://srs.epita.fr/"><img src="/img/srs.png" alt="Laboratoire SRS" style="width:30%"></a>
<img src="/img/rcc.png" alt="Réserve Citoyenne Cyberdéfense" style="width:30%">
</div>
</div>
<div class="item">
<div class="carousel-caption" style="padding: 0 10px">
<h2>Bienvenue au challenge forensic&nbsp;!</h2>
</div>
</div>
<div class="item">
<div class="carousel-caption">
<p class="text-justify text-bold" style="padding: 20px 16px; font-size: 111%">
Ce challenge met en scène des scénarii d'attaques auxquels
nos systèmes d'information font faces chaque jour.
</p>
</div>
</div>
<div class="item">
<div class="carousel-caption">
<p class="text-justify text-bold" style="padding: 20px 16px; font-size: 111%">
Les 42 équipes doivent, en 4 heures, retracer les attaques à la
recherche des données exfiltrées.
</p>
</div>
</div>
<div class="item">
<div class="carousel-caption row" style="padding: 12px">
<div class="col-xs-4">
<a href="https://www.epita.fr/"><img src="/img/epita.png" alt="Épita" style="height: 10vh"></a>
</div>
<p class="col-xs-8 text-bold" style="font-size: 111%">
Les challenges ont été réalisés par les étudiants de la
spécialisation SRS de l'Épita
</p>
</div>
</div>
<div class="item">
<div class="carousel-caption row" style="padding: 12px">
<div class="col-xs-4">
<img src="/img/rcc.png" alt="Réserve Citoyenne Cyberdéfense" style="max-width:100%; max-height: 11vh">
</div>
<p class="col-xs-8 text-bold" style="padding: 10px 10px 10px 0; font-size: 111%">
Avec le parrainage du réseau de la Réserve Citoyenne Cyberdéfense
</p>
</div>
</div>
<div class="item">
<div class="carousel-caption" style="padding: 3px 25px; width: 32vw;">
<table class="table table-bordered table-condensed table-striped">
<tbody>
<tr>
<td>11&nbsp;h</td>
<td>Accueil des équipes</td>
</tr>
<tr>
<td>11&nbsp;h&nbsp;30</td>
<td>Début du challenge</td>
</tr>
<tr>
<td>15&nbsp;h&nbsp;30</td>
<td>Fin du challenge</td>
</tr>
<tr>
<td>16&nbsp;h&nbsp;00</td>
<td>Remise des prix</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="item">
<div class="carousel-caption row" style="padding: 12px">
<p class="text-bold" style="padding: 5px; font-size: 105%">
Retrouvez la correction des challenges dès demain sur :
<span style="display: block; font-size: 150%" class="text-center">
<a style="font-family: mono" href="https://fic.srs.epita.fr/"><span class="text-info">https://fic.srs.epita.fr/</span></a>
</span>
</p>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
@ -209,5 +302,10 @@
<script src="/js/i18n/angular-locale_fr-fr.js"></script> <script src="/js/i18n/angular-locale_fr-fr.js"></script>
<script src="/js/public.js"></script> <script src="/js/public.js"></script>
<script src="/js/common.js"></script> <script src="/js/common.js"></script>
<script>
$(".carousel").carousel({
interval: 21000
});
</script>
</body> </body>
</html> </html>