From d752ac5acbc5db1e0b0057fc93c329212746d33b Mon Sep 17 00:00:00 2001 From: Starystars67 Date: Tue, 28 Jan 2020 23:04:21 +0000 Subject: [PATCH] Creation of NodeJS Branch --- .gitignore | 491 ++----------- .idea/.gitignore | 2 - .idea/BeamNG-MP-Server.iml | 2 - .idea/misc.xml | 7 - .idea/modules.xml | 8 - .idea/vcs.xml | 6 - CMakeLists.txt | 11 - enet.lib | Bin 53768 -> 0 bytes index.html | 52 ++ index.js | 345 +++++++++ main.js | 235 ++++++ out/build/x64-Debug/enet64.lib | Bin 57720 -> 0 bytes out/build/x86-Debug/enet.lib | Bin 53768 -> 0 bytes package-lock.json | 1268 ++++++++++++++++++++++++++++++++ package.json | 20 + preload.js | 12 + renderer.js | 3 + src/config.cpp | 119 --- src/enet/callbacks.h | 27 - src/enet/enet.h | 607 --------------- src/enet/list.h | 43 -- src/enet/protocol.h | 198 ----- src/enet/time.h | 18 - src/enet/types.h | 13 - src/enet/unix.h | 48 -- src/enet/utility.h | 12 - src/enet/win32.h | 57 -- src/logger.cpp | 94 --- src/logger.h | 41 -- src/main.cpp | 46 -- src/main.h | 12 - src/network.cpp | 68 -- src/network.h | 15 - 33 files changed, 2009 insertions(+), 1871 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/BeamNG-MP-Server.iml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 CMakeLists.txt delete mode 100644 enet.lib create mode 100644 index.html create mode 100644 index.js create mode 100644 main.js delete mode 100644 out/build/x64-Debug/enet64.lib delete mode 100644 out/build/x86-Debug/enet.lib create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 preload.js create mode 100644 renderer.js delete mode 100644 src/config.cpp delete mode 100644 src/enet/callbacks.h delete mode 100644 src/enet/enet.h delete mode 100644 src/enet/list.h delete mode 100644 src/enet/protocol.h delete mode 100644 src/enet/time.h delete mode 100644 src/enet/types.h delete mode 100644 src/enet/unix.h delete mode 100644 src/enet/utility.h delete mode 100644 src/enet/win32.h delete mode 100644 src/logger.cpp delete mode 100644 src/logger.h delete mode 100644 src/main.cpp delete mode 100644 src/main.h delete mode 100644 src/network.cpp delete mode 100644 src/network.h diff --git a/.gitignore b/.gitignore index eaa9d4f..6704566 100644 --- a/.gitignore +++ b/.gitignore @@ -1,447 +1,104 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj +# Logs +logs *.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* -# Chutzpah Test files -_Chutzpah* +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb +# Runtime data +pids +*.pid +*.seed +*.pid.lock -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov -# Visual Studio Trace Files -*.e2e +# Coverage directory used by tools like istanbul +coverage +*.lcov -# TFS 2012 Local Workspace -$tf/ +# nyc test coverage +.nyc_output -# Guidance Automation Toolkit -*.gpState +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user +# Bower dependency directory (https://bower.io/) +bower_components -# TeamCity is a build add-in -_TeamCity* +# node-waf configuration +.lock-wscript -# DotCover is a Code Coverage Tool -*.dotCover +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat +# Dependency directories node_modules/ +jspm_packages/ -# Visual Studio 6 build log -*.plg +# TypeScript v1 declaration files +typings/ -# Visual Studio 6 workspace options file -*.opt +# TypeScript cache +*.tsbuildinfo -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw +# Optional npm cache directory +.npm -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions +# Optional eslint cache +.eslintcache -# Paket dependency manager -.paket/paket.exe -paket-files/ +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ -# FAKE - F# Make -.fake/ +# Optional REPL history +.node_repl_history -# CodeRush personal settings -.cr/personal +# Output of 'npm pack' +*.tgz -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc +# Yarn Integrity file +.yarn-integrity -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config +# dotenv environment variables file +.env +.env.test -# Tabs Studio -*.tss +# parcel-bundler cache (https://parceljs.org/) +.cache -# Telerik's JustMock configuration file -*.jmconfig +# Next.js build output +.next -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs +# Nuxt.js build / generate output +.nuxt +dist -# OpenCover UI analysis results -OpenCover/ +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public -# Azure Stream Analytics local run output -ASALocalRun/ +# vuepress build output +.vuepress/dist -# MSBuild Binary and Structured Log -*.binlog +# Serverless directories +.serverless/ -# NVidia Nsight GPU debugger configuration file -*.nvuser +# FuseBox cache +.fusebox/ -# MFractors (Xamarin productivity tool) working folder -.mfractor/ +# DynamoDB Local files +.dynamodb/ -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ -out/build/x86-Debug/VSInheritEnvironments.txt -out/build/x86-Debug/rules.ninja -out/build/x86-Debug/CMakeFiles/untitled.dir/manifest.res -out/build/x86-Debug/CMakeFiles/untitled.dir/manifest.rc -out/build/x86-Debug/CMakeFiles/untitled.dir/intermediate.manifest -out/build/x86-Debug/CMakeFiles/untitled.dir/embed.manifest -out/build/x86-Debug/CMakeFiles/TargetDirectories.txt -out/build/x86-Debug/CMakeFiles/ShowIncludes/main.c -out/build/x86-Debug/CMakeFiles/ShowIncludes/foo.h -out/build/x86-Debug/CMakeFiles/cmake.check_cache -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.exe -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.cpp -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdC/CMakeCCompilerId.exe -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdC/CMakeCCompilerId.c -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeSystem.cmake -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeRCCompiler.cmake -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeDetermineCompilerABI_CXX.bin -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeDetermineCompilerABI_C.bin -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeCXXCompiler.cmake -out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeCCompiler.cmake -out/build/x86-Debug/CMakeCache.txt -out/build/x86-Debug/cmake_install.cmake -out/build/x86-Debug/build.ninja -out/build/x86-Debug/.ninja_log -out/build/x86-Debug/.ninja_deps -out/build/x86-Debug/.cmake/api/v1/reply/target-untitled-Debug-03f16c5921ae0bd48990.json -out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-27T23-42-34-0718.json -out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-2b93246ca751d7a49cd1.json -out/build/x86-Debug/.cmake/api/v1/reply/cmakeFiles-v1-d93b224eb363971ee2c4.json -out/build/x86-Debug/.cmake/api/v1/reply/cache-v2-43521627501184045d13.json -out/build/x86-Debug/.cmake/api/v1/query/client-MicrosoftVS/query.json -out/build/x64-Debug/VSInheritEnvironments.txt -out/build/x64-Debug/rules.ninja -out/build/x64-Debug/CMakeFiles/untitled.dir/manifest.res -out/build/x64-Debug/CMakeFiles/untitled.dir/manifest.rc -out/build/x64-Debug/CMakeFiles/untitled.dir/intermediate.manifest -out/build/x64-Debug/CMakeFiles/untitled.dir/embed.manifest -out/build/x64-Debug/CMakeFiles/TargetDirectories.txt -out/build/x64-Debug/CMakeFiles/ShowIncludes/main.c -out/build/x64-Debug/CMakeFiles/ShowIncludes/foo.h -out/build/x64-Debug/CMakeFiles/cmake.check_cache -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.exe -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.cpp -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdC/CMakeCCompilerId.exe -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdC/CMakeCCompilerId.c -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeSystem.cmake -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeRCCompiler.cmake -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeDetermineCompilerABI_CXX.bin -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeDetermineCompilerABI_C.bin -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeCXXCompiler.cmake -out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeCCompiler.cmake -out/build/x64-Debug/CMakeCache.txt -out/build/x64-Debug/cmake_install.cmake -out/build/x64-Debug/build.ninja -out/build/x64-Debug/.ninja_log -out/build/x64-Debug/.ninja_deps -out/build/x64-Debug/.cmake/api/v1/reply/target-untitled-Debug-8918286eee207fe0275b.json -out/build/x64-Debug/.cmake/api/v1/reply/index-2020-01-27T23-42-03-0431.json -out/build/x64-Debug/.cmake/api/v1/reply/codemodel-v2-ee254da00ecbf4b22928.json -out/build/x64-Debug/.cmake/api/v1/reply/cmakeFiles-v1-ee926bd040d82c324cbe.json -out/build/x64-Debug/.cmake/api/v1/reply/cache-v2-6f7cb0917968b934d35c.json -out/build/x64-Debug/.cmake/api/v1/query/client-MicrosoftVS/query.json -CMakeSettings.json -cmake-build-debug/Resource1.resx -out/build/x64-Debug/.cmake/api/v1/reply/index-2020-01-28T10-34-19-0746.json -out/build/x64-Debug/untitled.exe -out/build/x64-Debug/.cmake/api/v1/reply/index-2020-01-28T11-19-41-0061.json -out/build/x64-Debug/.cmake/api/v1/reply/cmakeFiles-v1-52c1d9386071c1490278.json -out/build/x86-Debug/CMakeFiles/cmake-main.dir/manifest.res -out/build/x86-Debug/CMakeFiles/cmake-main.dir/manifest.rc -out/build/x86-Debug/CMakeFiles/cmake-main.dir/intermediate.manifest -out/build/x86-Debug/CMakeFiles/cmake-main.dir/embed.manifest -out/build/x86-Debug/cmake-main.exe -out/build/x86-Debug/.cmake/api/v1/reply/target-enet-Debug-1cc90e5d191bd520f961.json -out/build/x86-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-0c9bd3464adc40e447af.json -out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-28T11-21-26-0362.json -out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-1850e17888d5bab56568.json -out/build/x86-Debug/.cmake/api/v1/reply/cmakeFiles-v1-7c376457f6b736ad28ac.json -out/build/x64-Debug/CMakeFiles/cmake-main.dir/manifest.res -out/build/x64-Debug/CMakeFiles/cmake-main.dir/manifest.rc -out/build/x64-Debug/CMakeFiles/cmake-main.dir/intermediate.manifest -out/build/x64-Debug/CMakeFiles/cmake-main.dir/embed.manifest -out/build/x64-Debug/cmake-main.exe -out/build/x64-Debug/.cmake/api/v1/reply/target-enet-Debug-645fd45f5bd4fab53aa9.json -out/build/x64-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-b124668c8fb6ca5df286.json -out/build/x64-Debug/.cmake/api/v1/reply/index-2020-01-28T11-21-06-0706.json -out/build/x64-Debug/.cmake/api/v1/reply/codemodel-v2-63a6ab1789a1732f4563.json -out/build/x86-Debug/.cmake/api/v1/reply/target-enet-Debug-d301abed48f6c38bdcfb.json -out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-28T12-30-44-0946.json -out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-3eaabe43603befc605b1.json -out/build/x86-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-70eff68e1e381b42992e.json -*.xml -out/build/x86-Debug/.cmake/api/v1/reply/target-enet-Debug-48db38ae5d08e27876b8.json -out/build/x86-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-540e487569703b71c785.json -out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-28T17-35-38-0764.json -out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-6a61e390ef8eaf17e9f8.json -out/build/x86-Debug/Server.cfg +# TernJS port file +.tern-port diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index e7e9d11..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Default ignored files -/workspace.xml diff --git a/.idea/BeamNG-MP-Server.iml b/.idea/BeamNG-MP-Server.iml deleted file mode 100644 index f08604b..0000000 --- a/.idea/BeamNG-MP-Server.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 8822db8..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 35f1ecb..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 568c400..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 3.15) -project(BeamNG-MP-Server) - -set(CMAKE_CXX_STANDARD 14) - -add_executable(cmake-main src/main.cpp src/network.cpp src/logger.cpp src/config.cpp) -ADD_LIBRARY( - enet STATIC - enet.lib -) -set_target_properties(enet PROPERTIES LINKER_LANGUAGE CXX) \ No newline at end of file diff --git a/enet.lib b/enet.lib deleted file mode 100644 index 4ecef81bfe8d04f85fcb2bac6674093e9faf02b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53768 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 + + + + Hello World! + + +

BeamNG.drive MP Development Tool!

+ +

Make:

+

Clutch:

+

Throttle:

+

Brake:

+

Steering:

+

POS:

+

Time difference:

+

+ +
    + +
