WEBVTT

00:00.000 --> 00:11.720
All right, so our last talk of the day is 20 years of yourbuttal.net.

00:11.720 --> 00:18.160
I expect you from the PVPGN server and its open source ecosystem by Clemen.

00:18.160 --> 00:20.160
Thank you.

00:20.160 --> 00:27.400
Yeah, so I have to compress 20 years into 40 minutes, so let's get started.

00:27.400 --> 00:33.720
So here battle is basically an unofficial work of 3 multiplayer server, so if you have a

00:33.720 --> 00:39.480
bunch of friends, you want to play work of together, we are the place to be, I guess.

00:39.480 --> 00:43.520
So the server was set up in 2003.

00:43.520 --> 00:47.920
It is initially a small community in Poland.

00:47.920 --> 00:52.880
Later we kind of became a European and global server.

00:52.880 --> 01:00.480
So the original logo, which is on the top right, still has like a Polish and English

01:00.480 --> 01:10.280
form sections, the major gain that is played today on our server since 2005 is Dota

01:10.280 --> 01:11.760
all stars.

01:11.760 --> 01:20.360
For those that don't know, Dota all stars, which gave us Dota 2, leave a glad legend, etc.

01:20.440 --> 01:25.880
It all started on the workcraft, because workcraft shipped a word editor.

01:25.880 --> 01:33.040
With word editor, you could create whatever maps you wanted, so minigames, tower defense maps,

01:33.040 --> 01:35.640
hero, or in assets, etc.

01:35.640 --> 01:42.120
And because of so many maps were created, there are thousands of them, the game is still

01:42.120 --> 01:48.560
kind of relevant 25 years later.

01:48.600 --> 01:54.720
So according to Google Trends, our server was most popular around 2009.

01:54.720 --> 02:01.240
Then I checked our counter-editration numbers, and it's maybe 2013, so like 5 years

02:01.240 --> 02:02.240
later.

02:02.240 --> 02:08.880
But whatever, like the best year was, if you joined the server in like the evening hours,

02:08.880 --> 02:15.160
there were like 4,000 players online, you could hop into some game lobby, find people

02:15.160 --> 02:17.000
very quickly.

02:17.160 --> 02:25.800
Today it's maybe a little less, much less, so 200 to 300 online people in like evening

02:25.800 --> 02:27.280
hours.

02:27.280 --> 02:36.840
So today it takes maybe 10, 15 minutes to find 10 different people to join a lobby.

02:36.840 --> 02:45.480
Most statistics from our data leagues, so 2015, we had 25,000 games per month.

02:45.480 --> 02:52.400
Then in 2020, I guess we all know why that peak is there, because people had really

02:52.400 --> 02:57.080
logged on, had nothing better to do, and a lot of old players came back for a couple of

02:57.080 --> 02:59.080
months.

02:59.080 --> 03:06.120
Before 2015, unfortunately we had an accident, so I don't have the data and the culprit

03:06.200 --> 03:10.800
might be in this room today.

03:10.800 --> 03:18.480
These are technical stack, so the core component that we run is a BNAD demon or server.

03:18.480 --> 03:22.760
It is also known under the name of PVPGN.

03:22.760 --> 03:28.120
Then you have a PD manager, which is kind of a chatbot, you can ask it to host a game

03:28.120 --> 03:29.520
for you.

03:29.520 --> 03:35.520
It will then instruct one of the ghost instances to actually host something, so we have

03:35.560 --> 03:40.500
them in different regions, so if you are from Asia, you can get the ghost instance from

03:40.500 --> 03:44.600
Asia and you will have better latency to play.

03:44.600 --> 03:53.560
Finally, there is this G-Proxy component, which stands between the game client and the ghost,

03:53.560 --> 03:56.280
and this is a TCP proxy.

03:56.280 --> 04:02.840
So now we will deep dive into each one of these cedar history and how they came to be.

04:02.840 --> 04:14.200
So BNAD was a reverse engineer, implementation of the Bethelnet V1 server protocol, the initial

04:14.200 --> 04:22.080
release in 1998 supported Starcraft, and later they added support for all the classic

04:22.080 --> 04:28.960
Blizzard games like Diablo and of course Workraft, which we host.

04:28.960 --> 04:37.960
Fortunately, in 2002 Blizzard opened a lawsuit against the project and took down the project.

