La technologie webpatch

De T4C Tech
Révision datée du 23 avril 2017 à 19:47 par FunJp (discussion | contributions) (Page créée avec « == Qu'est-ce que c'est ? == Le webpatch est un système imaginé par Vircom pour forcer les joueurs de T4C à tenir automatiquement leur jeu à jour, en les forçant à t... »)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à la navigation Aller à la recherche

Qu'est-ce que c'est ?

Le webpatch est un système imaginé par Vircom pour forcer les joueurs de T4C à tenir automatiquement leur jeu à jour, en les forçant à télécharger si nécessaire les fichiers du jeu à partir d'un serveur de fichiers.

Quand un joueur se connecte à un serveur La Quatrième Prophétie, son client T4C demande d'abord au serveur le message du jour. Puis, quand il clique une deuxième fois sur "Connecter", le client demande alors au serveur l'adresse du serveur de webpatch.

(T4C Guard),03/12/08,17:51:45,Network_Init(): Network layer successfully initialized.

Ceci correspond au démarrage du jeu.

(T4C Guard),03/12/08,17:51:51,Client to server:
        Notice: an acknowledgment for this pak is requested.

        Resolved data: 2 bytes
                int16 pak_type = 0x0042; // PAK_CLIENT_MessageOfTheDay


        Raw data: 2 bytes
        00016         00 42                                                  .B              


(T4C Guard),03/12/08,17:51:51,Server to client:
        Notice: this pak is an acknowledgment reply.

Le client commence par demander au serveur le message du jour. Le serveur lui répond aussitôt par un accusé de réception : "oui, j'ai bien entendu que tu m'as demandé le message du jour."

(T4C Guard),03/12/08,17:51:51,Server to client:
        Notice: an acknowledgment for this pak is requested.

        Resolved data: 14 bytes
                int16 pak_type = 0x0042; // PAK_SERVER_MessageOfTheDay
                string16 message = "Bienvenue!";


        Raw data: 14 bytes
        00016         00 42 04 3A 42 69 65 6E 76 65 6E 75 65 21              .B.:Bienvenue!  


(T4C Guard),03/12/08,17:51:51,Client to server:
        Notice: this pak is an acknowledgment reply.

Le serveur envoie alors le message du jour au client, et le client répond par un accusé de réception : "oui, j'ai bien reçu ton message du jour."

