项目作者: Thomas-Smyth

项目描述 :
Squad Server Script Framework
高级语言: JavaScript
项目地址: git://github.com/Thomas-Smyth/SquadJS.git
创建时间: 2020-01-29T14:03:17Z
项目社区:https://github.com/Thomas-Smyth/SquadJS

开源协议:Boost Software License 1.0

下载




Logo
Logo

#### SquadJS

GitHub release
GitHub contributors
GitHub release




GitHub issues
GitHub pull requests
GitHub issues
Discord




About

SquadJS is a scripting framework, designed for Squad servers, that aims to handle all communication and data collection to and from the servers. Using SquadJS as the base to any of your scripting projects allows you to easily write complex plugins without having to worry about the hassle of RCON or log parsing. However, for your convenience SquadJS comes shipped with multiple plugins already built for you allowing you to experience the power of SquadJS right away.


Using SquadJS

SquadJS relies on being able to access the Squad server log directory in order to parse logs live to collect information. Thus, SquadJS must be hosted on the same server box as your Squad server or be connected to your Squad server via FTP.

Prerequisites

Installation

  1. Download SquadJS and unzip the download.
  2. Open the unzipped folder in your terminal.
  3. Install the dependencies by running yarn install in your terminal. Due to the use of Yarn Workspaces it is important to use yarn install and not npm install as this will not work and will break stuff.
  4. Configure the config.json file. See below for more details.
  5. Start SquadJS by running node index.js in your terminal.

Note - If you are interested in testing versions of SquadJS not yet released please download/clone the master branch. Please also see here for more information on our versions and release procedures.


Configuring SquadJS

SquadJS can be configured via a JSON configuration file which, by default, is located in the SquadJS and is named config.json.

The config file needs to be valid JSON syntax. If an error is thrown saying the config cannot be parsed then try putting the config into a JSON syntax checker (there’s plenty to choose from that can be found via Google).


Server

## Server Configuration

The following section of the configuration contains information about your Squad server.

json "server": { "id": 1, "host": "xxx.xxx.xxx.xxx", "queryPort": 27165, "rconPort": 21114, "rconPassword": "password", "logReaderMode": "tail", "logDir": "C:/path/to/squad/log/folder", "ftp": { "host": "xxx.xxx.xxx.xxx", "port": 21, "user": "FTP Username", "password": "FTP Password" }, "sftp": { "host": "xxx.xxx.xxx.xxx", "port": 22, "username": "SFTP Username", "password": "SFTP Password" }, "adminLists": [ { "type": "local", "source": "C:/Users/Administrator/Desktop/Servers/sq_arty_party/SquadGame/ServerConfig/Admins.cfg", }, { "type": "remote", "source": "http://yourWebsite.com/Server1/Admins.cfg", }, { "type": "ftp", "source": "ftp://<user>:<password>@<host>:<port>/<url-path>", } ] },
id - An integer ID to uniquely identify the server. host - The IP of the server.
queryPort - The query port of the server. rconPort - The RCON port of the server.
rconPassword - The RCON password of the server. logReaderMode - tail will read from a local log file, ftp will read from a remote log file using the FTP protocol, sftp will read from a remote log file using the SFTP protocol.
logDir - The folder where your Squad logs are saved. Most likely will be C:/servers/squad_server/SquadGame/Saved/Logs. ftp - FTP configuration for reading logs remotely.
sftp - SFTP configuration for reading logs remotely. adminLists - Sources for identifying an admins on the server, either remote or local.

—-

Connectors

## Connector Configuration

Connectors allow SquadJS to communicate with external resources.
json "connectors": { "discord": "Discord Login Token", },
Connectors should be named, for example the above is named discord, and should have the associated config against it. Configs can be specified by name in plugin options. Should a connector not be needed by any plugin then the default values can be left or you can remove it from your config file.

See below for more details on connectors and their associated config.