04:37.960 --> 04:43.200
The KJ was pretty famous, you can check a bunch of stories on Slavdoc, they are interesting

04:43.200 --> 04:44.200
read.

04:44.200 --> 04:51.200
Legally, it was about enforcing end user license agreements, so the wall of text that you

04:51.200 --> 04:56.920
agree when you installed the game against reverse engineering, so they were claiming that

04:56.920 --> 05:02.800
because you agreed to the terms you couldn't reverse engineer the game.

05:02.800 --> 05:09.520
After this happened, the project was forked under a new name, PGM, player versus player

05:09.520 --> 05:11.720
game network.

05:11.720 --> 05:19.240
They added west to the online support, so now you could play Red Alert and CNC games.

05:19.240 --> 05:28.480
When it comes to the code, it is licensed under GPLV2, initially it is a C code and later

05:28.480 --> 05:33.320
it is supported to C++.

05:33.320 --> 05:40.120
So a few words about the protocol itself, it is proprietary and encrypted today, the easiest way

05:40.120 --> 05:46.560
to look at it is to open Wireshark and BNAD V filter.

05:46.560 --> 05:51.160
Once you capture some traffic, BNAD V filter will translate the protocol, so you can look

05:51.160 --> 05:53.160
at all the fields.

05:53.160 --> 06:00.880
The protocol itself is documented on a community website called BNADdocs.org.

06:00.880 --> 06:07.120
This is a very old community of reverse engineers, hackers, who were trying different

06:07.120 --> 06:12.960
stuff, documenting every packet, trying different things, so you have the whole packet

06:13.000 --> 06:19.720
index on this site today and you can check each packet and hit the description.

06:19.720 --> 06:26.920
When it comes to workraft itself, there are kind of two sub protocols that it needs.

06:26.920 --> 06:34.200
The first one is SID protocol, which implement things like chat rooms, login, etc.

06:34.200 --> 06:40.680
The important thing to know is that once you as a player create the game lobby, you enter

06:40.680 --> 06:42.080
a peer-to-peer protocol.

06:42.080 --> 06:48.280
So you are no longer in the BNAD realm, all the traffic goes through the player host and

06:48.280 --> 07:00.560
it's all within the game client, and this second part is called W3GS protocol.

07:00.560 --> 07:09.000
So when TPUN was created, they chose a European-based coding platform, Beryllios, the

07:09.040 --> 07:15.200
Berlin open source, which no longer exists today, it wasn't able to research, but I suspect

07:15.200 --> 07:20.680
they chose a European-based platform because of the previous lawsuit.

07:20.680 --> 07:27.440
The project kind of died down in 2011 because of lack of developers and lack of interest.

07:27.440 --> 07:37.080
Then a year later, it was forked under the name of PGN Pro, this fork had quite a lot

07:37.160 --> 07:43.600
of conductivity for the next 10 years, it stopped for years ago, unfortunately.

07:43.600 --> 07:51.240
They added a bunch of stuff like modern C-Make, JSON config files, Lua plugins, you could

07:51.240 --> 07:57.200
write Lua scripts and hook into various server events with that.

07:57.200 --> 08:04.720
Unfortunately, not many unit tests were written, so something's also broke, and it is perhaps

08:04.800 --> 08:11.560
a bit unstable, but if you wanted to run your own instance, this one is like the latest

08:11.560 --> 08:15.440
and best version to run.

08:15.440 --> 08:21.640
Because of some of those disabilities, we never transitioned to this fork on our server,

08:21.640 --> 08:28.960
so we still use the old one dot 99, and we have added some patches on top of that.

08:28.960 --> 08:34.680
The most important one is command flooding prevention, so the issue is that when

08:34.680 --> 08:43.400
you play against someone, you could do denial of service, floods you with packets, for example,

08:43.400 --> 08:47.640
if that player dropped, then you automatically win.

08:47.640 --> 08:55.040
It was a huge problem, one of our former admins kind of scrambled the patch and it was

08:55.040 --> 09:01.040
upstream later.

09:01.040 --> 09:08.240
So original problems, as I said, players are the game hosts, so especially in competitive

09:08.240 --> 09:14.480
delta, that's not really something you want, because your latency will depend on where

09:14.480 --> 09:24.640
the player is coming from, how good their internet speed is, so the second demand from

09:24.640 --> 09:30.560
the delta community was to have competitive games, so tracking player stats, having

09:30.600 --> 09:36.640
ladders, tournaments, everything.