(T4C Guard),03/12/08,17:51:51,Client to server:

        Resolved data: 2 bytes
                int16 pak_type = 0x005b; // PAK_CLIENT_PatchServerInformation


        Raw data: 2 bytes
        00016         00 5B                                                  .[              

Voici le pak qui nous intéresse. Ici le client demande au serveur s'il ne disposerait pas par hasard d'informations sur un serveur de webpatch.

(T4C Guard),03/12/08,17:51:51,Server to client:
        Notice: an acknowledgment for this pak is requested.

        Resolved data: 57 bytes
                int16 pak_type = 0x005b; // PAK_SERVER_PatchServerInformation
                int32 server_version = 125;
                string16 url = "serveur-aegir.com";
                string16 filename = "/webpatch/webpatch.image";
                string16 login = "";
                string16 password = "";
                int16 unknown1 = 2;


        Raw data: 57 bytes
        00016         00 5B 00 00 00 7D 00 11 73 65 72 76 65 75 72 2D        .[...}..serveur-
        00032         61 65 67 69 72 2E 63 6F 6D 00 18 2F 77 65 62 70        aegir.com../webp
        00048         61 74 63 68 2F 77 65 62 70 61 74 63 68 2E 69 6D        atch/webpatch.im
        00064         61 67 65 00 00 00 00 00 02                             age......       


(T4C Guard),03/12/08,17:51:51,Client to server:
        Notice: this pak is an acknowledgment reply.

Et le serveur de lui répondre aussitôt par la liste des serveurs de webpatch qu'il lui recommande d'interroger. Le client répond à cette information par un nouvel accusé de réception, comme on peut le voir.

A ce moment-là, le client met en pause ses communications UDP avec le serveur, change de protocole et lance en parallèle une requête HTTP pour récupérer le fichier spécifié dans le pak (en l'occurence, il s'agit du fichier http://serveur-aegir.com/webpatch/webpatch.image).

Une fois que le client a reçu ce fichier (par HTTP), il l'analyse et contrôle s'il est à jour par-rapport au webpatch.

  • S'il ne l'est pas, le client se ferme, et lance en quittant une autre application qui télécharge chacun des fichiers à jour mentionnés dans le fichier webpatch.image qui vient d'être téléchargé sur le serveur de webpatch. Une fois téléchargés, ces fichiers sont décompressés, l'application qui les a téléchargés se ferme et le client est relancé : prêt à se connecter à nouveau.
  • S'il l'est, la communication UDP avec le serveur T4C reprend :
(T4C Guard),03/12/08,17:51:52,Client to server:
        Notice: an acknowledgment for this pak is requested.

        Resolved data: 21 bytes
                int16 pak_type = 0x000e; // PAK_CLIENT_Login
                string8 login = "Aegir";
                string8 password = "*******";
                int16 client_version_number = 150;
                int16 unknown = 0;


        Raw data: 21 bytes
        00016         00 0E 05 41 65 67 69 72 07 00 00 00 00 00 00 00        ...Aegir.*******
        00032         00 96 00 00                                            ....            


(T4C Guard),03/12/08,17:51:52,Server to client:
        Notice: this pak is an acknowledgment reply.

Le client envoie sa demande de login

(T4C Guard),03/12/08,17:51:52,Server to client:
        Notice: an acknowledgment for this pak is requested.

        Resolved data: 27 bytes
                int16 pak_type = 0x000e; // PAK_SERVER_Login
                int8 status = 0; // (0:welcome, 1:error, 2:already logged in)
                string message = "Bienvenue à Prophétie!";


        Raw data: 27 bytes
        00016         00 0E 00 00 16 42 69 65 6E 76 65 6E 75 65 20 E0        .....Bienvenue .
        00032         20 50 72 6F 70 68 E9 74 69 65 21                        Proph.tie!     

Et le serveur lui répond.

Ainsi, cette bizarrerie du protocole réseau permet aux clients de toujours se maintenir à jour pour un serveur de jeu donné. Ceci assure que chaque client aura une version du jeu identique.

Intérêt du webpatch pour les administrateurs de serveur

Cette technologie présente en outre un intérêt non négligeable : si l'équipe qui administre un serveur T4C décide d'apporter des changements aux données du jeu, comme par exemple :

  • Changer des musiques
  • Redessiner des cartes
  • Remodeler le terrain de jeu

Elle peut se servir de la technologie webpatch pour propager automatiquement tous ces changements à chacun de leurs clients.

Encore pour cela faut-il créer un fichier webpatch.image correct et interprétable par le client T4C, et placer les fichiers de mise à jour adéquatements sur le serveur de fichiers qui fera office de serveur de webpatch.

Jusqu'à récemment il n'y avait qu'une seule méthode pour générer ces "packs" de webpatch : il fallait utiliser une application fournie par Vircom à ses clients sous licence, peu intuitive et non scriptable. On ne pouvait pas automatiser la création et la propagation des webpatches, il fallait le faire à la main.

Automatisation de la création des webpatch

Imaginons que, lorsqu'un serveur T4C redémarre, un script .bat soit lancé. L'idéal serait, pour que l'administrateur du serveur n'ait strictement rien à faire :

  • Que ce script rapatrie la dernière version des données du jeu prise chez les techniciens et l'équipe de développement (par exemple, via un système SVN)
  • Que ce script compile et mette en place ces données dans le dossier du serveur (par exemple, grâce aux WDATools)
  • Que ce script génère automatiquement le fichier webpatch.image qui va bien s'il détecte un changement au niveau des fichiers clients
  • Qu'il compresse et envoie automatiquement par FTP sur le serveur de webpatch, à la fois le fichier webpatch.image, et également tous les fichiers qui doivent être mis à jour chez les clients (par exemple, via un client FTP scriptable en ligne de commandes)
  • Et enfin, qu'il redémarre le serveur T4C.

La principale difficulté de cette procédure est le point numéro 3. Il s'agit de générer un fichier webpatch.image valide.

Note sur la compression des fichiers du webpatch

La compression utilisée par Vircom pour ses fichiers de webpatch est de type MS-ZIP, autrement dit LZ77. Vous pouvez télécharger une version Open Source de cet utilitaire de compression ici. D'ailleurs, il est fourni avec l'application Vircom de création de webpatch, car cette dernière l'utilise directement.

Structure d'un fichier de webpatch

Examinons la structure d'un fichier de webpatch. Ici, le fichier de webpatch du serveur Aegir en date du 12 mars 2008.

[Version 1]

[Patches]

[Mandatory]
FILE "/webpatch/mandatory/isp.pcx_" "\isp.pcx" 308097 101415 11/30/2007 10:36:23 [] 36B2122E7A
FILE "/webpatch/mandatory/load.pcx_" "\load.pcx" 308097 85327 11/30/2007 10:36:23 [] 3646F89CF6
FILE "/webpatch/mandatory/game files/cavernmap.map_" "\Game Files\cavernmap.map" 1009528 264270 12/30/2007 05:02:15 [] 02A0840628
FILE "/webpatch/mandatory/game files/dungeonmap.map_" "\Game Files\dungeonmap.map" 827548 221167 02/06/2008 06:02:20 [] 02607FC85A
FILE "/webpatch/mandatory/game files/underworld.map_" "\Game Files\underworld.map" 2185944 607025 01/27/2008 06:03:43 [] 03E39EB1EA
FILE "/webpatch/mandatory/game files/worldmap.map_" "\Game Files\worldmap.map" 1880252 633831 01/29/2008 15:42:07 [] 42569715B2
FILE "/webpatch/mandatory/prophetie.exe_" "\prophetie.exe" 164864 156058 03/07/2008 06:02:24 [] 02A4417529

[Webpatch]

[Modules]

On remarque tout de suite qu'il s'agit d'un fichier texte.

La section qui nous intéresse est la section des fichiers qui doivent être tenus à jour obligatoirement: la section [Mandatory].

Structure d'une entrée dans la section [Mandatory] du fichier de webpatch

Comme on peut le voir, chaque ligne de cette section fait référence à un fichier du jeu qu'il convient de tenir à jour. Cette ligne, par exemple:

FILE "/webpatch/mandatory/game files/worldmap.map_" "\Game Files\worldmap.map" 1880252 633831 01/29/2008 15:42:07 [] 42569715B2

Exige que le client vérifie que le fichier \Game Files\worldmap.map ait bien une taille de 1880252 octets, que sa date de création soit le 29 janvier 2008, son heure de création soit 15:42:07 GMT (soit 16h en France), et que la somme de contrôle qu'il lui trouvera en l'analysant avec un mystérieux algorithme de chez Vircom soit bien 0x42569715B2. Si ce n'est pas le cas, il faudra le retélécharger à partir de l'adresse "/webpatch/mandatory/game files/worldmap.map_", et sa taille compressée sera de 633831 octets.

Je récapitule :

FILE "adresse/sur/le/serveur/web" "\Chemin Relatif\au jeu" taille_décompressé taille_compressé date heure [options] checksum

Nous pouvons aisément déduire programmatiquement toutes ces valeurs. Sauf une. C'est cette somme de contrôle qui nous empêchera de créer un générateur de webpatches valide.

Algorithme de calcul de la somme de contrôle de redondance cyclique (CRC)

L'algorithme utilisé ici par Vircom est une bizarrerie. Premièrement parce que la valeur retournée fait 5 octets, alors que les algorithmes de CRC habituels en font 4 (32 bits). Un coup d'oeil attentif nous renseigne alors que ce premier octet n'est qu'en fait la valeur littérale de la minute de modification du fichier :

15:42:07 GMT

42569715B2

Les quatre octets restants sont alors un CRC valide, mais dont l'ordre des octets a été inversé comme suit :

0x12345678
0x87654321

Qui plus est, il s'agit d'un algorithme de CRC non standard (JamCRC): en fait, l'algorithme de calcul est le même, mais le polynômial n'est pas le même.

unsigned long crc32 (char *buffer, int length)
{
   // cette fonction calcule et retourne la somme de contrôle de redondance cyclique (CRC) de
   // length octets lus dans le tableau d'octets buffer.

   unsigned long crc;
   int index;

   crc = -1; // initialise le CRC à 0xFFFFFFFF (-1)

   // pour chaque caractère du buffer...
   for (index = 0; index < length; index++)
      crc = crctable[((char) crc ^ buffer[index]) & 0xFF] ^ (crc >> 8); // ajoute au CRC

   return (crc); // et retourne la valeur finale (pas de XOR en sortie)
}

La table de CRC utilisée par cet algorithme est donnée ci-dessous.

Table de calcul de l'algorithme de contrôle de redondance cyclique (CRC)

Cette table peut être générée algorithmiquement, mais comme elle est toujours identique (car elle délivre toujours la même valeur pour chacun des 256 caractères du jeu ASCII étendu), il est plus simple de la déclarer statiquement en début de programme. La voici :

unsigned long crctable[256] =
{
   0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
   0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
   0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
   0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
   0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
   0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
   0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
   0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
   0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
   0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
   0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
   0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
   0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
   0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
   0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
   0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
   0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
   0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
   0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
   0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
   0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
   0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
   0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
   0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
   0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
   0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
   0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
   0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
   0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
   0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
   0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
   0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
   0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
   0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
   0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
   0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
   0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
   0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
   0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
   0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
   0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
   0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
   0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
   0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
   0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
   0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
   0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
   0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
   0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
   0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
   0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
   0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
   0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
   0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
   0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
   0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
   0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
   0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
   0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
   0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
   0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
   0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
   0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
   0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};

Le polynômial ayant servi à générer cette table est 0x04C11DB7. Vous trouverez plus de détails sur les paramètres de l'algorithme JamCRC sur cette page.

Ainsi, le véritable JamCRC du fichier "\Game Files\worldmap.map" n'est pas 42569715B2 comme indiqué dans le fichier webpatch, mais 2B517965 (les huit premiers demi-octets, lus à l'envers). Fûtés, Vircom, mais pas assez ;-)