##### Discord
Connects to Discord via discord.js.
json "discord": "Discord Login Token",
Requires a Discord bot login token.


##### Databases
SquadJS uses Sequelize to connect and use a wide range of SQL databases.

The connector should be configured using any of Sequelize’s single argument configuration options.

For example:
json "mysql": "mysql://user:pass@example.com:5432/dbname"

or:
json "sqlite": { "dialect": "sqlite", "storage": "path/to/database.sqlite" }

See Sequelize’s documentation for more details.

—-

Plugins

## Plugin Configuration

The plugins section in your config file lists all plugins built into SquadJS
json "plugins": [ { "plugin": "auto-tk-warn", "disabled": false, "message": "Please apologise for ALL TKs in ALL chat!" } ]

The disabled field can be toggled between true/ false to enabled/disable the plugin.

Plugin options are also specified. A full list of plugin options can be seen below.

—-

Verboseness

## Console Output Configuration

The logger section configures how verbose a module of SquadJS will be as well as the displayed color.
json "logger": { "verboseness": { "SquadServer": 1, "LogParser": 1, "RCON": 1 }, "colors": { "SquadServer": "yellowBright", "SquadServerFactory": "yellowBright", "LogParser": "blueBright", "RCON": "redBright" } }
The larger the number set in the verboseness section for a specified module the more it will print to the console.

—-


Plugins

The following is a list of plugins built into SquadJS, you can click their title for more information:

Interested in creating your own plugin? See more here


AutoKickUnassigned

AutoKickUnassigned


The AutoKickUnassigned plugin will automatically kick players that are not in a squad after a specified ammount of time.


Options


  • warningMessage


    Description

    Message SquadJS will send to players warning them they will be kicked


    Default

    1. Join a squad, you are unassigned and will be kicked

  • kickMessage


    Description

    Message to send to players when they are kicked


    Default

    1. Unassigned - automatically removed

  • frequencyOfWarnings


    Description

    How often in Seconds should we warn the player about being unassigned?


    Default

    1. 30

  • unassignedTimer


    Description

    How long in Seconds to wait before a unassigned player is kicked


    Default

    1. 360

  • playerThreshold


    Description

    Player count required for AutoKick to start kicking players, set to -1 to disable


    Default

    1. 93

  • roundStartDelay


    Description

    Time delay in Seconds from start of the round before AutoKick starts kicking again


    Default

    1. 900

  • ignoreAdmins


    Description

    • true: Admins will NOT be kicked
    • false: Admins WILL be kicked


    Default

    1. false

  • ignoreWhitelist


    Description

    • true: Reserve slot players will NOT be kicked
    • false: Reserve slot players WILL be kicked


    Default

    1. false


AutoTKWarn

AutoTKWarn


The AutoTkWarn plugin will automatically warn players with a message when they teamkill.


Options


  • attackerMessage


    Description

    The message to warn attacking players with.


    Default

    1. Please apologise for ALL TKs in ALL chat!

  • victimMessage


    Description

    The message that will be sent to the victim.


    Default

    1. null


CBLInfo

CBLInfo


The CBLInfo plugin alerts admins when a harmful player is detected joining their server based on data from the Community Ban List.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to alert admins through.


    Default

  • Example

    1. 667741905228136459

  • threshold


    Description

    Admins will be alerted when a player has this or more reputation points. For more information on reputation points, see the Community Ban List’s FAQ


    Default

    1. 6


ChatCommands

ChatCommands


The ChatCommands plugin can be configured to make chat commands that broadcast or warn the caller with present messages.


Options


  • commands


    Description

    An array of objects containing the following properties:

    • command - The command that initiates the message.
    • type - Either warn or broadcast.
    • response - The message to respond with.
    • ignoreChats - A list of chats to ignore the commands in. Use this to limit it to admins.


    Default

    1. [
      {
      command”: squadjs”,
      type”: warn”,
      response”: This server is powered by SquadJS.”,
      ignoreChats”: []
      }
      ]