09:36.640 --> 09:42.160
The final problem in the original protocol is that you can fake your username.

09:42.160 --> 09:49.560
When you join the lobby, you can lie, you can impersonate staff members, administrators,

09:49.560 --> 09:57.360
as you can imagine, this is not good.

09:57.360 --> 10:03.240
So those projects were created to tackle these problems.

10:03.240 --> 10:09.840
It is essentially a bot that can simulate player hosts, so you will deploy it on some dedicated

10:09.840 --> 10:17.920
server or VPS, so everyone in the proximate region will have good latencies to play.

10:17.920 --> 10:23.880
You communicate with the bot through chat channels, you can issue it commands like load

10:23.880 --> 10:28.840
me this map, create me this game, and it will do it for you.

10:28.840 --> 10:34.440
It can natively capture all the game events, so each kill in a dot again, each hero pick,

10:34.440 --> 10:41.000
all the winners, all of that is collected, and it can store that in a mySQL database.

10:41.000 --> 10:47.440
So after you have that, you can write your own websites, platforms, tournaments, whatever

10:47.440 --> 10:49.680
you like.

10:49.680 --> 10:56.680
For other maps, it also added some generic WVNMD protocol, so if you are a map maker,

10:56.680 --> 11:05.680
you can emit generic key value events and go to capture that and store it for you.

11:05.680 --> 11:12.520
Finally, how it solved the name spoofing issue, when you join again, goes towards the lobby,

11:12.520 --> 11:15.120
you have to send it a private message.

11:15.120 --> 11:22.640
After you do that, goes to a chat with BNFD, and ask it in which game is this player

11:22.640 --> 11:28.840
currently supposed to be, and if there is a mismatch with this information, we know that

11:28.840 --> 11:35.680
you are doing something funky and we teach you all basically.

11:35.680 --> 11:43.440
So initially, the project was written in VBNF, and it was called those panel project,

11:43.520 --> 11:51.680
done in 2008, it was ported to C++ by Trevor Hogan, and this is the main product used

11:51.680 --> 11:53.400
today.

11:53.400 --> 11:59.320
One interesting fork was Ghost One, which added Windows UI, so a lot of players who were

11:59.320 --> 12:03.520
less technical like to use this one.

12:03.520 --> 12:11.440
Support the development discussions on two different forums, one was CodeLane.com, and GhostPp.com,

12:11.480 --> 12:16.520
decides unfortunately no longer exists today, so you can check it on on internet archive,

12:16.520 --> 12:18.800
for example.

12:18.800 --> 12:26.520
The code itself was in Google Code SVN repo, which no longer exists of course, and one

12:26.520 --> 12:32.360
useful thing about the forums was that you could download pre-compiled DLLs for the

12:32.360 --> 12:39.280
dependencies, otherwise you'd have to build everyone from source, and that was quite complicated

12:39.280 --> 12:42.360
back in the day.

12:42.360 --> 12:48.280
So some of these dependencies of the Ghost Project, the first one is BNCS Util.

12:48.280 --> 12:54.000
This is a small C++ library that implemented the login sequence, which is quite complex

12:54.000 --> 13:01.280
to implement, so most chat bots just use this one to get the login working.

13:01.280 --> 13:07.600
We comment in this today with binaddocs.org community, it is basically feature complete,

13:07.600 --> 13:12.600
so just basic maintenance is needed at this point.

13:12.600 --> 13:18.600
We have GitHub releases with DLLs, RPMs, and Debian archives.

13:18.600 --> 13:24.600
We would like to maybe push this one to various Linux distros, so it's easy to install

13:24.600 --> 13:26.600
that's why.

13:26.600 --> 13:29.600
The second dependency is Tomlip.

13:29.600 --> 13:37.600
We can manage NPQ archives, NPQ archives are property formats by Blizzard for game assets

13:37.600 --> 13:40.600
and custom maps.

13:40.600 --> 13:46.600
Ghost needs this library, so it can read information like how many players this map supports,

13:46.600 --> 13:48.600
and how many teams.

13:48.600 --> 13:54.600
Based on this information, it can then construct the correct login for the game.

13:54.600 --> 14:02.600
Finally, that is a bunch of boost components for basic stuff like threading, date time, projects.

14:02.600 --> 14:09.600
Yeah, this is purely maintenance, I guess, because boost is continually evolving,

