Merge Upstream
Conflicts: README.md config.lua.example otouto/plugins/cleverbot.lua
This commit is contained in:
378
README.md
378
README.md
@@ -1,189 +1,189 @@
|
|||||||
# Mikubot V2
|
# Mikubot V2
|
||||||
[](https://travis-ci.org/Akamaru/Mikubot-V2)
|
[](https://travis-ci.org/Akamaru/Mikubot-V2)
|
||||||
|
|
||||||
Der multifunktionale Telegram-Bot.
|
Der multifunktionale Telegram-Bot.
|
||||||
|
|
||||||
[Offizielle Webseite](https://ponywave.de/projekte/mikubot-v2/) | [Entwickler auf Telegram](http://telegram.me/Akamaru) **KEIN SUPPORT!** | [Offizieller Telegram-Kanal](https://telegram.me/Mikubot_Updates)
|
[Offizielle Webseite](https://ponywave.de/projekte/mikubot-v2/) | [Entwickler auf Telegram](http://telegram.me/Akamaru) **KEIN SUPPORT!** | [Offizieller Telegram-Kanal](https://telegram.me/Mikubot_Updates)
|
||||||
|
|
||||||
Mikubot ist ein auf Plugins basierender Bot, der die [offizielle Telegram Bot API](http://core.telegram.org/bots/api) benutzt. Geforkt wurde er von [Brawlbot](https://github.com/Brawl345/Brawlbot-v2) Ursprünglich wurde er 2015 auf Basis von Yagops [Telegram Bot](https://github.com/yagop/telegram-bot/) entwickelt, da aber die Entwicklung von tg-cli [zum Stillstand](https://brawlbot.tk/posts/ein-neuanfang) gekommen ist, wurden alle Plugins des bisher proprietären Brawlbots im Juni 2016 auf die Bot-API portiert und open-sourced. Im Juli und August 2016 wurden die zusätzlichen Plugins von Mikubot ebenfalls auf die Bot-API migriert.
|
Mikubot ist ein auf Plugins basierender Bot, der die [offizielle Telegram Bot API](http://core.telegram.org/bots/api) benutzt. Geforkt wurde er von [Brawlbot](https://github.com/Brawl345/Brawlbot-v2) Ursprünglich wurde er 2015 auf Basis von Yagops [Telegram Bot](https://github.com/yagop/telegram-bot/) entwickelt, da aber die Entwicklung von tg-cli [zum Stillstand](https://brawlbot.tk/posts/ein-neuanfang) gekommen ist, wurden alle Plugins des bisher proprietären Brawlbots im Juni 2016 auf die Bot-API portiert und open-sourced. Im Juli und August 2016 wurden die zusätzlichen Plugins von Mikubot ebenfalls auf die Bot-API migriert.
|
||||||
**Mikubot V2 basiert auf [otouto](https://github.com/topkecleon/otouto) von topkecleon.**
|
**Mikubot V2 basiert auf [otouto](https://github.com/topkecleon/otouto) von topkecleon.**
|
||||||
|
|
||||||
Mikubot V2 ist freie Software; du darfst ihn modifizieren und weiterverbreiten, allerdings musst du dich an die GNU Affero General Public License v3 halten, siehe **LICENSE** für Details.
|
Mikubot V2 ist freie Software; du darfst ihn modifizieren und weiterverbreiten, allerdings musst du dich an die GNU Affero General Public License v3 halten, siehe **LICENSE** für Details.
|
||||||
|
|
||||||
##Anleitung
|
##Anleitung
|
||||||
|
|
||||||
| Für User | Für Entwickler|
|
| Für User | Für Entwickler|
|
||||||
|:----------------------------------------------|:------------------------------|
|
|:----------------------------------------------|:------------------------------|
|
||||||
| [Setup](#setup) | [Plugins](#plugins) |
|
| [Setup](#setup) | [Plugins](#plugins) |
|
||||||
| [Bot steuern](#bot-steuern) | [Bindings](#bindings) |
|
| [Bot steuern](#bot-steuern) | [Bindings](#bindings) |
|
||||||
| | [Datenbank](#datenbank)
|
| | [Datenbank](#datenbank)
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
# Für User
|
# Für User
|
||||||
## Setup
|
## Setup
|
||||||
### Ubuntu und Debian
|
### Ubuntu und Debian
|
||||||
Falls du Ubuntu oder Debian verwendest, kannst du einfach `./install-dependencies.sh` ausführen, damit alles installiert wird. Ergänze dann noch den `bot_api_key` und die `admin`-ID (Bekommst du in Telegram mit `@Mikubot id`) und kopiere die config.lua.example nach config.lua.
|
Falls du Ubuntu oder Debian verwendest, kannst du einfach `./install-dependencies.sh` ausführen, damit alles installiert wird. Ergänze dann noch den `bot_api_key` und die `admin`-ID (Bekommst du in Telegram mit `@Mikubot id`) und kopiere die config.lua.example nach config.lua.
|
||||||
|
|
||||||
####Optionale Pakete
|
####Optionale Pakete
|
||||||
Diese Pakete werden für `flip-text.lua`, `shell.lua`, `speedtest_cli.lua` und `youtube_dl.lua` benötigt.
|
Diese Pakete werden für `flip-text.lua`, `shell.lua`, `speedtest_cli.lua` und `youtube_dl.lua` benötigt.
|
||||||
* `sudo apt-get install -y cowsay scrot fswebcam vnstat vnstati youtube-dl npm`
|
* `sudo apt-get install -y cowsay scrot fswebcam vnstat vnstati youtube-dl npm`
|
||||||
* `sudo npm install -g flip-text`
|
* `sudo npm install -g flip-text`
|
||||||
* `wget -O speedtest https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py`
|
* `wget -O speedtest https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py`
|
||||||
* `chmod +x speedtest`
|
* `chmod +x speedtest`
|
||||||
* `sudo mv speedtest /usr/local/bin/speedtest`
|
* `sudo mv speedtest /usr/local/bin/speedtest`
|
||||||
|
|
||||||
Für eine manuelle Installation musst du LuaRocks für 5.2 [selbst kompilieren](http://stackoverflow.com/a/20359102).
|
Für eine manuelle Installation musst du LuaRocks für 5.2 [selbst kompilieren](http://stackoverflow.com/a/20359102).
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
Du benötigst **Lua 5.2** (Lua 5.3 funktioniert NICHT!), eine aktive **Redis-Instanz** und die folgenden **LuaRocks-Module**:
|
Du benötigst **Lua 5.2** (Lua 5.3 funktioniert NICHT!), eine aktive **Redis-Instanz** und die folgenden **LuaRocks-Module**:
|
||||||
* luautf8
|
* luautf8
|
||||||
* luasocket
|
* luasocket
|
||||||
* luasec
|
* luasec
|
||||||
* multipart-post
|
* multipart-post
|
||||||
* dkjson
|
* dkjson
|
||||||
* lpeg
|
* lpeg
|
||||||
* redis-lua
|
* redis-lua
|
||||||
* fakeredis
|
* fakeredis
|
||||||
* oauth
|
* oauth
|
||||||
* xml
|
* xml
|
||||||
* feedparser
|
* feedparser
|
||||||
* serpent
|
* serpent
|
||||||
|
|
||||||
Klone danach diese Repo. kopiere die `config.lua.example` nach `config.lua` und trage folgendes ein:
|
Klone danach diese Repo. kopiere die `config.lua.example` nach `config.lua` und trage folgendes ein:
|
||||||
|
|
||||||
- `bot_api_key`: API-Token vom BotFather
|
- `bot_api_key`: API-Token vom BotFather
|
||||||
- `admin`: Deine Telegram-ID
|
- `admin`: Deine Telegram-ID
|
||||||
|
|
||||||
Starte danach den Bot mit `sh launch.sh`. Um den Bot anzuhalten, führe erst `/halt` über Telegram aus.
|
Starte danach den Bot mit `sh launch.sh`. Um den Bot anzuhalten, führe erst `/halt` über Telegram aus.
|
||||||
|
|
||||||
Beim Start werden einige Werte in die Redis-Datenbank unter `telegram:credentials` und `telegram:enabled_plugins` eingetragen. Mit `/plugins enable` kannst du Plugins aktivieren, es sind nicht alle von Haus aus aktiviert.
|
Beim Start werden einige Werte in die Redis-Datenbank unter `telegram:credentials` und `telegram:enabled_plugins` eingetragen. Mit `/plugins enable` kannst du Plugins aktivieren, es sind nicht alle von Haus aus aktiviert.
|
||||||
|
|
||||||
Einige Plugins benötigen API-Keys, bitte gehe die einzelnen Plugins durch, bevor du sie aktivierst!
|
Einige Plugins benötigen API-Keys, bitte gehe die einzelnen Plugins durch, bevor du sie aktivierst!
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
|
|
||||||
## Bot steuern
|
## Bot steuern
|
||||||
Ein Administrator kann den Bot über folgende Plugins steuern:
|
Ein Administrator kann den Bot über folgende Plugins steuern:
|
||||||
|
|
||||||
| Plugin | Kommando | Funktion |
|
| Plugin | Kommando | Funktion |
|
||||||
|:----------------|:-----------|:---------------------------------------------------|
|
|:----------------|:-----------|:---------------------------------------------------|
|
||||||
| `banhammer.lua` | Siehe /hilfe banhammer| Blockt User vom Bot und kann Whitelist aktivieren
|
| `banhammer.lua` | Siehe /hilfe banhammer| Blockt User vom Bot und kann Whitelist aktivieren
|
||||||
| `control.lua` | /restart | Startet den Bot neu |
|
| `control.lua` | /restart | Startet den Bot neu |
|
||||||
| | /halt | Speichert die Datenbank und stoppt den Bot |
|
| | /halt | Speichert die Datenbank und stoppt den Bot |
|
||||||
| `plugins.lua` | /plugins enable/disable | Aktiviert/deaktiviert Plugins |
|
| `plugins.lua` | /plugins enable/disable | Aktiviert/deaktiviert Plugins |
|
||||||
| `shell.lua` | /cmd | Führt Shell-Kommandos aus |
|
| `shell.lua` | /cmd | Führt Shell-Kommandos aus |
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
|
|
||||||
## Liste aller Plugins
|
## Liste aller Plugins
|
||||||
|
|
||||||
Mikubot erhält laufend neue Plugins und wird kontinuierlich weiterentwickelt! Siehe [hier](https://github.com/Akamaru/Mikubot-V2/tree/master/miku/plugins) für eine Liste aller Plugins.
|
Mikubot erhält laufend neue Plugins und wird kontinuierlich weiterentwickelt! Siehe [hier](https://github.com/Akamaru/Mikubot-V2/tree/master/miku/plugins) für eine Liste aller Plugins.
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
#Für Entwickler
|
#Für Entwickler
|
||||||
## Plugins
|
## Plugins
|
||||||
Mikubot benutzt ein Plugin-System, ähnlich Yagops [Telegram-Bot](http://github.com/yagop/telegram-bot).
|
Mikubot benutzt ein Plugin-System, ähnlich Yagops [Telegram-Bot](http://github.com/yagop/telegram-bot).
|
||||||
|
|
||||||
Ein Plugin kann zehn Komponenten haben, aber nur zwei werden benötigt:
|
Ein Plugin kann zehn Komponenten haben, aber nur zwei werden benötigt:
|
||||||
|
|
||||||
| Komponente | Beschreibung | Benötigt? |
|
| Komponente | Beschreibung | Benötigt? |
|
||||||
|:------------------|:---------------------------------------------|:----------|
|
|:------------------|:---------------------------------------------|:----------|
|
||||||
| `plugin:action` | Hauptfunktion. Benötigt `msg` als Argument, empfohlen wird auch `matches` als drittes Argument nach `config` | J |
|
| `plugin:action` | Hauptfunktion. Benötigt `msg` als Argument, empfohlen wird auch `matches` als drittes Argument nach `config` | J |
|
||||||
| `plugin.triggers` | Tabelle von Triggern (Lua-Patterns), auf die der Bot reagiert | J |
|
| `plugin.triggers` | Tabelle von Triggern (Lua-Patterns), auf die der Bot reagiert | J |
|
||||||
| `plugin.inline_triggers` | Tabelle von Triggern (Lua-Patterns), auf die der Bot bei Inline-Querys reagiert | N |
|
| `plugin.inline_triggers` | Tabelle von Triggern (Lua-Patterns), auf die der Bot bei Inline-Querys reagiert | N |
|
||||||
| `plugin:init` | Optionale Funkion, die beim Start geladen wird | N |
|
| `plugin:init` | Optionale Funkion, die beim Start geladen wird | N |
|
||||||
| `plugin:cron` | Wird jede Minute ausgeführt | N |
|
| `plugin:cron` | Wird jede Minute ausgeführt | N |
|
||||||
| `plugin.command` | Einfaches Kommando mit Syntax. Wird bei `/hilfe` gelistet | N |
|
| `plugin.command` | Einfaches Kommando mit Syntax. Wird bei `/hilfe` gelistet | N |
|
||||||
| `plugin.doc` | Plugin-Hilfe. Wird mit `/help $kommando` gelistet | N |
|
| `plugin.doc` | Plugin-Hilfe. Wird mit `/help $kommando` gelistet | N |
|
||||||
| `plugin.error` | Plugin-spezifische Fehlermeldung | N |
|
| `plugin.error` | Plugin-spezifische Fehlermeldung | N |
|
||||||
| `plugin:callback` | Aktion, die ausgeführt wird, nachdem auf einen Callback-Button gedrückt wird. Siehe `gImages.lua` für ein Beispiel. Argumente: `callback` (enthält Callback-Daten), `msg`, `self`, `config`, `input` (enthält Parameter ohne `callback`) | N |
|
| `plugin:callback` | Aktion, die ausgeführt wird, nachdem auf einen Callback-Button gedrückt wird. Siehe `gImages.lua` für ein Beispiel. Argumente: `callback` (enthält Callback-Daten), `msg`, `self`, `config`, `input` (enthält Parameter ohne `callback`) | N |
|
||||||
| `plugin:inline_callback` | Aktion, die ausgeführt wird, wenn der Bot per Inline-Query ausgelöst wird. Argumente sind `inline_query` für die Daten, `config` und `matches` | N |
|
| `plugin:inline_callback` | Aktion, die ausgeführt wird, wenn der Bot per Inline-Query ausgelöst wird. Argumente sind `inline_query` für die Daten, `config` und `matches` | N |
|
||||||
|
|
||||||
|
|
||||||
Die`bot:on_msg_receive` Funktion fügt einige nützte Variablen zur ` msg` Tabelle hinzu. Diese sind:`msg.from.id_str`, `msg.to.id_str`, `msg.chat.id_str`, `msg.text_lower`, `msg.from.name`.
|
Die`bot:on_msg_receive` Funktion fügt einige nützte Variablen zur ` msg` Tabelle hinzu. Diese sind:`msg.from.id_str`, `msg.to.id_str`, `msg.chat.id_str`, `msg.text_lower`, `msg.from.name`.
|
||||||
|
|
||||||
Interaktionen mit der Bot-API sind sehr einfach. Siehe [Bindings](#bindings) für Details.
|
Interaktionen mit der Bot-API sind sehr einfach. Siehe [Bindings](#bindings) für Details.
|
||||||
|
|
||||||
Einige Funktionen, die oft benötigt werden, sind in `utilites.lua` verfügbar.
|
Einige Funktionen, die oft benötigt werden, sind in `utilites.lua` verfügbar.
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
|
|
||||||
## Bindings
|
## Bindings
|
||||||
Die Telegram-API wird mithilfe der `binding.lua` über die multipart-post Library kontaktiert. Mikubots Bindings-Datei unterstützt alle Standard API-Methoden und Argumente. Die Hauptufnktion `bindings.request` akzeptiert drei Parameter: `method`, `parameters` und `file`. Bevor du die Bindings-Datei nutzt, initialisiere das Modul mit der `init`-Funktion, wobei der Bot-Token als Argument übergeben werden sollte.
|
Die Telegram-API wird mithilfe der `binding.lua` über die multipart-post Library kontaktiert. Mikubots Bindings-Datei unterstützt alle Standard API-Methoden und Argumente. Die Hauptufnktion `bindings.request` akzeptiert drei Parameter: `method`, `parameters` und `file`. Bevor du die Bindings-Datei nutzt, initialisiere das Modul mit der `init`-Funktion, wobei der Bot-Token als Argument übergeben werden sollte.
|
||||||
|
|
||||||
`method` ist der Name der API-Methode (bspw. `sendMessage`), `parameters` (optional) ist eine Tabelle mit Schlüssel/Werte-Paaren der Parameter dieser Methode. `file` (optional) ist eine Tabelle mit einem einzigen Schlüssel/Werte-Paar, wobei der Schlüssel der Name de Parameters und der Wert der Dateiname oder die File-ID ist (wenn dies in den `parameters` übergeben wird, wird Mikubot den Dateinamen als File-ID senden).
|
`method` ist der Name der API-Methode (bspw. `sendMessage`), `parameters` (optional) ist eine Tabelle mit Schlüssel/Werte-Paaren der Parameter dieser Methode. `file` (optional) ist eine Tabelle mit einem einzigen Schlüssel/Werte-Paar, wobei der Schlüssel der Name de Parameters und der Wert der Dateiname oder die File-ID ist (wenn dies in den `parameters` übergeben wird, wird Mikubot den Dateinamen als File-ID senden).
|
||||||
|
|
||||||
Zusätzlich kann jede Methode als Schlüssel in der `bindings` Tabelle (zum Beispiel `bindings.getMe`) aufgerufen werden. Die `bindings.gen` Funktion (welche auch die `__index` Funktion in der Metatabelle ist) wird ihre Argumente an `bindings.request` in der richtigen Form übergeben. Mit diesem Weg sind die folgenden zwei Funktionsaufrufe gleich:
|
Zusätzlich kann jede Methode als Schlüssel in der `bindings` Tabelle (zum Beispiel `bindings.getMe`) aufgerufen werden. Die `bindings.gen` Funktion (welche auch die `__index` Funktion in der Metatabelle ist) wird ihre Argumente an `bindings.request` in der richtigen Form übergeben. Mit diesem Weg sind die folgenden zwei Funktionsaufrufe gleich:
|
||||||
|
|
||||||
```
|
```
|
||||||
bindings.request(
|
bindings.request(
|
||||||
'sendMessage',
|
'sendMessage',
|
||||||
{
|
{
|
||||||
chat_id = 987654321,
|
chat_id = 987654321,
|
||||||
text = 'Mikubot is best bot.',
|
text = 'Mikubot is best bot.',
|
||||||
reply_to_message_id = 54321,
|
reply_to_message_id = 54321,
|
||||||
disable_web_page_preview = false,
|
disable_web_page_preview = false,
|
||||||
parse_method = 'Markdown'
|
parse_method = 'Markdown'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
bindings.sendMessage{
|
bindings.sendMessage{
|
||||||
chat_id = 987654321,
|
chat_id = 987654321,
|
||||||
text = 'Mikubot is best bot.',
|
text = 'Mikubot is best bot.',
|
||||||
reply_to_message_id = 54321,
|
reply_to_message_id = 54321,
|
||||||
disable_web_page_preview = false,
|
disable_web_page_preview = false,
|
||||||
parse_method = 'Markdown'
|
parse_method = 'Markdown'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`utilities.lua` hat mehrere "Abkürzungen", die dir das leben einfacher machen. Z.b.:
|
`utilities.lua` hat mehrere "Abkürzungen", die dir das leben einfacher machen. Z.b.:
|
||||||
|
|
||||||
```
|
```
|
||||||
utilities.send_message(987654321, 'Mikubot is best bot.', false, 54321, true)
|
utilities.send_message(987654321, 'Mikubot is best bot.', false, 54321, true)
|
||||||
```
|
```
|
||||||
|
|
||||||
Eine Datei mit `sendPhoto` hochzuladen würde so aussehen:
|
Eine Datei mit `sendPhoto` hochzuladen würde so aussehen:
|
||||||
|
|
||||||
```
|
```
|
||||||
utilites.sendPhoto(987654321, 'photo.jpg', 'Beschreibungstext')
|
utilites.sendPhoto(987654321, 'photo.jpg', 'Beschreibungstext')
|
||||||
```
|
```
|
||||||
|
|
||||||
oder mit einer File-ID:
|
oder mit einer File-ID:
|
||||||
|
|
||||||
```
|
```
|
||||||
utilites.sendPhoto(987654321, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', 'Beschreibungstext')
|
utilites.sendPhoto(987654321, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', 'Beschreibungstext')
|
||||||
```
|
```
|
||||||
|
|
||||||
Falls erfolgreich, wird bindings das deserialisierte Ergebniss der API zurückgeben. Falls nicht erfolgreich, wird `false` und das Ergebnis zurückgegeben. Falls es einen Verbindungsfehler gab, werden zwei `false` Werte zurückgegeben. Wenn ein invalider Methodenname übergeben wurde, wird bindings eine Exception ausgeben. Damit sollen "stille Fehler" vermieden werden.
|
Falls erfolgreich, wird bindings das deserialisierte Ergebniss der API zurückgeben. Falls nicht erfolgreich, wird `false` und das Ergebnis zurückgegeben. Falls es einen Verbindungsfehler gab, werden zwei `false` Werte zurückgegeben. Wenn ein invalider Methodenname übergeben wurde, wird bindings eine Exception ausgeben. Damit sollen "stille Fehler" vermieden werden.
|
||||||
|
|
||||||
* * *
|
* * *
|
||||||
|
|
||||||
## Datenbank
|
## Datenbank
|
||||||
Mikubot benutzt eine interne Datenbank, wie Otouto sie benutzt und Redis. Die "Datenbank" ist eine Tabelle, auf die über die Variable `database` zugegriffen werden kann (normalerweise `self.database`) und die als JSON-encodierte Plaintext-Datei jede Stunde gespeichert wird oder wenn der Bot gestoppt wird (über `/halt`).
|
Mikubot benutzt eine interne Datenbank, wie Otouto sie benutzt und Redis. Die "Datenbank" ist eine Tabelle, auf die über die Variable `database` zugegriffen werden kann (normalerweise `self.database`) und die als JSON-encodierte Plaintext-Datei jede Stunde gespeichert wird oder wenn der Bot gestoppt wird (über `/halt`).
|
||||||
|
|
||||||
Das ist die Datenbank-Struktur:
|
Das ist die Datenbank-Struktur:
|
||||||
|
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
users = {
|
users = {
|
||||||
["55994550"] = {
|
["55994550"] = {
|
||||||
id = 55994550,
|
id = 55994550,
|
||||||
first_name = "Drew",
|
first_name = "Drew",
|
||||||
username = "topkecleon"
|
username = "topkecleon"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
userdata = {
|
userdata = {
|
||||||
["55994550"] = {
|
["55994550"] = {
|
||||||
nickname = "Best coder ever",
|
nickname = "Best coder ever",
|
||||||
lastfm = "topkecleon"
|
lastfm = "topkecleon"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
version = "2.1"
|
version = "2.1"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`database.users` speichert User-Informationen, wie Usernamen, IDs, etc., wenn der Bot den User sieht. Jeder Tabellen-Key ist die User-ID als String.
|
`database.users` speichert User-Informationen, wie Usernamen, IDs, etc., wenn der Bot den User sieht. Jeder Tabellen-Key ist die User-ID als String.
|
||||||
|
|
||||||
`database.userdata` speichert Daten von verschiedenen Plugins, hierzu wird aber für Mikubot-Plugins Redis verwendet.
|
`database.userdata` speichert Daten von verschiedenen Plugins, hierzu wird aber für Mikubot-Plugins Redis verwendet.
|
||||||
|
|
||||||
`database.version` speichert die Bot-Version.
|
`database.version` speichert die Bot-Version.
|
||||||
|
0
install-dependencies.sh
Executable file → Normal file
0
install-dependencies.sh
Executable file → Normal file
Reference in New Issue
Block a user