DBLog

DBLog


The mysql-log plugin will log various server statistics and events to a database. This is great for server performance monitoring and/or player stat tracking.

Grafana:

  • Grafana is a cool way of viewing server statistics stored in the database.

  • Install Grafana.

  • Add your database as a datasource named SquadJS.

  • Import the SquadJS Dashboard to get a preconfigured MySQL only Grafana dashboard.

  • Install any missing Grafana plugins.


Options


  • database (Required)


    Description

    The Sequelize connector to log server information to.


    Default

    1. mysql

  • overrideServerID


    Description

    A overridden server ID.


    Default

    1. null


DiscordAdminBroadcast

DiscordAdminBroadcast


The DiscordAdminBroadcast plugin will send a copy of admin broadcasts made in game to a Discord channel.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log admin broadcasts to.


    Default

  • Example

    1. 667741905228136459

  • color


    Description

    The color of the embed.


    Default

    1. 16761867


DiscordAdminCamLogs

DiscordAdminCamLogs


The DiscordAdminCamLogs plugin will log in game admin camera usage to a Discord channel.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log admin camera usage to.


    Default

  • Example

    1. 667741905228136459

  • color


    Description

    The color of the embed.


    Default

    1. 16761867


DiscordAdminRequest

DiscordAdminRequest


The DiscordAdminRequest plugin will ping admins in a Discord channel when a player requests an admin via the !admin command in in-game chat.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log admin broadcasts to.


    Default

  • Example

    1. 667741905228136459

  • ignoreChats


    Description

    A list of chat names to ignore.


    Default

    1. []
  • Example

    1. [
      ChatSquad
      ]

  • ignorePhrases


    Description

    A list of phrases to ignore.


    Default

    1. []
  • Example

    1. [
      switch
      ]

  • command


    Description

    The command that calls an admin.


    Default

    1. admin

  • pingGroups


    Description

    A list of Discord role IDs to ping.


    Default

    1. []
  • Example

    1. [
      500455137626554379
      ]

  • pingHere


    Description

    Ping @here. Great if Admin Requests are posted to a Squad Admin ONLY channel, allows pinging only Online Admins.


    Default

    1. false

  • pingDelay


    Description

    Cooldown for pings in milliseconds.


    Default

    1. 60000

  • color


    Description

    The color of the embed.


    Default

    1. 16761867

  • warnInGameAdmins


    Description

    Should in-game admins be warned after a players uses the command and should we tell how much admins are active in-game right now.


    Default

    1. false

  • showInGameAdmins


    Description

    Should players know how much in-game admins there are active/online?


    Default

    1. true


DiscordChat

DiscordChat


The DiscordChat plugin will log in-game chat to a Discord channel.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log admin broadcasts to.


    Default

  • Example

    1. 667741905228136459

  • chatColors


    Description

    The color of the embed for each chat.


    Default

    1. {}
  • Example

    1. {
      ChatAll”: 16761867
      }

  • color


    Description

    The color of the embed.


    Default

    1. 16761867

  • ignoreChats


    Description

    A list of chat names to ignore.


    Default

    1. [
      ChatSquad
      ]


DiscordDebug

DiscordDebug


The DiscordDebug plugin can be used to help debug SquadJS by dumping SquadJS events to a Discord channel.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log events to.


    Default

  • Example

    1. 667741905228136459

  • events (Required)


    Description

    A list of events to dump.


    Default

    1. []
  • Example

    1. [
      PLAYER_DIED
      ]


DiscordFOBHABExplosionDamage

DiscordFOBHABExplosionDamage


The DiscordFOBHABExplosionDamage plugin logs damage done to FOBs and HABs by explosions to help identify engineers blowing up friendly FOBs and HABs.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log FOB/HAB explosion damage to.


    Default

  • Example

    1. 667741905228136459

  • color


    Description

    The color of the embeds.


    Default

    1. 16761867