14:09.600 --> 14:13.600
and maybe in the future we will get rid of some of these components,

14:13.600 --> 14:19.600
because we have some modern C++ alternatives today.

14:20.600 --> 14:27.600
So within our server community, two different Ghost folks kind of independently appeared.

14:27.600 --> 14:31.600
I don't have much time, so I'll just talk about one of them.

14:31.600 --> 14:34.600
It's called PDManager.

14:34.600 --> 14:41.600
It was created by an independent data leak, which after a few years we merged together,

14:41.600 --> 14:47.600
and we comb and taint this code until today.

14:47.600 --> 14:54.600
So the problem of the original project was that if two players want to create a game at the same time,

14:54.600 --> 14:57.600
and you have one ghost instance, they can do it.

14:57.600 --> 15:03.600
You have to wait for the first one to start, and then the second one can reuse that instance.

15:03.600 --> 15:13.600
Obviously, when you have thousands or hundreds of players online, that is a big bottleneck, so we need a solution.

15:14.600 --> 15:17.600
The solution was to split the bot into two bots.

15:17.600 --> 15:24.600
So one is a manager bot, which sits in some public chat channel, let's say.

15:24.600 --> 15:28.600
And then we connect multiple ghost instances to this bot.

15:28.600 --> 15:34.600
They use a UDP protocol to communicate between each other.

15:34.600 --> 15:38.600
So when the player requests a game from the manager bot,

15:38.600 --> 15:45.600
we'll find one of the three ghost instances and instruct it to actually host the game.

15:45.600 --> 15:50.600
Manager also can give you information like which lobbies are currently open,

15:50.600 --> 15:53.600
and how many players are in each lobby.

15:53.600 --> 15:58.600
So if you see that one lobby has eight out of ten players, you can join that one,

15:58.600 --> 16:04.600
because you know, it will fill up very quickly, and you don't have to wait as much time.

16:05.600 --> 16:12.600
Just last year, we got some new players from Asia and South America, so we added support,

16:12.600 --> 16:18.600
so that when you create a game, you can request a specific region for the bot.

16:18.600 --> 16:22.600
For scoring, we have PSR scoring system.

16:22.600 --> 16:28.600
It is kind of an ELO based algorithm scoring system.

16:29.600 --> 16:34.600
We also enforce that you can start the game unless the teams are balanced.

16:34.600 --> 16:43.600
So you can't have a team one that is all professionals with high scores and team two that are like noobs with low scores.

16:43.600 --> 16:50.600
So we enforce that either you manually or automatically balance the lobby before you start.

16:50.600 --> 16:55.600
When it comes to the code itself, we have modern CMake support today.

16:55.600 --> 17:01.600
We have added column two and VC package for dependency resolution.

17:01.600 --> 17:10.600
Before the original project came with a make file and Visual Studio 2008 solution file.

17:10.600 --> 17:15.600
So compared to that, there is big progress, I guess.

17:15.600 --> 17:24.600
We also have a Docker file and a proposed support, so you can get up and running quite fast with that.

17:24.600 --> 17:30.600
Okay, final component is G proxy project.

17:30.600 --> 17:38.600
So the 2000s were the age of early DSL and dial up and the connections were flaky.

17:38.600 --> 17:46.600
One annoying limitation of the work of the game client is that if you happen to lose your internet connection in the middle of the game,

17:46.600 --> 17:50.600
you only have like 70 seconds to reconnect.

17:50.600 --> 17:57.600
Otherwise the game will just drop you out and you're basically done.

17:57.600 --> 18:03.600
If you have to reset your router or anything like that, there is no chance you will do that in 70 seconds.

18:03.600 --> 18:10.600
So G proxy found a clever way to extend this reconnection window.

18:10.600 --> 18:13.600
So the name itself stands for game proxy.

18:13.600 --> 18:19.600
It was developed by the same person to our home in 2010.

18:19.600 --> 18:26.600
It is a client side binary that each player will run on their computer and it is basically a TCP proxy.

18:26.600 --> 18:32.600
So the game connects through this binary and to the ghost distance.

18:32.600 --> 18:40.600
The way it works is that ghost and G proxy will do a GPS protocol handshake when you join the lobby.

18:40.600 --> 18:48.600
After that, G proxy will start inserting empty actions for each game action.

18:48.600 --> 18:56.600
So this sounds like a big increase in packets and it is, yeah, it's an timing increase.