Sauf que :

Cas des fichiers de taille supérieure à 64 kilo-octets

On s'aperçoit assez rapidement que cette théorie fonctionne parfaitement pour n'importe quel fichier de taille inférieure ou égale à 65536 octets (0x10000), mais dès qu'on veut aligner le checksum d'un fichier de taille supérieure, on ne trouve pas le bon.

La raison est simple (merci à Ikar/Zubrow Shane pour l'explication, obtenue par reverse-engineering de l'application de création de webpatch de Vircom) : quand le fichier à analyser fait plus de 64 kilo-octets, l'algorithme de CRC en lit 32 ko au début, 32 ko à la fin, colle les deux bouts ensemble et passe le checksum dessus.

Ceci permettant au jeu de se lancer plus vite en n'ayant pas à analyser les très gros fichiers en détail ; de toute façon, une modification à l'intérieur de ces fichiers se répercuterait sur la compression et affecterait les octets de fin.

Dans votre application de calcul de checksum, il faut donc que vous réalisiez les opérations suivantes (en pseudocode) :

OuvreFichier (fichier à analyser)

taille = TailleDuFichier (fichier à analyser)

SI (taille > 65536)
   buffer = LitDébutDuFichier (fichier à analyser)
   buffer = buffer + LitFinDuFichier (fichier à analyser)