DiscordKillFeed

DiscordKillFeed


The DiscordKillFeed plugin logs all wounds and related information to a Discord channel for admins to review.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log teamkills to.


    Default

  • Example

    1. 667741905228136459

  • color


    Description

    The color of the embeds.


    Default

    1. 16761867

  • disableCBL


    Description

    Disable Community Ban List information.


    Default

    1. false


DiscordPlaceholder

DiscordPlaceholder


The DiscordPlaceholder plugin allows you to make your bot create placeholder messages that can be used when configuring other plugins.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • command


    Description

    Command to create Discord placeholder.


    Default

    1. !placeholder

  • channelID (Required)


    Description

    The bot will only answer with a placeholder on this channel


    Default



DiscordRcon

DiscordRcon


The DiscordRcon plugin allows a specified Discord channel to be used as a RCON console to run RCON commands.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    ID of channel to turn into RCON console.


    Default

  • Example

    1. 667741905228136459

  • permissions


    Description


    Default

    1. {}
  • Example

    1. {
      123456789123456789”: [
      AdminBroadcast”,
      AdminForceTeamChange”,
      AdminDemoteCommander
      ]
      }

  • prependAdminNameInBroadcast


    Description

    Prepend admin names when making announcements.


    Default

    1. false


DiscordRoundWinner

DiscordRoundWinner


The DiscordRoundWinner plugin will send the round winner to a Discord channel.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log admin broadcasts to.


    Default

  • Example

    1. 667741905228136459

  • color


    Description

    The color of the embed.


    Default

    1. 16761867


DiscordRoundEnded

DiscordRoundEnded


The DiscordRoundEnded plugin will send the round winner to a Discord channel.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log round end events to.


    Default

  • Example

    1. 667741905228136459

  • color


    Description

    The color of the embed.


    Default

    1. 16761867


DiscordServerStatus

DiscordServerStatus


The DiscordServerStatus plugin can be used to get the server status in Discord.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • messageStore (Required)


    Description

    Sequelize connector name.


    Default

    1. sqlite

  • command


    Description

    Command name to get message.


    Default

    1. !status

  • disableSubscriptions


    Description

    Whether to allow messages to be subscribed to automatic updates.


    Default

    1. false

  • updateInterval


    Description

    How frequently to update the time in Discord.


    Default

    1. 60000

  • setBotStatus


    Description

    Whether to update the bot’s status with server information.


    Default

    1. true


DiscordSquadCreated

DiscordSquadCreated


The SquadCreated plugin will log Squad Creation events to a Discord channel.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log Squad Creation events to.


    Default

  • Example

    1. 667741905228136459

  • color


    Description

    The color of the embed.


    Default

    1. 16761867

  • useEmbed


    Description

    Send message as Embed


    Default

    1. true


DiscordSubsystemRestarter

DiscordSubsystemRestarter


The DiscordSubSystemRestarter plugin allows you to manually restart SquadJS subsystems in case an issues arises with them.

  • !squadjs restartsubsystem rcon
  • !squadjs restartsubsystem logparser


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • role (Required)


    Description

    ID of role required to run the sub system restart commands.


    Default

  • Example

    1. 667741905228136459


DiscordTeamkill

DiscordTeamkill


The DiscordTeamkill plugin logs teamkills and related information to a Discord channel for admins to review.


Options


  • discordClient (Required)


    Description

    Discord connector name.


    Default

    1. discord

  • channelID (Required)


    Description

    The ID of the channel to log teamkills to.


    Default

  • Example

    1. 667741905228136459

  • color


    Description

    The color of the embeds.


    Default

    1. 16761867

  • disableCBL


    Description

    Disable Community Ban List information.


    Default

    1. false


FogOfWar

FogOfWar


The FogOfWar plugin can be used to automate setting fog of war mode.


Options


  • mode


    Description

    Fog of war mode to set.


    Default

    1. 1

  • delay


    Description

    Delay before setting fog of war mode.


    Default

    1. 10000