18:56.600 --> 19:01.600
A practice is not really an issue, it turns out.

19:01.600 --> 19:04.600
But why do we need these empty actions?

19:04.600 --> 19:13.600
So when you lose the internet connection, G proxy will start feeding one empty action per minute to the game client.

19:13.600 --> 19:21.600
This way we kind of lie to the game and keep it interested that, hey, we haven't actually quite loved the connection yet.

19:21.600 --> 19:29.600
So this way each empty action will give us one extra minute of reconnection time.

19:29.600 --> 19:35.600
And this is great solution, very clever, and it works.

19:36.600 --> 19:51.600
Finally, in our fork of this binary, it turns out that if you force every player to run something or the computer, you can add a bunch of other stuff random features it with.

19:51.600 --> 19:56.600
So the first one is that it will automatically spoof jack for you.

19:56.600 --> 20:13.600
Instead of having to write that private message manually each time you join a lobby, G proxy will automatically spoof jack, that's the green line in the chat there.

20:13.600 --> 20:21.600
We can also enforce that all the players that join the lobby have the same work of client version.

20:21.600 --> 20:37.600
So usually you can miss a match patch versions, but it's not really recommended because there is a small possibility that players will go out of sync during the game and then they drop and the game is ruined basically.

20:38.600 --> 20:50.600
We have also added some random stuff like out a login feature, so it kind of simulates key strokes to get you logged in into the game.

20:50.600 --> 21:04.600
One weird feature is chat history, so if you press up and down arrows in chat, it works like a Linux terminal, it cycles for your chat history basically, so we have stuff like that.

21:04.600 --> 21:08.600
Finally, let's do a live demo.

21:08.600 --> 21:26.600
So the game itself works quite okay on wine, so I'm running here, there be a testing with wine staging on fourth and Wi-Fi so many things could go wrong, but let's try.

21:26.600 --> 21:44.600
This is one, this is our small QT desktop client, the only reason we need this is so that it will start G proxy and game in the appropriate order and configure stuff behind the scenes to make everything work basically.

21:44.600 --> 21:56.600
So when I click this button, it will launch the game and G proxy is secretly running as a background processor and it's listening on local forest.

21:56.600 --> 22:05.600
So before we connect, we can check the gateway we are connecting to and we see that we are connecting to a G proxy gateway.

22:05.600 --> 22:18.600
So this behind the scenes is Windows registry entry, you give it a gateway name and IP or DNS and in this entry there is basically just local host.

22:18.600 --> 22:25.600
So now that we can connect all the traffic will go through local G proxy and upstream from there.

22:25.600 --> 22:32.600
Now please everyone close your eyes.

22:33.600 --> 22:41.600
So once we are in the battle net, it's classic UI, it's basically the same as if you joined an official server.

22:41.600 --> 22:46.600
We just have some custom banners and stuff like that, custom icons.

22:46.600 --> 22:53.600
Now we are in a chat room and we can ask one of our manager bots to host the game for us.

22:53.600 --> 22:59.600
So we can do that through a private message.

22:59.600 --> 23:07.600
Legabuse.com is the name of our manager bot and the command to load a map is dot map and we give it a name.

23:07.600 --> 23:13.600
So today we are going to play.

23:14.600 --> 23:26.600
It's a random custom map I like to play sometimes, it's like a dodgeball, you pick up a ball and throw it with your opponent basically that's the whole story.

23:26.600 --> 23:35.600
So now the map was loaded and we can create a private or a public game.

23:35.600 --> 23:40.600
So we create a private game called false them.

23:40.600 --> 23:46.600
The game was created. Now we can enter the game list.

23:46.600 --> 23:51.600
We can type our game name here.

23:51.600 --> 23:58.600
So we can see the map we are playing is Magos Arena and we have 12 player slots.

23:58.600 --> 24:01.600
If we check the chat lobby.

24:01.600 --> 24:07.600
So this is the initiation of the G proxy handshake with ghost instance.

24:07.600 --> 24:11.600
Then we have like a welcome message from our ghost bot.

24:11.600 --> 24:14.600
It's in the EU region.

24:14.600 --> 24:23.600
Finally ghost required us to spoof check and we G proxy did that for us automatically.

24:24.600 --> 24:29.600
And we can see that the G proxy protocol was successfully established.

24:29.600 --> 24:38.600
So now I don't have anyone to play against me, so I guess I'll just set computer to slot 2.