SINON
   buffer = LitToutLeFichier (fichier à analyser)
FIN SI

FermeFichier (fichier à analyser)

checksum = CalculeJamCRC (buffer, taille)

Sans oublier, une fois le checksum obtenu, d'en inverser les huit demi-octets et de les préfixer par la minute de modification du fichier.

Vous avez maintenant toutes les informations dont vous avez besoin pour automatiser la création de vos webpatches.

Inclusion dans un fichier Batch

Voici un exemple de fichier .bat générant un webpatch.image valide, une fois que vous aurez conçu votre générateur de webpatch :

ECHO Création du webpatch

ECHO Etape 1: compression des fichiers :

compress.exe -S -Z "isp.pcx" "wwwroot\webpatch\Mandatory\isp.pcx_"
compress.exe -S -Z "load.pcx" "wwwroot\webpatch\Mandatory\load.pcx_"
compress.exe -S -Z "cavernmap.map" "wwwroot\webpatch\Mandatory\Game Files\cavernmap.map_"
compress.exe -S -Z "dungeonmap.map" "wwwroot\webpatch\Mandatory\Game Files\dungeonmap.map_"
compress.exe -S -Z "underworld.map" "wwwroot\webpatch\Mandatory\Game Files\underworld.map_"
compress.exe -S -Z "worldmap.map" "wwwroot\webpatch\Mandatory\Game Files\worldmap.map_"