IntervalledBroadcasts

IntervalledBroadcasts


The IntervalledBroadcasts plugin allows you to set broadcasts, which will be broadcasted at preset intervals


Options


  • broadcasts


    Description

    Messages to broadcast.


    Default

    1. []
  • Example

    1. [
      This server is powered by SquadJS.”
      ]

  • interval


    Description

    Frequency of the broadcasts in milliseconds.


    Default

    1. 300000


SeedingMode

SeedingMode


The SeedingMode plugin broadcasts seeding rule messages to players at regular intervals when the server is below a specified player count. It can also be configured to display “Live” messages when the server goes live.


Options


  • interval


    Description

    Frequency of seeding messages in milliseconds.


    Default

    1. 150000

  • seedingThreshold


    Description

    Player count required for server not to be in seeding mode.


    Default

    1. 50

  • seedingMessage


    Description

    Seeding message to display.


    Default

    1. Seeding Rules Active! Fight only over the middle flags! No FOB Hunting!

  • liveEnabled


    Description

    Enable “Live” messages for when the server goes live.


    Default

    1. true

  • liveThreshold


    Description

    Player count required for “Live” messages to not bee displayed.


    Default

    1. 52

  • liveMessage


    Description

    “Live” message to display.


    Default

    1. Live!

  • waitOnNewGames


    Description

    Should the plugin wait to be executed on NEW_GAME event.


    Default

    1. true

  • waitTimeOnNewGame


    Description

    The time to wait before check player counts in seconds.


    Default

    1. 30


SocketIOAPI

SocketIOAPI


The SocketIOAPI plugin allows remote access to a SquadJS instance via Socket.IO
As a client example you can use this to connect to the socket.io server;


  1. const socket = io.connect(‘ws://IP:PORT’, {
    auth: {
    token: MySecretPassword
    }
    })
If you need more documentation about socket.io please go ahead and read the following;
General Socket.io documentation: Socket.io Docs
Authentication and securing your websocket: Sending-credentials
How to use, install and configure a socketIO-client: Usage Guide with Examples


Options


  • websocketPort (Required)


    Description

    The port for the websocket.


    Default

  • Example

    1. 3000

  • securityToken (Required)


    Description

    Your secret token/password for connecting.


    Default

  • Example

    1. MySecretPassword


TeamRandomizer

TeamRandomizer


The TeamRandomizer can be used to randomize teams. It’s great for destroying clan stacks or for social events. It can be run by typing, by default, !randomize into in-game admin chat


Options


  • command


    Description

    The command used to randomize the teams.


    Default

    1. randomize


Statement on Accuracy

Some information SquadJS collects from Squad servers was never intended or designed to be collected. As a result, it is impossible for any framework to collect the same information with 100% accuracy. SquadJS aims to get as close as possible to that figure, however, it acknowledges that this is not possible in some specific scenarios.

Below is a list of scenarios we know may cause some information to be inaccurate:

  • Use of Realtime Server and Player Information - We update server and player information periodically every 30 seconds (by default) or when we know that it requires an update. As a result, some information about the server or players may be up to 30 seconds out of date or greater if an error occurs whilst updating this information.
  • SquadJS Restarts - If SquadJS is started during an active Squad game some information will be lost or not collected correctly:
    • The current state of players will be lost. For example, if a player was wounded prior to the bot starting and then is revived/gives up after the bot is started information regarding who originally wounded them will not be known.
    • The accurate collection of some server log events will not occur. SquadJS collects players’ “suffix” name, i.e. their Steam name without the clan tag added via the game settings, when they join the server and uses this to identify them in certain logs that do not include their full name. As a result, for players connecting prior to SquadJS starting some log events associated with their actions will show the player as null.
  • Duplicated Player Names - If two or more players have the same name or suffix name (see above) then SquadJS will be unable to identify them in the logs. When this occurs event logs will show the player as null. Be on the watch for groups of players who try to abuse this in order to TK or complete other malicious actions without being detected by SquadJS plugins.