24:38.600 --> 24:50.600
And we also have to change teams so that the game engine will see as a opponent and not be in the same team because otherwise we can't kill each other basically.

24:50.600 --> 24:55.600
So now everything should be ready.

24:55.600 --> 24:57.600
We have a 10 second countdown.

24:57.600 --> 25:02.600
You can abort if you messed up something.

25:02.600 --> 25:06.600
Best directions. Pretty clear. Pick up the ball.

25:06.600 --> 25:09.600
Throw with R.

25:09.600 --> 25:17.600
We can choose multiple arenas. We'll just go with the first one.

25:17.600 --> 25:24.600
A few options last man standing speed killing is whoever comes to like 10, 15 kills whatever.

25:24.600 --> 25:29.600
So because I'm almost out of time let's just go last man standing.

25:29.600 --> 25:37.600
And after the game starts we can pick some balls and throw it.

25:37.600 --> 25:44.600
So what's important to know here is that unless we are playing the standard strategy games here.

25:45.600 --> 25:50.600
The computer doesn't, the game engine doesn't know how to play this specific map right.

25:50.600 --> 26:01.600
So unless you actually code your own AI into the map, the computer has no idea that it has to pick up the ball and throw it to the right.

26:01.600 --> 26:08.600
And yeah, I guess I'm almost out of time and this concludes my presentation.

26:08.600 --> 26:21.600
All right, there should be some time for questions.

26:21.600 --> 26:24.600
So thank you for your talk.

26:24.600 --> 26:32.600
I don't know if I've missed it before, but do you handle and if so, how do you handle the host migration?

26:32.600 --> 26:36.600
If the host changes, for example, if the host leaves?

26:37.600 --> 26:46.600
So we actually don't because host never leaves because it's hosted by ghost and we control ghost.

26:46.600 --> 26:48.600
Yeah, never leaves basically.

26:48.600 --> 26:57.600
But in original protocol if the host player human host leaves, it will just negotiate a new host basically.

26:57.600 --> 27:00.600
All right, my questions.

27:01.600 --> 27:07.600
First off, thanks for your talk.

27:07.600 --> 27:18.600
In the part about proxy, you say send empty actions and then if the players disconnect, you send empty packets for 60 seconds.

27:18.600 --> 27:23.600
So what exactly is the use of those empty packets when a player does an action?

27:23.600 --> 27:26.600
I don't think I quite got that.

27:26.600 --> 27:33.600
So you lose connection and unless you send something to the game, it will drop you, right?

27:33.600 --> 27:38.600
So you take one of those empty actions, which you have in reserve.

27:38.600 --> 27:41.600
And you feel it to the game.

27:41.600 --> 27:44.600
Basically, yeah, that's how it works.

27:44.600 --> 27:47.600
Okay, my questions.

27:48.600 --> 28:02.600
Maybe a little unrelated to your presentation, but how did the release of the work referee

28:02.600 --> 28:05.600
forged impact your project at all?

28:05.600 --> 28:08.600
Did it impact it at all or not?

28:08.600 --> 28:11.600
Which project specifically?

28:11.600 --> 28:14.600
The Euro Battleman.

28:14.600 --> 28:18.600
Basically, we are only hosting work of free.

28:18.600 --> 28:22.600
So we never hosted any other game like Starcraft or Diablo.

28:22.600 --> 28:30.600
So yeah, without work of free, I guess, we didn't exist before work of free and we wouldn't exist without work of free.

28:30.600 --> 28:34.600
Just follow up, but did not.

28:34.600 --> 28:39.600
Didn't Blizzard replace regular work referee with re-forged.

28:39.600 --> 28:43.600
So you can't get base work referee anymore, is that?

28:43.600 --> 28:45.600
Yes, excellent question.

28:45.600 --> 28:48.600
We are staying on an ultra patch.

28:48.600 --> 28:53.600
We, the new remaster, they destroyed a lot of things.

28:53.600 --> 28:55.600
The protocol is no longer compatible.

28:55.600 --> 29:01.600
So we are basically staying on like eight year old work of patch.

29:01.600 --> 29:05.600
That's how we did it.

29:05.600 --> 29:10.600
All right, my questions.

29:10.600 --> 29:13.600
All right, then I guess we are done.

29:13.600 --> 29:15.600
So thank you.

29:15.600 --> 29:20.600
Thank you.