+ + + + + + diff --git a/index.js b/index.js new file mode 100644 index 0000000..4e161a4 --- /dev/null +++ b/index.js @@ -0,0 +1,345 @@ +// Server Settings! +var map = ""; +let _VERSION = "0.0.3" +let UDPExpireTime = 30// In Seconds + +const net = require('net'); +const uuidv4 = require('uuid/v4'); +const args = require('minimist')(process.argv.slice(2)); +const chalk = require("chalk") + +//console.log(args.port) +if (args.port) { + var tcpport = args.port; +} else { + var tcpport = 30813; +} + +var udpport = tcpport + 1; +var wsport = tcpport + 2; +const host = '0.0.0.0'; + +//========================================================== +// WebSocket Server +//========================================================== + +const WebSocket = require('ws'); + +const wss = new WebSocket.Server({ port: wsport }); + +wss.on('connection', function connection(ws) { + ws.on('message', function incoming(message) { + console.log('[WS] received: %s', message); + wss.clients.forEach(function each(client) { + if (client.readyState === WebSocket.OPEN) { + client.send(message); + } + }); + }); + + ws.send('Welcome!'); +}); +console.log(chalk.cyan('[WS]')+' Server listening on 0.0.0.0:' + wsport); + +//========================================================== +// TCP Server +//========================================================== + +const TCPserver = net.createServer(); +TCPserver.listen(tcpport, () => { + console.log(chalk.green('[TCP]')+' Server listening on 0.0.0.0:' + tcpport); +}); + +let sockets = []; +let players = []; +let names = []; +let vehicles = []; + +TCPserver.on('connection', function(sock) { + console.log(chalk.green('[TCP]')+' CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort); + sockets.push(sock); + + var player = {}; + player.remoteAddress = sock.remoteAddress; + player.remotePort = sock.remotePort; + player.nickname = "New User, Loading..."; + player.id = uuidv4(); + player.currentVehID = 0; + players.push(player); + + sock.write('HOLA'+player.id+'\n'); + if (map == "") { + sock.write("MAPS\n"); + } else { + sock.write("MAPC"+map+'\n') + } + sock.write("VCHK"+_VERSION+'\n') + + sock.on('data', function(data) { + // Write the data back to all the connected, the client will receive it as data from the server + var str = data.toString(); + data = str.trim(); //replace(/\r?\n|\r/g, ""); + var code = data.substring(0, 4); + var message = data.substr(4); + + if (code != "PING") { + //console.log(code) + } + //if (data.length > 4) { + //console.log(data.length) + //} + + switch (code) { + case "PING": + //console.log("Ping Received") + sock.write('PONG\n'); + break; + case "CHAT": + sockets.forEach(function(socket, index, array) { // Send update to all clients + socket.write(data+'\n'); + }); + break; + case "MAPS": + map = message; + console.log("Setting map to: "+map); + sock.write("MAPC"+map+'\n'); + break; + case "USER": + players.forEach(function(player, index, array) { + if (player.remoteAddress == sock.remoteAddress && player.remotePort == sock.remotePort) { + console.log("Player Found ("+player.id+"), setting nickname("+data.substr(4)+")"); + player.nickname = ""+data.substr(4)+""; + sockets.forEach(function(socket, index, array) { // Send update to all clients + socket.write('PLST'+JSON.stringify(players)+'\n'); + socket.write('SMSG'+data.substr(4)+' Just Joined the Session.\n'); + }); + } + }); + break; + case "QUIT": + case "2001": + let index = sockets.findIndex(function(o) { + return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort; + }) + if (index !== -1) sockets.splice(index, 1); + console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort); + break; + case "U-VI": + case "U-VE": + case "U-VN": + case "U-VP": + case "U-VL": + case "U-VR": + case "U-VV": + //console.log(data) + //players.forEach(function(player, index, array) { + //if (player.remoteAddress != sock.remoteAddress) { + //console.log(player.remoteAddress+' != '+sock.remoteAddress+' Is not the same so we should send?') + //console.log("Got Update to send!") + sockets.forEach(function(socket, index, array) { // Send update to all clients + //console.log(socket.remotePort+' != '+sock.remotePort+' Is not the same so we should send?') + if ((sock.remoteAddress != socket.remoteAddress && sock.remotePort != socket.remotePort) || (sock.remoteAddress == socket.remoteAddress && sock.remotePort != socket.remotePort)) { + socket.write(data+'\n'); + } + }); + //} + //}); + break; + case "U-VC": + sockets.forEach(function(socket, index, array) { // Send update to all clients + socket.write(data+'\n'); + }); + break; + case "U-NV": + console.log(message) + var vid = uuidv4(); + + break; + case "C-VS": // Client has changed vehicle. lets update our records. + console.log(message) + players.forEach(function(player, index, array) { + if (player.currentVehID != message && player.remoteAddress == sock.remoteAddress && player.remotePort == sock.remotePort) { + console.log(chalk.green('[TCP]')+" Player Found ("+player.id+"), updating current vehile("+message+")"); + player.currentVehID = message; + } + }); + break; + default: + console.log(chalk.green('[TCP]')+' Unknown / unhandled data from:' + sock.remoteAddress); + console.log(chalk.green('[TCP]')+' Data -> ' + data); + sockets.forEach(function(socket, index, array) { // Send update to all clients + //if ((sock.remoteAddress != socket.remoteAddress && sock.remotePort != socket.remotePort) || (sock.remoteAddress == socket.remoteAddress && sock.remotePort != socket.remotePort)) { + socket.write(data+'\n'); + //} + }); + break; + } + sockets.forEach(function(sock, index, array) { + //sock.write(sock.remoteAddress + ':' + sock.remotePort + " said " + data + '\n'); + }); + }); + + // Add a 'close' event handler to this instance of socket + sock.on('close', function(data) { + var index = players.findIndex(function(o) { + return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort; + }) + if (index !== -1) sockets.splice(index, 1); + index = sockets.findIndex(function(o) { + return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort; + }) + if (index !== -1) sockets.splice(index, 1); + console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort); + players = removePlayer(players, sock.remoteAddress); + console.log("Player list now holds: "+JSON.stringify(players)); + sockets.forEach(function(socket, index, array) { // Send update to all clients + socket.write('PLST'+JSON.stringify(players)+'\n'); + }); + }); + + sock.on('error', (err) => { + // handle errors here + if (err.code == "ECONNRESET") { + console.error(chalk.red("ERROR ")+"Connection Reset for player: "); + players.forEach(function(player, index, array) { + if (player.remoteAddress == sock.remoteAddress && player.remotePort == sock.remotePort) { + console.error(+player.nickname+" ("+player.id+")"); + console.error(chalk.red("ERROR ")+"End Error."); + } + }); + } else { + console.error("Sock Error"); + console.error(err); + throw err; + } + }); +}); + +TCPserver.on('error', (err) => { + // handle errors here + console.error("TCPserver Error"); + console.error(err); + throw err; +}); + +function removePlayer(array, ip) { + return array.filter(player => player.remoteAddress != ip); +} + +//========================================================== +// UDP Server +//========================================================== + +var clients = {}; +var intervalTime = UDPExpireTime*2*1000; + +setInterval(function() { + console.log(clients); + for (var client in clients) { + var lastupdate = clients[client]; + var millis = Date.now() - lastupdate; + var t = Math.floor(millis/1000) + if (t > UDPExpireTime) { + console.warn("Found Old Client: "+client) + delete clients[client]; + } + } +}, intervalTime); + +function updateClient (rinfo) { + for (var client in clients) { + client = JSON.parse(client); + var address = client[0]; + var port = client[1]; + if (port == rinfo.port && address == rinfo.address) { + client + } + } +} + +var dgram = require('dgram'); +var UDPserver = dgram.createSocket('udp4'); + +function UDPsend(message, info) { + UDPserver.send(message, 0, message.length, info.port, info.address, function(error){ + if (error) { + console.log("ERROR"); + console.log(error); + client.close(); + }; + }); +} + +UDPserver.on('listening', function() { + var address = UDPserver.address(); + console.log(chalk.rgb(123, 45, 67)('[UDP]')+' Server listening on ' + address.address + ':' + address.port); +}); + +UDPserver.on('message',function(msg,rinfo){ + clients[JSON.stringify([rinfo.address, rinfo.port])] = Date.now(); + //sending msg + var str = msg.toString(); + data = str.trim(); //replace(/\r?\n|\r/g, ""); + var code = data.substring(0, 4); + //if (code != "PING") { + //console.log(msg.toString()); + //} + switch (code) { + case "PING": + UDPsend("PONG", rinfo) + break; + case "U-VC": + for (var client in clients) { + client = JSON.parse(client); + var port = client[1]; + var address = client[0]; + UDPserver.send(msg, 0, msg.length, port, address, function(error){ + if (error) { + console.log("ERROR"); + console.log(error); + client.close(); + }; + }); + } + break; + case "U-VR": + case "U-VL": + case "U-VP": + case "U-VN": + case "U-VE": + case "U-VI": + for (var client in clients) { + client = JSON.parse(client); + var port = client[1]; + var address = client[0]; + if (port != rinfo.port && address != rinfo.address) { + UDPserver.send(msg, 0, msg.length, port, address, function(error){ + if (error) { + console.log("ERROR"); + console.log(error); + client.close(); + }; + }); + } + } + break; + default: + // Unhandled data, this at the moment includes the extra packets of vehicles so it needs to be here until it is handled correctly + for (var client in clients) { + client = JSON.parse(client); + var port = client[1]; + var address = client[0]; + UDPserver.send(msg, 0, msg.length, port, address, function(error){ + if (error) { + console.log("ERROR"); + console.log(error); + client.close(); + }; + }); + } + //console.log(chalk.rgb(123, 45, 67)('[UDP]')+' Data received from client : ' + msg.toString()); + //console.log(chalk.rgb(123, 45, 67)('[UDP]')+' Received %d bytes from %s:%d\n',msg.length, rinfo.address, rinfo.port); + } +}); + +UDPserver.bind(Number(udpport)); diff --git a/main.js b/main.js new file mode 100644 index 0000000..d0b26c7 --- /dev/null +++ b/main.js @@ -0,0 +1,235 @@ +// Modules to control application life and create native browser window +const {app, BrowserWindow} = require('electron') +const path = require('path') + +// Keep a global reference of the window object, if you don't, the window will +// be closed automatically when the JavaScript object is garbage collected. +let mainWindow + +var windowReady = false +function createWindow () { + // Create the browser window. + mainWindow = new BrowserWindow({ + width: 800, + height: 600, + webPreferences: { + nodeIntegration: true, + preload: path.join(__dirname, 'preload.js') + } + }) + + // and load the index.html of the app. + mainWindow.loadFile('index.html') + + windowReady = true + + // Open the DevTools. + // mainWindow.webContents.openDevTools() + + // Emitted when the window is closed. + mainWindow.on('closed', function () { + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + mainWindow = null + }) +} + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.on('ready', createWindow) + +// Quit when all windows are closed. +app.on('window-all-closed', function () { + // On macOS it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') app.quit() +}) + +app.on('activate', function () { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) createWindow() +}) + +// In this file you can include the rest of your app's specific main process +// code. You can also put them in separate files and require them here. + +function SendToUI(type, data) { + if (windowReady) { + mainWindow.webContents.send(type, data) + } +} + +// Server Settings! +var map = ""; + +const net = require('net'); +const uuidv4 = require('uuid/v4'); +const args = require('minimist')(process.argv.slice(2)); +console.log(args.port) +if (args.port) { + var tcpport = args.port; +} else { + var tcpport = 30813; +} +var udpport = tcpport + 1; +const host = '192.168.1.195'; + +const TCPserver = net.createServer(); +TCPserver.listen(tcpport, () => { + console.log('TCP Server listening on ' + TCPserver.address().address + ':' + tcpport); + SendToUI('log', 'TCP Server listening on ' + TCPserver.address().address + ':' + tcpport) +}); + +let sockets = []; +let players = []; +let vehicles = []; + +TCPserver.on('connection', function(sock) { + console.log('[TCP] CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort); + sockets.push(sock); + + var player = {}; + player.remoteAddress = sock.remoteAddress; + player.remotePort = sock.remotePort; + player.nickname = ""; + player.id = uuidv4(); + player.currentVehID = 0; + + players.push(player); + + sock.write('HOLA'+player.id+'\n'); + if (map == "") { + sock.write("MAPS\n"); + } else { + sock.write("MAPC"+map+'\n') + } + + sock.on('data', function(data) { + // Write the data back to all the connected, the client will receive it as data from the server + var str = data.toString(); + data = str.trim(); //replace(/\r?\n|\r/g, ""); + var code = data.substring(0, 4); + var message = data.substr(4); + console.log(code) + switch (code) { + case "PING": + console.log("Ping Received") + sock.write('PONG\n'); + break; + case "CHAT": + sock.write(data+'\n'); + break; + case "MAPS": + map = message; + console.log("Setting map to: "+map); + sock.write("MAPC"+map+'\n'); + case "USER": + players.forEach(function(player, index, array) { + if (player.nickname == "" && player.remoteAddress == sock.remoteAddress && player.remotePort == sock.remotePort) { + console.log("Player Found ("+player.id+"), setting nickname("+data.substr(4)+")"); + player.nickname = data.substr(4); + } + }); + break; + case "U-VI": + case "U-VE": + case "U-VN": + case "U-VP": + case "U-VL": + //console.log(data) + //players.forEach(function(player, index, array) { + //if (player.remoteAddress != sock.remoteAddress) { + //console.log(player.remoteAddress+' != '+sock.remoteAddress+' Is not the same so we should send?') + //console.log("Got Update to send!") + sockets.forEach(function(socket, index, array) { // Send update to all clients + //console.log(socket.remotePort+' != '+sock.remotePort+' Is not the same so we should send?') + if ((sock.remoteAddress != socket.remoteAddress && sock.remotePort != socket.remotePort) || (sock.remoteAddress == socket.remoteAddress && sock.remotePort != socket.remotePort)) { + socket.write(data+'\n'); + } + }); + //} + //}); + break; + case "U-NV": + console.log(message) + var vid = uuidv4(); + + break; + case "C-VS": // Client has changed vehicle. lets update our records. + console.log(message) + players.forEach(function(player, index, array) { + if (player.currentVehID != message && player.remoteAddress == sock.remoteAddress && player.remotePort == sock.remotePort) { + console.log("Player Found ("+player.id+"), updating current vehile("+message+")"); + player.currentVehID = message; + } + }); + break; + default: + console.log('Unknown / unhandled data: ' + sock.remoteAddress + ': ' + data); + } + sockets.forEach(function(sock, index, array) { + //sock.write(sock.remoteAddress + ':' + sock.remotePort + " said " + data + '\n'); + }); + }); + + // Add a 'close' event handler to this instance of socket + sock.on('close', function(data) { + let index = sockets.findIndex(function(o) { + return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort; + }) + if (index !== -1) sockets.splice(index, 1); + console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort); + }); + + sock.on('error', (err) => { + // handle errors here + if (err == "ECONNRESET") { + console.error("Connection Reset!") + } else { + console.error("Sock Error"); + console.error(err); + throw err; + } + }); +}); + +TCPserver.on('error', (err) => { + // handle errors here + console.error("TCPserver Error"); + console.error(err); + throw err; +}); + +var dgram = require('dgram'); +var UDPserver = dgram.createSocket('udp4'); + +function UDPsend(message, info) { + UDPserver.send(message,info.port,info.address,function(error){if(error){console.log("ERROR");console.log(error);client.close();};}); +} + +UDPserver.on('listening', function() { + var address = UDPserver.address(); + console.log('UDP Server listening on ' + address.address + ':' + address.port); +}); + +var UDPMembers = []; + +UDPserver.on('message',function(msg,info){ + //sending msg + var str = msg.toString(); + data = str.trim(); //replace(/\r?\n|\r/g, ""); + var code = data.substring(0, 4); + switch (code) { + case "PING": + UDPsend("PONG", info) + break; + default: + console.log('[UDP] Data received from client : ' + msg.toString()); + console.log('Received %d bytes from %s:%d\n',msg.length, info.address, info.port); + } +}); + +UDPserver.bind(udpport); diff --git a/out/build/x64-Debug/enet64.lib b/out/build/x64-Debug/enet64.lib deleted file mode 100644 index 150213d4b789a34ab72f67daf51f706e0d279c9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57720 zcmeFa3wTu3wFiDC8A8D5iHMde*3pibsnjNlHY2EWl9}WTOdtwkd_fR00wSbg2B@MY z%uJHg<5+CfzI(aW_S)7~@4c3Q)tX6w3HWHh7nIf_zH*EY@Bsmo{C{ihbI!~pptra8 z-tYf?|Nr?iIcu-|-h1t})?WK@&Ym)_Y5u~?M}NbW`;=xm1)TlgCC5x8c(y(CeiiW1;iE1xVP3?{ zX5q5s5#%D05k<~QM&u~M42_giC^MO*OB?1#vLfBov~1pj`SX@%6a_ zU9#xbMcF}bnzwYp%0&y%jK}whENog9i7YXzvt$ufXGz1nCXqb57cE`h&}62|h^B^H zm#xT-F~qqX-6!HVqU+GB*)3+Ga;k6Q&=q#f`AzdLy3kCd0extd6OFwzyy)g=la)iZ zXIA*8hWQPPtU@+YAf%3>d@I@zZ7@5W(aV-nl9`6LkP8+qACBiVvT|u$wDjg7PLOb< zp=rguC0Y2$qFWo5Ma?GU433#Pmu)VZZ0WL&9zWqF(d7$8Rm6B&*f9T=xeY7Oh-QHp z4PsugXue548Ga)oE@&8v;W!x63zpqFcX>mD+1%8lb8l`idxu@<9g)Vo1q+C&AarCd z$6nNUY>!+lQag5V%R>ZTzKn;|O^dAlG!Yca%sD3@jo1d0RhmJwhogz2vMy_k*i1Dm z(PN-<28J1Q-u(Fujb;m2i7t#r7A#wtn|aQ_w*uP4X(Dn)ufS0Wmp3f28KfC<j} zyPz>Q9Fz&^Q-u4KnQsx?6z&_7vSU)2C267=#_~b=d}{37aV>`i^BmHOt5rQu)u$G! ziO$HSYGP}|uWEjG;YaeF_^)aqccFY5AlWm55>WMuVhTA@)kYMPJGN<@!5)dN8wT-2 z{zj;7hWkI3&x(_$wBe+DhtwUuz;e$-0bGNpiin-6)*USvJeAYab|Sv(`tEQhuzZ%J z4xU?xz-z6CB7WZEK<7EnktAwL$A~;>#D$Jht63MC5gYMdfgdH@jNgO!Q9C|{Uk83; z@vE+^ywp`vJ^gBr>zfx`^!1gCmR@wB>%!8q^3sb-FMscrlma%?W<&Se(0|&{ zbU>7{6F*6!7I1J0PGg9g;7bhQALH{mB$Y9r-6t_b0Kw}`IV?Gy{SRz0g8IlBrR-$(2ScH&5 z_%-8~!PLP;eIPK|Ba^bpcTnGm5e$Hz>`}>iIj99hj%E-kdqk2C=yBMSJsPQh@;RN{ zVA&&)Mnt}&6#uC|a-W+_CzUkc@s(Up({-zjMH@<{UTfkA!`f|5n0YrXgJxzu6y^>% zE@&d|;J)p)+k_;@h_slY2~mzpQK!)%vP>eW?g;FY+{)uW$&rl^YZ#Chum?eQ|sz| z$I}~547S6)zB8;<w(ofkdV(JgmWbHbxV!s-6!)*`Pw$4<(* zzg0fVCk0b)Is;{I1Rb9#^7?>7lu(g7u68Qz0ZvQN0(s%Yj_A3HV-q|AoZ=`-G3eOb zzZH4p`5k-0T6JE3GQ3tz?L~SAYLcr@m5^d}CdF%zq9~n$u$1Cyien2>6lJ_bq?o1@ zx2dVuoWW#~-1obqgM(ouzd8>=!xYa7AMF+GPbEVB``{VKGp>a^%juAz{jspDvnB!Y z^-LHdbB=spswS~jzOS<|6&;}_c1KSs>qK)e%xUhBzPJz)_fN!rRQ*YJFTL}hbnnDF zP_{Ls-zQLMW?vykpPKf&eeje>ESIQB$X@{E!K80cVJS<_Qgs6{Ob1d`wMvL>zgrDW zUg9p1V;VRjy7dP4oPfN(K~j@T+;f7d*U{X&L*CtToC<(yR~CY1QqTuy(bCsucOP&axeH$JT=f6s;2(jdt`X@}r#r z`Oz(kBh`PJU+W3Rx*SSsPhqNWoRWI2P-(9itV}u`{<5CSP&jGDmz0(Pyd}Bq-;sYn z>roEwL_Io#-os6uM*1^Uz|@NTAh)L!_{Dpdts%Q0AWsy;Z zkpjKTu^k!8F%=Ds+%Q&mM8B2E3FI;MB9V!e12RjCOpy3(CuZkV(0|`rHMZJaD#`Kl z(cG#IGFD?t+@+3?zOYb@br!3-x{s+lp9@8p(BO`^|;Dp1vamGwxE}9I*~e`2axD_A}tjp z2FeP9z|27g8Z$Pa44~vjhe^Q!?V#VYUrAn**Iw%YpRs5Wqg&A9LSi44MRGiblE@vs z=vfRsMe8lwp&Z-?znP=K)wVdc%a8U@Un`ES|D_Rlia7#TekHeqHyJ^6R)$_U_gH5h zdidxOi8+X9vjQ5CqTP%* zatT09m_*!Robl^J+2sp)Uyhbj7|w^A5n3PBWM|__W4B47JX&wCoS)`Q_Z!z z-F-B2%CKqIU&B+zDo_q~4@LE*~wg|B@O@JCso`f#oZyw+ofz*pdFS!!2khF#A`)^D%&XM4rh0 zDu}DSDB0c`?~8I`2?8NIl;Q?=5wR{vla3|s(FZ@GV(dg^O0<0kBkq#0ceC8KY$VIX zS?)qlA6Ol8{~jpCsvdHe2g*AAc$c*M-61u3Ed<_cPF33$a_nu-v&gNiGsB)MPNb14 zvI}|kqG*11k&p$m+;t#!WFvRHX zssGCg3=Px*-Ab}HA50m2#Az3q9TaXkEDf%7#ycY(lm(^+mfGiIa;3c!-u{l~rDVK> zxuv3^T@V$etnqfKdc<7|^#z>+O1=SA*8XDrjEEyS6;;wv1d_iL|`ct}nh9ri+(Tz(}Qx{i1^ zcy2d(@^1l8x8IAV_k-jX`w?Y{ocvFW*(@Ovy%S1s%O>IsIeM_rw@scI*-ag$8Ibb* zNg7YdYDa4CxS)57qP--yeg(8Z%D)Ohk=j$NjM^OZzAU%yC&Euw=gaG_$wN@NwGRk= zBnG2X?oqVOMv54|pWVF^ib=4eoMdHl@cZiLrnw6zxaj7E%J#2fhUwo0=!DA00?K zzuX>jhm>Tf&=L0bG~Gcy1z_N4%=2jA5Ccg1^BtZZEyetgmCGdL7!R>M?S&9Wrk)?x zRE(mOsqU+u?X2sk4q?1ZEdW12bAi!V>~O%zOqH6VuB_AON0~7UDjZ5I1wjd?1(o(5WVy6*A+fg+!#dY>=`vCHUD_}fDMb+M~(e^^v89xRW4x+pKT6f5?&G=VP z5HY8aqszFTwSkUTF~^{h8$#RF`PxBRL|==Ovq?K+K8Xn)HG>Z-muIuwu~~6+W8Sk1 znpeoZB;fe_aRdYnNyx{|83EyhfEc(8<%WE;igb#pX+zkX!glW4X+YY!>fvnJ*cR>UUe`d)t*7Bq|Tt$#2mpG6I(HA z)nwyIa{M`T1{%u;bskwCVhzt%B)6SG*=gI2(RdRvqia8b^nbZu_G^a^{zdNCk=kpD zdgqtyn)H*zhoIX{x_T+;U8DyYM}d{squEHrFJ@9;ibA5Ga!e#VyV@&Iz+SmyzuC%Y z)MwBXhta=?C)(f#oyIcE8lg}b#(}{>6hPI|P&$m=Z~-)4;P-Z;g6ePTXB){XkY!(D zE0PL>1$)rQcATjZj8NHF_vM2`(dE+IbSQj;UzM_;JgE>-)G zFtAOGc=r>+Q0Zqp@OVY{WCAsi^5CI?{q{r~yP$)@c z8}G!s4o164fa~#Ij2~H~8}a@Gzgoawv5gRs$@H?|cNZA4-cJ2U_}gs{vFtml*~^7!T!5y}_{gMKzCMugv!MUp`oIlVbo)JgeL#gDiZtZ;z3KkE^#Kf0 z^C3$=J>8~TqIPEZ&pDXAa1FKBXYEhP-5Im|+qd3?)pe|0&!1;)2+0m?8TZ9nLAK9= zhU5EXFE)#1d6Qy>@0J-_(#&q2>^(j?iAdzKRvTP+zG%ha;tR{nAej}1he57HjYKEe z^g|fe3BZDo#-2znN%|Uo{}(F`jmXD6WEtsLD-QJtcOSxSprt-M#2Jpa;_&gX^lE+C zs|hLu7McR{awwf4E$!EyliM!C*xXoreun9*+7>x}9BvKV&Vgry5DOD?wG>DCQIF9QEV z6R%adpu#r`4HW&kdIj^Ngqj-A5Fv1dAdk9sqX{M zg2BgaxHt=TWx=I33~i&On@V-;B6iDbZXs=0+n2r0)%`z4O2#Ids_7@Gu|tEA5uyzG z^b!GR`}tjVU}*M1-RVZZ6&kHHY06j^X~j&e>#?Qmc{zS3HI_bVNag0B{dcO~?&VFG zaeYw>H2qE0?;+ZwwZ$>2-b%zpTQ&*?d$}vM?N)I`8yVC?n2yKkO&dC}KG>acYk%qg zeO8%s)+6hmLQh~2W8nW8>i_}m*+_8^Ya2j5MgM|wRiC=3+9acusK!3kyQS$2V?E*t z3xL|Pg^3LF_t-jM{ra48*yW;chmuQv$LonX{G}W1=#%3s5HhG2sM=CBT~$tn0N$-v zyD%5is$E*uc)fZocu9O7{8D|zsXaxP5xL84bAd>=zK9r7u_R4RI?tzuU2502Y-`yL z7}CPpv^=t4CZ}OabPAOA$_e;4&FtyqH0+@1t`+T=u3S&4f!6;-Z%m^BZZT2M^INa- zA@usd}&!l1E46ee zuPL>H3x)tY8nx}8)z}qMWRx}hK`)0amLAmZ@fs1C|)Ls(qiMiBUs4mC_s<4Q&sl>;VtKQvtz4gJT2z zQ{~EDRlBmh+iG9!%3{B!j7=+UqU!FoLv{cxRJG^15n$i)pTBgR)~&RB_BN#7iZ6%s zpA)YS>8-@)Ato@40@|z5lTrWNHE6wR?9(7V*qslPN#aM4hh^_!6e~}^P;*nUPriS1 zrpQP{j?)5T;ypS30^W-Eu=1n}z={*KfwCQ`JtLHZA1d0W(4y()IG>Jf3PH!#kaufS zRsYjk%UT5Xw%koo3N(Ie*WQp;>Vc4ySid8!EFjSDNe4V#%u&=9CIqA)$8JYKb*0>& z^c_)R1CEui>q;%S*$jCBXB>$g za;!Yhd)*C@bG&P)X4)F6CF;knbVWT}Qo4dGrnYnuStE8+mtN&2wzLStA*4?))t45B z^r{k5&8S(lodVW4y3p7O8pJi;UO6^}0%NZKr|+PwA^luR8r;!c+CM(LHfWBSmNe%< zgCH%(Mj?t`T^{QjK}|*mwTQb^pFUO@d=X>1+&i~Uj(><`G(%t}i6L(>fROeM#*I1H zs!FJ&{SOF!O$+aF;%-bBPXQ>~q4i<8m5X{W1YAh#3c&tp%9BiUo#nl*E^@j)bry!3 z)0$%=aV2_jGM*Moa83QM$CR7WcHL4oS+ zK^q}s<`;TxdF-7LvBQp)PJe#w0(As63xYJgWsF0Zwfc-%W|fUXG$*XYWC_cdBpgK} zrJ{<$(vkHAjU#HEoq6EG4zem#2&;nQq(bSW{}^35s=lysWNksGvo~*#qi}>&Sm7+q zug`0A)D8)cno;eJXU%|@)I!=Tp0#*i>=gS0eR$svebWVeGwGdJ`Jwqcy_@j!6CUp$ z;)g7yb$CCD-z>n7;eFZ(uxtSSBI^Zdd|$@TDNV=!(;1>!xWF~qxZ41o!M;Di|M3iw z+#^}#l(yQ?Uv20E8#)4rcECBM@o0*(7@7d4<6`Je8~Tn7Jzzr*+R*Q9=m{Iz3g~Q3 z#eudHWf^NjG-(mIOKqqI&^a7qHlVLEG{=U1W&1t@NTfUhJt4xa2PE3X2c_J_acgYo zen7(d^GiT9FLO#4qUYQUJq_qwhBl#h&SR(>#uyQ9B1DM@cZ!|cr-(6u!{MKV?ldh& z0xE=?tXslzByh!cxUse`r7wJ`&jjSMeJM|YE3u)8wr{D8Bgzxu%5C2%HqK{5e%n{I zaUmNbIu&ImDi!I~+0YHP?{KRV&-&*hK+Xe&jvoj5;&@gk7edgu;xHWgLj3okl`|MB zHI1vErYp*!sK9Lz|g46g!vgTH1-50+p^$*Prif3Bt&!8^S@`AqLG{X47W_x zBLLAy?gPz@A2i5ucdl+W!_W&u5YKl0Fa8P4-)szeN4mA)Ryr_YK7^r%RWgPw%%|+4 ze-`FMYCL`{468;tm?^`;Tr~`H(=bfaFih((%-UfX+Os7dt2~{%^9sYt8|bjERv$f8pt;tYcK-Xj@Kd_NgE$%0FV2EGwHdY#;P*FeHd?libMW z9fVm&SevE@L*rxkc@*K3```CZoJXPZJTxTVV_79h7HmMcv0_;B+QM#)Q|qEi%TmO6X&FS>3xW`Z29nQIUuKsFg_y(?gQilGP+N1Nf02 zNxYT#72(&6A4v!b`$bwAf^hu*>(d`pb}Dy1>zV>0iBHDnd}+8`X1f1x$z{?4sUovGXa)9i6tkDu#;Yv{Bf1^?(kfj7TUo+yJ^}|L?A#k+y;@k@ z-<#oU)~uWpuPlz7swUoxJjT{B%-F?xO#eEV%F1?gA^QI#iz&i7#pmwW*!)c7B2`yh zWEh6M>p*3pGYT8nG#u{RY8kd+X^!D29_wiGS=|rsU0!fN zDRf4@q-x7)nSz4PnVW4*HjU3@GEPU%QuUcIfK(!~C_9xvw4Qc*asLzI6ye59{b$eA zM@Z-gkr~Q9AC|gMa`vDc-vlxXC3)3O9E;Fr7KZeE(`@51`8xK;YN-n=22(~Mj?5?* z6}1Gty;@K7tzhgO?4s%}4#o}-M!OI8YN_kz;M5^kI!R0UFzoJDcs0te?euHAlnp*0 zV|yHt6O;{|05>$_-+>g)lmt3)G(d^VGtp zA6de*b}^M9v2`PHazzey!eqSmVMkDX4>#l(#*bz?jd;^+-wpVSWH8O;Ps7hC(X>TCYXONl{!al>icV>#4NXGo zB3uZN2zRxaGg1LWpl?a1c9!0ReKk5dVp@ z{%`Ig87})x*)bm(XFZm*V=0b09qTy@O8oQc?vY^>^7(Da8gs}Ji||llElej*oY8ykdP|U99H-6hfS@Y6%3n3BadvIlme%30?i#W39Y9=aY zo@3%Lw;FO^N9LsIg37BZae+rx2A?}gO< zw%xC_5<~NA_pHN<78kLigV!N#^WX~`>w(kKLN1fw?v~>ks;K-?Cky(jNo82aT;;|h zLtV*69bx@i{X}hHY1-$411n;_I)3YS`Zx`o+Hqq;fum|c^X(o;?&shuudghLWADek zfFH&J?;*UyvDPYN<0#vjt}Lb$Xx~F6tKI3!@r1yhf(fdA8G(bZ!0|OoM(c|0m75Qb zl;b}FzWMN|=*e=&J(LoMnJBVSllK$@wQ3{)7XX|dFtrsNjb)W5qjks~ZI8_$1pqQ` zE2`P{A8;kH!&Lh&;jva+j1v*?m^Q|!LzBoIt$#(wPrHYg)Au(oVOc|CGD`tQtmMGs~khg8Sg?|(jJ0L!7+jMW9hhM19J51EuHkj zO4uB4?~3#Fd#Q`_@4XxUX|7HI)^dO@jgc!x`o;2GcU98qE9+Fey~{t=dBIMNw&hEABm*$ATOWl^1$cwI}+}JOx$rwZ4RK#3IPhj6fI#M97 z_nq2~h1ZqX_d26ija}f#R!PO86qbL+sh(IbCq-L5a<$B|1O0tjdhc4B{!8^1AIEu~ zmIKcPcgJ3dJt(4@{5ik8yCP?V*9uCvRZvhb zY3OPlmHt&V=5a)K@-A7^1N&wB)0S4P-$N_|h2R&GJ*|IoR-z_0a^8O_QItn#+D3Xr z;_9&UOzc0Bo=cREU*2bil+VQe1L^&o`#$-5etG{E{ZfC>Z1i2??foqBO;tNWyIu6j zX0@krTaKo-l;hZBfXVJ`D$onQ0rJsv({;`Te{A*ZI5RHm5*N23Cl<-;o zHP-kRiI`=k^l_x}Sm_r~RU`APw0o>-Qrg%#ftu;lu@NO*o2gh2Rcy`qU?w7ybd?XK z0}rlJ`5oI-DmHF(v%f)#xTtUc4>6eI6iDo?GCW8`jBgH_ZuOzL=rPiClvF#^|5KBG zu{*_r_#zNSJdKHk6&Y0 zUN*wTxHZjqk+W1diGh*RC!Fg{XRUBPW;*MIvlA~}8BZrl*1QOqv{Y?PFWy>jSo;pK zd(S|6jo)mq^qL+MO12Y3Vr)&Xi2|r*z)llP8TlWnzr_)RxyBVZ#N^j2Y6F< zErC6o1$O0v<~u!u5gh-hVqyI;0z+6Qp2b_A{RJ|s3NmYYasO9gg^)X9)JB$k)X71f zLWs^DLk(0VcpGFp|r* zR1`#W*CX+vq0;U4YYM-T+!nJCe(X^-QT8BbaAO(_QjB-KN) zLwPHliO%R)RM;Bv_V@!I!I`azeQyl#@s^3&cCiHwI-g!y&eX!=Iq%DZvA2D(v_CeG z_vQCuZwhLNZT7SI3A=&|P%mHm!jdgM&!BdQ)IO7-Xail98@*_1ezzQxkg6?0x;{@3 z(nWY<10X0VLD~!` zDt0`olG~TTH$zf9u+VN`)5U@f%B?3LgoPJ4Rj(|TTOS0T*p{07BXO*xHuuFWomj ztZ@@*v0k`gZA`~3E(W$0v)NW`INM^C3z5JhVi~pt4V7@%X=$=8G8~#zXWWHjNqz`w zI>SDUf1%1WnK5S5##sAyu-x%zXk;uBLm5YnxLJ+6fwSp(_;?*n-dX7-h;V3{@|3N* zGcA?9M|>x&Egb{iW4y?lh8{OKeP5B+UxlMv&#RNKR57VqJ{k8T zd=Ce^s`L2VY5tWy7|Oz_z9Jk~oZwHY#oD%T>K!_6j$@%a6uBamoLYdx`EhxkcWe>by3RZEtRlf#SY{3z3aPWyZhf{{oSsQz6iYiHV-N!ub*0ijouvnSo1Z6 z!=}xdIP>K+RjR)D4!OM*<&5pc{EZmwKRtibkjOtae`BjTGk3Xz&cloOnlCRo19K>x z?arF0EdygV^_MT4uT@gm-1*vV99`&3`ZRE?+B|5YBVk__ho6zzOfgF=0VMmm%3Ail}=4&_H zrX+o;6@}KiS(eu5H;=PgT#o+>y3!As3Au@ZhO33@CPMwX0K2U%WejrE9nx0S1!E%} zef7|_aqM_0V%hv|YSLdeh|}5!4_rnjZtUnRmD{Qjf=U?MGb%PvC?{?vHxB#fg>mLa zj@Q8nK26usUq_3Cjvd8$X`vfY%Ys(+m# z8*A~;E{|5n*D1M?-Sbp%I_-LKpnZwkqhQ~937vDj1c!S4Zg42hl#jL(;)21KaH9l( zQk)PTd`Zz~j3d`1pmz~aZr%||*IM9+5TT}UQ&Q0?_%50k_+ZMDR3lF>w>Rzr2+7s^ ztR@d?o8-i`=ngtS>{BNrsmPfo^;+|G%OmthIvgXx>d8=sKc5YkaU$W(uMI$8oaB%k(q@)c59pLR&IplaDB3Sy3S=jv` zm%dt@CeDP5z5&{}ii%6?1d{SpP$U^gl9}>eL(6{Ug5A(uxCq@zI^t`e$q7=Bp`p-1 z99W6m8ihM+V#R6-ENkOT9fc=WLQnbM(oZVJ(+LV&C9$-Wu=ahLC;Sg;DCO7BHD1FZ z<+bQ)z!`noVyBzniR0h4e$3RBF@#1+l?{G0J%kJxC(M7o5{q?WT>CW@3b1MV1PlEE zlx+QEJBV(oy4?w{5U9zbfx(+=eJ zd#Fup)2=y!=x$k75$N{AOn-l&t}qY1{Dn#a2{W)nKjcY{ssOXL)&xJ4hUyK)?3ktb zd?n)V+598B|5bglPfa%Yg4%OI?M2o5i5#b`k8DtSM@?=lg`mt{uxDK zxDL&R7@#%EAo?Ij9ce}lCX-YzZbwB=aCGps9+W$XYk_T-4b# z9mZ}3nz7NKQM|7Na63$51LpIC*|TaI+@iA+7vr! z8Zq2(v8rENIR?4o`c&w*0SpGPd#xIi#cReBLBS1PUk$c?%|y6eaD&(1jBdMG4QY3Q z)mKka)77=e0foM1iX49jCBp57q-M&k55ZxTCWvEpQS7c1T%l~x_!8*Q)c?^?+vGI| zKyAh@{97CAE0|Isx4lV}D0b*z?~OX&*@BCN2KRuT=!&Ee-S;Te7&QOP3HY}!M0#Jq zdpLm0QQ|+M-1X(EN~bTOlgB%e9&Y)(8ZrgzeWN0)5OPIr|4E>a6@{u7$7z3#5OT-t zVic%XZe2^^abaFt8-OO<;xc^9fQKAdrDI)KWzGJvJHI@fme(!)Be*@GE6`&k_Uy2$;&H;AiH*qUfhf+)> z8AYL5N!5q78#UM;eG?>N>_jw$PIb-7_(a~aB4P6PJcarXgfiPd08RcZ@cIz}trK_r zV6SV6F7+}GuM)vP$*-=J9(JevK>rJG~-~UUpuTim>O}`S+FeJXNAp9@|1$e zSEm$W;})40jJ_t^HDjEKoWqkVOXSvkKt>%m0yqk|N|3n9XPCm+TxA~|%vE3!DW;`O z1rjIm7hs9Gz&ecf68r@hpn(jtd5oO63z%c`nXV|V^~vxVmJb;|W6G?^1dGqeiAzDR z#!bi<^ykH`ThGgF-$ludD}drrnZ>X({JQ^77CXA%I2R%L;Fx1{fi(KUg3=N7&c^)O zyiRnJ7RC%0z}+13B7oyv0dwNg7GdoU6OhL7vuddel+jc zhxhf^PeP+1ekS6L$KDORAHt!yIDYN;Jqg^<#{~ratOv~@(T}YBv@GB0v=0M91<)S+KaZh*MaExeXfvP-7<$fz%Fsi?*9%DaF0i4f z?RyWPZ*bg=w(mCE_jTKMl+#M(bU-5IivWqZ*V?{|ZQq#f`zzb`_coNW!@X(a$}s5` zCH2}+2$0CF(Z=0tLqD>iN9=IV+PDKYbQ)+;l=N&HDzhO4kjUdi(CInc8slx~d>gvd zhJrR!P-ykh6hNYndH|irskmW$n!wOhK%y@bfJC^{Pq4zx1vHVvtprrc&=x?VEHBy6 z8#eTj4doSC;hqO1QhDS=E4NPp3EX6iqw_iCb$~?qKEZeroi%}xlc|0J|(>DVW>3z?JQg*mE zZCn^5T(m~ihT=B#eH(hvhWy|IqExkjL<#NzBt6NNYr=K`9$g1w2|n`#?hiLJ;0ND^9ndK_DD30Qiis*uyGtAS*K*y2$h;AK{DQnUKr& zb=x?iDG`qHL=lk(^`pR19RyTv`%bZOJ{$7ezN(E2*-)+RJIlt^+0YHPZ@rCMU_%RS z-z7G#(S{5K-?)uyx1qaj-?cXGJ{$U>?fX+3x6XzhvV9-6agW&0W47<( zHg1CrJ!$)P+PF`9gHuSFT3xIpo33|7nLK`Zw zp<){vYeVB~=omYlX`kwR1ju>72>Ib1%2`r7JJ3WpNF&PZV!i?x(u*>fD=7k`W(Knm z2-1-)(HG-*>$g-F^?>_l;r=d4})%-iHuVazcr1(gKA}#6I*!{72^v zdA?@Wlzfi&6`_mGFcejQ$}mjLFwC{XFby`w+CToSVVJvzVSY9YL-#a@$4Y0zFwC>V zFn=9}d3PA*NDgNBiSm;`5Lp}0#SZuE??uv=AOHW4N&bKBW0DJ^x8C~gO7W%23(CD^ z-bvY1l6_1e16ya@mqwN?Twy$5yWn&0 zS)aKadg7hknUAsNp60O1Wu372qO+Z458}_Nqja35;dF8()cbehdu}H z_wl7-w725r`ad|69!EY?ydqEQzYpI&%;vj4E5zd{X@}PglHX)|CTtIGnD?wKikhdJA0?sp>y2M(fa5Es`4-69TuLX)oi7B^CwP ztKd^LeD?*ubeSaYSb$p%B^NjrBMl1~NKX6f6RiS7KU$+(QR+CpR4ticxpZM)> z#1l+?>I}(`?p2fbQ|3X>E5XztY_z|ms)e+txOBr-$k}>Vwj-oZtHYPDBGoY8PQe>% zjAu~2QGCg$f!$5N=Wc+0{pY=S$&d1_c4YK*`|}?l1u$jc0Cm9)S^*%#x9F@J)p1nXpLrC>!BT_Qy^fXAJvCO?8GV zV*ZK(2Or3&oPcAi2>KQM0aB{;R#I@2&b9gjj{v}ex%_A^wrGWttt91GHBKyQGaUWo_+lR&W6vu9?K9G@P);&S={BB(}HdF&`pm%gfOn zr>V&qDvZf~fecT)7;(1fXJmtPV>_^{S^!jp5K$>zNcL)`_Fe9Wzb~ z>R2g=7OLq0Pw<0UpnmX`Ed>rN+gx)heKrt3XZvipJ7yHqX{f3KcvbT{vQtjbx_d}_ zje9JB%&4CgaFTMA3cG{x>9Z>kg0{n;QsM$(B^~Er2q_t~$&3&*sh}s5mI#!U78X3I zHG|0-J1JTn3*w&1>?CQmN8GpU@mh;KgBXiOS4T9W$Kuiq_bNdKvu zWett1_h7;d!h_fj5f{CQ3C3q(5)sg^#*Wlp<$S-p@v_0|Cyc;%XPA`YoPg@xNfc5W znTY13dskgp-@(HDX~CrU_(;$z-g2C*oi#d_CW!1^s0Ib1Hzk4fEu0c`Vnm>Tfn*S379^44b83f znJ!ho2q)#-M346&NOJMW*qdi5lOJ)Dm{GJx7%R8!K+}9AFT(~FZC6k$z-RSpv^#Mh zOrTzoPnOB29KeiXf>eTBOnF$cqwN85d^W}(SSZ*_Ft!C;RDoav>4Bw|2DPdI$Pe)4 zs(nF6pk74eQ4{wfnyP&?REn*}*Y9*Eq}ch~c6S!5lc5fntIJsa?M2yZAjfJvJ44=1 zxy?zK(wXtGLBCz67nTdXLKSndp5YIBcWPm9bPLU4euu^K@Y^O2D&S6wEJI zZNqMgmCpvymJ$A<3msp=wFT(%h#X%Che10?Eqy1XfhT-o4IOYb@V$3bPdYP#a3997 z;e*eC;gf3k&|Z0gJ&5k7K@^=!n-Xh@vS|!OAwNOB`VEUFDGbpj)CCY8 z@feH0m;*!X2BMFj#ZSU0BSElA(QACfBj|=h1xwzmuzB>3h0yL+yH^FZr<&0Va{D5p z7_rk55`cyXLZhjZ=Dp5xd?nfzgNbjXrSxxRceEZkQ>AK>$qg`>1e5oZY@nreS17sS z(_pO65rRN~La~3a7rP0-cLNJ+=&&5!d{~2CYyBC3=4XA_eG^y+?~r>OzKn8IUWpAo z>u0%Lsl7#`df9VSiZ(gEgdAzZENydK6-@q)3X2*?zKPNijJQ~(JOTB_N&mSisN^^U&AYwco8qGvkU2BJOUm|42ikO(JaQ1NaN_2pmyU_ zh!k^mpV%!?s+B&KgxnVMhET*FQT~u2>*J6hL<==g+R-1TMnUwX@V)%#1F|e;ZfMrF zdAdxV(b|c0Jw2Dn=OMcvbYdr4yaojcfRI+$q@wh3Wd-KBtMJd8Z#HW5g$`QZ6bpkf30a_g@V)#4(i4E`xTt7Y5^ytTUnSbD4jivF>Xe80|A?>Y@j;1i$L0HgNS`M4tXVCR3xG`8eK z3}q;U;0c1=fdBA_zRhSO8l>b*LcAL}C{X4-DegSaHtl847HyyCK;u%@f}o(`#Mp{L z@Mt&M8A`7sf{TdrSJbI7@ug!)jxV6k6@hd}yGD)E%;G{?ePP-Mqp>+2tpIu<$=|K0 zHDc_6uklkv-vFsFXnYTl)ns=1(apwBxQ%=?kywTxw!V)~6Zwz=W-SoEJwtBT7W#kC zzGS<~XU+v`v`>Qg5CV7yW@~q^?#ZO5ND!_ zWc2?X*u6D-A-=+3DgOY8ms1PkBpoaN;A3+91SGE}s}{5QAe8()4Qn;|d$uuv?zw1~ z0jAX?$ET8F%Mnfs1E}qv05-_HCZq40yBuK<@X7HA@(XIO2E8B1v3Y>$Gt$uaX9J`` zOj-%{-(~cDK8P*!{pry6zfz;!QHZ$;>-)HrANszsWh5#5vrmQCz^A(L58v*-hIIbv zr1Qf~N`IB5^xuF^wfZvvMb<|-XOw(4<$FF#?(MSnzI0OB`eAvo&|(7rjd|#57CFk|E+3LH`hgEv<>ZF zor68>$JXE%Ku-(e3*^)mlm@*+`k#pU1j%5_SzHFKL4&`GH26?*bpb3>OjI@Cu|TQG zM+&H5D4#HKL1j0|E~v2vuTs(yl4j~NoAA}tbfjyr+ilHJAoOcos(uzU_zBeh zq`~`>w~bU{Z=V&I{3Pq}0qsdshra-<3HtdA=fCoy`vXdy+au4rRdp1 zhk!{EnG*=CE)IaXvObF&2uPiM8*zm?8@togW>xJ^LYuuE%8#kdf~66;pbLPpzET3l zP8>~dwY6DNOjNWUzGXlZ9!lOr8jPBJAWNHFK1`e4EO%5vnT3gSH{#cL-}*vQ43$dCsw|2|@aL+ss>Wed{Q)YmsmkIO|6ed6@Ici`n4I)^ zitHn{BKukNY$FEI3;At*|D*;MBkH0c8Gz1U)zDzY1nMzwUw@gEmEIhEwu^2jIV6bt zeW3<{&6mrGQm`dKc}6>NsAMZOaYz%=L`WVqo~b0FcB~|NLABZX;aZd@S3mp|iDmS| z_u=}-^uu0xO*7NdKc^o?k+H2GE-NOMGe*@O7vf8M)vp~o2#qG}~`bPMq2b zyWa1Fe)tmtC(nU)crPHF4uIkBpsHWO%`IlZ{eR4i528X?{SBRq;FB;yK35T3MH-dK zGSu@SSy>Uhi8VQ4`Z8Jh_uq!LGZlDB{p(0w@DG?4R45a~ag6Ig78!kS3F~{r18n`y z9Do`9E{cIH=)g{76%xr+@m}zBYdcL9ZzUy~sV(M9SKIdwl&~qCY_xJbfL>ISi?E(? zQ!#x(8?JOkq4^%iZylyuuOY`rBdDNFZA-e@2NylM4_f31IZn#|%E@Syrsu5#8L+k^ zP`audB1}s2C2qKIvJggd{*pxIxHF&gfzB2Ez8R&O6;h;=&ZjbE$KnzUiOTj-aZOFg z%eU2_Vi*Hvk01qc&nL|NaWch(CUc;4K3EqD4Ok~X_Ra8&ttI6lIj3O=u+rC=XABn(>DqYy2J=p#2`4w|?Tpt6B- zRke3$R`2Z_9OP53q$Fdufz#6n5(H0!))q|ud;?grAB$^#sF6PAq1p!^dQwU7rP8>2 zEs}!H%W4lT$iOg%&moBgAbe>EZ1HjT4=FoLK`AWlZssaM^tHcB1&jXy|JC`ujs$&$ zP1O^7@QNk=ivO^<{GpSO+WkHBf;M(`2pjA*W3ZPC{aZxkLSKl|tGWn?WMy?!+Ic3y069=@}46uWrvNwvfDiluP^sw)pNPnG?<@H>oT4`Ep+PG3yK za?jS#yOOELBdtieZoL;hqrb zBQboIhRdmFGu?8>{q#LO#Zg(0sR`Y1F#d9~nPFK#&~AWw=wwO)MX1Vy?H4{cRCypc-~R{1?!&1W`*sVOQYO9zHZF#xf{zJ_p|J}? z6Y+Rx^5CWM$z*HHMsUl1MAn|n;EMl(1%j9o8V|rxlWZwPf;C=#@yewfPXVK9heO&{ zGA@cw{DQJoEdWmV5IpJVPB|}bVlIe|m1-uN@oNerUVg#m1Rsoh+pI&!qN_pq**TF0LUVmM1mBbTBE7RV8VtzapQEArd2u`k6m*0$&_tw{zuBVBu(>}@6 z6LLHgnw+E!!z+EDJZ1&>P}w9kUr?d9du2&YvZ?^QsRS8Gc)LWyd}uAjp=IR+P0T~E z+NdE++K7po`V9yOR}kwXDGVKnieXOTkQ0+oK%*9AW!Ca<@W5Ts!Q>nal{<>%_^Y%& z$zoua9N!KH6Gjl9MIR=BkB}nM_CgVHsr;sGW}la4c0b(|q!p{Zu2n z3FS6gI_4a>`SI`0JT*B9my^8Z4Cb%&iG<~jKV!87XZfHIR!uPPW(oWGlUd;D$TF6~ zsiXqz4oJEPf%Q?P`Er=#i%|Vsh6E;H93U#NyIyX)feN8tQ!DO2`yHR;R`lskRlk_J zcJO65NKDoO(yC`6DsH|2w*xGKe_97B6KVnFqsaDdA zAyH&p%gtvJqa1q~9hP0HE#%I$F6y2|lr(nz{|&;d+* z)}=VX{A!;{n-xIKHb0m?0nM*%0}W!Q4i@R?b|5s}HaXUSF83!D7_&Q(OphSLyYE25 zqqeI}5&{7g2{J;e^$d*#)W{Hh33B1!%YLXZjY`V^=_zts4`|fyMPNDh6p$*oHU&Fayoa{!C8?g%9 zPp2rceh5MoXCDtnMqzZ}L}O~@n`-h&_d0ajMhqYH-GPsO8ODx^2jNhY_py&3WiGLJ z9=1Sm@7~~Uq%Jn~Q<5v-$#7F)8|C;Xm;`}E*TWK5s|{#}(AC)Jw1!o}7xp9|N~_T! zv8Ae`GFf!`s5}++I90D5r+T-qC{VN=0ncA>gS(oq7DIH8!|75crP!USBqvVft_Cex z%-1+Vt(G;&S0eXJZ#YG7fN~!~t=NH{ZTqQkXl?5N7#qwalC=Y@*gXt45$-y?t$a9( z0qmft#8&HM?GX<6XTUTcjPFPD+96|il}mDbJ|}948stg**Qg;Z0zd>*hyYlnHo1?6 zh6F9DSOydyKbG6}fapL|<5BR*Tmw1roItr4MfH#qPY9HoQB)&2@o$W(9JUAnaCWTSU!g*0O7|ndEts25+JnJQGy=F^r?E5xzZxX@4)s&i%w|ughD9k zYL>~WsW_xf(Y&fq(V1wV7aFJXYLTB6QaSN`EDRyT4C&w-1Hq)v{AMTed&6a&qk6C=rFFKvM&d_l z*~2ey&x#S4U_v-yjjH9Sm`#42($KD1f<}p;@g$ZfOb2L;X9@KKHTg6mdss4dh8zG^6@;O9o*w%ELzC|RE{L9F^528lA8@wf#PGsp zaOV`i zj$*OX~}jOZlpsKJPd+jO>Hi_?-%wEY(Q3%e_*?_n30E)MVG6N!$HpgeS#Syzm$S| zcZ#`t+c|K>2BAM6mSc4&jqgAjn*<$b0qg~gU~ADVcdc@uD^FfOru}|OR!*Eu8RNQV zVS+J@CaT6WFXPuA2)>f|2t~K&FJk(PSq>(y;M|~#nnIrIU>?IQWsJj`S{Pf2Zj)qf zG1nS~8R$gjydAfgmB$W^TIpeJRDEIZ!L9^}fW(t1fAd?82yLY~jW4Z0@&64-5KgC1 zY()m&2aX}LpYo_{WCyhZgbePR zOc2YifjC5Pw_r3RmRKTY%O)VllUQP$3%u$fB*6|h9HwrhPoD_KI^iR<7nZ712BRYY z@WUa5|CXQ5b2S}_L*{ZM{HNyI-!e~hs0;R=`k+?1vV@OR-FU5*{0e;izVwKqw z@NZ6uXs;yQyS=4WIMP+?kr=Jf|B2pwd+`<%^E|zS`Zcr!^|7s+f*p)-wN4NSxi)K|)(Z5T&Oncn@E7NBo;C}-= z_%c2kA@;ZozKm&KJsgiPUau(z{Fn)k1^hU}NQ;t(o5ULt$#;oB;3gT!?sdZ5$!>UT z0s#Iv-kL+u^Z_UwwxAE!L;XRR9=N%GjLBez-oRM7GB7r0GHv`G9c0ywq zMZnViSZneDU|^c_uus4&$WjnJ0n0*jaM{TlK=?sHtEpM-u~105sO=I{vs0;T2u0Jg zdf}HlMLQRRm!@b7<=E)}aXpJQLpuRZ(rIaiH3+r?P67D|?Zn%~b6~m602UwU#yZPv zUk$!sh=U-rC(t};b(rY2AWZXNQ7&wP> zC0WfAvO+}V=FGN3!9pa*qsSBUuZ2O}+b)AaEU zzjwz}ZM>uDJ!2_+L55m7^)@E*uspTV@MytUbVwKgG!GcqK=S~g@L#SN;9F`GZ*{FA zS60{NlJF=}Ut)LFO3_!dX;=pOiSHp@RsIDi=l3KAtP9*?Px~PAc~U^z=;g!)_^Q0` z{V)$0Bt#)7kZ~{k#O$PPC(<-NAnC&<2wYrQjkbiL#WcEL68^$oB_S*>Fw;`|b|SbL z{YC^fR?>`=?P+BCRyI%pOug&W=iz@2vZL#m)@;Jy0)OW{LAcD+*-yPvRTrA9j*}Ay z-a)>TtNe2OAc7fh!^vHypCWpzLZ5ZYrxn_)(>^sMC`8(J4>b0CY*k|bs=MKXE(Hyl z^hQ&C?9XStcpJX|5xZ@I6dB8^aX+iZxP__Hc-PX&NY6YQ5n0c?1$kqyo1AzVB{Xh? z3t@TsEvlu+_rckj-*?G#@c(xN;^EhJAN8BOUf~KB$%(HbCJhpmD|jlUGg(0e$pCK@ zu;;N#E61;<7NZhljYWW%U+?Al^EJ zSOHEt=4hD60C(a|h8s8F$MAj{zbS;r`y&MK0j5vf zF9w6F1K5c7iRF^CgkYB>-Q>Y-NF|c=iwTH_-?EAL;vMjGvB$Gtm83_{0f^tJ@VoJB z;E(Z8=h0ItUKEud3-2`D1w-&uetN8MMZ!r;k{`?8bPjuc(Je}g(D)>&ozkV?O=mJR z6%gGW;*>~dI*XwP014c`19CC$Wk6^)gnJgn7ja(%L`~q7=EL$K;(iB^i2JCGd&$QA z4c1f<_cT;eg!={{QK}CB3E#uEuZ-ypnj3js2S}7)HKx8_W!w(|i4yz{kcis@hck-`!OJq$L_IKxDp^l9s%6OBWk_? zkjUc>Kq8eN0uuH3t?j!RcTWi4=KzTqG*CpiIe$Vk;XoDkwN*H%B z#)~NFQ-DN__W_9*=i=ra(JtQvBN-`j26zuUNR$X=u}7tr|}w+E0Y-%&vLLwYmN03zJOHgq030|kTc?*Iwk z{Wf$Pnp>pzJRsp)g2ofjVn8D9jc7&@ZZjYn@lNTlfMA^iGyq71^P`FvFm5RzQQsI| z!uOZ|Pi@x&97T1;?~)_@33`lE2dy|>F&%?4k^ssdK@tdfFrlUrM=eY*m%B}JlH8rS zJ%VUU5K_2-l!#b64sFqKT4uBzr`48HY)^>@f`XBvqEj=DwIVpRg%PpT^!L5*?YFzP zhs@Y^XWs2^f8Y1M_jljh+xPZ8K^u^b9Q)^h5LsCH7>L9D5i%vDxIrNHy8>Cu(iedy zDd`quBXidxa%`^|i0zdjnk?M|#N{>wMC}$rL)1Bb7a_u|_bs4mCA|}fef$ZCS4aAn z==~kRPf>d31ib^Zs7A2-2@om(&^8#Gs?czl;B;In=xRaLg8l}?`P_&AIG81@twCEi1l(nd@np9=navc1!5~O>MMui6`dH3z%_1WaHBV24_6fv?=6j0^JTu7u=iUR81WhteIk(DB>x6qQ{?M)&3V#w!f z^~;J5F;H@#iB*RmbzV({6NwFG1J=Nm!Ii@Ke2d_k0F^JrwBk4KVm5)Hrv%a|Q98dM z9T)RE;!$yJomWB7a|1KZRU`b6l=|s;;s@kQj<2>lk9Zg0U7cs0$SmMoC1M!JQhy_U zsV%k-@9I1|AVfDJi=j_3 z+|2DB=57x|^Ge*lavtVU5A!PzL!WiI?Y!b)-u5sbdl)|_7^bXr(Yz?za`C-x=eTr8 zyTik*^DvKim>nKwpNBc(Vcz#J!}vBsJSY`6;L5Wyk+p72#z@8^okn|t_A`#8vSzDu zg`SKr#!J^M!QQ)i`5CJrh{O|_bkvNsMKWg8G<>|`k;|^voLfm7kJvl=7A`uYu48RR zY3-IF!4MkJ9$sUT!5SJlx0b%%l!xadg5 z(aKg8p@ggWMwC$}?G9MSv@4o$W+}%6`I1a^wHxtPqXR|H5pgblRJbCM$_VybSo6L# z71^XW9iy_z#7b-Rq7aS?tza~@nswKlU;H(~G0d}qk)jKJ{vRtC72Buz znSyX@uut=a{-JuG2viQmoTj|}ty9YQf7RcTHS6hva=Ta`NKeL&md^pZ63Ho(9mRX0 z(w%nWl*v>JxOAz{#XAag+zS-)u1}T5LmKswgF1@z4D{cWEIS#=JU{@rGW0g*yo#j2`+HVhby)|6+IEsT8pRY0TTz+W~wd4Y85@3ISo*lf_#wjGfH#XD48k9}{an^JlM8>mIQVK2ccHPo9_B zyQQ$?4|ttBbmCpi*Jku*OxES6E$lT^=`caN>r{q^@D~r2g;sah*rm@lucHStyjbtA zbncKzn-_(02Uumon>kAn8rW8#dzHT`dwcf`$iA**--hfi$l$O0UVl}vXDuS5{C-ZcD)bxdIYsgr zc!7QlpgNzMhM3c?hgeMuHfrgk0}L_p)aKcEfX7_Cr-{P2MrC-$f#ABwmBP#630R5X z^U~nvEx68|+VB!4md260dVcTutaY`}drVk*-CTxQ5@D=$wf1c3>IUqsu;v4d?G52` z{E>T)&xED(nz&j_T<$P&QO$ArW_ionm19bR>!>`cKczzKUBU&DU8M@*v0{Z7?D;A3 zO%>#t;syCG$*B@Vi~FbVk5oa{0yqnj>+5+-^Aa+r%OJQeKvz-@!Of=;DrMx{FDZcF zdiu9y*N8k_N!|rFQ+?4jf(EWQJ{xN=)d35<=Z0gb`2tn0>mDnDW~&{!)k_O1$zN1q z>-+aS>FvUXsjB9_WsbAsxO$AUe18i&h4n@6PP}m>=JeL*_DXSM;2rxhSX-yh_#|_A zeQynl8yidT+jo^ZwQQF%dEy`ZJ%F`)B2*8s$#8Fd#l%{*%IGfYhcJLSQGziig*RSi z-G*TVGpATE>b_aUH)3Zw7W9SC);x;q3~gS; z(X_usp!q=5KGq;?gf>z6M)_g$4aoyoFvntubt*09GC5buc3X1u0xE-R(6l=ZqWwKt zNoib-Y3Sj@#bV)Vp8Ki?u-UL$N+h`T1q?Z189uv-r}lpBNi=UGX;`@_xc+9`CH1|k z4bKfMj0O7Y{rRCm8o;NLt4B#T@hr4m^sb^<=;1vyIfW89YuEQ%0^P7Xi}g+%rTi$c z6@r;vG}S@t{JKD1f;@A|w-m_zZu#*PvZg?VV(u_;ydElcmKG?N71+DVYj0SA$~oLs zwmntnTDM59i**^9vquJ|h1$${zr|_C(8pxf^s7 zEdvuGW`1rE?Wv>(z11@FN|nKB{z7w4_5SMoiC^0Fi*-HaVX612@>t1BnKq(=VaWD{ zaL=cUbNdkHofM{-rYPWJJ=~`%Muae*o?`8ZvWl&{exlW#`DtCnUESFwFszC+PK{S{ zPQDLX5WpObW$Fvsl_*tA{6QifQsu+(SGCC;K6?QwRrZbQw?(y&pI7^(zEk_OP_37? z>-ELWW6r!sv7L?y$SP9Le^iE|n4TE;5U+5sWKli79!Tt`i#nud76Rt*sCx19sM<|= z&B-?0f^{_E{&j5@3ytPpwUUo1l?~KQ;3x>;@ccxc%0Fk5LV5?r+OUCp8U#NUxIaH%2+i2Yx*gg zR1xgwd-ZJ{fB%PPveLEXu!65uh1s{ZyyS#qH&kvvo>4m?(T{%wc60Dg_xY>v4j2zb zfw}Z9*nx+Y_=ZjPSE(J6tR0J-yB9gf$qRW)pKNr(Mxp%&bU1W&`lVfr9>C5=O^$d_ zoJL`1rUA#!Or-aoLyzo~m-)*5y}m$IX;Vqs-vDpER{Ft_hT8~7;{knekHFF2wC!-u z!qG@T9`0?p5ZoYKUkQ)e(fNDG{i)!(aef)D2KX?}cc6o;2X4aoH8{Gh25}ybPB9K# zg>xfZJL%xO3eE)X#`)NAUj2R$=W8$s(@pv~?}pm|oX5Fxq|djNc$^o(Z3k|^ISRJ} zIF0kIcw%{qc$~*#aAG%b2=eM1|H1_Ye?|CjMLy#r`U|fN#HWuL(zg7UnAH zAwjg?GjkC^j{{-o4pwf(jlFL5C-g^ z_W=-f7XjZWlnZm$3R)znL(rpwo)c7#dNe~>xf_V%w;pJw;vNUONul?EXe17C2I82G zMg3y#Mj(1K6Y$*ybhARcf!JOd>fRj1O$K6nPXg5_?hp{$`=>~oQ7dbebR_B~qiI0% z6}M0jF4c%Ck62!TE8c_V8wx>9OUDSJI>}PHtJ%jmK_QV=2v;d+qDZOa*)PSM5tRj7 zraWP;MiA8tmWG9^7t|oqM&YQnU@OZ++9X_DP@72Gg-Z)EMY>YB`vrB2be(V;1Z@&& zpKx0R{aB>igxfCY36bs)?kPb}i}V@cb_&`p(!6l}g7%5@pm2u;9TDl9!o4GCP^9k* z_o1MZBK<_T(}F$|={e!3OXM=5_Xb?PBZM0*h^8pA6ke4N9+4)$JR;3#v`EJY`kJ82 z1dS6E5>z3``-Yj{(#D|SJgnD@eji4+5W`{zwY+IKrK1$+p6+uox8Q2KFf^tzH<~d( z;BI8+^W6@VhqLWaYzAG-{kWq3)YhSQY25)Q^CTGRTWy`^!B7utGXr3#pS78fz)){% zGyf)EE{4je+r?Z1W)LlX5^^NF;5Y`KbRhGKjz^H}uUdyNDh&?WW5_y~8O6jjn@fHB#6xUSROr+eJWV8tF8hh6kqOq8f)&s_t(YCA^Pj$IXy7s%V z6lGvu6RuHo<|u|4qh00!XiYVW?I=~Ajc~`3+9hVR)6AyzRz9kyF*INv;5hv{pxkBaId~Y%;Tq241VZ)$kp$?Ua=4k$dH7`PyA4eAE zC@~IWyzvlAb@}lHCt90Bj?gvAM-z!u%xrh5Xw$ZeRdSL|NLhU}W6tmFOj*&?C8&wKskSCS-!dgB4p;szj&hV5kK}%?R3ofgu`<#3UrGF(d+Gs3f5<15u*| z&J3_U9!u+IZ$GZKw%1zktM9Fbm{!Y>gh^smlC&}EwWevSoS+s>n~+2^|KHmCoHH{_ zG`(%#|MR@h^Uee3th3JkSbOcY*IN7Y%qm;e*0B2O%rECB|B4bG1)O-z&o6dgULu05 z%#32xVB4y-w=~r^tZQs)t8Z*-545ej?Idp+)~#u6Yic)hNRIR=FB{sL zRt3zgRMZ(Z)!8s=9spo zHS0Q(B29g6N1YmJw4y>$*GUXCaLK$dkf@z_eTI++ zn%X*6wIsd>G_Pq|7c_awb2)hyoW^=^aP7LzmZrvAn$|R}O^Sws1Y7Ho)-CIhISJ(& zRD5Dy@r3JJAi`$V@=V*CJ~1pZOiV=(a*BLfR|OhYqrjkohzYK3Yiem;b#n_fOHNl3 zw?WvH2%j2UP+%oKrKFJKbq(uU%#7+2WQeyhe@n1^wNW6^=vFs1+*;q%0e+fPaXe(b zqq)J9sf4)|Oy*M^*Wc1)))s$6Z5ipTYHTDmgb0CpoSFT3b&Q(yBmbJNf z9XI)(Walq05$4@}#bt&kurjm8W{0Vlq(9jtDThOL+r@#V^#Klx%OkkKU`t&HL%-?x z&zEXfUfj4Uu!>{EB@4I32s2`YOUJWEDjK@@W|*l{{JIeC%O%Ny^6|LRNXvYK^gP`g zoc36nO;RhJj*iP!hgxe7?+6rxcLxgCObW=(qC%-2M|dbO?Z*zlI-#{^X47o|0spuu zhTj%#BOx}Oo^F%27;m)>X_4}7F4E3tc4zD?3J@M*TY?#}vnVBHYcAV&qZK+ZTN;Rc zfwCL0eiX(0ReQZx=DVsFEGfvp;^Irc)Y-iD(o6C$DJq^@bXn2m2=saUle3i}U1&jH zwxBf@bejcz$AXAm+4#@Fza*W3{|t#J`3#4M*fTkFvA-FXQT$HCBC{8RnHkHdd0{&_4yNY~?kCH~`><#-yfFp2U-*`(VZ#FeBf{!5fC zo|lcJOXO&VN|Y;lgIYZ4?-m0~yh*p6chWFz78Yff>J8saAUTFRXl5XeS#|R|coW8t zFbd#{+o(}EZ@>L^LnXzvY>I1W)q)Z9@AMKsB?~DN)`Yu-hAPNEl`govxX3M(L0lKy z4WSn@m8uI`@!}bjvywNAPu2w{UlQ;CtS)dGd75dGE9D8-dJUm2XC^o$f#bh-5-9VAJ3FrRa)?i zwqbd&iYJss32htSrID^s5g9q8*+wbXaV_#kdof}xc4pef*|5CPYZIx-8z=g`NZo7q zvvyE76r7ER4BLl9S|+8q1u1q&Y}B7#l_n1&0m^s0AFqlJYh~&3#%eRE!Rzh))q=8W zB()=Wj%`F9tmedhg_4RQDML5PgAouzBy0BRV=tVD#r)~jX(~{*5kIR&PCQ<4yAi>k z4(dRmz5@Cb^ekBlZXZ_OtwF`CRyR0X{4C(SIy@xb9|_0g`-dI7f(~`Lb7lCAU=C_! zYYk^>T=(K#Yx;6$KpC?kcB9(jY<+=LHR>)8Nv@2dGN_s3?jku*ziDU7ow{8SNEoj3n%Z5m73_)_(TT0XcAip@qK4wwG%yBPwX3NS4&@;#)TOM5Q zyjtEUp=vn%7crtv`WY6 zl;`05Ow?OohTpwQ?)ff~QzFxp;prqfc*7QDk!)xAyN^k+jteZ>Rw5u$$z;3yyYzyc z2$yLa=Ao4h&MZj|XF_YrgEyX@P*OQO3*6@UZ(L5I>JjDq8iE4rfc#P&*r^V*S}HCT zltiX@HKC)6cRgN3^KHd0A}Y$OrP^i)@4w zF<6^v+bKV_SAHshOn(PK%pE_2jVV!EOX-v+`sMap_!eYI$&ASDFy{#B%8=&j(C z@O_YGUU-KbY8CaHue3PxZ0a(*GUPzJ%1&Q43CYR_n4|Cii1>HFZX4ByL8^!ke%khp zJ$Nh@)4xspWfN>~@$Mss<-rfAuH>gC{@&{P6NyAZb^ZRhkVDcI5JQN#-Kh+v`>&E> ze&)^UJi`w^aP~2h$}G_6==cgT)DYMJX)uz^vExUP3{PTyCfn)Xb+BL;H5%<62NVO3 zj7OdT8imW&v4-^h)f59M08T%h+Sb*`%keQBB>0<1b*dKn6s1FL6!8@(7MuPpl!+QM zRk=PF`~=!%8~>3(EQ`n+q4O7}U5OSZ_pStiuoZS?INi?{k`a)@84wCk;7D$JWH}JU zY?u&B-UL&{GL6Won8`*-8Vk0I=4ju9j3h3YmCo7vt)PqA$Hnr-S{rl+HEuF6v;Bya z)sH4is6s+rY_u3{VVaud>__lnN>~{ptwjlPMdN2@P=V!82`~OmHUSAi8(#!I)F7da z0q1OLau9+o#({m<`w;?sPMQwfii?%gt|Kpb%oXqGWy;iX?+D3 z*elx}&TC~8IABFj#xwOsH--{j53&QV_{e}^T z{g%UDg>8j#4iq1@Mcud~SSwl9PiX~mPc=oVbZ(%Co1uPU?1SPrAh7u)d$>DslZxMC zdqGZ~Fi5R1y{&R+^K>YN39|AGx_kv%alt{Bg;HE9t|%ZUAz4B^4?FWki;%RUTXh zlL%vW$WNpf??#?L-k1r(vO$<1iGa9l5GVK5!A)UXD4Kr`rR{-XI)t=byv@5{UGOfy zcy~Wc@<^q#NYYvj)7y$r4kF|e3@_Pa@-yZjZQj~_4$?ah z2{Fup;&jPRk;d9Ko@cZz;?S$aq3Oh-2w7inD8cUjUNpvzS4hgpAwy{wI~Q;v^k&gB z@oEq0@6PF68&HS5ezE(Q^hEr)-MvJx3^4xp+>*)Rn`A)qSoUJGS&t-Y9V6FC!&twtqqrFxz3f^%$J|FCxu2o(n+%o7E#hW=z8JbQeiHgSlMh@5=aGGLr z_ zU>7eHDw3B-FCZC)ceLE;0uQqah9Mv1ujg|80%;7?gEp|a5J8G;6UB$wOMX@YG5Qen zlpqd-h#qUxYVvj>70PP@l0jN#`Z?u&UHuS-i;(W=s;Nl`;mL^qLk1iQ+4;JXn)}Y zEzrLJRSHMiwq4Ih5k!0B{Y?joquDdY7EDlo(?|VHhb`)7KKSCI(Baci9r{ynO^DG{ zyalL-e0?{pJ)9_~O<%_A3kgAcwQ>oqaTc)=kvC%SXmt?7i*2J!*IHb*et7VH_qg11 zKQDNl@U-ixinp_a;A)Y!JeMk#I9ph-$MU&aNe{!=I7FX^4fp33dj=HS`E+ z5I?KSKn=Cd0cl)+%Yz-6TpdFdlUUPB;Naw<1>qrEZw0SNDB%2|TZs;6i9EQCI!sr} zgF6bg!((vap-jGa5mz2Qw2nIABK{|phH6)ofoP|4q%C)rP+3k^4k|(M8=qVTKU>DF z2=cJ&mx9qIn<05)-+iC_MY3ur9mygzI=3zQr6>d2UNFXBR;W_Q(fAX&F4UG$AGW=E zGo+ErGOr;0Yk2g-xXT-}nNE~L6pQ*{*5yH1eCnH_pM52?34F~tlpQL;PMBP}6%OC(tF`!OFmdB02P1F0kG#qN)4namW{JN?(W)dS4IXW{%E4 zf9{c=f^#%JlN~(rx;(f$azGgFv#bvDd*tE3wfQ}W%9{g)q2JDB5Awpss18W7Kz@<3 zCB1(IoJc6|0&s1i_|4$`8R^;l=#-BcN_ElDPH3tWOMv*9{qQ|JM-c-(VqVIpzoq4AzPCVbsG@C`u#m4 z_5}!?kAE7Chl_;Y)%d3}$H(Wt3JjG#j_CkqKgfz>z6A^o3kyu@7(R^*!&6WArHGH> zO6JbJgu>b6FYzx;M0euu#T?#+{^0GMm1Zb7SPdbQmS} zJ41)CYNs43M-=kDrUpmiBz!!mG8tpj<Gq@eu86aS1f5 zra}C&XkWlUMEllT&;|?YvVxPL^hEnY)~kLC8nB@It>D?kL(#s6@kn*;XML>zwd#^+ z-}gn3v}oTW7PQG^Dw4g={T5Uo1xD4VAQ=nG6)TK_%?uqQ5ZX0zE%gPTBfbC)X z*d2}$?^&^e(GhP>Eb7gtc#+BJ%|kzb;)y3HreEqnU+M6B4IPBO2q&3qNY=4MV*d@5OA0|sMSsr zghRv027$$~8`&hyu^HB1h4sbEzACY$4pwc~S5lWj%u?~51GVlPwCw!w;XqK$FjG{0 zE_H=jJNw*Q+HWx;P2m%Q)tSLY-CNrBtGy%;=;3}wy_YH<^DRViY!||z@pCfao#!iC zb8cLr6R$aBk~_d&AOBS%eM0}Vs3B)R)yuD(UATd{E@C#aIpZp7Vw>qA`$pjzxv1_s zO`0a$BW>sCnbasnp}R+@lHDV+@;BT;6lN^PZ$)}#pc2iwkW)xY6`0Q@hejz7-bQ^+ z%8>aAK}iUZ;HfWHMWe3EqYg9xU$$DEO?}IsB5-6ZJF-9PDxohQ10u@1hP2iIDHayL zXCuD06b}{erdbZ}Z0cj33BaX!;VjNi13{b^&0AuE#Y5Vn%&3r@a$2mvl1RF!Igx^d1^0l zFacAe`Zgpy)~dZ-$pIFtzHH>Y49veL`OR{;pGB<136U`UR&K?p{UIa`GYIRTY;9o^ zyzv4mK71pa;4{%irNAH4{pdAaWdpRC+%wrb%y>EV1;889;~y~XAx7Td)X$|+_Y!rf zORa~*-N0TWWk%I{xe;MNxx+av_*t@Wka{~>53f@7dM6?whR`__Ydb1vw^~IqeHz-a zP&1gBZb6ShJo45e+Us)kdjd|Usu+z;R`27DZFgWA@o_gAa{(GNf35oLOd;K@`W#Fl z)vWrmm_p%2(~I(8#H^&IXv}PZk6LXEog2It&CELtD{N;KghXcNaM03Lln3e?f-uTk;Vg^hW_x zXQ~KMo%winZ|OKKvVR(ex(^|mQ>}8T*O462J4q|?MBbimd)fU#`%|ccxn_N;qT&AqRqn(Zsz zjogm>jr7CYU=k~Db(gnvq_grCr3Lz|0DW|JTUoT+L;2&WFj`(oAdy5&<@&li(goQ4 zf!x!E(o<1M3{l+h8T4F(qVEXQqu7P0j-pNZi09tZF@ueY+z+YOxzr_2E$^DhAE(>) zxL*@qB}ukRQ!{qfp7h z4S-&rPO17#F2A+uZj_63mIqS65>ysY^W1mMl|xS;TQEF-%F9Y<1`l|5a1w7iw-j!#?ZS-fbZ%`L?XDk}9GkTu2+U8uG)Ho`<(5$#V* zejpTyx0AAe2cvhz?^*I_<$u0={oKGgYHbO|c{55EJM-ITvh{P7aa+OO=ZOT9wwEyD zV-LR<{0VY%8SN6X;?x^J9r#5(4oQCuxzJL)Q}xs@L||G_lp|H)`dJPwv2Xzk*9GWv z_|K9416LYS$dPv7dNzlsc?#%b3;G<07C5r?=kRdVfX?O666gXNV#twxXhBa}&}IwT zZb5r3=uZ~(At17RIZ{cwncD&jT5Ul+7W5#X^LUI$0iDmGpIOi$>+LyqGv!)9BHV|7 z1h2k1&7}Tr3)&AztTfaCQ70io+6GIX&-1teg95WSbUhUJg&evMOCCkIr!D9$KqAIh zPcz@Huqe0(sa(M0rjCv9o^1nOCjHO@;6EEu{iM~5MAv?loQL6|OK|N%u5nB?FxkjG zj^V2rlQ69m7p04bVL;?3VIBj7^o_(}bmrZuz_JdPn~(s%|3jC8VWCd$N|mx8%G1#^80#-D=eOu_W0 zV1AH-c{~NPGX?W{3g$0Km=kzP8H*8PF8`P8l}V(&zIjb+ef{ddy0z_|5~)7^*g}td zlT*^*lCl0gY2eDhr7qO}v~~8$3-~$zQnw(a?C0T|J`%UB7Ho;}K51_akv1 ziP-LwoT9ZCf++f*jHX>N_lkV+i;t#-AVJ*5OVd);+&_&5^NiVOjQjszqiKznoQsUj zb+$}m9=qWk!|u}fxI?|x&a$z(joDZQ-WmOK!@H)H`7Bd)u!ZqgBE&%5BE+V7l^mKF z!GbgO5_T#6SJ>6B+SxKhW9f)?;|eoBjFlA+sb{!%26D)qR6m2Bt9xhg2p0U}ap2Gv zYxz9~PG$X5tq8Btf5?jDgH2SAaqWKzo{Ew%m3XR6!Ysy9mxW2S2S38QzKR*08J-Mlx3fF4qFxd>DeBFko3b?tkG@7J2(1z5# zj=*_nc<2ZPo}@b#$k0F+`U|30G5#RSa~8kBi5Y*)h>yWGTGN9rX`n>)qEn0hdY&^j zdf02X2W8buTWzcXKJ*Ckm94oq@_xVQ4bY=S9vZADKcz^+0q*v!_6$lYkj2`wXbDI* z6^E6GK?e{W4a`;-Wg#CF1eDV3q0t8d${23K@ay={CiF;R<1ZMa9gj+2BiKv*-5a5C zO2R|hvX~rt1S*b)RF~S-E3ks=!}fEPVXVNoq#_p4v94z5(yTDC*1eZ)5B?c_5iA;4 zj>m$p92rG+Rwu|D?plTxi3R9;sauI!iB6+>A`XiB39rP9;vxOpxCy;}Dt%7SC2>p*5G#`~%P0&u3gY;`Bz>JQ_z6s^wYdl{ zNGHaB|CqHg^=mvGf~ZdD2a-Oq_wh|0LR>^&<6aA6_B9$>Z!>UaKjM2yVSb9I1gj$a zR%1JMlB;UqlASvP3AZw3-*$W#SEKg^FYV;UhVI3*BRDC)Q@YLEBPCxnZs|@v6I)#D zzT#5uJd*E-E;fGWxG5YzilIcA*&2$Kap`ihCZ+Lk(0!CA)J2d$tR~8Q%**N|=x8 z!yHsP^8_4)!4S|0EbC$fHY}O%WqTQ;dQRK~nCB$db73)vm6sFy4-EGcacL+egdpm-8kw4Z0&ZmX*7x?>j1$8O-U)G$AUdDDjhKkku3@8j-Q!iRCgI?Sk- zbh(86KVC7aFAO#opr2;d<89Z`8NtuVgFI0) zB-Tdpkf9-%*-Gt!eF(QcLwjI9rMB4VQMMM+&@;Ea@?h`QQlf(9X&xK_2(Q`CI1-s+ zRUBq+=4a|lh%Hzv6#f+w!S*c*#9=E?d!|mK*H})U$;TVH4}J%hdfiK@!b`!t4I=R; zBUeh9;_FAC#VNc&ndt@$EQ0spPfMjv>fYWl9}C;EI?hqA-H?853mfOmxy;^!FCM$a+7ZP8EQoOo%7V{O66i(lDA{bVPbNkK-mB} zBX^7@Y_=319zSHd1Sr2L-^(G{$^^2ZA?D9P@v6!YW&I1fx+em&OrOp4YmB=H=AH;?HAj5gkbJ?CGpp!SiD6-7h9OxT6lYJDHqv-uQM!Ufb{dSsQ|{!t$YKjGRn!I zD{{#hr~Pgs9Djop3oXp2r^xxO@&RY<7bKxm(-XM=X?puPeROq?B-1Bw|HJftL50(P zPFMHe0yXN@ro*ZF=AnjXC@z~EqN1q2N<5!$7Tyfz{y6YCc49ng)|cU~x<3x;>K(3d zEYPTW3lZ_ATZhVQlkRBywd%S;t-6r-@7@-;Qw>V2(BN=YJjcIMj#ZT7byki>u+o4t zFHpt)Holb|Lq+n+iF#d#01d`R53NRq891Z%^sCTv;ggwpQ6j-#s_ROyG{PX|2Hu{h zk~0kq2z*tLa)FszVk&`iK#Cs};t4OGmC+;ZSeD8k@j$rHiKHY)Ti+ z&DpFi!O7v%4sA(@@wkZbIFDiIi=~L*KnCiy4l#2k_kI`6dlOBJM=P>9(<_{Gqs<7> ziXsBF%^%?!ttg>~XvJJ{D-$;l-7pVg%u7Wp<_SD`a0py0Ze+Odv`pNVi`zhG@qdonA{)&=Bd+q_0kN;@T0IuTg{eX&s zgnJl}2={#pdIS*tqCJlZKvK(d$-LbCD?Dp=Px5z<<0@i4X@rXQY%-vNqpas?!06`b zUD2LrI2xODd;V$!i0En29@_Lkzi1DsQ~^=i0ty(oLqDg^V7>k*R;&)Fw-=$!O;>&< z>hfp2F7@k3n7BSN^gXTNxXU>$kZtrbEqO}z8PE&={iZPFG}%LdMazeaaF^*KP%m+e zh{ArhJlm+v$6bVg*K`l2gHpH$;R6Vw&WFK#h#SluFqp$InEXi|>?1Qx8+6HFjynat zu%pD&;+Qbn1Y7p_j?7PUEv`aP?pnNx2$pLxtQ?TLj!h4^yN+?UqW5q@s3f<-zW&1Q zk^S`6P-zCM$o!ALWH4-?dt_fi5dA;FXurY}jXOZxwJ;(W#T4EMFE}rlQTDhuasjC; z*fSO5i&d&5Dt{`M5huT~m^` z-MFhh$lC*4-i8c$<4E>r^&x`tU z2vig0%?Ek&aaY!mH#tNLA`O{S5@gN?nd2eh$_B8+zyCCZ)0F*4(KH3%r@F|}zBIrtQrsHFZMC=w&FmGL*&7hZ_2MQpv(kkpkS#@(5UyPJD*b@C z-c(3<^YI^525=Q`?+3&+v+^(?5$^jI^avpOMU}?{fD>@AZ%h3Zo-}omzj+*25${PO zOq6eZr3dI`rFDhvm)^R&EWHlfOuX2kbnR?^WGqWtosIqFk%QQeIv>d0+O-*S#Wpk^cSOFY z8>B)jkfeU+-ubow8(@1Akj_S=~Rk;{%WmS2q zH-}Z_tKM8zl&Lp> z3#NhH!C!M@YXw2C*u#Us;)R7g8uo5#MwUI`=6z`z4p^DaZTnJ)0rC_^UH_2$5F@O( zP3eD9F#)M;WO!1QC6v4~ln_wdtRi&(>o@Y%X$wdaunh><;<}eEr{V&@vJg za>oKw8H)jb8nf4HS=+UYVjiG`oJ7{0%CqAb15rQGhECWk%HvZWP;Y?rKD22j1hfp%5e zLuxe^ZMt_f-jT9 zmeof7kUe83!vd*v8!=z4bk5#);$0L+#njh=0<LaY)EO9nA_WoOuQXHbispxHL}gxtFe zh=K`&_wH?S^%xIA6G?Ko64it(T^g2=x%UN}hFDR5lu$e*V38=ox%UPC1g48|ql6Xe zTJxXueR1=H@w1FmvA19Ueq0S8kLStuS%son$kC&Qc^WV|Zqf&uvu)`_A|OzOg`(6V zmpf~Pellr>8bCt!u{?B&D5Qq9LvRKUFV@2bq>9i z1Vz2`=tk~`_y2BxtODmiM3u);m``%T{OmsR*Gx|=dJ;G6f8>MZ)5_?2y?Y$}V-8v! z9?^eUjTh)qSR%-x$qFk_xS5(u@eWu9n1p=GI?S7D9sU>gcaqm)Hk?Gyz3)#XsPl`k z!gq>#*LTJx((Hdh+ZjYa@H}w6D%BR}JknLXNum*NkwY#BpPCVVj|TIxP8_*mk+|1I zE5yBpwCLVjr22B0w*;La=AEnh@|d?w^=x*u5biDrOGztTsY zo_L@5(|n@K5R!~Z@}z*(lcHsXhEK#3HA7D6y$8Fa`zak`WEy@rUmtMO7N{uU60H?3 zQHJI3z$I!#MWc^S@>eWeA`V+Y;1ZQ1h@p;Xz5tT}x5qKvQF2>SGqv;=4S&?d{UdC~ z9|Qr0fAn@-F&Yu#@=&R+FHweQurdcji6PpekNWbkEz?!#MWUDjU^f>*%3STAK+YI!2vKFL=dw3(m`9Er?f^q@s6gn2l;|EoYhoG$ zJPoW!UrC`c&84=MxDUypJCWqT$;YGLrrh{=^z|k=rnB!p9;i+nk0#f_LrW#F&Bxk_ z!)ZS^+C@1dQ%Uzy4RU*Kj$a=SK4*@0P#wd$s>BGVOFdUVJ6_uufAxCcuf6FW4>Wxm zpPuGrJRGQHZy|->#jDwm%>asmXU^~N03dc;e})3^{-0SqeJ17FA-RvM>4DqTJM3(W zelGA-{FDON%eRp6S@HL#e3F79 zfw-$sTR~&{x$d{*&=0Aas=**Rd>=q~VY6|5guiqt+_D}Z*yQ+`>S_;`v#-M$Cl0OI z=64?qHmIx1R7tD3D25}KDtE&3c*D;Y%*N?K9{6Z=+~0vx%tbB^t&fYoDNf%K;uvsi zz7n^uB#;l9=pdX*g!Py`@t?tibmL%+1+#-cH>=nvE$WkwSi;E`q{WkEMvTCdw2VJ$ z1V??C<)^Y^DpFbR%m`dhCmDEcnD9uicClfklOu0T=dChuy*zjWPO)rHLnAyA`3u@0 z+M#<<8v9sQJV;zyhi14#9(+%UWVm%%E2B2C*twX_zncm81>`T0E)%<<22j8p_(;6F zqOC9Cbr1k89*5dR+dSR9G;}O0E+%h0Gf@P@30Cw%t;pT!P*OE z)}Z?px#va5r~WK1=;F&lzVT% zgZpKr(yI3LeG)!f#b>4>x-0Vq5EjyeD_4>6?}Z497GOxI;h9+ z?^NJx?Czt%F;k}WClHf1Tq@?fz@KnN9FH@GbAAlb(-q1T3RJ5-KXPzdX!fMzau5a2!JY+yT*jn8(_XlQ(Mw$Xkv0$(n31m;jR83OD< zB4e*&09vP=HU0sA>1vnUyA!Zpj_i2*P}dh~%L?7c<GdWKtA5Vh80r0=H714y1p;J;Gj*`&OW6`k(3e zJVX6+`jgCCT%C_UMro7An?GBe(5C+qQN^0F+I&fB!g@8j7h!8mj`2^pQ>{0f0VZ64 z{|sp{t~7;^Bhh-ZFLH7NTky5FnPZjkl_9N z87A)^0_5Uc+iXG4XPWi)As|t27oBFt{Ux9a5hFvAv&^^!fC_mk=bUch-T@@y)?zML z#58MD4!>NaS(Mg6KSN5$<+C;_aQ-_9pVZ7m!GA2OvTH zg|NE<_ai`}__oN<<|f5w6XG+@CkYJqSp=orM;T0I1&ppf7V;?gk{vaSqzOpr8PdkhN8S5CAdO z0{Q}ncIBHf{tBoFxE$%sS!N#Z021_-gLxv~1u!52x+dF%{>y@pfJ9DAhJ>bNKn@Fn z_!&4vFd$T$0Z}{=_av)MX`NvM0wnz)oczbvkAkj~{YdU6@Gic_v>cdL=&d+rF);g+ zFfG6oWh92_0cK?q=6k>lBw?PUFeq+3W#$%n2 z611YYaZEWd6JTQ;a}zK{Xnk?a8ej&{2I81LV2H_a%+G+yh789sv|H?Hh*lgk1H5?} zk{8F!0fv6*{6BRK?$<96Yc+Wwe)-4N;MT+wFrdVhnj~ZCHfjaaQ^I}4pb$#;6W8fp zYlNZ50{m(UW_1dtGX>LYVa&C>_oZN-O2I@@FndxkzfZv&O2OEv68O)|{j3zs7m_fk zdmY_)pSs$ZzRUFgKJN7YKJLW79ED@N#AmD;gKO5@<`qvDUtWA!kvmCrrYszfKPK$P zTpL)on(xLGZ|RZ0P2HT?`Y9ig`g^u)CGML%*)B-FOEd99R43mUmhdgLs1pIHGfQc1pc;fqCydX?UG z;eW$ijP9fVPQRJ>_ed*Gx&rt2)Hupv0}v18K}UJ z0CqernuTMEF(OmC1ZVivI4=-u9G19nA~zOR1-^t{s*BFfI0{PCb15c~Lu3VCz!-g= z-UcNL6!|8YGNlE_bh-{r>1L_t63G;H{2sNcg;vwcPlcbsbGo((SDZ9b8h#ppT)}Vd zNat^8JRRdkrC4>L+QS~a1l9OV$0X&CQ&P1B4lDyN1F0pl@<)NpQ+afCfrpJ0yo`0O z*>cZzyaFv4+rX474q;ATl;_7Xh#o$|5x}rOI#zgB(uvsK^8)AMfZgC{=~(&;HWRsf z4)|x(;o#-U1sOK#Bs1@MeD_=MJoN!`T-5O6xN7zR^?`ecLT@&Xv1f~Nv%(YBlA7*}YRbLUN%fPg3b{lro+I$|29r?Q#R7zcJIt?II zV{FdFsxg0E$f_{}Rm7?>1XaSSF$6W2RbvRMjE-3IdRR4vpeiu|t9s|r1nZ(&)mwu# zan*%#=pmxOo10$Yz_>Rn{|E)oW95^`%@(H007r9`s^!@6R)o%TA!?2sPf33T!yJC) zj`J{c|9SMm{XdJza`;R@^58D5LPlNTpnYEkuzmlHpqpZd^c+Pkz?l1<6KvO>{WQHj z11GeW+rt=JdljMd|4oA@&&;MAFak+us6uk}4PwNX?P$H!5a?xOGM#a`C)O(FH)kOKOIfr|D?h%7z09zgBpb4Y zD(P^GO5&@IS-TSwakdgI;R6!Jgi3roR1rHBjS}#PK18T)G(EIH$VWE zgS(5>f#1?(S^p>jV=s?ifB{EHf-)k;s?6a>w0|T*hd5#0V*}3FRcetST3nH=_yD1% zX+YK`7FDPo4|@?MFD%%i9G{M(_$dVR3BEF--Xujckc`Cc!pTe?d^9P3yw}KdOu$_? zldn&}my00&{numpLY0G=1DL>JYep3<7oag_yBxj_lEcNw92bX3seGCx>TzNi0J=a9 zyC@JXAHWcjR-QO^R1zOM($f$s%1>WMwD>se3ln(4v1&XqEdMBix2#ps+2?$~io!;F zDGUlJ;b0~@ghvSY0G*q~k8u;{W{t=_7eTB+?lRR=MpFfc(HhLNqcB2=c~2Mn0Ii@T zTE(TEP0qpC7zz3)ohhh=xrj&DE9?QP@klJ4Jx>*`_8O|c5Q$@KSq|+&<*U8hL6UYa zT~QlzaVSsdHbhfzDq^qASy0=3G#v25(%CHcH_{DMs45=>_av-wj4(bL!W;} z;|aO>RStchlIHoVKip3l^wO2Y4Cjr9954$gxAp)RF&rlhMwQ{nXEcUN?ZHtBzhRnB z<#GyKjTYL*4cIpQ_jrftf;`)Z`$M^h%!j%tSG^Q!EZ}qnKM%H)sdWLwnTKy7DF@Ck zt!rU*0l6;&6~d|{oC8kl_6pgZ7^x>s`cLXmZw=HZ)c6?4f4u6_kw01%a4i_dgm z^1_>kroxtd#HvW0g7r1#FeZ;fEQi#|A?jJ6wPRk{v~iV&jcc#bt|Plvg!=Kce}(8r zLn(trQ~&E}B!X%{%OVC8>~xQIo~O>QrE}?NR!uzWE(pO&z;oTaW`pn|NQ6ZF2QSiksTSS* z8q8C9i(!e!RPofv-yr|N26<3@%hc=O8OY(+@x&G^^DB2&N?3ZdnuTj2d~*M1AXASL z)1q9&5sC!LrG~}1aabKlEYwyy#1w2hJ>BWi9%#u$Kp1+h{v)tH2me_rZxIZOdzR7x z)DG0isM`%uD#T$>w4MaXF%fH82+nH$elCgjSF%jf5@7#lh89p z#R@7g#1$J=AE32k#uBR4g0+xPyo3A0X~#OH)moknBjVk6Wg)e6bwRd*4-cHi_-jM* zNfYsB5E|Rf(&_sV8i_ow5OqnB_Cw+_tDA?kvy7lL3y9?nG!R}zQwl;fU*G{jf%`3N zlDfm3kXJe0{T9BGX_zs!8bXY1VJ>V7>&BQcvNIDI-$C_75)r%-1vRDMV!);pT#zIM zIjQx|?YRrJ-0whb+QM|es}k| z)hN^&UYDWFh5mtLB_)TK(svvZWK#||0s~P~>uPWi{b<3?tGI@%9(MQkgPU?+CB5h8 zM9!)5D3j@O?D_`Ajd~ui$S=(0>vhPsr=9o7KwzWQ;AkAr&InuqFE2$N;>K;`^X`+ZZ(dReKj(k zR`8a(qLIE3a|5-L;eyvA2h(kP3id_D(rlB=x0%J6`8321-0yN>g7s-E%-7s z7Tb+)rTElzievg7P*0BofTILIGn)v(j5%_HXI4TLs-FfHb{{j!uOBCWZfgBK1p6X3 z?1&U#`(ObxSX0-s!&ge#)WuBV38_()BrQS*7<55K?)EkjrXu1O~oF zQ=3=tAbHEs&LxU(rOmdR)n=Qm2ZY$sQVPvyVR&Io=LRy|q#C{o?LQZvuYoOakrcq! zQkNCs=AzHpW~o?9PVUKT?A3x@1#iJAD=|p)9d&=)Ijr8bnDoP!;GjU))Gd}nw04Jo znSsm-x+v*bIqs_+|0$C6@FpZ`p^!!NNpRBS$Lj^dkf?$^3;-MDQlA_M{sr!9cvBhx$PBhBSx{PrJ)f5gWCS*so2SVW+>mxM5?gI33!L81*O#B^(L zkFTUO8=6QmxI_PAy!Oz35Ek2a`I1Y%A_T$6&ogZ07Gni)i*dNF&>`2On^dInlc;f0 zDL(OtdVv1{14#4<#|w_NObzON_7VuPU5|kBM(F@PDNDc91no2$Ua$D0YY|R3vTE~y9-PVN|LISqQJ!#}KttexEg8~k}4xz{K zxk&C_hv(G%2Dwn8kI8<>JD;3>Q3?=P6TtU3 z*u>bm_*M#cpc9HBhpMOt!3(MWfQkwQO};CaIhwlvEMyhqJleg63q98mD)OS?CTbcP z{P++MaP!Pzplxv%(_=Intbzv{gqvB2u;{z-{@DG_E+nH~>w!v}tA6KcJm75+IhEvV z%6&A$qPEv!xCClloJ<>c&;LL#g?kRy9EMz7NUnLM;hHaOVGH4!kHfnXu6dCu9q`V} z{||ZRKLFoO;+?Caq~xSmkdrQ&(Uqeu}7 zjEF_~ghOqddM<~aA!glcI@CXh!B>g{$0-Sl=%f;aZ?*DQ_h{~1d%vwk{Il=l*;_4jXh5v~UuaY6eC=pgr zZeuS(JGjQ(R3MX6=3O+tNhIelU5ka1G^R>Es8}*de&`Y5hmODlrf6aZxXkf;|=4bW^cb zbP{7U2!vL`If}1T^R>bJwa2MUP7B=G>4W3fwwooaYlD%TFB2sGgh5j{DX%TyvK;;<6dPnoeK|-h2(iGP6m=NW8X~(H^0Il<;o!+^f5%r zF6gm#1z_+!G>80-#bP);O5bCXN=3v)cAj?NKcYPoz;as4Xh>f84)N@Y-xycS`u` z43&C|)6uD%mP6Mfj@;J>!inQAqhZiGa^@2d+l#(w_%eXc@eE$axL=75 z?})aL%>jAn2w+_--lI3{06macA_WC31jfZ77melM4L|r7qDZp{t0gdk6f9(%zAo7U zIC0zpwygg}q9F7nu9#3kQnoOC`b7!TXJ2gW*#M;;rccITMrRf`+lA2WoU{Q%;-p;x z8euOf9&JmaRc~sT$HaPWd5{GCQSgCCnH$3wM$w0)uNco*#*wA31iu^7aYk4=0p&(v$;f-6JQk(4;$Z3|A$Zfe+Ln z1rJJu?Ia~QjzF$F=Eny$LOe3e7@VC|T43_U-x=3rxqzk59yz|TSC%dquWIgoy3?OAfTf>MUQ z@E<{`B#foJhHO>NKEwiDff}vy>W`p^OVn)STUNXqTXWLYh1vKLJ7*p0CxAM$a}mH7 z-cX;dU>wDcjiL(+JM|`7u8}6CBdTRb;BzV`mMx^S2UUUzej z$vw39AIs=xbYX91n2s8N)uB(2fL7Em`ZV~K9_qLZNzvD{W6tN1jM%|QJ-)D?I;f&) zdAUyFEe;I}?HJ+VAY_^LDXE>ozR~DTywQYSL`tSX(O)1v|Lrj(;O1Ab8Iy0n14BWW z3-*gU*Jj@Z1CgY@HqvW2-Kft(Lw$+J^X-ApM!PM|h0}18Y2q{+p9V3s7uoBFc>er~ z{Nc3U21|ncornzy6}k_3S0V2e^a_DWd2kdSLPYu{@PlZdm2rvCM=<6hu8!|&#n?z( zRm}LaP!-`(#1{N|fwZVW8@eO5(yGGtZ=&BV&Tr@ppuWic7WIXi!tg3w^dZEzQ8R>a ziOss5*Q(#4cI@8O=0TUA0;E4g?cBYq^UEkr7JXF4n1IGT+mK!QkiFfk7BtE5?Zjk5 z6onX?`ksb%)YE7{{iiUi__#%pO%4~Mg!&~Y0{W+<`c$&GIPmlh?M|Ak1XI&6^r2R9 zOL_z=NKqDIyTl@?`u!l>3AyhGB9MOHDa0UA$CGaE=6b$7(X7rVv#RI7=`c7bD{hcv zaZ&EO2#??-d96vDyvO1sh%G|}my~vktJLU?1!`fQ1_~ z?hjMyx|2%`Z{7GJ8U>8k;k|g|9K!fAub-1~C`mS#Qvw!;7T_t)ArGZyY%;2%(QJ&b zkc{$_<-u=aU&D4}fPT21g}L)dA&QTMKnjDlk%bW}i0gi;VTsx8U|@x(v8GF0~(4*!f`Z9B@TJxf>j2f;J-r9g82&A^t*&^37SE4Mjp!M}9fHY*m?-5;Rt`T7Al zREU?|cNWs(oQ~O8njjDM>?}oi_=KMWwYd8k#{?aIICDyN(~nl)NYMhPSb|x z;N#(C5>16H%qw_c6Vk&#ha4&b7ZE`O7OS8>49rj~vePTFu#QIsQ^@|~q#IgsMHLAY z{InbV@UzgWGy1E}!fkqg71lKI_V?;lq=7fnWg&F+W)GCqRdj(8bcdg&f?(R3?vMt~ zIIO-izJ*pt5hx~4gGZoMXB2_%Mw5Q^25voadE|x4uXsNReqV`UaH1aW7viIOSkPxm z2HtH&645GdreSCJ6Ea4S)pldRt|Cj%ichx;&~~aGzE3_;Qt*{B2ygc>8ef(BZl?D_ zeHg||y~c%pfmU)2eb);|mCMT22t!qh2-J=77~#jyq+O#2jn7>nTpK#(Y6T`Z0&l~0 z3B0X#Q$NC8ksEwN9_%LP-0!Z)lS2m_s67&q@hxZ>)L81Ut&GoyTnB(uw^dOKp|jrBj`AFLAKuJX6faQY1l*nYqhsvr2B-JaZ5u|Y)MVDYB8sq*2@^9 zFKYNnDhcMI(h4x6{y05E+a)1+TCZ?q@>?*7-&CS)Sl^>qRQ;*@r3ivy_HNi9P!W zU=mpE`R#T?7qu3RuHIPN}zs`HSX z$e{wfD!s0--E-@XGBifARJNU9ux6h@D%FPWDK_fi!}LRe&zr5YA|rSPbZyxtN@CCc zBcuLV6?QsF4U=h@9K!)PWn*}QPejrhOlqbc-b{UY1$=!UPJxv}L6{3`@=Y|;V~Nca z>XV-=tW0Lep_f4=smsvq96&eg3QYas8|Y=}a`?Y6J#IFcDeWaZN>*IBdC&3Q#KAGP z58m`79S8<}Z+TQ}kVt~^UxCLYp+o!lq+WsCS45GGo`KwR0X-%64&=U>K$1NK=W~cR z@ZSMKFF=XEb|^9L-sPZ8e-k)9erej+8QlC9V$Bzs-xI+<>wS=Bq*21txNm~epl+M9 zU{tIz=)DDVJw`Vd2D%Y*?x!8DbT-=M5FIJctB4Il@nHJdSR!y4#dwYSR!F!J!>Lk1 zr2D9}eD*Z9oxbWwV<+)-9*~Kr^nd#h89%@m#lWGxmWmRlFD1gLLk{H7Tq?-3eAE`l zB$D&4*{>!}s2VxjDgxo$H&|*_BNv?IIBoQ3kByQRI7X=>4jj(D_W>(0yR2*mVK`^= zY!tTgNR&KAdE;mL`N|tP{A=2iGnqJ2BZg6srAP1ji%=@zSCE#$8qwLoc()j-!dG)i zta*3V?0;WJLtLg!(X-z}PYgnRtt7L{i9SB6Ji{ac&@sdTfa*8u|r(C%mM0@(-R`g$Y76yYx+FR*!vKe&o zrSU8OzO2us;iwj)XN@BcOb{QIt;>wk#3+<3^Vv0DM$~r!JtciuHfo1p0>?it`ypkS zUgc6o%J7xl0n^XmjsnUhe1$2VhT<72wIH=5dQ1%vpjXhoR#ErgSCM#17?tgot-2 z&6=E_rF!U)t?+N4A0gwhSFeh}H>=xB##8S79wO0_*k3E?f5IYo{Ll_G5N93OBRVcL zU>Ts(x5~ix4gzWbbc*>73Qq1Z8mtH5)}xX0XTTf4iCXhL3pu;MBa<`_cc!>s9dd>e zUx=;`$wbK6PcOI>B_wkXA*(hdUUQ&ii+if^W{PsT64L+Ad=XJAg-)nm+cr72pLS}m|gC1(cB!A zIN_+tfQLAg1!_dKqbko(hVA%pX-ykx{#yMwTmy(C%W~p7+H55Ds(S?W`wI9*m2GrQ zHc_`k_U-LH#(|1a{Y-dEZde#^RZ)^aKg)ZWMN;rUfZtR2Z?RU2}~!Dsqm%xmGOEA-$^1|5{|k0_D!u>&vR^+JSE zwS-JDo>oc_5Y!MGGsc;pqpF~pRWhISGqexp z*49%_3JBo?qs#E#phd(vIJT4m1i%||xZ$ys(`1~{M>T?49n_a8X`^E*CNEZ7EAx!L zmVO6V;O5S~99{=ltUPju_am+xzKP!QK8_q-2-xVzCXUuz3ACTYUGDh}D%q-A)aOqy zgKpOCcL|2}<8}Kx1l0S0>BbBv%E*kZPkJZ(toY&xv^S&k0ziKTg^u!(7LaCjyr;_d z&%qC~`aV&59K z-#ZrZKJx`hx)%Sp&5@)7=V4#@MUpfG$K!{yBxwfz>97E2KJHU~lywpQ3-M1d^e}e* z3m966^@$FGxAkAwbxw4yYdr@>~u*21wu{fbux* zhag16_$i>zbKGgu#2584q%T>}^?*bwcK{NpJYwOtTDYHL)KaAPIv^451Rz1*ZWJ9% z164Ab1{uN(sT?jE7!2H30SO9j1te1G1(eUD`zoltj5jPFhB=T4TNTmEN z3;N%H1h4i35_w#S#02%LFf=bxuEYr+BE4?{65+mxj;aW^5|BvwJGcoBJp)MOyAzOz z`)5F+lt-+$fBmfa_9H+d#>F_pLxk%9B)Ap_(u*_aN5;L8<&oSX+8 zfCQxn0pSl^I|m36!v{$4>L{Qu@VCui1&BZ%=YtSY@>?wE`+!6qQ9!eKjKhFLZgf76 z$gK^K!2K@^w*pK-lLQ4j0SQ`801~uZf+C`L$oFAnAi`|`aRT=ZBqngL0Yc+ODu)0S za3}|)i*QYVF5E)q%IyAXyQk z4UmZOE?x=#6%?8$uAGk%HIZ*GAp9ZjL%4}>wu{YkN1R_a&o=q81r-*V^?Mm0(kmI# ztYV>wa-?4Z5>)-hg5I*A2@CqkB_^+CUTX5{LO=)rTFNmNBBcFRK%%x*UT)I-C?Fxv z?*q!`F*2?&p;>@L-1&e++?y>N0!wJ%pxJIgq&o!;joX0G$P5Tg#(=1-A{^C#fbuN} z6>Z?C=EYku+TS-iC=UVm@{ngKmwDWg88zAF?m>? zf?1S;X-UEKq+n>PmiU<||2PHnYzpS@`Re$1N~~ikn3)QjX0!>rj@}y6a zVsaWr`t=E4k4!lzLwp~8byLHw^-Ud3YXc@B9N*s5*3sPXNnezlauUdt$Ap7H=p*j& zueS4}Iog^M&f-Wt0fc`Xecf8(Lc_YXYnvJZCI{#+8@x!yCLRw$0aBtFA7ek&$JBYY zt*E5L+!8pEMS8gFS@ z1KBX5tXb94vaZ2+NI7VQXL9QA+NYK#xHh#snZdQq>&-J+^6@*>xhy5cb14{pEAeGg z((?HFC;l@zl=@YBj-GPKmx@*<+MFq`tw#@?w{mlPyM_1!pbOzn_Qla>ri4d&o>TRw zQmsDcP(xx;sWvt7t$-8DM{4h6o+b2bI!f@`JVe{FFN<%Ao zCth8+|DRoVlsyS4`-j?fe_1eqUvArx=Xdz|hl|!n?XG17Lz*{S1}B> zx>%l3&v&$27_$hMc(!as(tIhfihmGb0;8H5dYS)$c$Rj4sYwyMS9FjsHQAf^|AbMT zaIpBIU|dm77*7o1NY|whC)(v62u~0CFnSsA%dD;3{q6qA?OAJjbD>u-7v4{B25%$7h1{BssU!Mg5nc6XG63Dx!A@8 z?=H@ldA6|z3%sC)j%7!6Vd{zuyO)YI}jYTOr{f z*mXJbpzvLIFU(1`z*_OP?A`E|ies9N|0pJHYxgJ50BW_5Ii3+?TwJo{3;J!S?BS`} z%Sg!n2G2USrl@rRmd2GYoR4PvR4Yu+%C{>Usm#~qYt5J1o|?n{=M{Vx=1lI{Bk8d; zpliISIGWcS4R#b|iI`%m6U<=XOPJcCpX{^Xy^V%G%-M_0n1+3)IJI5bFmy9=#sm(O zfIh=UHure1n_@%bL~Y`7kgq{R*j}Z$g4P)F=whiMlPJ;!bh<|1f;xSqD!q9Zh=vN7 zPa6&K`%BsLzeyIo4aiHWT|JlQ+V|r(ITmLB604Q(cjG;on_5y|(nG_2}2@^l}CqS4mXK>lQ0qPR2N4 zh&7krVT+*q+a72u+Bnuv$)IH0ElD>ZrCm~JfRbcMsw7t}aaCRZVaW^qwN+uHTabz| zjm_+&a)ADt)n}awgXpTFaJn5T4_I+3OUFFE9iV;_c7+v4xl%M@oCo2<+1^QBEdq@&fYL+5lVftsh7pYZ_D?HSAY9Oe^#SI z{SBeVj3b{;W`rld)s4wz{~3O7L3y1nUb_$;WH_FRPw)<&nx!1dyi@PPEBc6m2%Hp`NYlZdaio(Y`uJz9(NA;^I$z4mXQd9(8(rRX(v!v!S;SMml!2d`B6A(?1ZJm}J;y7mwQM z^TFTWC=(}~D$z1oeD+bb6nJb)NAYxtEW5Y8z^*;;qFQr9(R1Mgp*DZ3Pw40!N)&cB ze{0R+Ye)6>$19eTbS8+}+uVTvV7PO*pT}Lqy?~qUO@_aT&glLAeRJe~D{goO@q4#G zL-@T%pi}szNb8MrHtwr{=(njiSZ@{d5+JyOfcu4wyK3W3LWmrXZ!tQH-+yzK`5D;68dgBxzmG1=`cO6i-g!=Gr?|y+E2c+oz z5YPjHn+K%mJqgE4kKpov6ulnOMVOX0J z=UreHDlq*29)VRkaX4&{tH9g?%#SKC4+0a0a-3BAfSIYl(C-q4Eje*=z!WPmUkBzd z6_}TRsXRU4XN&_|bLh+ivjF>YFlAsOFcF3Ej_LKo%A}7(Y1Q?=jp;$WRhN4-i=nl? zHvEF!s_S3ikQao%uAhwSo2^TMcX%*6J(zwE=AZ|Y^ZOv8+Wx0^s-1@nZ2fyf;}SH4h1?pIS;?2nU#1gR`n432oMsa#$4RH-iciU{c6Cg^zQIopnz4*IHX7+N4k?_d zG4XVAWN#vqOvfXgRsbS@DwT+hAadBkG4ewr@#?5V_b1FDJe;_Y78QTw { + const replaceText = (selector, text) => { + const element = document.getElementById(selector) + if (element) element.innerText = text + } + + for (const type of ['chrome', 'node', 'electron']) { + replaceText(`${type}-version`, process.versions[type]) + } +}) diff --git a/renderer.js b/renderer.js new file mode 100644 index 0000000..901d75e --- /dev/null +++ b/renderer.js @@ -0,0 +1,3 @@ +// This file is required by the index.html file and will +// be executed in the renderer process for that window. +// All of the Node.js APIs are available in this process. diff --git a/src/config.cpp b/src/config.cpp deleted file mode 100644 index c0d8416..0000000 --- a/src/config.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// -// Created by Anonymous275 on 1/28/2020. -// - -#include "main.h" -#include -#include -#include -#include "logger.h" -using namespace std; //nameSpace STD -void GenerateConfig(); -string RemoveComments(string Line); -string convertToString(char* a, int size); -void SetValues(string Line, int Index); -void SetMainValues(bool D,int P,string Name,string serverName); -bool D; -int P; -string M; -string S; - - -//Generates or Reads Config -void ParseConfig(){ - ifstream InFileStream; - InFileStream.open("Server.cfg"); - if(InFileStream.good()){ //Checks if Config Exists - info("Config Found Updating Values"); - string line; - int index = 1; - while (getline(InFileStream, line)) { - if(line.rfind('#', 0) != 0){ //Checks if it starts as Comment - string CleanLine = RemoveComments(line); //Cleans it from the Comments - SetValues(CleanLine,index); //sets the values - index++; - } - } - SetMainValues(D,P,M,S); //gives the values to Main - }else{ - info("Config Not Found Generating A new One"); - GenerateConfig(); - } - InFileStream.close(); -} - - - -void SetValues(string Line, int Index) { - int i = 0, state = 0; - char Data[50] = ""; - bool Switch = false; - if (Index > 2) { Switch = true; } - for (char &c : Line) { - if (Switch) { - if (c == '\"') { state++; } - if (state > 0 && state < 2) { - Data[i] = c; - i++; - } - } else { - if (c == ' ') { state++; } - if (state > 1) { - Data[i] = c; - i++; - } - } - } - for (int C = 1; C <= i; C++){ - Data[C-1] = Data[C]; - } - string::size_type sz; - bool Boolean = (convertToString(Data,i-1).find("true") != string::npos);//searches for "true" - switch (Index){ - case 1 : - if(Boolean){D = true;}else{D = false;}//checks and sets the Debug Value - break; - case 2 : P = stoi(Data, &sz);//sets the Port - break; - case 3 : M = Data; //Map - break; - case 4 : S = Data; //Name - } -} - - - -//generates default Config -void GenerateConfig(){ - ofstream FileStream; - FileStream.open ("Server.cfg"); - FileStream << "# This is the BeamNG-MP Server Configuration File\n" - "Debug = false # true or false to enable debug console output\n" - "Port = 30813 # Port to run the server on\n" - "Map = \"levels/gridmap/level.json\"\n" - "Name = \"BeamNG-MP FTW\""; - FileStream.close(); -} - - -string RemoveComments(string Line){ - int i = 0; - char Data[50] = ""; - for(char& c : Line) { - if(c == '#'){break;} //when it finds the # it will stop - Data[i] = c; - i++; - } - return convertToString(Data,i); //Converts it from a char array to string and returns it -} - -//Converts a char array or pointer to string -string convertToString(char* a, int size) -{ - int i; - string s = ""; - for (i = 0; i < size; i++) { - s = s + a[i]; - } - return s; -} \ No newline at end of file diff --git a/src/enet/callbacks.h b/src/enet/callbacks.h deleted file mode 100644 index aa4fc70..0000000 --- a/src/enet/callbacks.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - @file callbacks.h - @brief ENet callbacks -*/ -#ifndef __ENET_CALLBACKS_H__ -#define __ENET_CALLBACKS_H__ - -#include - -typedef struct _ENetCallbacks -{ - void * (ENET_CALLBACK * malloc) (size_t size); - void (ENET_CALLBACK * free) (void * memory); - void (ENET_CALLBACK * no_memory) (void); -} ENetCallbacks; - -/** @defgroup callbacks ENet internal callbacks - @{ - @ingroup private -*/ -extern void * enet_malloc (size_t); -extern void enet_free (void *); - -/** @} */ - -#endif /* __ENET_CALLBACKS_H__ */ - diff --git a/src/enet/enet.h b/src/enet/enet.h deleted file mode 100644 index c22a417..0000000 --- a/src/enet/enet.h +++ /dev/null @@ -1,607 +0,0 @@ -/** - @file enet.h - @brief ENet public header file -*/ -#ifndef __ENET_ENET_H__ -#define __ENET_ENET_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include - -#ifdef _WIN32 -#include "enet/win32.h" -#else -#include "enet/unix.h" -#endif - -#include "enet/types.h" -#include "enet/protocol.h" -#include "enet/list.h" -#include "enet/callbacks.h" - -#define ENET_VERSION_MAJOR 1 -#define ENET_VERSION_MINOR 3 -#define ENET_VERSION_PATCH 14 -#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) -#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) -#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) -#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF) -#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) - -typedef enet_uint32 ENetVersion; - -struct _ENetHost; -struct _ENetEvent; -struct _ENetPacket; - -typedef enum _ENetSocketType -{ - ENET_SOCKET_TYPE_STREAM = 1, - ENET_SOCKET_TYPE_DATAGRAM = 2 -} ENetSocketType; - -typedef enum _ENetSocketWait -{ - ENET_SOCKET_WAIT_NONE = 0, - ENET_SOCKET_WAIT_SEND = (1 << 0), - ENET_SOCKET_WAIT_RECEIVE = (1 << 1), - ENET_SOCKET_WAIT_INTERRUPT = (1 << 2) -} ENetSocketWait; - -typedef enum _ENetSocketOption -{ - ENET_SOCKOPT_NONBLOCK = 1, - ENET_SOCKOPT_BROADCAST = 2, - ENET_SOCKOPT_RCVBUF = 3, - ENET_SOCKOPT_SNDBUF = 4, - ENET_SOCKOPT_REUSEADDR = 5, - ENET_SOCKOPT_RCVTIMEO = 6, - ENET_SOCKOPT_SNDTIMEO = 7, - ENET_SOCKOPT_ERROR = 8, - ENET_SOCKOPT_NODELAY = 9 -} ENetSocketOption; - -typedef enum _ENetSocketShutdown -{ - ENET_SOCKET_SHUTDOWN_READ = 0, - ENET_SOCKET_SHUTDOWN_WRITE = 1, - ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 -} ENetSocketShutdown; - -#define ENET_HOST_ANY 0 -#define ENET_HOST_BROADCAST 0xFFFFFFFFU -#define ENET_PORT_ANY 0 - -/** - * Portable internet address structure. - * - * The host must be specified in network byte-order, and the port must be in host - * byte-order. The constant ENET_HOST_ANY may be used to specify the default - * server host. The constant ENET_HOST_BROADCAST may be used to specify the - * broadcast address (255.255.255.255). This makes sense for enet_host_connect, - * but not for enet_host_create. Once a server responds to a broadcast, the - * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. - */ -typedef struct _ENetAddress -{ - enet_uint32 host; - enet_uint16 port; -} ENetAddress; - -/** - * Packet flag bit constants. - * - * The host must be specified in network byte-order, and the port must be in - * host byte-order. The constant ENET_HOST_ANY may be used to specify the - * default server host. - - @sa ENetPacket -*/ -typedef enum _ENetPacketFlag -{ - /** packet must be received by the target peer and resend attempts should be - * made until the packet is delivered */ - ENET_PACKET_FLAG_RELIABLE = (1 << 0), - /** packet will not be sequenced with other packets - * not supported for reliable packets - */ - ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), - /** packet will not allocate data, and user must supply it instead */ - ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), - /** packet will be fragmented using unreliable (instead of reliable) sends - * if it exceeds the MTU */ - ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), - - /** whether the packet has been sent from all queues it has been entered into */ - ENET_PACKET_FLAG_SENT = (1<<8) -} ENetPacketFlag; - -typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); - -/** - * ENet packet structure. - * - * An ENet data packet that may be sent to or received from a peer. The shown - * fields should only be read and never modified. The data field contains the - * allocated data for the packet. The dataLength fields specifies the length - * of the allocated data. The flags field is either 0 (specifying no flags), - * or a bitwise-or of any combination of the following flags: - * - * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer - * and resend attempts should be made until the packet is delivered - * - * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets - * (not supported for reliable packets) - * - * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead - * - * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable - * (instead of reliable) sends if it exceeds the MTU - * - * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into - @sa ENetPacketFlag - */ -typedef struct _ENetPacket -{ - size_t referenceCount; /**< internal use only */ - enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ - enet_uint8 * data; /**< allocated data for packet */ - size_t dataLength; /**< length of data */ - ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ - void * userData; /**< application private data, may be freely modified */ -} ENetPacket; - -typedef struct _ENetAcknowledgement -{ - ENetListNode acknowledgementList; - enet_uint32 sentTime; - ENetProtocol command; -} ENetAcknowledgement; - -typedef struct _ENetOutgoingCommand -{ - ENetListNode outgoingCommandList; - enet_uint16 reliableSequenceNumber; - enet_uint16 unreliableSequenceNumber; - enet_uint32 sentTime; - enet_uint32 roundTripTimeout; - enet_uint32 roundTripTimeoutLimit; - enet_uint32 fragmentOffset; - enet_uint16 fragmentLength; - enet_uint16 sendAttempts; - ENetProtocol command; - ENetPacket * packet; -} ENetOutgoingCommand; - -typedef struct _ENetIncomingCommand -{ - ENetListNode incomingCommandList; - enet_uint16 reliableSequenceNumber; - enet_uint16 unreliableSequenceNumber; - ENetProtocol command; - enet_uint32 fragmentCount; - enet_uint32 fragmentsRemaining; - enet_uint32 * fragments; - ENetPacket * packet; -} ENetIncomingCommand; - -typedef enum _ENetPeerState -{ - ENET_PEER_STATE_DISCONNECTED = 0, - ENET_PEER_STATE_CONNECTING = 1, - ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, - ENET_PEER_STATE_CONNECTION_PENDING = 3, - ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, - ENET_PEER_STATE_CONNECTED = 5, - ENET_PEER_STATE_DISCONNECT_LATER = 6, - ENET_PEER_STATE_DISCONNECTING = 7, - ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, - ENET_PEER_STATE_ZOMBIE = 9 -} ENetPeerState; - -#ifndef ENET_BUFFER_MAXIMUM -#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) -#endif - -enum -{ - ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, - ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, - ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, - ENET_HOST_DEFAULT_MTU = 1400, - ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024, - ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024, - - ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, - ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, - ENET_PEER_PACKET_THROTTLE_SCALE = 32, - ENET_PEER_PACKET_THROTTLE_COUNTER = 7, - ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, - ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, - ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, - ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), - ENET_PEER_PACKET_LOSS_INTERVAL = 10000, - ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, - ENET_PEER_TIMEOUT_LIMIT = 32, - ENET_PEER_TIMEOUT_MINIMUM = 5000, - ENET_PEER_TIMEOUT_MAXIMUM = 30000, - ENET_PEER_PING_INTERVAL = 500, - ENET_PEER_UNSEQUENCED_WINDOWS = 64, - ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, - ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, - ENET_PEER_RELIABLE_WINDOWS = 16, - ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, - ENET_PEER_FREE_RELIABLE_WINDOWS = 8 -}; - -typedef struct _ENetChannel -{ - enet_uint16 outgoingReliableSequenceNumber; - enet_uint16 outgoingUnreliableSequenceNumber; - enet_uint16 usedReliableWindows; - enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; - enet_uint16 incomingReliableSequenceNumber; - enet_uint16 incomingUnreliableSequenceNumber; - ENetList incomingReliableCommands; - ENetList incomingUnreliableCommands; -} ENetChannel; - -/** - * An ENet peer which data packets may be sent or received from. - * - * No fields should be modified unless otherwise specified. - */ -typedef struct _ENetPeer -{ - ENetListNode dispatchList; - struct _ENetHost * host; - enet_uint16 outgoingPeerID; - enet_uint16 incomingPeerID; - enet_uint32 connectID; - enet_uint8 outgoingSessionID; - enet_uint8 incomingSessionID; - ENetAddress address; /**< Internet address of the peer */ - void * data; /**< Application private data, may be freely modified */ - ENetPeerState state; - ENetChannel * channels; - size_t channelCount; /**< Number of channels allocated for communication with peer */ - enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ - enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ - enet_uint32 incomingBandwidthThrottleEpoch; - enet_uint32 outgoingBandwidthThrottleEpoch; - enet_uint32 incomingDataTotal; - enet_uint32 outgoingDataTotal; - enet_uint32 lastSendTime; - enet_uint32 lastReceiveTime; - enet_uint32 nextTimeout; - enet_uint32 earliestTimeout; - enet_uint32 packetLossEpoch; - enet_uint32 packetsSent; - enet_uint32 packetsLost; - enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ - enet_uint32 packetLossVariance; - enet_uint32 packetThrottle; - enet_uint32 packetThrottleLimit; - enet_uint32 packetThrottleCounter; - enet_uint32 packetThrottleEpoch; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 packetThrottleInterval; - enet_uint32 pingInterval; - enet_uint32 timeoutLimit; - enet_uint32 timeoutMinimum; - enet_uint32 timeoutMaximum; - enet_uint32 lastRoundTripTime; - enet_uint32 lowestRoundTripTime; - enet_uint32 lastRoundTripTimeVariance; - enet_uint32 highestRoundTripTimeVariance; - enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ - enet_uint32 roundTripTimeVariance; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 reliableDataInTransit; - enet_uint16 outgoingReliableSequenceNumber; - ENetList acknowledgements; - ENetList sentReliableCommands; - ENetList sentUnreliableCommands; - ENetList outgoingReliableCommands; - ENetList outgoingUnreliableCommands; - ENetList dispatchedCommands; - int needsDispatch; - enet_uint16 incomingUnsequencedGroup; - enet_uint16 outgoingUnsequencedGroup; - enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; - enet_uint32 eventData; - size_t totalWaitingData; -} ENetPeer; - -/** An ENet packet compressor for compressing UDP packets before socket sends or receives. - */ -typedef struct _ENetCompressor -{ - /** Context data for the compressor. Must be non-NULL. */ - void * context; - /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ - size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); - /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ - size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); - /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ - void (ENET_CALLBACK * destroy) (void * context); -} ENetCompressor; - -/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ -typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount); - -/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ -typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event); - -/** An ENet host for communicating with peers. - * - * No fields should be modified unless otherwise stated. - - @sa enet_host_create() - @sa enet_host_destroy() - @sa enet_host_connect() - @sa enet_host_service() - @sa enet_host_flush() - @sa enet_host_broadcast() - @sa enet_host_compress() - @sa enet_host_compress_with_range_coder() - @sa enet_host_channel_limit() - @sa enet_host_bandwidth_limit() - @sa enet_host_bandwidth_throttle() - */ -typedef struct _ENetHost -{ - ENetSocket socket; - ENetAddress address; /**< Internet address of the host */ - enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ - enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ - enet_uint32 bandwidthThrottleEpoch; - enet_uint32 mtu; - enet_uint32 randomSeed; - int recalculateBandwidthLimits; - ENetPeer * peers; /**< array of peers allocated for this host */ - size_t peerCount; /**< number of peers allocated for this host */ - size_t channelLimit; /**< maximum number of channels allowed for connected peers */ - enet_uint32 serviceTime; - ENetList dispatchQueue; - int continueSending; - size_t packetSize; - enet_uint16 headerFlags; - ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; - size_t commandCount; - ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; - size_t bufferCount; - ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ - ENetCompressor compressor; - enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; - ENetAddress receivedAddress; - enet_uint8 * receivedData; - size_t receivedDataLength; - enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ - ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */ - size_t connectedPeers; - size_t bandwidthLimitedPeers; - size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */ - size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */ - size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */ -} ENetHost; - -/** - * An ENet event type, as specified in @ref ENetEvent. - */ -typedef enum _ENetEventType -{ - /** no event occurred within the specified time limit */ - ENET_EVENT_TYPE_NONE = 0, - - /** a connection request initiated by enet_host_connect has completed. - * The peer field contains the peer which successfully connected. - */ - ENET_EVENT_TYPE_CONNECT = 1, - - /** a peer has disconnected. This event is generated on a successful - * completion of a disconnect initiated by enet_peer_disconnect, if - * a peer has timed out, or if a connection request intialized by - * enet_host_connect has timed out. The peer field contains the peer - * which disconnected. The data field contains user supplied data - * describing the disconnection, or 0, if none is available. - */ - ENET_EVENT_TYPE_DISCONNECT = 2, - - /** a packet has been received from a peer. The peer field specifies the - * peer which sent the packet. The channelID field specifies the channel - * number upon which the packet was received. The packet field contains - * the packet that was received; this packet must be destroyed with - * enet_packet_destroy after use. - */ - ENET_EVENT_TYPE_RECEIVE = 3 -} ENetEventType; - -/** - * An ENet event as returned by enet_host_service(). - - @sa enet_host_service - */ -typedef struct _ENetEvent -{ - ENetEventType type; /**< type of the event */ - ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ - enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ - enet_uint32 data; /**< data associated with the event, if appropriate */ - ENetPacket * packet; /**< packet associated with the event, if appropriate */ -} ENetEvent; - -/** @defgroup global ENet global functions - @{ -*/ - -/** - Initializes ENet globally. Must be called prior to using any functions in - ENet. - @returns 0 on success, < 0 on failure -*/ -ENET_API int enet_initialize (void); - -/** - Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. - - @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use - @param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults - @returns 0 on success, < 0 on failure -*/ -ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits); - -/** - Shuts down ENet globally. Should be called when a program that has - initialized ENet exits. -*/ -ENET_API void enet_deinitialize (void); - -/** - Gives the linked version of the ENet library. - @returns the version number -*/ -ENET_API ENetVersion enet_linked_version (void); - -/** @} */ - -/** @defgroup private ENet private implementation functions */ - -/** - Returns the wall-time in milliseconds. Its initial value is unspecified - unless otherwise set. - */ -ENET_API enet_uint32 enet_time_get (void); -/** - Sets the current wall-time in milliseconds. - */ -ENET_API void enet_time_set (enet_uint32); - -/** @defgroup socket ENet socket functions - @{ -*/ -ENET_API ENetSocket enet_socket_create (ENetSocketType); -ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); -ENET_API int enet_socket_get_address (ENetSocket, ENetAddress *); -ENET_API int enet_socket_listen (ENetSocket, int); -ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); -ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); -ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); -ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); -ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); -ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); -ENET_API int enet_socket_get_option (ENetSocket, ENetSocketOption, int *); -ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown); -ENET_API void enet_socket_destroy (ENetSocket); -ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); - -/** @} */ - -/** @defgroup Address ENet address functions - @{ -*/ - -/** Attempts to parse the printable form of the IP address in the parameter hostName - and sets the host field in the address parameter if successful. - @param address destination to store the parsed IP address - @param hostName IP address to parse - @retval 0 on success - @retval < 0 on failure - @returns the address of the given hostName in address on success -*/ -ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostName); - -/** Attempts to resolve the host named by the parameter hostName and sets - the host field in the address parameter if successful. - @param address destination to store resolved address - @param hostName host name to lookup - @retval 0 on success - @retval < 0 on failure - @returns the address of the given hostName in address on success -*/ -ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName); - -/** Gives the printable form of the IP address specified in the address parameter. - @param address address printed - @param hostName destination for name, must not be NULL - @param nameLength maximum length of hostName. - @returns the null-terminated name of the host in hostName on success - @retval 0 on success - @retval < 0 on failure -*/ -ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength); - -/** Attempts to do a reverse lookup of the host field in the address parameter. - @param address address used for reverse lookup - @param hostName destination for name, must not be NULL - @param nameLength maximum length of hostName. - @returns the null-terminated name of the host in hostName on success - @retval 0 on success - @retval < 0 on failure -*/ -ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); - -/** @} */ - -ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); -ENET_API void enet_packet_destroy (ENetPacket *); -ENET_API int enet_packet_resize (ENetPacket *, size_t); -ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t); - -ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); -ENET_API void enet_host_destroy (ENetHost *); -ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32); -ENET_API int enet_host_check_events (ENetHost *, ENetEvent *); -ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32); -ENET_API void enet_host_flush (ENetHost *); -ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *); -ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); -ENET_API int enet_host_compress_with_range_coder (ENetHost * host); -ENET_API void enet_host_channel_limit (ENetHost *, size_t); -ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); -extern void enet_host_bandwidth_throttle (ENetHost *); -extern enet_uint32 enet_host_random_seed (void); - -ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *); -ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID); -ENET_API void enet_peer_ping (ENetPeer *); -ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32); -ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); -ENET_API void enet_peer_reset (ENetPeer *); -ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32); -ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32); -ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32); -ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32); -extern int enet_peer_throttle (ENetPeer *, enet_uint32); -extern void enet_peer_reset_queues (ENetPeer *); -extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *); -extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); -extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32); -extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16); -extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *); -extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *); -extern void enet_peer_on_connect (ENetPeer *); -extern void enet_peer_on_disconnect (ENetPeer *); - -ENET_API void * enet_range_coder_create (void); -ENET_API void enet_range_coder_destroy (void *); -ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); -ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); - -extern size_t enet_protocol_command_size (enet_uint8); - -#ifdef __cplusplus -} -#endif - -#endif /* __ENET_ENET_H__ */ - diff --git a/src/enet/list.h b/src/enet/list.h deleted file mode 100644 index f4ea53a..0000000 --- a/src/enet/list.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - @file list.h - @brief ENet list management -*/ -#ifndef __ENET_LIST_H__ -#define __ENET_LIST_H__ - -#include - -typedef struct _ENetListNode -{ - struct _ENetListNode * next; - struct _ENetListNode * previous; -} ENetListNode; - -typedef ENetListNode * ENetListIterator; - -typedef struct _ENetList -{ - ENetListNode sentinel; -} ENetList; - -extern void enet_list_clear (ENetList *); - -extern ENetListIterator enet_list_insert (ENetListIterator, void *); -extern void * enet_list_remove (ENetListIterator); -extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); - -extern size_t enet_list_size (ENetList *); - -#define enet_list_begin(list) ((list) -> sentinel.next) -#define enet_list_end(list) (& (list) -> sentinel) - -#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list)) - -#define enet_list_next(iterator) ((iterator) -> next) -#define enet_list_previous(iterator) ((iterator) -> previous) - -#define enet_list_front(list) ((void *) (list) -> sentinel.next) -#define enet_list_back(list) ((void *) (list) -> sentinel.previous) - -#endif /* __ENET_LIST_H__ */ - diff --git a/src/enet/protocol.h b/src/enet/protocol.h deleted file mode 100644 index 434fd47..0000000 --- a/src/enet/protocol.h +++ /dev/null @@ -1,198 +0,0 @@ -/** - @file protocol.h - @brief ENet protocol -*/ -#ifndef __ENET_PROTOCOL_H__ -#define __ENET_PROTOCOL_H__ - -#include "enet/types.h" - -enum -{ - ENET_PROTOCOL_MINIMUM_MTU = 576, - ENET_PROTOCOL_MAXIMUM_MTU = 4096, - ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, - ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, - ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, - ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, - ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, - ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, - ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 -}; - -typedef enum _ENetProtocolCommand -{ - ENET_PROTOCOL_COMMAND_NONE = 0, - ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, - ENET_PROTOCOL_COMMAND_CONNECT = 2, - ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, - ENET_PROTOCOL_COMMAND_DISCONNECT = 4, - ENET_PROTOCOL_COMMAND_PING = 5, - ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, - ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, - ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, - ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, - ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, - ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, - ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, - ENET_PROTOCOL_COMMAND_COUNT = 13, - - ENET_PROTOCOL_COMMAND_MASK = 0x0F -} ENetProtocolCommand; - -typedef enum _ENetProtocolFlag -{ - ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), - ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), - - ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), - ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), - ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, - - ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), - ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 -} ENetProtocolFlag; - -#ifdef _MSC_VER -#pragma pack(push, 1) -#define ENET_PACKED -#elif defined(__GNUC__) || defined(__clang__) -#define ENET_PACKED __attribute__ ((packed)) -#else -#define ENET_PACKED -#endif - -typedef struct _ENetProtocolHeader -{ - enet_uint16 peerID; - enet_uint16 sentTime; -} ENET_PACKED ENetProtocolHeader; - -typedef struct _ENetProtocolCommandHeader -{ - enet_uint8 command; - enet_uint8 channelID; - enet_uint16 reliableSequenceNumber; -} ENET_PACKED ENetProtocolCommandHeader; - -typedef struct _ENetProtocolAcknowledge -{ - ENetProtocolCommandHeader header; - enet_uint16 receivedReliableSequenceNumber; - enet_uint16 receivedSentTime; -} ENET_PACKED ENetProtocolAcknowledge; - -typedef struct _ENetProtocolConnect -{ - ENetProtocolCommandHeader header; - enet_uint16 outgoingPeerID; - enet_uint8 incomingSessionID; - enet_uint8 outgoingSessionID; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 channelCount; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 connectID; - enet_uint32 data; -} ENET_PACKED ENetProtocolConnect; - -typedef struct _ENetProtocolVerifyConnect -{ - ENetProtocolCommandHeader header; - enet_uint16 outgoingPeerID; - enet_uint8 incomingSessionID; - enet_uint8 outgoingSessionID; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 channelCount; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 connectID; -} ENET_PACKED ENetProtocolVerifyConnect; - -typedef struct _ENetProtocolBandwidthLimit -{ - ENetProtocolCommandHeader header; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; -} ENET_PACKED ENetProtocolBandwidthLimit; - -typedef struct _ENetProtocolThrottleConfigure -{ - ENetProtocolCommandHeader header; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; -} ENET_PACKED ENetProtocolThrottleConfigure; - -typedef struct _ENetProtocolDisconnect -{ - ENetProtocolCommandHeader header; - enet_uint32 data; -} ENET_PACKED ENetProtocolDisconnect; - -typedef struct _ENetProtocolPing -{ - ENetProtocolCommandHeader header; -} ENET_PACKED ENetProtocolPing; - -typedef struct _ENetProtocolSendReliable -{ - ENetProtocolCommandHeader header; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendReliable; - -typedef struct _ENetProtocolSendUnreliable -{ - ENetProtocolCommandHeader header; - enet_uint16 unreliableSequenceNumber; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendUnreliable; - -typedef struct _ENetProtocolSendUnsequenced -{ - ENetProtocolCommandHeader header; - enet_uint16 unsequencedGroup; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendUnsequenced; - -typedef struct _ENetProtocolSendFragment -{ - ENetProtocolCommandHeader header; - enet_uint16 startSequenceNumber; - enet_uint16 dataLength; - enet_uint32 fragmentCount; - enet_uint32 fragmentNumber; - enet_uint32 totalLength; - enet_uint32 fragmentOffset; -} ENET_PACKED ENetProtocolSendFragment; - -typedef union _ENetProtocol -{ - ENetProtocolCommandHeader header; - ENetProtocolAcknowledge acknowledge; - ENetProtocolConnect connect; - ENetProtocolVerifyConnect verifyConnect; - ENetProtocolDisconnect disconnect; - ENetProtocolPing ping; - ENetProtocolSendReliable sendReliable; - ENetProtocolSendUnreliable sendUnreliable; - ENetProtocolSendUnsequenced sendUnsequenced; - ENetProtocolSendFragment sendFragment; - ENetProtocolBandwidthLimit bandwidthLimit; - ENetProtocolThrottleConfigure throttleConfigure; -} ENET_PACKED ENetProtocol; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif - -#endif /* __ENET_PROTOCOL_H__ */ - diff --git a/src/enet/time.h b/src/enet/time.h deleted file mode 100644 index 46539af..0000000 --- a/src/enet/time.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - @file time.h - @brief ENet time constants and macros -*/ -#ifndef __ENET_TIME_H__ -#define __ENET_TIME_H__ - -#define ENET_TIME_OVERFLOW 86400000 - -#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) -#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) - -#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) - -#endif /* __ENET_TIME_H__ */ - diff --git a/src/enet/types.h b/src/enet/types.h deleted file mode 100644 index eab0603..0000000 --- a/src/enet/types.h +++ /dev/null @@ -1,13 +0,0 @@ -/** - @file types.h - @brief type definitions for ENet -*/ -#ifndef __ENET_TYPES_H__ -#define __ENET_TYPES_H__ - -typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ -typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ -typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ - -#endif /* __ENET_TYPES_H__ */ - diff --git a/src/enet/unix.h b/src/enet/unix.h deleted file mode 100644 index 93a67f6..0000000 --- a/src/enet/unix.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - @file unix.h - @brief ENet Unix header -*/ -#ifndef __ENET_UNIX_H__ -#define __ENET_UNIX_H__ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef MSG_MAXIOVLEN -#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN -#endif - -typedef int ENetSocket; - -#define ENET_SOCKET_NULL -1 - -#define ENET_HOST_TO_NET_16(value) (htons (value)) /**< macro that converts host to net byte-order of a 16-bit value */ -#define ENET_HOST_TO_NET_32(value) (htonl (value)) /**< macro that converts host to net byte-order of a 32-bit value */ - -#define ENET_NET_TO_HOST_16(value) (ntohs (value)) /**< macro that converts net to host byte-order of a 16-bit value */ -#define ENET_NET_TO_HOST_32(value) (ntohl (value)) /**< macro that converts net to host byte-order of a 32-bit value */ - -typedef struct -{ - void * data; - size_t dataLength; -} ENetBuffer; - -#define ENET_CALLBACK - -#define ENET_API extern - -typedef fd_set ENetSocketSet; - -#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) -#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) -#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) -#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) - -#endif /* __ENET_UNIX_H__ */ - diff --git a/src/enet/utility.h b/src/enet/utility.h deleted file mode 100644 index 6f7f473..0000000 --- a/src/enet/utility.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - @file utility.h - @brief ENet utility header -*/ -#ifndef __ENET_UTILITY_H__ -#define __ENET_UTILITY_H__ - -#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) -#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) - -#endif /* __ENET_UTILITY_H__ */ - diff --git a/src/enet/win32.h b/src/enet/win32.h deleted file mode 100644 index 5b2be16..0000000 --- a/src/enet/win32.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - @file win32.h - @brief ENet Win32 header -*/ -#ifndef __ENET_WIN32_H__ -#define __ENET_WIN32_H__ - -#ifdef _MSC_VER -#ifdef ENET_BUILDING_LIB -#pragma warning (disable: 4267) // size_t to int conversion -#pragma warning (disable: 4244) // 64bit to 32bit int -#pragma warning (disable: 4018) // signed/unsigned mismatch -#pragma warning (disable: 4146) // unary minus operator applied to unsigned type -#endif -#endif - -#include -#include - -typedef SOCKET ENetSocket; - -#define ENET_SOCKET_NULL INVALID_SOCKET - -#define ENET_HOST_TO_NET_16(value) (htons (value)) -#define ENET_HOST_TO_NET_32(value) (htonl (value)) - -#define ENET_NET_TO_HOST_16(value) (ntohs (value)) -#define ENET_NET_TO_HOST_32(value) (ntohl (value)) - -typedef struct -{ - size_t dataLength; - void * data; -} ENetBuffer; - -#define ENET_CALLBACK __cdecl - -#ifdef ENET_DLL -#ifdef ENET_BUILDING_LIB -#define ENET_API __declspec( dllexport ) -#else -#define ENET_API __declspec( dllimport ) -#endif /* ENET_BUILDING_LIB */ -#else /* !ENET_DLL */ -#define ENET_API extern -#endif /* ENET_DLL */ - -typedef fd_set ENetSocketSet; - -#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) -#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) -#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset)) -#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) - -#endif /* __ENET_WIN32_H__ */ - - diff --git a/src/logger.cpp b/src/logger.cpp deleted file mode 100644 index 2947d13..0000000 --- a/src/logger.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// -// Created by jojos38 on 28.01.2020. -// - - -#include "logger.h" -using namespace std; - -int loggerlevel; - -void setLoggerLevel(char level_string[]) { - if (!strcmp(level_string, "ALL")) - loggerlevel = 0; - - if (!strcmp(level_string, "DEBUG")) - loggerlevel = 1; - - if (!strcmp(level_string, "INFO")) - loggerlevel = 2; - - if (!strcmp(level_string, "WARN")) - loggerlevel = 3; - - if (!strcmp(level_string, "ERROR")) - loggerlevel = 4; - - if (!strcmp(level_string, "OFF")) - loggerlevel = 5; -} - -stringstream getDate() { - // current date/time based on current system - time_t now = time(0); - tm* ltm = localtime(&now); - - int month = 1 + ltm->tm_mon; - int day = ltm->tm_mday; - int hours = 1 + ltm->tm_hour; - int minutes = 1 + ltm->tm_min; - int seconds = 1 + ltm->tm_sec; - - string month_string; - if (month < 10) month_string = "0" + to_string(month); - else month_string = to_string(month); - - string day_string; - if (day < 10) day_string = "0" + to_string(day); - else day_string = to_string(day); - - string hours_string; - if (hours < 10) hours_string = "0" + to_string(hours); - else hours_string = to_string(hours); - - string minutes_string; - if (minutes < 10) minutes_string = "0" + to_string(minutes); - else minutes_string = to_string(minutes); - - string seconds_string; - if (seconds < 10) seconds_string = "0" + to_string(seconds); - else seconds_string = to_string(seconds); - - std::stringstream date; - date - << "[" - << day_string << "/" - << month_string << "/" - << 1900 + ltm->tm_year << " " - << hours_string << ":" - << minutes_string << ":" - << seconds_string - << "] "; - return date; -} - -/* -void info(char obj[]) { - if (level <= 2) - cout << getDate().str() << "\u001b[36m" << "[INFO]" << "\u001b[0m" << " " << obj << endl; -} - -void error(char obj[]) { - if (level <= 4) - cout << getDate().str() << "\x1B[31m" << "[ERRO]" << "\u001b[0m" << " " << obj << endl; -} - -void warn(char obj[]) { - if (level <= 3) - cout << getDate().str() << "\u001b[33m" << "[WARN]" << "\u001b[0m" << " " << obj << endl; -} - -void debug(char obj[]) { - if (level <= 1) - cout << getDate().str() << "\u001b[35m" << "[DBUG]" << "\u001b[0m" << " " << obj << endl; -}*/ \ No newline at end of file diff --git a/src/logger.h b/src/logger.h deleted file mode 100644 index 0df8c2b..0000000 --- a/src/logger.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Created by jojos38 on 28.01.2020. -// - -#ifndef LOGGER_H -#define LOGGER_H - -#include -#include -#include -#include -using namespace std; - -extern int loggerlevel; -stringstream getDate(); -void setLoggerLevel(char level_string[]); - -template -void info(const T& toPrint) { - if (loggerlevel <= 2) - cout << getDate().str() << "[INFO] " << toPrint << endl; -} -template -void error(const T& toPrint) { - if (loggerlevel <= 4) - cout << getDate().str() "[ERRO] " << toPrint << endl; -} - -template -void warn(const T& toPrint) { - if (loggerlevel <= 3) - cout << getDate().str() << "[WARN] " << toPrint << endl; -} - -template -void debug(const T& toPrint) { - if (loggerlevel <= 1) - cout << getDate().str() << "[DBUG] " << toPrint << endl; -} - -#endif // LOGGER_H diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 7a3e4d3..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Created by Anonymous275 on 28.01.2020. -// - -#include "main.h" -#include -#include -#include "enet/enet.h" -#include "network.h" -#include "logger.h" - -using namespace std; //nameSpace STD - -void DebugData(); -void ParseConfig(); - -bool Debug = false; -int Port = 30813; -string MapName = "levels/gridmap/level.json"; -string ServerName = "BeamNG-MP FTW"; - -//Entry -int main() { - ParseConfig(); - if(Debug){ //checks if debug is on - DebugData(); //Prints Debug Data - } - setLoggerLevel("ALL"); - startRUDP("localhost", 30814); -} - - -void DebugData(){ - cout << "Debug : true" << "\n"; - cout << "Port : " << Port << "\n"; - cout << "MapName : " << MapName << "\n"; - cout << "ServerName : " << ServerName << "\n"; -} - -void SetMainValues(bool D, int P,string Name,string serverName){ - Debug = D; - Port = P; - MapName = Name; - ServerName = serverName; -} - diff --git a/src/main.h b/src/main.h deleted file mode 100644 index e43af72..0000000 --- a/src/main.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by Антон on 28.01.2020. -// - -#ifndef BEAMNG_MP_SERVER_MAIN_H -#define BEAMNG_MP_SERVER_MAIN_H - -class main { - -}; - -#endif //BEAMNG_MP_SERVER_MAIN_H diff --git a/src/network.cpp b/src/network.cpp deleted file mode 100644 index f0fc9bb..0000000 --- a/src/network.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// Created by jojos38 on 28.01.2020. -// - -#include -#include "network.h" -#include "logger.h" -using namespace std; -#define EXIT_SUCCESS /*implementation defined*/ -#define EXIT_FAILURE /*implementation defined*/ - -void listen(); - -ENetAddress address; -ENetHost* server; -ENetEvent event; - -void startRUDP(char host[], int port) { - // ---------- Initializing ENet ---------- // - if (enet_initialize() != 0) { - fprintf(stderr, "An error occurred while initializing ENet.\n"); - return EXIT_FAILURE; - } - atexit(enet_deinitialize); - info("ENet initialized"); - - // ---------- Starting server ---------- // - enet_address_set_host(&address, host); // Set host - address.port = port; // Set port - server = enet_host_create( - &address /* the address to bind the server host to */, - 32 /* allow up to 32 clients and/or outgoing connections */, - 2 /* allow up to 2 channels to be used, 0 and 1 */, - 0 /* assume any amount of incoming bandwidth */, - 0 /* assume any amount of outgoing bandwidth */); - if (server == NULL) { - fprintf(stderr, "An error occurred while trying to create an ENet server host.\n"); - return EXIT_FAILURE; - } - info("Server started"); - listen(); -} - -void listen() { - info("Listening for packets..."); - while (true) { - switch (event.type) { - case ENET_EVENT_TYPE_CONNECT: - printf("A new client connected from %x:%u.\n", event.peer->address.host, event.peer->address.port); - /* Store any relevant client information here. */ - event.peer->data = "Client information"; - break; - case ENET_EVENT_TYPE_RECEIVE: - printf("A packet of length %u containing %s was received from %s on channel %u.\n", - event.packet->dataLength, - event.packet->data, - event.peer->data, - event.channelID); - /* Clean up the packet now that we're done using it. */ - enet_packet_destroy(event.packet); - break; - case ENET_EVENT_TYPE_DISCONNECT: - printf("%s disconnected.\n", event.peer->data); - /* Reset the peer's client information. */ - event.peer->data = NULL; - } - } -} \ No newline at end of file diff --git a/src/network.h b/src/network.h deleted file mode 100644 index 53a7ecf..0000000 --- a/src/network.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by jojos38 on 28.01.2020. -// - -#ifndef NETWORK_H -#define NETWORK_H - -#include "enet/enet.h" -#pragma comment(lib,"ws2_32.lib") -#pragma comment(lib,"winmm.lib") -#pragma comment(lib,"enet.lib") - -void startRUDP(char host[], int port); - -#endif // NETWORK_H