SquadJS API

SquadJS pings the following data to the SquadJS API at regular intervals to assist with its development:

  • Squad server IP, query port, name & player count (including queue size).
  • SquadJS version.
  • Log reader mode, i.e. tail or ftp.
  • Plugin configuration.

At this time, this cannot be disabled.

Please note, plugin configurations do not and should not contain any sensitive information which allows us to collect this information. Any sensitive information, e.g. Discord login tokens, should be included in the connectors section of the config which is not sent to our API. It is important that developers of custom plugins maintain this approach to avoid submitting confidential information to our API.

Versions and Releases

Whilst installing SquadJS you may do the following to obtain slightly different versions:

  • Download the latest release - To get the latest stable version of SquadJS.
  • Download/clone the master branch - To get the most up to date version of SquadJS.

All changes proposed to SquadJS will be merged into the master branch prior to being released in the next stable version to allow for a period of larger-scale testing to occur. Therefore, we only recommend individuals who are willing to update regularly and partake in testing/bug reporting use the master branch. Please note, updates to the master branch will not be advertised in the SquadJS startup information, however, notifications of merged pull requests into the master branch may be found in our Discord. Once the master branch is deemed stable a release will be published and advertised via the SquadJS startup information and our Discord.

Releases will be given a version number with the format v{major}.{minor}.{patch}, e.g. v3.1.4. Changes to {major}/{minor}/{patch} will imply the following:

  • {major} - The release contains a new/updated feature that is (potentially) breaking, e.g. changes to event outputs that may cause custom plugins to break.
  • {minor} - The release contains a new/updated feature.
  • {patch} - The release contains a bug fix.

Please note, {minor}/{patch} releases may still break SquadJS installations, however, this may be prevented with configuration changes and should not require custom plugins to be updated.

Release version numbers and changelogs are managed by Release Drafter which relies on the appropriate labels being applied to pull requests. Version numbers are updated in the package.json file manually prior to publishing the release draft.

The above policy was written and put into effect after the release of SquadJS v2.0.5. A major version bump to SquadJS v3.0.0 was made to signify this policy taking affect and to draw a line under the previous poor management of releases and version numbers.

Credits

SquadJS would not be possible without the support of so many individuals and organisations. Our thanks goes out to:

  • SquadJS’s contributors.
  • Thomas Smyth’s GitHub sponsors.
  • subtlerod for proposing the initial log parsing idea, helping to design the log parsing process and for providing multiple servers to test with.
  • Shanomac99 and the rest of the Squad Wiki team for providing us with layer information.
  • Fourleaf, Mex, various members of ToG / ToG-L and others that helped to stage logs and participate in small scale tests.
  • Various Squad servers/communities for participating in larger scale tests and for providing feedback on plugins.
  • Everyone in the Squad RCON Discord and others who have submitted bug reports, suggestions, feedback and provided logs.

License

  1. Boost Software License - Version 1.0 - August 17th, 2003
  2. Copyright (c) 2020 Thomas Smyth
  3. Permission is hereby granted, free of charge, to any person or organization
  4. obtaining a copy of the software and accompanying documentation covered by
  5. this license (the "Software") to use, reproduce, display, distribute,
  6. execute, and transmit the Software, and to prepare derivative works of the
  7. Software, and to permit third-parties to whom the Software is furnished to
  8. do so, all subject to the following:
  9. The copyright notices in the Software and this entire statement, including
  10. the above license grant, this restriction and the following disclaimer,
  11. must be included in all copies of the Software, in whole or in part, and
  12. all derivative works of the Software, unless such copies or derivative
  13. works are solely in the form of machine-executable object code generated by
  14. a source language processor.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  18. SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  19. FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  20. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21. DEALINGS IN THE SOFTWARE.