2021-08-01 19:13:52 +02:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
2021-12-26 18:47:58 +01:00
|
|
|
* 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.
|
2021-08-01 19:13:52 +02:00
|
|
|
*
|
|
|
|
* 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
|
2021-12-26 18:47:58 +01:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2021-08-01 19:13:52 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
%require "3.0"
|
2021-08-23 08:31:19 +02:00
|
|
|
%defines "engines/hypno/tokens_arc.h"
|
|
|
|
%output "engines/hypno/grammar_arc.cpp"
|
2021-08-01 19:13:52 +02:00
|
|
|
%define api.prefix {HYPNO_ARC_}
|
|
|
|
|
|
|
|
%{
|
|
|
|
|
|
|
|
#include "common/array.h"
|
2021-09-19 12:41:49 +02:00
|
|
|
#include "hypno/hypno.h"
|
2021-08-01 19:13:52 +02:00
|
|
|
|
|
|
|
#undef yyerror
|
|
|
|
#define yyerror HYPNO_ARC_xerror
|
|
|
|
|
|
|
|
Hypno::Shoot *shoot;
|
|
|
|
|
|
|
|
extern int HYPNO_ARC_lex();
|
|
|
|
extern int HYPNO_ARC_parse();
|
2021-09-19 12:41:49 +02:00
|
|
|
extern int HYPNO_ARC_lineno;
|
2021-08-01 19:13:52 +02:00
|
|
|
|
|
|
|
void HYPNO_ARC_xerror(const char *str) {
|
2021-09-19 12:41:49 +02:00
|
|
|
error("%s at line %d", str, HYPNO_ARC_lineno);
|
2021-08-01 19:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int HYPNO_ARC_wrap() {
|
2021-09-08 22:14:14 +02:00
|
|
|
return 1;
|
2021-08-01 19:13:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
using namespace Hypno;
|
|
|
|
|
2021-09-08 22:14:14 +02:00
|
|
|
%}
|
2021-08-01 19:13:52 +02:00
|
|
|
|
|
|
|
%union {
|
|
|
|
char *s; /* string value */
|
|
|
|
int i; /* integer value */
|
|
|
|
}
|
|
|
|
|
2022-02-13 11:27:52 +01:00
|
|
|
%token<s> NAME FILENAME BNTOK SNTOK KNTOK YXTOK FNTOK ENCTOK
|
2022-01-26 09:31:50 +01:00
|
|
|
%token<i> NUM BYTE
|
2021-08-01 19:13:52 +02:00
|
|
|
// header
|
2022-02-13 11:27:52 +01:00
|
|
|
%token COMMENT CTOK DTOK HTOK HETOK HLTOK HUTOK RETTOK QTOK RESTOK
|
2022-01-26 09:31:50 +01:00
|
|
|
%token PTOK FTOK TTOK TPTOK ATOK VTOK OTOK ONTOK NTOK NSTOK RTOK R0TOK ITOK JTOK ZTOK
|
2021-08-01 19:13:52 +02:00
|
|
|
|
|
|
|
// body
|
2022-01-30 11:26:17 +01:00
|
|
|
%token NONETOK A0TOK P0TOK WTOK
|
2021-08-01 19:13:52 +02:00
|
|
|
|
|
|
|
// end
|
|
|
|
%token XTOK
|
|
|
|
|
|
|
|
// bytes??
|
|
|
|
%token CB3TOK C02TOK
|
|
|
|
|
2022-02-13 11:27:52 +01:00
|
|
|
%type<s> enc
|
|
|
|
|
2021-08-01 19:13:52 +02:00
|
|
|
%%
|
|
|
|
|
2021-11-06 00:04:35 +01:00
|
|
|
start: YXTOK { g_parsedArc->mode = $1; } header ZTOK RETTOK body XTOK
|
2021-10-31 11:57:21 +01:00
|
|
|
| RETTOK start
|
2021-09-08 22:14:14 +02:00
|
|
|
;
|
2021-08-01 19:13:52 +02:00
|
|
|
|
2021-09-19 12:41:49 +02:00
|
|
|
header: hline header
|
2021-10-31 11:57:21 +01:00
|
|
|
| RETTOK header
|
2021-09-19 12:41:49 +02:00
|
|
|
| /* nothing */
|
2021-09-08 22:14:14 +02:00
|
|
|
;
|
2021-08-01 19:13:52 +02:00
|
|
|
|
2021-10-31 11:57:21 +01:00
|
|
|
hline: CTOK NUM {
|
2021-10-31 11:47:48 +01:00
|
|
|
g_parsedArc->id = $2;
|
|
|
|
debugC(1, kHypnoDebugParser, "C %d", $2); }
|
2021-09-19 12:41:49 +02:00
|
|
|
| FTOK NUM { debugC(1, kHypnoDebugParser, "F %d", $2); }
|
2022-01-30 11:26:17 +01:00
|
|
|
| DTOK NUM {
|
|
|
|
g_parsedArc->frameDelay = $2;
|
|
|
|
debugC(1, kHypnoDebugParser, "D %d", $2);
|
|
|
|
}
|
2021-09-19 12:41:49 +02:00
|
|
|
| PTOK NUM NUM { debugC(1, kHypnoDebugParser, "P %d %d", $2, $3); }
|
|
|
|
| ATOK NUM NUM { debugC(1, kHypnoDebugParser, "A %d %d", $2, $3); }
|
|
|
|
| VTOK NUM NUM { debugC(1, kHypnoDebugParser, "V %d %d", $2, $3); }
|
2022-01-26 09:31:50 +01:00
|
|
|
| VTOK RESTOK { debugC(1, kHypnoDebugParser, "V 320,200"); }
|
2022-01-30 11:26:17 +01:00
|
|
|
| OTOK NUM NUM {
|
|
|
|
g_parsedArc->obj1KillsRequired = $2;
|
|
|
|
g_parsedArc->obj1MissesAllowed = $3;
|
|
|
|
debugC(1, kHypnoDebugParser, "O %d %d", $2, $3);
|
|
|
|
}
|
2021-12-20 14:05:11 +01:00
|
|
|
| ONTOK NUM NUM { debugC(1, kHypnoDebugParser, "ON %d %d", $2, $3); }
|
2022-01-26 09:31:50 +01:00
|
|
|
| ONTOK NUM { debugC(1, kHypnoDebugParser, "ON %d", $2); }
|
2021-09-08 22:14:14 +02:00
|
|
|
| TPTOK FILENAME NUM FILENAME {
|
2021-10-31 11:47:48 +01:00
|
|
|
g_parsedArc->transitionVideo = $2;
|
|
|
|
g_parsedArc->transitionTime = $3;
|
2022-01-28 23:46:11 +01:00
|
|
|
g_parsedArc->transitionPalette = $4;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "Tp %s %d %s", $2, $3, $4);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
|
|
|
| TTOK FILENAME NUM {
|
2021-10-31 11:47:48 +01:00
|
|
|
g_parsedArc->transitionVideo = $2;
|
|
|
|
g_parsedArc->transitionTime = $3;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "T %s %d", $2, $3);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2021-09-19 12:41:49 +02:00
|
|
|
| TTOK NONETOK NUM { debugC(1, kHypnoDebugParser, "T NONE %d", $3); }
|
2021-09-08 22:14:14 +02:00
|
|
|
| NTOK FILENAME {
|
2022-01-30 11:26:17 +01:00
|
|
|
g_parsedArc->backgroundVideo = $2;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "N %s", $2);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2022-01-26 09:31:50 +01:00
|
|
|
| NSTOK FILENAME {
|
2022-01-30 11:26:17 +01:00
|
|
|
g_parsedArc->backgroundVideo = $2;
|
2022-01-26 09:31:50 +01:00
|
|
|
debugC(1, kHypnoDebugParser, "N* %s", $2);
|
|
|
|
}
|
2022-01-10 20:22:07 +01:00
|
|
|
| RTOK FILENAME {
|
2022-01-30 11:26:17 +01:00
|
|
|
g_parsedArc->backgroundPalette = $2;
|
2022-01-10 20:22:07 +01:00
|
|
|
debugC(1, kHypnoDebugParser, "R %s", $2); }
|
2021-09-08 22:14:14 +02:00
|
|
|
| ITOK FILENAME {
|
2021-10-31 11:47:48 +01:00
|
|
|
g_parsedArc->player = $2;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "I %s", $2);
|
2021-08-21 19:24:26 +02:00
|
|
|
}
|
2021-09-19 12:41:49 +02:00
|
|
|
| QTOK NUM NUM { debugC(1, kHypnoDebugParser, "Q %d %d", $2, $3); }
|
2021-09-08 22:14:14 +02:00
|
|
|
| BNTOK FILENAME {
|
|
|
|
if (Common::String("B0") == $1)
|
2022-02-05 09:30:57 +01:00
|
|
|
g_parsedArc->beforeVideo = $2;
|
2021-11-11 19:50:39 +01:00
|
|
|
//else if (Common::String("B1") == $1)
|
|
|
|
// g_parsedArc->nextLevelVideo = $2;
|
|
|
|
else if (Common::String("B2") == $1)
|
|
|
|
g_parsedArc->nextLevelVideo = $2;
|
|
|
|
else if (Common::String("B3") == $1)
|
2022-01-30 11:26:17 +01:00
|
|
|
g_parsedArc->defeatNoEnergyFirstVideo = $2;
|
2021-11-11 19:50:39 +01:00
|
|
|
else if (Common::String("B4") == $1)
|
|
|
|
g_parsedArc->defeatMissBossVideo = $2;
|
2022-01-30 11:26:17 +01:00
|
|
|
else if (Common::String("B5") == $1)
|
|
|
|
g_parsedArc->defeatNoEnergySecondVideo = $2;
|
2022-02-05 09:30:57 +01:00
|
|
|
else if (Common::String("BA") == $1)
|
|
|
|
g_parsedArc->briefingVideo = $2;
|
2021-09-08 22:14:14 +02:00
|
|
|
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "BN %s", $2);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
|
|
|
| SNTOK FILENAME enc {
|
2022-02-13 11:27:52 +01:00
|
|
|
uint32 sampleRate = 11025;
|
|
|
|
if (Common::String("22K") == $3 || Common::String("22k") == $3)
|
|
|
|
sampleRate = 22050;
|
|
|
|
|
|
|
|
if (Common::String("S0") == $1) {
|
2021-10-31 11:47:48 +01:00
|
|
|
g_parsedArc->music = $2;
|
2022-02-13 11:27:52 +01:00
|
|
|
g_parsedArc->musicRate = sampleRate;
|
|
|
|
} else if (Common::String("S1") == $1) {
|
2021-10-31 11:47:48 +01:00
|
|
|
g_parsedArc->shootSound = $2;
|
2022-02-13 11:27:52 +01:00
|
|
|
g_parsedArc->shootSoundRate = sampleRate;
|
|
|
|
} else if (Common::String("S2") == $1) {
|
2021-11-28 22:32:54 +01:00
|
|
|
g_parsedArc->hitSound = $2;
|
2022-02-13 11:27:52 +01:00
|
|
|
g_parsedArc->hitSoundRate = sampleRate;
|
|
|
|
} else if (Common::String("S4") == $1) {
|
|
|
|
g_parsedArc->enemySound = $2;
|
|
|
|
g_parsedArc->enemySoundRate = sampleRate;
|
|
|
|
}
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "SN %s", $2);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2022-01-28 23:46:11 +01:00
|
|
|
| HETOK BYTE NUM NUM {
|
|
|
|
Segment segment($2, $3, $4);
|
|
|
|
g_parsedArc->segments.push_back(segment);
|
2022-01-26 09:31:50 +01:00
|
|
|
debugC(1, kHypnoDebugParser, "HE %x %d %d", $2, $3, $4);
|
|
|
|
}
|
|
|
|
| HLTOK BYTE NUM NUM {
|
|
|
|
debugC(1, kHypnoDebugParser, "HL %x %d %d", $2, $3, $4);
|
|
|
|
}
|
|
|
|
| HUTOK BYTE NUM NUM {
|
|
|
|
debugC(1, kHypnoDebugParser, "HU %x %d %d", $2, $3, $4);
|
|
|
|
}
|
|
|
|
| HTOK BYTE NUM NUM {
|
2022-01-28 23:46:11 +01:00
|
|
|
Segment segment($2, $3, $4);
|
|
|
|
g_parsedArc->segments.push_back(segment);
|
2022-01-26 09:31:50 +01:00
|
|
|
debugC(1, kHypnoDebugParser, "H %x %d %d", $2, $3, $4);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
|
|
|
;
|
2021-08-01 19:13:52 +02:00
|
|
|
|
2022-02-13 11:27:52 +01:00
|
|
|
enc: ENCTOK { $$ = $1; }
|
|
|
|
| /* nothing */ { $$ = scumm_strdup(""); }
|
2021-09-08 22:14:14 +02:00
|
|
|
;
|
2021-08-01 19:13:52 +02:00
|
|
|
|
2021-09-19 12:41:49 +02:00
|
|
|
body: bline body
|
|
|
|
| RETTOK body
|
|
|
|
| /* nothing */
|
|
|
|
;
|
2021-08-01 19:13:52 +02:00
|
|
|
|
2021-08-19 11:58:56 +02:00
|
|
|
bline: FNTOK FILENAME {
|
|
|
|
shoot = new Shoot();
|
2022-01-30 11:26:17 +01:00
|
|
|
if (Common::String("F0") == $1)
|
|
|
|
shoot->animation = $2;
|
2022-01-30 18:33:00 +01:00
|
|
|
else if (Common::String("F4") == $1)
|
|
|
|
shoot->explosionAnimation = $2;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "FN %s", $2);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
|
|
|
| FNTOK NONETOK {
|
2021-08-19 11:58:56 +02:00
|
|
|
shoot = new Shoot();
|
|
|
|
shoot->animation = "NONE";
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "FN NONE");
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
|
|
|
| FTOK FILENAME {
|
2021-08-01 19:13:52 +02:00
|
|
|
shoot = new Shoot();
|
|
|
|
shoot->animation = $2;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "FN %s", $2);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2021-09-19 12:41:49 +02:00
|
|
|
| ITOK NAME {
|
2021-09-08 22:14:14 +02:00
|
|
|
shoot->name = $2;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "I %s", $2);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2021-09-19 12:41:49 +02:00
|
|
|
| ITOK BNTOK { // Workaround for NAME == B1
|
2021-09-08 22:14:14 +02:00
|
|
|
shoot->name = $2;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "I %s", $2);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2021-11-06 00:04:35 +01:00
|
|
|
| ITOK ATOK { // Workaround for NAME == A
|
|
|
|
shoot->name = "A";
|
|
|
|
debugC(1, kHypnoDebugParser, "I A");
|
|
|
|
}
|
|
|
|
| ITOK CTOK { // Workaround for NAME == C
|
|
|
|
shoot->name = "C";
|
|
|
|
debugC(1, kHypnoDebugParser, "I C");
|
|
|
|
}
|
|
|
|
| ITOK DTOK { // Workaround for NAME == D
|
|
|
|
shoot->name = "D";
|
|
|
|
debugC(1, kHypnoDebugParser, "I D");
|
|
|
|
}
|
|
|
|
| ITOK FTOK { // Workaround for NAME == F
|
|
|
|
shoot->name = "F";
|
|
|
|
debugC(1, kHypnoDebugParser, "I F");
|
|
|
|
}
|
|
|
|
| ITOK HTOK { // Workaround for NAME == H
|
|
|
|
shoot->name = "H";
|
|
|
|
debugC(1, kHypnoDebugParser, "I H");
|
|
|
|
}
|
|
|
|
| ITOK ITOK { // Workaround for NAME == I
|
|
|
|
shoot->name = "I";
|
|
|
|
debugC(1, kHypnoDebugParser, "I I");
|
|
|
|
}
|
|
|
|
| ITOK JTOK { // Workaround for NAME == I
|
|
|
|
shoot->name = "J";
|
|
|
|
debugC(1, kHypnoDebugParser, "I J");
|
|
|
|
}
|
|
|
|
| ITOK NTOK { // Workaround for NAME == N
|
|
|
|
shoot->name = "N";
|
|
|
|
debugC(1, kHypnoDebugParser, "I N");
|
|
|
|
}
|
|
|
|
| ITOK OTOK { // Workaround for NAME == O
|
|
|
|
shoot->name = "O";
|
|
|
|
debugC(1, kHypnoDebugParser, "I O");
|
|
|
|
}
|
|
|
|
| ITOK PTOK { // Workaround for NAME == P
|
|
|
|
shoot->name = "P";
|
|
|
|
debugC(1, kHypnoDebugParser, "I P");
|
|
|
|
}
|
|
|
|
| ITOK QTOK { // Workaround for NAME == Q
|
|
|
|
shoot->name = "Q";
|
|
|
|
debugC(1, kHypnoDebugParser, "I Q");
|
|
|
|
}
|
|
|
|
| ITOK RTOK { // Workaround for NAME == R
|
|
|
|
shoot->name = "R";
|
|
|
|
debugC(1, kHypnoDebugParser, "I R");
|
|
|
|
}
|
|
|
|
| ITOK SNTOK { // Workaround for NAME == S1
|
|
|
|
shoot->name = $2;
|
|
|
|
debugC(1, kHypnoDebugParser, "I %s", $2);
|
|
|
|
}
|
|
|
|
| ITOK TTOK { // Workaround for NAME == T
|
|
|
|
shoot->name = "T";
|
|
|
|
debugC(1, kHypnoDebugParser, "I T");
|
|
|
|
}
|
|
|
|
| JTOK NUM {
|
|
|
|
debugC(1, kHypnoDebugParser, "J %d", $2);
|
|
|
|
}
|
2021-09-08 22:14:14 +02:00
|
|
|
| A0TOK NUM NUM {
|
|
|
|
shoot->position = Common::Point($2, $3);
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "A0 %d %d", $2, $3);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2022-01-30 11:26:17 +01:00
|
|
|
| RTOK NUM NUM {
|
|
|
|
shoot->obj1KillsCount = $2;
|
|
|
|
shoot->obj1MissesCount = $3;
|
|
|
|
debugC(1, kHypnoDebugParser, "R %d %d", $2, $3);
|
|
|
|
}
|
2021-12-20 14:05:11 +01:00
|
|
|
| R0TOK NUM NUM { debugC(1, kHypnoDebugParser, "R0 %d %d", $2, $3); }
|
2021-09-19 12:41:49 +02:00
|
|
|
| BNTOK NUM NUM { debugC(1, kHypnoDebugParser, "BN %d %d", $2, $3); }
|
2021-11-06 00:04:35 +01:00
|
|
|
| KNTOK NUM NUM {
|
2022-02-02 19:13:32 +01:00
|
|
|
shoot->explosionFrames.push_front($3);
|
2021-11-06 00:04:35 +01:00
|
|
|
debugC(1, kHypnoDebugParser, "KN %d %d", $2, $3);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2022-01-10 20:22:07 +01:00
|
|
|
| P0TOK NUM NUM {
|
|
|
|
shoot->paletteSize = $2;
|
|
|
|
shoot->paletteOffset = $3;
|
|
|
|
debugC(1, kHypnoDebugParser, "P0 %d %d", $2, $3); }
|
2021-09-08 22:14:14 +02:00
|
|
|
| OTOK NUM NUM {
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "O %d %d", $2, $3);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2021-09-19 12:41:49 +02:00
|
|
|
| CTOK NUM { debugC(1, kHypnoDebugParser, "C %d", $2); }
|
2021-11-11 19:50:39 +01:00
|
|
|
| HTOK NUM {
|
2022-02-02 19:13:32 +01:00
|
|
|
shoot->attackFrames.push_back($2);
|
2021-11-11 19:50:39 +01:00
|
|
|
debugC(1, kHypnoDebugParser, "H %d", $2); }
|
|
|
|
| WTOK NUM {
|
|
|
|
shoot->attackWeight = $2;
|
|
|
|
debugC(1, kHypnoDebugParser, "W %d", $2); }
|
|
|
|
| DTOK NUM {
|
|
|
|
shoot->pointsToShoot = $2;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "D %d", $2);
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
|
|
|
| SNTOK FILENAME enc {
|
|
|
|
if (Common::String("S1") == $1)
|
2021-11-11 19:50:39 +01:00
|
|
|
shoot->deathSound = $2;
|
|
|
|
else if (Common::String("S2") == $1)
|
|
|
|
shoot->hitSound = $2;
|
2021-08-26 23:09:12 +02:00
|
|
|
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "SN %s", $2); }
|
|
|
|
| NTOK { debugC(1, kHypnoDebugParser, "N"); }
|
2021-09-08 22:14:14 +02:00
|
|
|
| ZTOK {
|
2021-10-31 11:47:48 +01:00
|
|
|
g_parsedArc->shoots.push_back(*shoot);
|
2021-08-06 22:27:03 +02:00
|
|
|
//delete shoot;
|
|
|
|
//shoot = nullptr;
|
2021-09-19 12:41:49 +02:00
|
|
|
debugC(1, kHypnoDebugParser, "Z");
|
2021-09-08 22:14:14 +02:00
|
|
|
}
|
2021-09-08 22:49:56 +02:00
|
|
|
;
|
|
|
|
|