Compare commits

...

29 Commits

Author SHA1 Message Date
02794a2fb5 Remove matirx monitor box 2022-01-30 17:29:17 -06:00
0882e7e330 Pin postgres to 13 2021-10-01 12:36:32 -05:00
5f0ea6780c Correct an occurence of matrix.org to boba.best 2021-09-20 18:26:48 -05:00
7a6aad0436 Add meta tags for embeds on privacy policy 2021-09-18 22:22:21 -05:00
973b445d1f Change New Vector to boba.best in privacy policy 2021-09-18 21:53:08 -05:00
afd870c767 Remove unnecessary parts of privacy policy style 2021-09-18 18:38:02 -05:00
6a0ca701cc Improve accept button in privacy policy 2021-09-18 17:04:14 -05:00
a18b15c56b Add privacy policy 2021-09-18 16:23:31 -05:00
b5adfef2df Add command to control synapse processes only in manage.sh 2021-09-18 16:20:09 -05:00
036f8697ab Set network bridge name 2021-09-10 17:13:50 -05:00
57eea5681e Add matrix-monitor-bot 2021-09-08 17:25:21 -05:00
c0908ecff9 Add non-operational healthchecks to media-repo and mjolnir
Both those containers don't have curl somehow
2021-09-05 21:10:08 -05:00
b19c6b958f Add pantalaimon and mjolnir 2021-09-05 19:48:25 -05:00
2cda0911a2 Add matrix-media-repo to prometheus 2021-08-28 20:46:44 -05:00
f88ecf071e Add matrix-media-repo 2021-08-28 20:02:08 -05:00
a58a1b12c9 Revert removal of generic and sender workers 3 & 4
This reverts commits 0e7f3b6120,
70aa3d517e, and
b0627430bd
2021-08-27 18:21:00 -05:00
0e7f3b6120 Remove obsolete workers from prometheus config 2021-08-27 17:45:24 -05:00
70aa3d517e Remove generic3 and generic4 workers 2021-08-27 15:56:24 -05:00
b0627430bd Remove sender3 and sender4 2021-08-26 22:06:32 -05:00
65222e991e Move coturn out of docker
It entirely broke the docker daemon for me today.
2021-08-19 17:52:40 -05:00
6fcc5f7da0 Work with the latest docker-compose version on Debian 11 2021-08-19 16:45:07 -05:00
f3deb21a2f Remove unnecessary port for prometheus 2021-08-16 02:38:05 -05:00
9aa4dbae1f Add coturn 2021-08-13 16:46:25 -05:00
66fe5554e8 Fix hostnames in prometheus.yml 2021-08-07 15:40:47 -05:00
ccd4f2699f Remove postgres and redis from grafana network 2021-08-07 13:10:44 -05:00
6558ea9aa5 Track conf/ with git 2021-08-07 11:48:23 -05:00
4d31752d1a Move prometheus.yml to conf 2021-08-07 11:47:43 -05:00
14e468cc6f Remove exporters 2021-08-06 23:51:44 -05:00
442edefbe2 Revert "Move prometheus to grafana"
This reverts commit 8d98629d0c.
2021-08-06 23:50:50 -05:00
5 changed files with 333 additions and 136 deletions

59
conf/prometheus.yml Normal file
View File

@ -0,0 +1,59 @@
scrape_configs:
- job_name: "synapse"
scrape_interval: 15s
metrics_path: "/_synapse/metrics"
static_configs:
- targets: ["synapse:8008"]
labels:
instance: "matrix.boba.best"
job: "master"
index: 1
- targets: ["generic1:8008"]
labels:
instance: "matrix.boba.best"
job: "generic_worker"
index: 1
- targets: ["generic2:8008"]
labels:
instance: "matrix.boba.best"
job: "generic_worker"
index: 2
- targets: ["generic3:8008"]
labels:
instance: "matrix.boba.best"
job: "generic_worker"
index: 3
- targets: ["generic4:8008"]
labels:
instance: "matrix.boba.best"
job: "generic_worker"
index: 4
- targets: ["sender1:8008"]
labels:
instance: "matrix.boba.best"
job: "federation_sender"
index: 1
- targets: ["sender2:8008"]
labels:
instance: "matrix.boba.best"
job: "federation_sender"
index: 2
- targets: ["sender3:8008"]
labels:
instance: "matrix.boba.best"
job: "federation_sender"
index: 3
- targets: ["sender4:8008"]
labels:
instance: "matrix.boba.best"
job: "federation_sender"
index: 4
- job_name: "matrix-media-repo"
scrape_interval: 15s
static_configs:
- targets: ["media-repo:9000"]
labels:
instance: "matrix.boba.best"