ECHO Etape 2: création du fichier webpatch.image

ECHO.> wwwroot\webpatch\webpatch.image
ECHO [Version 1]>> wwwroot\webpatch\webpatch.image
ECHO.>> wwwroot\webpatch\webpatch.image
ECHO [Patches]>> wwwroot\webpatch\webpatch.image
ECHO.>> wwwroot\webpatch\webpatch.image
ECHO [Mandatory]>> wwwroot\webpatch\webpatch.image
makewebpatch.exe "isp.pcx" "wwwroot\webpatch\Mandatory\isp.pcx_" "/webpatch/mandatory/isp.pcx_" "\isp.pcx">> wwwroot\webpatch\webpatch.image
makewebpatch.exe "load.pcx" "wwwroot\webpatch\Mandatory\load.pcx_" "/webpatch/mandatory/load.pcx_" "\load.pcx">> wwwroot\webpatch\webpatch.image
makewebpatch.exe "cavernmap.map" "wwwroot\webpatch\Mandatory\Game Files\cavernmap.map_" "/webpatch/mandatory/game files/cavernmap.map_" "\Game Files\cavernmap.map">> wwwroot\webpatch\webpatch.image
makewebpatch.exe "dungeonmap.map" "wwwroot\webpatch\Mandatory\Game Files\dungeonmap.map_" "/webpatch/mandatory/game files/dungeonmap.map_" "\Game Files\dungeonmap.map">> wwwroot\webpatch\webpatch.image
makewebpatch.exe "underworld.map" "wwwroot\webpatch\Mandatory\Game Files\underworld.map_" "/webpatch/mandatory/game files/underworld.map_" "\Game Files\underworld.map">> wwwroot\webpatch\webpatch.image
makewebpatch.exe "worldmap.map" "wwwroot\webpatch\Mandatory\Game Files\worldmap.map_" "/webpatch/mandatory/game files/worldmap.map_" "\Game Files\worldmap.map">> wwwroot\webpatch\webpatch.image
ECHO.>> wwwroot\webpatch\webpatch.image
ECHO [Webpatch]>> wwwroot\webpatch\webpatch.image
ECHO.>> wwwroot\webpatch\webpatch.image
ECHO [Modules]>> wwwroot\webpatch\webpatch.image

ECHO Terminé.

Une fois ceci fait, il ne vous reste plus qu'à uploader le contenu du dossier wwwroot\webpatch grâce à un client FTP scriptable en ligne de commandes, ou par tout autre moyen, pour être sûr que vos clients auront toujours des fichiers de jeu à jour.

--Sorkvild 14 mars 2008 à 05:01 (MSK)