View File

@ -0,0 +1,173 @@
<!doctype html>
<html lang="en">
<head>
<title>boba.best Privacy policy</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="title" content="boba.best Privacy Policy" />
<meta name="description" content="The Matrix protocol is designed with your privacy and data sovereignty in mind. Because it is a decentralised, federated service with cryptographically-validated message integrity, there are a few important things to know before you use the Service." />
<meta name="keywords" content="boba.best, privacy, policy" />
<meta property="og:title" content="boba.best Privacy Policy" />
<meta property="og:description" content="The Matrix protocol is designed with your privacy and data sovereignty in mind. Because it is a decentralised, federated service with cryptographically-validated message integrity, there are a few important things to know before you use the Service." />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://matrix.boba.best/_matrix/consent" />
<meta property="og:image" content="https://boba.best/img/boba_mochi.gif"/>
<meta property="og:site_name" content="boba.best" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:image" content="https://boba.best/img/boba_mochi.gif"/>
<meta name="twitter:title" content="boba.best Privacy Policy" />
<meta name="twitter:description" content="The Matrix protocol is designed with your privacy and data sovereignty in mind. Because it is a decentralised, federated service with cryptographically-validated message integrity, there are a few important things to know before you use the Service." />
<meta itemprop="title" content="boba.best Privacy Policy" />
<meta itemprop="description" content="The Matrix protocol is designed with your privacy and data sovereignty in mind. Because it is a decentralised, federated service with cryptographically-validated message integrity, there are a few important things to know before you use the Service." />
<style>
body {
margin: 100px auto;
max-width: 600px;
padding: 0px 25px;
font-family: 'Open Sans', Arial, sans-serif;
color: #24292e;
}
h1, h2, h3 {
font-weight: 500;
}
h1, h2 {
border-bottom: 1px solid #eaecef;
}
h1 {
font-size: 23pt;
padding-bottom: 20px;
}
h2 {
font-size: 17pt;
padding-top: 10px;
padding-bottom: 15px;
}
p, li {
line-height: 1.5em;
font-size: 10.5pt;
}
li {
margin-bottom: 10px;
}
input[type="submit"] {
opacity: 1;
margin: 10px auto;
display: block;
padding: 10px;
background-color: #fff;
color: #000;
border-radius: 3px;
border: 2px solid #888;
font-size: 16pt;
cursor: pointer;
}
input[type="submit"][disabled] {
opacity: 0.3;
cursor: default;
}
input[type="checkbox"] {
margin: 3px 10px 3px 0px;
}
</style>
</head>
<body>
<h1>Understand how your data is used</h1>
<p>
The Matrix protocol is designed with your privacy and data sovereignty in mind. Because it is a decentralised, federated service with cryptographically-validated message integrity, there are a few important things to know before you use the Service.
</p>
<p>
This Service (via the Matrix homeserver hosted at <a href="https://boba.best">https://boba.best</a>) is run and managed by <a href="https://bbaovanc.com" target="_blank">bbaovanc</a>.
</p>
<h2>Federation</h2>
<p>
Services using the Matrix protocol rely on Matrix homeservers which share user data with the wider ecosystem over federation.
</p>
<ul>
<li>
When you send messages or files in a room, a copy of the data is sent to all participants in the room. If these participants are registered on remote homeservers, your username, display name, messages and files may be replicated across each participating homeserver.
</li>
<li>
We will forget your copy of your data upon your request. We will also forward your request onto federated homeservers. However - these homeservers are outside our span of control, so we cannot guarantee they will forget your data.
</li>
<li>
Federated homeservers can be located anywhere in the world, and are subject to local laws and regulations.
</li>
</ul>
<h2>Bridging</h2>
<p>
Some Matrix rooms are bridged to third-party services, such as IRC networks, twitter or email. When a room has been bridged, your messages and media may be copied onto the bridged service.
</p>
<ul>
<li>
It may not be technically possible to support your management of your data once it has been copied onto a bridged service.
</li>
<li>
Bridged services can be located anywhere in the world, and are subject to local laws and regulations.
</li>
</ul>
<h2>Forgetting your Data</h2>
<p>
You can request that we forget your data if you deactivate your account. Each user in a Matrix conversation receives their own copy of all messages and files in that conversation (similar to email), so we ensure data is forgotten by ensuring that your data is not shared further and is not visible to future users. Once all users copies have been forgotten the messages and files will be deleted from the boba.best homeserver database. For full details, please see the <a href="https://matrix.org/legal/privacy-notice/" target="_blank">full privacy notice</a>.
</p>
<p>
If you remove (redact) a message, the message content will no longer be accessible to users. Redactions only remove message content, your display name and avatar - your username will still be visible. Federated homeservers and some matrix clients may not honour the redaction request.
</p>
<h2>Legal Basis for Processing</h2>
<p>
boba.best processes your data under Legitimate Interest. This means that we process your data only as necessary to deliver the Service, and in a manner that you understand and expect.
</p>
<p>
The Legitimate Interest of our Service is the provision of decentralised, openly-federated and (optionally) end-to-end encrypted communication services. The processing of user data we undertake is necessary to provide the Service. The nature of the Service and its implementation results in some caveats concerning this processing, particularly in terms of GDPR Article 17 Right to Erasure (Right to be Forgotten). We believe these caveats are in line with the broader societal interests served by providing the Service. These caveats are discussed in detail in the full privacy notice, but the most important restriction is that your username will still be publicly associated with rooms in which you have participated even if you deactivate your account and ask us to forget your data.
</p>
<p>
In situations where the interests of the individual appear to be in conflict with the broader societal interests, we will seek to reconcile those differences in accordance with our policy.
</p>
<p>
If any of the above are unacceptable to you, <b>please do not use the Service.</b>
</p>
<p>
Please review the <a href="https://matrix.org/legal/privacy-notice/" target="_blank">full privacy notice</a> and <a href="https://boba.best/rules/" target="_blank">boba.best rules</a> before using this Service.
</p>
<p>
Please review the <a href="https://matrix.org/legal/terms-and-conditions/" target="_blank">terms and conditions</a> before using this Service.
</p>
{% if has_consented %}
<hr>
<p>
Note: You have already accepted the privacy policy.
</p>
{% else %}
{% if not public_version %}
<hr>
<!-- The variables used here are only provided when the 'u' param is given to the homeserver -->
<form method="post" action="consent">
<input type="hidden" name="v" value="{{version}}"/>
<input type="hidden" name="u" value="{{user}}"/>
<input type="hidden" name="h" value="{{userhmac}}"/>
<input type="submit" value="Accept"/>
</form>
{% endif %}
{% endif %}
</body>
</html>

View File

@ -0,0 +1,11 @@
<!doctype html>
<html lang="en">
<head>
<title>boba.best Privacy policy</title>
</head>
<body>
<p>
Success.
</p>
</body>
</html>

View File

@ -10,7 +10,7 @@ services:
# - /var/run/docker.sock:/var/run/docker.sock # - /var/run/docker.sock:/var/run/docker.sock
postgres: postgres:
image: postgres:latest image: postgres:13
environment: environment:
- POSTGRES_USER=synapse - POSTGRES_USER=synapse
- POSTGRES_PASSWORD - POSTGRES_PASSWORD
@ -19,11 +19,6 @@ services:
volumes: volumes:
- ./data/postgres:/var/lib/postgresql/data/ - ./data/postgres:/var/lib/postgresql/data/
- ./progs:/progs - ./progs:/progs
networks:
default:
grafana:
aliases:
- synapse_postgres
restart: always restart: always
healthcheck: healthcheck:
test: pg_isready -U synapse -d synapsedb test: pg_isready -U synapse -d synapsedb
@ -34,11 +29,6 @@ services:
redis: redis:
image: redis:latest image: redis:latest
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_redis
healthcheck: healthcheck:
test: ["CMD", "redis-cli", "ping"] test: ["CMD", "redis-cli", "ping"]
interval: 10s interval: 10s
@ -48,255 +38,200 @@ services:
synapse: synapse:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_synapse
environment: environment:
- SYNAPSE_CONFIG_PATH=/data/homeserver.yaml - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
depends_on: depends_on:
postgres: - postgres
condition: service_healthy - redis
redis:
condition: service_healthy
ports: ports:
- 127.0.0.1:8008:8008/tcp - 127.0.0.1:8008:8008/tcp
labels: labels:
synapse-autoheal: "true" synapse-autoheal: "true"
mem_limit: 2G
sender1: sender1:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_sender1
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/sender1.yaml"] command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/sender1.yaml"]
environment: environment:
- SYNAPSE_WORKER=synapse.app.federation_sender - SYNAPSE_WORKER=synapse.app.federation_sender
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
- ./workers:/workers - ./workers:/workers
depends_on: depends_on:
synapse: - synapse
condition: service_healthy
healthcheck: healthcheck:
disable: true disable: true
mem_limit: 2G
sender2: sender2:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_sender2
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/sender2.yaml"] command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/sender2.yaml"]
environment: environment:
- SYNAPSE_WORKER=synapse.app.federation_sender - SYNAPSE_WORKER=synapse.app.federation_sender
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
- ./workers:/workers - ./workers:/workers
depends_on: depends_on:
synapse: - synapse
condition: service_healthy
healthcheck: healthcheck:
disable: true disable: true
mem_limit: 2G
sender3: sender3:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_sender3
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/sender3.yaml"] command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/sender3.yaml"]
environment: environment:
- SYNAPSE_WORKER=synapse.app.federation_sender - SYNAPSE_WORKER=synapse.app.federation_sender
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
- ./workers:/workers - ./workers:/workers
depends_on: depends_on:
synapse: - synapse
condition: service_healthy
healthcheck: healthcheck:
disable: true disable: true
mem_limit: 2G
sender4: sender4:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_sender4
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/sender4.yaml"] command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/sender4.yaml"]
environment: environment:
- SYNAPSE_WORKER=synapse.app.federation_sender - SYNAPSE_WORKER=synapse.app.federation_sender
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
- ./workers:/workers - ./workers:/workers
depends_on: depends_on:
synapse: - synapse
condition: service_healthy
healthcheck: healthcheck:
disable: true disable: true
mem_limit: 2G
media:
image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always
networks:
default:
grafana:
aliases:
- synapse_media
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/media.yaml"]
environment:
- SYNAPSE_WORKER=synapse.app.media_repository
volumes:
- ./data/synapse:/data
- ./workers:/workers
depends_on:
synapse:
condition: service_healthy
ports:
- 127.0.0.1:8009:8008
labels:
synapse-autoheal: "true"
mem_limit: 2G
generic1: generic1:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_generic1
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/generic.yaml"] command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/generic.yaml"]
environment: environment:
- SYNAPSE_WORKER=synapse.app.generic_worker - SYNAPSE_WORKER=synapse.app.generic_worker
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
- ./workers:/workers - ./workers:/workers
depends_on: depends_on:
synapse: - synapse
condition: service_healthy
ports: ports:
- 127.0.0.1:8010:8008/tcp - 127.0.0.1:8010:8008/tcp
labels: labels:
synapse-autoheal: "true" synapse-autoheal: "true"
mem_limit: 2G
generic2: generic2:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_generic2
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/generic.yaml"] command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/generic.yaml"]
environment: environment:
- SYNAPSE_WORKER=synapse.app.generic_worker - SYNAPSE_WORKER=synapse.app.generic_worker
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
- ./workers:/workers - ./workers:/workers
depends_on: depends_on:
synapse: - synapse
condition: service_healthy
ports: ports:
- 127.0.0.1:8011:8008/tcp - 127.0.0.1:8011:8008/tcp
labels: labels:
synapse-autoheal: "true" synapse-autoheal: "true"
mem_limit: 2G
generic3: generic3:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_generic3
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/generic.yaml"] command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/generic.yaml"]
environment: environment:
- SYNAPSE_WORKER=synapse.app.generic_worker - SYNAPSE_WORKER=synapse.app.generic_worker
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
- ./workers:/workers - ./workers:/workers
depends_on: depends_on:
synapse: - synapse
condition: service_healthy
ports: ports:
- 127.0.0.1:8012:8008/tcp - 127.0.0.1:8012:8008/tcp
labels: labels:
synapse-autoheal: "true" synapse-autoheal: "true"
mem_limit: 2G
generic4: generic4:
image: matrixdotorg/synapse:$SYNAPSE_TAG image: matrixdotorg/synapse:$SYNAPSE_TAG
restart: always restart: always
networks:
default:
grafana:
aliases:
- synapse_generic4
command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/generic.yaml"] command: ["run", "--config-path=/data/homeserver.yaml", "--config-path=/workers/replication.yaml", "--config-path=/workers/generic.yaml"]
environment: environment:
- SYNAPSE_WORKER=synapse.app.generic_worker - SYNAPSE_WORKER=synapse.app.generic_worker
volumes: volumes:
- ./data/synapse:/data - ./data/synapse:/data
- ./conf/templates:/templates
- ./workers:/workers - ./workers:/workers
depends_on: depends_on:
synapse: - synapse
condition: service_healthy
ports: ports:
- 127.0.0.1:8013:8008/tcp - 127.0.0.1:8013:8008/tcp
labels: labels:
synapse-autoheal: "true" synapse-autoheal: "true"
mem_limit: 2G
#redis_exporter: media-repo:
# image: oliver006/redis_exporter image: turt2live/matrix-media-repo:latest
# restart: always restart: always
# networks: ports:
# default: - 127.0.0.1:8000:8000
# grafana: volumes:
# aliases: - ./data/media-repo:/data
# - synapse_redis_exporter depends_on:
# environment: - postgres
# - REDIS_ADDR=redis://redis:6379 - redis
# depends_on: #healthcheck:
# redis: # test: curl -fSs http://localhost:8000/healthz || exit 1
# condition: service_healthy # interval: 15s
# timeout: 5s
# retries: 5
#postgres_exporter: pantalaimon:
# image: quay.io/prometheuscommunity/postgres-exporter:latest image: matrixdotorg/pantalaimon:latest
# restart: always restart: always
# networks: volumes:
# default: - ./data/pantalaimon:/data
# grafana:
# aliases: mjolnir:
# - synapse_postgres_exporter image: matrixdotorg/mjolnir:latest
# environment: restart: always
# - DATA_SOURCE_NAME=postgresql://synapse:$POSTGRES_PASSWORD@postgres:5432/synapsedb?sslmode=disable volumes:
# depends_on: - ./data/mjolnir:/data
# postgres: depends_on:
# condition: service_healthy - pantalaimon
#healthcheck:
# test: curl -fSs http://localhost:8080/healthz || exit 1
# interval: 15s
# timeout: 5s
# retries: 5
prometheus:
image: prom/prometheus:latest
restart: always
command:
- --config.file=/etc/prometheus/prometheus.yml
volumes:
- ./conf/prometheus.yml:/etc/prometheus/prometheus.yml
- ./data/prometheus:/prometheus
networks:
default:
grafana_default:
aliases:
- synapse_prometheus
networks: networks:
grafana: default:
driver_opts:
com.docker.network.bridge.name: br-synapse
grafana_default:
external: true external: true
name: grafana_default

View File

@ -40,6 +40,25 @@ case "$1" in
docker-compose exec postgres psql -U synapse -d synapsedb $@ docker-compose exec postgres psql -U synapse -d synapsedb $@
;; ;;
synapses)
shift
case "$1" in
stop)
docker-compose stop synapse generic1 generic2 generic3 generic4 sender1 sender2 sender3 sender4
;;
start)
docker-compose start synapse generic1 generic2 generic3 generic4 sender1 sender2 sender3 sender4
;;
restart)
docker-compose restart synapse generic1 generic2 generic3 generic4 sender1 sender2 sender3 sender4
;;
*)
echo "You have to choose a subcommand too, dummy."
esac
;;
*) *)
echo "You have to choose a command, dummy." echo "You have to choose a command, dummy."
;; ;;