This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
jitsi [2020/04/29 19:30] willy [Jitsi] si quand meme avant de partir on rajoute celui-ci |
jitsi [2021/06/05 11:12] (current) willy |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | Repris et traduit depuis le site officiel, | + | Repris et traduit depuis le [[https://github.com/jitsi/ |dépôt officiel]], |
| >Jitsi est un ensemble de projets open-source qui vous permettent de facilement construire et déployer des solutions sécurisées de vidéoconférence. | >Jitsi est un ensemble de projets open-source qui vous permettent de facilement construire et déployer des solutions sécurisées de vidéoconférence. | ||
| >Au coeur de Jitsi on trouve Jitsi Vidéobridge et Jitsi Meet qui vous permettent d'organiser des conférences sur Internet... | >Au coeur de Jitsi on trouve Jitsi Vidéobridge et Jitsi Meet qui vous permettent d'organiser des conférences sur Internet... | ||
| - | Sur cette page nous présenterons l'usage de Jitsi au cmNOG. | + | Sur cette page nous présenterons l'usage de Jitsi au cmNOG |
| + | |||
| + | Principales fonctions utilisées | ||
| + | * vidéoconférence | ||
| + | * enregistrement local des conférences | ||
| + | * diffusion en direct sur Youtube | ||
| + | |||
| + | Afin d'améliorer la lisibilité, pour certains fichiers, nous ne présenterons que la différence entre le fichier à son installation et après modification. | ||
| ====== Environnement et versions employées ====== | ====== Environnement et versions employées ====== | ||
| Line 11: | Line 18: | ||
| ^ Instance ^ Hardware ^ Software ^ Notes^ | ^ Instance ^ Hardware ^ Software ^ Notes^ | ||
| | meet.cmnog.cm | CPU: 4 coeurs\\ RAM: 8 GB | OS: Debian 10\\ Jitsi-meet (2.0.4468-1)\\ Jitsi-videobridge2 (2.1-183-gdbddd169-1)\\ Jicofo (1.0-549-1)| | | | meet.cmnog.cm | CPU: 4 coeurs\\ RAM: 8 GB | OS: Debian 10\\ Jitsi-meet (2.0.4468-1)\\ Jitsi-videobridge2 (2.1-183-gdbddd169-1)\\ Jicofo (1.0-549-1)| | | ||
| - | | stream2.cmnog.cm | CPU: 4 coeurs\\ RAM: 8 GB | OS: ubuntu 20.04\\ Jibri (8.0-14-g0ccc3f6-1)| | | + | | stream2.cmnog.cm | CPU: 4 coeurs\\ RAM: 8 GB | OS: ubuntu 20.04\\ Jibri (8.0-14-g0ccc3f6-1)\\ ffmpeg (7:4.2.2-1ubuntu1)| | |
| Line 33: | Line 40: | ||
| Le logiciel recommande des entrées statiques dans le fichier /etc/hosts également. Le notre est donc | Le logiciel recommande des entrées statiques dans le fichier /etc/hosts également. Le notre est donc | ||
| - | <code bash> | + | <code diff> |
| - | root@vps2:~# cat /etc/hosts | + | diff --git a/hosts b/hosts |
| - | 127.0.0.1 localhost vps2 meet.cmnog.cm | + | index 45c0345..eee6c00 100644 |
| - | + | --- a/hosts | |
| - | # The following lines are desirable for IPv6 capable hosts | + | +++ b/hosts |
| - | ::1 localhost ip6-localhost ip6-loopback vps2 meet.cmnog.cm | + | @@ -1,6 +1,6 @@ |
| - | ff02::1 ip6-allnodes | + | -127.0.0.1 localhost vps2 |
| - | ff02::2 ip6-allrouter | + | +127.0.0.1 localhost vps2 meet.cmnog.cm |
| + | |||
| + | # The following lines are desirable for IPv6 capable hosts | ||
| + | -::1 localhost ip6-localhost ip6-loopback vps2 | ||
| + | +::1 localhost ip6-localhost ip6-loopback vps2 meet.cmnog.cm | ||
| + | ff02::1 ip6-allnodes | ||
| + | ff02::2 ip6-allrouters | ||
| </code> | </code> | ||
| Line 71: | Line 84: | ||
| </code> | </code> | ||
| - | Les clés seront utilisées dans la déclaration du virtualhost dans nginx | + | Les clés seront utilisées dans la déclaration du virtualhost dans nginx. |
| + | |||
| + | Jitsi aura besoin de certains comptes xmpp pour son fonctionnement. Les scripts d'installation créeront les comptes utilisés pour son fonctionnement interne. | ||
| + | Il faudra rajouter au moins 2 types de comptes: | ||
| + | |||
| + | * Pour ceux qui pourront ouvrir/gérer des salons | ||
| + | * Pour //Jibri//, qui aura besoin de deux comptes | ||
| + | |||
| + | Pour créer un compte il faut proceder ainsi | ||
| + | <code bash> | ||
| + | root@vps2:~# prosodyctl adduser JID | ||
| + | </code> | ||
| + | où ''JID'' correspond au compte à créer. Ex: me@meet.cmnog.cm | ||
| La configuration fait appel à la modification de certains logiciels. | La configuration fait appel à la modification de certains logiciels. | ||
| Line 78: | Line 103: | ||
| * /etc/nginx/sites-available/meet.cmnog.cm.conf | * /etc/nginx/sites-available/meet.cmnog.cm.conf | ||
| - | <code nginx> | + | <code diff> |
| - | server_names_hash_bucket_size 64; | + | diff --git a/nginx/sites-available/meet.cmnog.cm.conf b/nginx/sites-available/meet.cmnog.cm.conf |
| + | index 490ac7a..c862cc3 100644 | ||
| + | --- a/nginx/sites-available/meet.cmnog.cm.conf | ||
| + | +++ b/nginx/sites-available/meet.cmnog.cm.conf | ||
| + | @@ -27,8 +27,8 @@ server { | ||
| - | server { | + | add_header Strict-Transport-Security "max-age=31536000"; |
| - | listen 80; | + | |
| - | listen [::]:80; | + | |
| - | server_name meet.cmnog.cm; | + | |
| - | location ^~ /.well-known/acme-challenge/ { | + | - ssl_certificate /etc/jitsi/meet/meet.cmnog.cm.crt; |
| - | default_type "text/plain"; | + | - ssl_certificate_key /etc/jitsi/meet/meet.cmnog.cm.key; |
| - | root /usr/share/jitsi-meet; | + | + ssl_certificate /etc/letsencrypt/live/meet.cmnog.cm/fullchain.pem; |
| - | } | + | + ssl_certificate_key /etc/letsencrypt/live/meet.cmnog.cm/privkey.pem; |
| - | location = /.well-known/acme-challenge/ { | + | |
| - | return 404; | + | |
| - | } | + | |
| - | location / { | + | |
| - | return 301 https://$host$request_uri; | + | |
| - | } | + | |
| - | } | + | |
| - | server { | + | |
| - | listen 4444 ssl http2; | + | |
| - | listen [::]:4444 ssl http2; | + | |
| - | server_name meet.cmnog.cm; | + | |
| - | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; | + | root /usr/share/jitsi-meet; |
| - | ssl_prefer_server_ciphers on; | + | </code> |
| - | ssl_ciphers "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL:!eNULL:!MEDIUM:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SEED"; | + | * Le fichier ''/etc/nginx/modules-enables/60-jitsi-meet.conf'' est utilisé pour faire le mapping entre jitsi et nginx sur notamment les ports à utiliser |
| - | add_header Strict-Transport-Security "max-age=31536000"; | ||
| - | |||
| - | ssl_certificate /etc/letsencrypt/live/meet.cmnog.cm/fullchain.pem; | ||
| - | ssl_certificate_key /etc/letsencrypt/live/meet.cmnog.cm/privkey.pem; | ||
| - | |||
| - | root /usr/share/jitsi-meet; | ||
| - | |||
| - | # ssi on with javascript for multidomain variables in config.js | ||
| - | ssi on; | ||
| - | ssi_types application/x-javascript application/javascript; | ||
| - | |||
| - | index index.html index.htm; | ||
| - | error_page 404 /static/404.html; | ||
| - | |||
| - | location = /config.js { | ||
| - | alias /etc/jitsi/meet/meet.cmnog.cm-config.js; | ||
| - | } | ||
| - | |||
| - | location = /external_api.js { | ||
| - | alias /usr/share/jitsi-meet/libs/external_api.min.js; | ||
| - | } | ||
| - | |||
| - | #ensure all static content can always be found first | ||
| - | location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-known)/(.*)$ | ||
| - | { | ||
| - | add_header 'Access-Control-Allow-Origin' '*'; | ||
| - | alias /usr/share/jitsi-meet/$1/$2; | ||
| - | } | ||
| - | |||
| - | # BOSH | ||
| - | location = /http-bind { | ||
| - | proxy_pass http://localhost:5280/http-bind; | ||
| - | proxy_set_header X-Forwarded-For $remote_addr; | ||
| - | proxy_set_header Host $http_host; | ||
| - | } | ||
| - | |||
| - | # xmpp websockets | ||
| - | location = /xmpp-websocket { | ||
| - | proxy_pass http://127.0.0.1:5280/xmpp-websocket?prefix=$prefix&$args; | ||
| - | proxy_http_version 1.1; | ||
| - | proxy_set_header Upgrade $http_upgrade; | ||
| - | proxy_set_header Connection "upgrade"; | ||
| - | proxy_set_header Host $http_host; | ||
| - | tcp_nodelay on; | ||
| - | } | ||
| - | |||
| - | location ~ ^/([^/?&:'"]+)$ { | ||
| - | try_files $uri @root_path; | ||
| - | } | ||
| - | |||
| - | location @root_path { | ||
| - | rewrite ^/(.*)$ / break; | ||
| - | } | ||
| - | |||
| - | location ~ ^/([^/?&:'"]+)/config.js$ | ||
| - | { | ||
| - | set $subdomain "$1."; | ||
| - | set $subdir "$1/"; | ||
| - | |||
| - | alias /etc/jitsi/meet/meet.cmnog.cm-config.js; | ||
| - | } | ||
| - | |||
| - | #Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to / | ||
| - | location ~ ^/([^/?&:'"]+)/(.*)$ { | ||
| - | set $subdomain "$1."; | ||
| - | set $subdir "$1/"; | ||
| - | rewrite ^/([^/?&:'"]+)/(.*)$ /$2; | ||
| - | } | ||
| - | |||
| - | # BOSH for subdomains | ||
| - | location ~ ^/([^/?&:'"]+)/http-bind { | ||
| - | set $subdomain "$1."; | ||
| - | set $subdir "$1/"; | ||
| - | set $prefix "$1"; | ||
| - | |||
| - | rewrite ^/(.*)$ /http-bind; | ||
| - | } | ||
| - | |||
| - | # websockets for subdomains | ||
| - | location ~ ^/([^/?&:'"]+)/xmpp-websocket { | ||
| - | set $subdomain "$1."; | ||
| - | set $subdir "$1/"; | ||
| - | set $prefix "$1"; | ||
| - | |||
| - | rewrite ^/(.*)$ /xmpp-websocket; | ||
| - | } | ||
| - | } | ||
| - | |||
| - | </code> | ||
| - | * /etc/nginx/modules-enables/60-jitsi-meet.conf | ||
| <code nginx> | <code nginx> | ||
| # this is jitsi-meet nginx module configuration | # this is jitsi-meet nginx module configuration | ||
| Line 230: | Line 155: | ||
| </code> | </code> | ||
| ==== Coturn ==== | ==== Coturn ==== | ||
| - | * /etc/turnserver.conf | + | * Rien à modifir par défaut sur ''/etc/turnserver.conf'' |
| <code bash> | <code bash> | ||
| Line 253: | Line 178: | ||
| ==== Prosody ==== | ==== Prosody ==== | ||
| - | * /etc/prosody/conf.d/meet.cmnog.cm.cfg.lua | ||
| - | <code lua> | + | Configuration locale du serveur xmpp. |
| - | plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" } | + | |
| - | -- domain mapper options, must at least have domain base set to use the mapper | + | * ''/etc/prosody/conf.d/meet.cmnog.cm.cfg.lua'' |
| - | muc_mapper_domain_base = "meet.cmnog.cm"; | + | |
| - | turncredentials_secret = "IwannaBewithYouuuuuuuu"; | + | <code diff> |
| - | + | diff --git a/prosody/conf.avail/meet.cmnog.cm.cfg.lua b/prosody/conf.avail/meet.cmnog.cm.cfg.lua | |
| - | turncredentials = { | + | index 61a1443..b0b1f9a 100644 |
| - | { type = "stun", host = "meet.cmnog.cm", port = "443" }, | + | --- a/prosody/conf.avail/meet.cmnog.cm.cfg.lua |
| - | { type = "turn", host = "meet.cmnog.cm", port = "443", transport = "udp" }, | + | +++ b/prosody/conf.avail/meet.cmnog.cm.cfg.lua |
| - | { type = "turns", host = "meet.cmnog.cm", port = "443", transport = "tcp" } | + | @@ -16,7 +16,7 @@ consider_bosh_secure = true; |
| - | }; | + | |
| - | + | VirtualHost "meet.cmnog.cm" | |
| - | cross_domain_bosh = false; | + | -- enabled = false -- Remove this line to enable this host |
| - | consider_bosh_secure = true; | + | - authentication = "anonymous" |
| - | + | + authentication = "internal_plain" | |
| - | VirtualHost "meet.cmnog.cm" | + | -- Properties below are modified by jitsi-meet-tokens package config |
| - | -- enabled = false -- Remove this line to enable this host | + | -- and authentication above is switched to "token" |
| - | authentication = "internal_plain" | + | --app_id="example_app_id" |
| - | -- Properties below are modified by jitsi-meet-tokens package config | + | @@ -42,11 +42,22 @@ VirtualHost "meet.cmnog.cm" |
| - | -- and authentication above is switched to "token" | + | } |
| - | --app_id="example_app_id" | + | c2s_require_encryption = false |
| - | --app_secret="example_app_secret" | + | |
| - | -- Assign this host a certificate for TLS, otherwise it would use the one | + | +VirtualHost "guest.meet.cmnog.cm" |
| - | -- set in the global section (if any). | + | + authentication = "anonymous" |
| - | -- Note that old-style SSL on port 5223 only supports one certificate, and will always | + | + c2s_require_encryption = false |
| - | -- use the global one. | + | + |
| - | ssl = { | + | +VirtualHost "recorder.meet.cmnog.cm" |
| - | key = "/etc/prosody/certs/meet.cmnog.cm.key"; | + | + modules_enabled = { |
| - | certificate = "/etc/prosody/certs/meet.cmnog.cm.crt"; | + | + "ping"; |
| - | } | + | + } |
| - | speakerstats_component = "speakerstats.meet.cmnog.cm" | + | + authentication = "internal_plain" |
| - | conference_duration_component = "conferenceduration.meet.cmnog.cm" | + | + |
| - | -- we need bosh | + | Component "conference.meet.cmnog.cm" "muc" |
| - | modules_enabled = { | + | storage = "memory" |
| - | "bosh"; | + | modules_enabled = { |
| - | "pubsub"; | + | "muc_meeting_id"; |
| - | "ping"; -- Enable mod_ping | + | "muc_domain_mapper"; |
| - | "speakerstats"; | + | + "muc_mam"; |
| - | "turncredentials"; | + | -- "token_verification"; |
| - | "conference_duration"; | + | } |
| - | } | + | admins = { "focus@auth.meet.cmnog.cm" } |
| - | c2s_require_encryption = false | + | @@ -56,6 +67,7 @@ Component "conference.meet.cmnog.cm" "muc" |
| - | + | -- internal muc component | |
| - | VirtualHost "guest.meet.cmnog.cm" | + | Component "internal.auth.meet.cmnog.cm" "muc" |
| - | authentication = "anonymous" | + | storage = "memory" |
| - | c2s_require_encryption = false | + | + muc_room_cache_size = 1000 |
| - | + | modules_enabled = { | |
| - | VirtualHost "recorder.meet.cmnog.cm" | + | "ping"; |
| - | modules_enabled = { | + | } |
| - | "ping"; | + | |
| - | } | + | |
| - | authentication = "internal_plain" | + | |
| - | + | ||
| - | Component "conference.meet.cmnog.cm" "muc" | + | |
| - | storage = "memory" | + | |
| - | modules_enabled = { | + | |
| - | "muc_meeting_id"; | + | |
| - | "muc_domain_mapper"; | + | |
| - | "muc_mam"; | + | |
| - | -- "token_verification"; | + | |
| - | } | + | |
| - | admins = { "focus@auth.meet.cmnog.cm" } | + | |
| - | muc_room_locking = false | + | |
| - | muc_room_default_public_jids = true | + | |
| - | + | ||
| - | + | ||
| - | -- internal muc component | + | |
| - | Component "internal.auth.meet.cmnog.cm" "muc" | + | |
| - | storage = "memory" | + | |
| - | muc_room_cache_size = 1000 | + | |
| - | modules_enabled = { | + | |
| - | "ping"; | + | |
| - | } | + | |
| - | admins = { "focus@auth.meet.cmnog.cm", "jvb@auth.meet.cmnog.cm" } | + | |
| - | + | ||
| - | VirtualHost "auth.meet.cmnog.cm" | + | |
| - | ssl = { | + | |
| - | key = "/etc/prosody/certs/auth.meet.cmnog.cm.key"; | + | |
| - | certificate = "/etc/prosody/certs/auth.meet.cmnog.cm.crt"; | + | |
| - | } | + | |
| - | authentication = "internal_plain" | + | |
| - | + | ||
| - | Component "focus.meet.cmnog.cm" | + | |
| - | component_secret = "bumbleBe33" | + | |
| - | + | ||
| - | Component "speakerstats.meet.cmnog.cm" "speakerstats_component" | + | |
| - | muc_component = "conference.meet.cmnog.cm" | + | |
| - | + | ||
| - | Component "conferenceduration.meet.cmnog.cm" "conference_duration_component" | + | |
| - | muc_component = "conference.meet.cmnog.cm" | + | |
| </code> | </code> | ||
| ==== Jitsi ==== | ==== Jitsi ==== | ||
| - | * /etc/jitsi/meet/meet.cmnog.cm-config.js | ||
| - | <code javascript> | + | Les modifications locales vont porter sur 2 fichiers. |
| - | /* eslint-disable no-unused-vars, no-var */ | + | |
| - | var config = { | + | * /etc/jitsi/meet/meet.cmnog.cm-config.js |
| - | // Connection | + | |
| - | // | + | |
| - | hosts: { | + | <code diff> |
| - | // XMPP domain. | + | diff --git a/jitsi/meet/meet.cmnog.cm-config.js b/jitsi/meet/meet.cmnog.cm-config.js |
| - | domain: 'meet.cmnog.cm', | + | index 3cd639d..f4166b2 100644 |
| + | --- a/jitsi/meet/meet.cmnog.cm-config.js | ||
| + | +++ b/jitsi/meet/meet.cmnog.cm-config.js | ||
| + | @@ -9,7 +9,7 @@ var config = { | ||
| + | domain: 'meet.cmnog.cm', | ||
| - | // When using authentication, domain for guest users. | + | // When using authentication, domain for guest users. |
| - | anonymousdomain: 'guest.meet.cmnog.cm', | + | - // anonymousdomain: 'guest.example.com', |
| + | + anonymousdomain: 'guest.meet.cmnog.cm', | ||
| - | // Domain for authenticated users. Defaults to <domain>. | + | // Domain for authenticated users. Defaults to <domain>. |
| - | // authdomain: 'meet.cmnog.cm', | + | // authdomain: 'meet.cmnog.cm', |
| + | @@ -179,7 +179,8 @@ var config = { | ||
| + | // Recording | ||
| - | // Jirecon recording component domain. | + | // Whether to enable file recording or not. |
| - | // jirecon: 'jirecon.meet.cmnog.cm', | + | - // fileRecordingsEnabled: false, |
| + | + fileRecordingsEnabled: true, | ||
| + | + hiddenDomain:'recorder.meet.cmnog.cm', | ||
| + | // Enable the dropbox integration. | ||
| + | // dropbox: { | ||
| + | // appKey: '<APP_KEY>' // Specify your app key here. | ||
| + | @@ -200,7 +201,7 @@ var config = { | ||
| + | // fileRecordingsServiceSharingEnabled: false, | ||
| - | // Call control component (Jigasi). | + | // Whether to enable live streaming or not. |
| - | // call_control: 'callcontrol.meet.cmnog.cm', | + | - // liveStreamingEnabled: false, |
| + | + liveStreamingEnabled: true, | ||
| - | // Focus component domain. Defaults to focus.<domain>. | + | // Transcription (in interface_config, |
| - | // focus: 'focus.meet.cmnog.cm', | + | // subtitles and buttons can be configured) |
| + | </code> | ||
| + | * /etc/jitsi/videobridge/sip-communicator.properties | ||
| - | // XMPP MUC domain. FIXME: use XEP-0030 to discover it. | + | <code diff> |
| - | muc: 'conference.<!--# echo var="subdomain" default="" -->meet.cmnog.cm' | + | diff --git a/jitsi/jicofo/sip-communicator.properties b/jitsi/jicofo/sip-communicator.properties |
| - | }, | + | index cbcb394..e65a34b 100644 |
| + | --- a/jitsi/jicofo/sip-communicator.properties | ||
| + | +++ b/jitsi/jicofo/sip-communicator.properties | ||
| + | @@ -1 +1,4 @@ | ||
| + | org.jitsi.jicofo.BRIDGE_MUC=JvbBrewery@internal.auth.meet.cmnog.cm | ||
| + | +org.jitsi.jicofo.auth.URL=XMPP:meet.cmnog.cm | ||
| + | +org.jitsi.jicofo.jibri.BREWERY=JibriBrewery@internal.auth.meet.cmnog.cm | ||
| + | +org.jitsi.jicofo.jibri.PENDING_TIMEOUT=90 | ||
| + | </code> | ||
| - | // BOSH URL. FIXME: use XEP-0156 to discover it. | + | ===== Sur stream2.cmnog ===== |
| - | bosh: '//meet.cmnog.cm/http-bind', | + | |
| - | // Websocket URL | + | Cette instance accueille principalement le nécessaire pour enregistrer les réunions et streamer (sur Youtube). Le composant de jitsi impliqué ici est: [[https://github.com/jitsi/jibri | jibri]]. |
| - | // websocket: 'wss://meet.cmnog.cm/xmpp-websocket', | + | |
| - | // The name of client node advertised in XEP-0115 'c' stanza | ||
| - | clientNode: 'http://jitsi.org/jitsimeet', | ||
| - | // The real JID of focus participant - can be overridden here | + | L'installation s'est faite sur Ubuntu 20.04 qui vient avec une version récente de ''ffmpeg'' qui est un ensemble d'outils pour transcodage et streaming de fichiers multimédia. |
| - | // focusUserJid: 'focus@auth.meet.cmnog.cm', | + | |
| + | ==== Préconfiguration ==== | ||
| - | // Testing / experimental features. | ||
| - | // | ||
| - | testing: { | + | * Installer le paquet linux-image-extra-virtual afin de pouvoir utiliser le module ALSA. |
| - | // Enables experimental simulcast support on Firefox. | + | * ajouter snd-aloop dans /etc/modules |
| - | enableFirefoxSimulcast: false, | + | * Si vous voulez charger directement en mémoire vive : modprobe snd-aloop |
| + | * Installer ffmpeg | ||
| + | * Installer le navigateur web Chrome et chromedriver | ||
| - | // P2P test mode disables automatic switching to P2P when there are 2 | + | <code bash> |
| - | // participants in the conference. | + | root@stream2:~# curl -sS -o - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add |
| - | p2pTestMode: false | + | root@stream2:~# echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list |
| + | root@stream2:~# apt update | ||
| + | root@stream2:~# apt install google-chrome-stable | ||
| + | </code> | ||
| - | // Enables the test specific features consumed by jitsi-meet-torture | + | * Ajouter le fichier de gestion de stratégie de chrome |
| - | // testMode: false | + | |
| - | // Disables the auto-play behavior of *all* newly created video element. | + | <code bash> |
| - | // This is useful when the client runs on a host with limited resources. | + | root@stream2:~# mkdir -p /etc/opt/chrome/policies/managed |
| - | // noAutoPlayVideo: false | + | root@stream2:~# echo '{ "CommandLineFlagSecurityWarningsEnabled": false }' >>/etc/opt/chrome/policies/managed/managed_policies.json |
| - | }, | + | </code> |
| - | // Disables ICE/UDP by filtering out local and remote UDP candidates in | + | * Installation de chromedriver |
| - | // signalling. | + | <code bash> |
| - | // webrtcIceUdpDisable: false, | + | root@stream2:~# CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` |
| + | root@stream2:~# wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ | ||
| + | root@stream2:~# unzip ~/chromedriver_linux64.zip -d ~/ | ||
| + | root@stream2:~# rm ~/chromedriver_linux64.zip | ||
| + | root@stream2:~# mv -f ~/chromedriver /usr/local/bin/chromedriver | ||
| + | root@stream2:~# chown root:root /usr/local/bin/chromedriver | ||
| + | root@stream2:~# chmod 0755 /usr/local/bin/chromedriver | ||
| + | </code> | ||
| - | // Disables ICE/TCP by filtering out local and remote TCP candidates in | + | === Autres paquets nécessaires === |
| - | // signalling. | + | |
| - | // webrtcIceUdpDisable: false, | + | |
| - | // Disables ICE/TCP by filtering out local and remote TCP candidates in | + | <code bash> |
| - | // signalling. | + | root@stream2:~# apt install default-jre-headless curl alsa-utils icewm xdotool xserver-xorg-input-void xserver-xorg-video-dummy |
| - | // webrtcIceTcpDisable: false, | + | </code> |
| + | ==== Jibri ==== | ||
| - | // Media | + | <code bash> |
| - | // | + | root@stream2:~# wget -qO - https://download.jitsi.org/jitsi-key.gpg.key | apt-key add - |
| + | root@stream2:~# sh -c "echo 'deb https://download.jitsi.org stable/' > /etc/apt/sources.list.d/jitsi-stable.list" | ||
| + | root@stream2:~# apt update | ||
| + | root@stream2:~# apt install jibri | ||
| + | </code> | ||
| - | // Audio | + | Ajouter jibri dans certains groupes : |
| + | <code bash> | ||
| + | root@stream2:~# for group in adm plugdev; do adduser jibri $group; done | ||
| + | </code> | ||
| + | A l'installation; jibri faisait déjà partie des groupes ''audio'' et ''video'' | ||
| - | // Disable measuring of audio levels. | + | Créer le repertoire de destination des enregistrements /srv/jibri/recordings |
| - | // disableAudioLevels: false, | + | |
| - | // audioLevelsInterval: 200, | + | |
| - | // Enabling this will run the lib-jitsi-meet no audio detection module which | + | Jibri doit en être le propriétaire |
| - | // will notify the user if the current selected microphone has no audio | + | <code bash> |
| - | // input and will suggest another valid device if one is present. | + | root@stream2:~# mkdir -p /srv/jibri/recordings |
| - | enableNoAudioDetection: true, | + | root@stream2:~# chown -R jibri /srv/jibri/ |
| + | </code> | ||
| - | // Enabling this will run the lib-jitsi-meet noise detection module which will | + | Le principal fichier à considérer sur cette instance est ''/etc/jitsi/jibri/config.json''. |
| - | // notify the user if there is noise, other than voice, coming from the current | + | |
| - | // selected microphone. The purpose it to let the user know that the input could | + | |
| - | // be potentially unpleasant for other meeting participants. | + | |
| - | enableNoisyMicDetection: true, | + | |
| - | // Start the conference in audio only mode (no video is being received nor | + | <code diff> |
| - | // sent). | + | diff --git a/jitsi/jibri/config.json b/jitsi/jibri/config.json |
| - | // startAudioOnly: false, | + | index 6edaf3a..adfe5cf 100644 |
| + | --- a/jitsi/jibri/config.json | ||
| + | +++ b/jitsi/jibri/config.json | ||
| + | @@ -3,9 +3,9 @@ | ||
| + | // values from your environment | ||
| + | |||
| + | // Where recording files should be temporarily stored | ||
| + | - "recording_directory":"/tmp/recordings", | ||
| + | + "recording_directory":"/srv/jibri/recordings", | ||
| + | // The path to the script which will be run on completed recordings | ||
| + | - "finalize_recording_script_path": "/path/to/finalize_recording.sh", | ||
| + | + "finalize_recording_script_path": "", | ||
| + | "xmpp_environments": [ | ||
| + | { | ||
| + | // A friendly name for this environment which can be used | ||
| + | @@ -14,34 +14,34 @@ | ||
| + | // The hosts of the XMPP servers to connect to as part of | ||
| + | // this environment | ||
| + | "xmpp_server_hosts": [ | ||
| + | - "prod.xmpp.host.net" | ||
| + | + "meet.cmnog.cm" | ||
| + | ], | ||
| + | // The xmpp domain we'll connect to on the XMPP server | ||
| + | - "xmpp_domain": "xmpp.domain", | ||
| + | + "xmpp_domain": "meet.cmnog.cm", | ||
| + | // Jibri will login to the xmpp server as a privileged user | ||
| + | "control_login": { | ||
| + | // The domain to use for logging in | ||
| + | - "domain": "auth.xmpp.domain", | ||
| + | + "domain": "auth.meet.cmnog.cm", | ||
| + | // The credentials for logging in | ||
| + | - "username": "username", | ||
| + | - "password": "password" | ||
| + | + "username": "jibri", | ||
| + | + "password": "sssssskjkjkjksssssss" | ||
| + | }, | ||
| + | // Using the control_login information above, Jibri will join | ||
| + | // a control muc as a means of announcing its availability | ||
| + | // to provide services for a given environment | ||
| + | "control_muc": { | ||
| + | - "domain": "internal.auth.xmpp.domain", | ||
| + | + "domain": "internal.auth.meet.cmnog.cm", | ||
| + | "room_name": "JibriBrewery", | ||
| + | - "nickname": "jibri-nickname" | ||
| + | + "nickname": "jibri" | ||
| + | }, | ||
| + | // All participants in a call join a muc so they can exchange | ||
| + | // information. Jibri can be instructed to join a special muc | ||
| + | // with credentials to give it special abilities (e.g. not being | ||
| + | // displayed to other users like a normal participant) | ||
| + | "call_login": { | ||
| + | - "domain": "recorder.xmpp.domain", | ||
| + | - "username": "username", | ||
| + | - "password": "password" | ||
| + | + "domain": "recorder.meet.cmnog.cm", | ||
| + | + "username": "recorder", | ||
| + | + "password": "seeUseeMe" | ||
| + | }, | ||
| + | // When jibri gets a request to start a service for a room, the room | ||
| + | // jid will look like: | ||
| - | // Every participant after the Nth will start audio muted. | + | </code> |
| - | // startAudioMuted: 10, | + | |
| - | // Start calls with audio muted. Unlike the option above, this one is only | + | ==== A Considerer sur l'instance de jitsi-meet ==== |
| - | // applied locally. FIXME: having these 2 options is confusing. | + | |
| - | // startWithAudioMuted: false, | + | |
| - | // Enabling it (with #params) will disable local audio output of remote | ||
| - | // participants and to enable it back a reload is needed. | ||
| - | // startSilent: false | ||
| - | // Video | + | Sur l'instance hébergeant jitsi-meet; les sections les plus importantes sont |
| + | * prosody | ||
| + | * le ''Component "internal.meet.cmnog.cm" "muc" '' | ||
| + | * le virtualhost //recorder.meet.cmnog.cm// | ||
| + | * la creation de deux comptes xmpp | ||
| + | * ''jibri@auth.meet.cmnog.cm'' | ||
| + | * ''recorder@meet.cmnog.cm'' | ||
| - | // Sets the preferred resolution (height) for local video. Defaults to 720. | + | * jicofo |
| - | // resolution: 720, | + | * le fichier ''/etc/jitsi/jicofo/sip-communicator.properties'' avec ces deux informations |
| + | <code text> | ||
| + | org.jitsi.jicofo.jibri.BREWERY=JibriBrewery@internal.auth.meet.cmnog.cm | ||
| + | org.jitsi.jicofo.jibri.PENDING_TIMEOUT=90 | ||
| + | </code> | ||
| - | // w3c spec-compliant video constraints to use for video capture. Currently | + | * Dans ''/etc/jitsi/meet/yourdomain-config.js'' activez |
| - | // used by browsers that return true from lib-jitsi-meet's | + | * ''fileRecordingsEnabled: true'' |
| - | // util#browser#usesNewGumFlow. The constraints are independent from | + | * ''liveStreamingEnabled: true'' |
| - | // this config's resolution value. Defaults to requesting an ideal aspect | + | * ''hiddenDomain: 'recorder.meet.cmnog.cm''' |
| - | // ratio of 16:9 with an ideal resolution of 720. | + | |
| - | // constraints: { | + | |
| - | // video: { | + | |
| - | // aspectRatio: 16 / 9, | + | |
| - | // height: { | + | |
| - | // ideal: 720, | + | |
| - | // max: 720, | + | |
| - | // min: 240 | + | |
| - | // } | + | |
| - | // } | + | |
| - | // }, | + | |
| - | // Enable / disable simulcast support. | + | ====== Exploitation ====== |
| - | // disableSimulcast: false, | + | |
| - | // Enable / disable layer suspension. If enabled, endpoints whose HD | + | ===== Création d'un salon ===== |
| - | // layers are not in use will be suspended (no longer sent) until they | + | |
| - | // are requested again. | + | |
| - | // enableLayerSuspension: false, | + | |
| - | // Every participant after the Nth will start video muted. | + | * Pour créer un salon, il faut se rendre saisir le nom que l'on souhaite donner à la salle. |
| - | // startVideoMuted: 10, | + | * Si vous êtes l'hôte, il vous faudra saisir vos paramètres d'authentification |
| + | * la création de compte s fait à l'aide de la commande ''prosodyctl adduser JID'' | ||
| + | * Si vous n'êtes pas l'hôte, il faudra attendre qu'une personne //ouvre// la salle | ||
| - | // Start calls with video muted. Unlike the option above, this one is only | + | ===== Enregistrement et streaming ===== |
| - | // applied locally. FIXME: having these 2 options is confusing. | + | |
| - | // startWithVideoMuted: false, | + | |
| - | // If set to true, prefer to use the H.264 video codec (if supported). | + | {{ wiki:jitsi_menu.png?direct&250 | Vu d'ensemble du menu}} |
| - | // Note that it's not recommended to do this because simulcast is not | + | |
| - | // supported when using H.264. For 1-to-1 calls this setting is enabled by | + | |
| - | // default and can be toggled in the p2p section. | + | |
| - | // preferH264: true, | + | |
| - | // If set to true, disable H.264 video codec by stripping it out of the | + | ==== Enregistrement ==== |
| - | // SDP. | + | |
| - | // disableH264: false, | + | |
| - | // Desktop sharing | + | Le modérateur de la salle peut démarrer l'enregistrement si l'instance de jibri est disponible. Pour cela il faut |
| - | // The ID of the jidesha extension for Chrome. | + | * Être modérateur |
| - | desktopSharingChromeExtId: null, | + | * Etant dans une salle; cliquer sur les trois points |
| + | * Menu //Commencer l'enregistrement// | ||
| + | * Vous terminez l'enregistrement en suivant le même chemin | ||
| - | // Whether desktop sharing should be disabled on Chrome. | + | Les enregistrements par défaut sont stockés sur stream2 dans le dossier indiqué par la variable ''recording_directory'' |
| - | // desktopSharingChromeDisabled: false, | + | |
| - | // The media sources to use when using screen sharing with the Chrome | + | ==== Streaming sur Youtube ==== |
| - | // extension. | + | |
| - | desktopSharingChromeSources: [ 'screen', 'window', 'tab' ], | + | |
| - | // Required version of Chrome extension | + | === Côté youtube === |
| - | desktopSharingChromeMinExtVersion: '0.1', | + | |
| - | // Whether desktop sharing should be disabled on Firefox. | + | {{ ::jitsi_streaming_youtubestudio.png?direct&250| Page d'édition du flux dans Youtube studio}} |
| - | // desktopSharingFirefoxDisabled: false, | + | |
| - | // Optional desktop sharing frame rate options. Default value: min:5, max:5. | + | * Ouvrir [[https://studio.youtube.com/ | Youtube studio]] |
| - | // desktopSharingFrameRate: { | + | * Cliquer sur le menu "Créer" --> "Passer au direct" |
| - | // min: 5, | + | * Configurer la diffusion |
| - | // max: 5 | + | * Copier la clé de flux |
| - | // }, | + | * Attendre que jibri envoie le flux avant de passer effectivement au direct |
| - | // Try to start calls with screen-sharing instead of camera video. | ||
| - | // startScreenSharing: false, | ||
| - | // Recording | ||
| - | // Whether to enable file recording or not. | + | === Côté Jitsi === |
| - | fileRecordingsEnabled: true, | + | |
| - | hiddenDomain:'recorder.meet.cmnog.cm', | + | |
| - | // Enable the dropbox integration. | + | |
| - | // dropbox: { | + | |
| - | // appKey: '<APP_KEY>' // Specify your app key here. | + | |
| - | // // A URL to redirect the user to, after authenticating | + | |
| - | // // by default uses: | + | |
| - | // // 'https://meet.cmnog.cm/static/oauth.html' | + | |
| - | // redirectURI: | + | |
| - | // 'https://meet.cmnog.cm/subfolder/static/oauth.html' | + | |
| - | // }, | + | |
| - | // When integrations like dropbox are enabled only that will be shown, | + | |
| - | // by enabling fileRecordingsServiceEnabled, we show both the integrations | + | |
| - | // and the generic recording service (its configuration and storage type | + | |
| - | // depends on jibri configuration) | + | |
| - | // fileRecordingsServiceEnabled: false, | + | |
| - | // Whether to show the possibility to share file recording with other people | + | |
| - | // (e.g. meeting participants), based on the actual implementation | + | |
| - | // on the backend. | + | |
| - | // fileRecordingsServiceSharingEnabled: false, | + | |
| - | // Whether to enable live streaming or not. | + | * Être modérateur |
| - | liveStreamingEnabled: true, | + | * Etant dans une salle; cliquer sur les trois points |
| + | * Menu //Démarrer la diffusion en direct// | ||
| + | * Insérer la clé de flux | ||
| + | * Si tout est ok, une charmante voix vous préviendra que le streaming a démarré | ||
| + | * A la fin de session, arrêter la diffusion | ||
| - | // Transcription (in interface_config, | ||
| - | // subtitles and buttons can be configured) | ||
| - | // transcribingEnabled: false, | ||
| - | |||
| - | // Enables automatic turning on captions when recording is started | ||
| - | // autoCaptionOnRecord: false, | ||
| - | |||
| - | // Misc | ||
| - | |||
| - | // Default value for the channel "last N" attribute. -1 for unlimited. | ||
| - | channelLastN: -1, | ||
| - | |||
| - | // Disables or enables RTX (RFC 4588) (defaults to false). | ||
| - | // disableRtx: false, | ||
| - | |||
| - | // Disables or enables TCC (the default is in Jicofo and set to true) | ||
| - | // (draft-holmer-rmcat-transport-wide-cc-extensions-01). This setting | ||
| - | // affects congestion control, it practically enables send-side bandwidth | ||
| - | // estimations. | ||
| - | // enableTcc: true, | ||
| - | |||
| - | // Disables or enables REMB (the default is in Jicofo and set to false) | ||
| - | // (draft-alvestrand-rmcat-remb-03). This setting affects congestion | ||
| - | // control, it practically enables recv-side bandwidth estimations. When | ||
| - | // both TCC and REMB are enabled, TCC takes precedence. When both are | ||
| - | // disabled, then bandwidth estimations are disabled. | ||
| - | // enableRemb: false, | ||
| - | |||
| - | // Defines the minimum number of participants to start a call (the default | ||
| - | // is set in Jicofo and set to 2). | ||
| - | // minParticipants: 2, | ||
| - | |||
| - | // Use XEP-0215 to fetch STUN and TURN servers. | ||
| - | useStunTurn: true, | ||
| - | |||
| - | // Enable IPv6 support. | ||
| - | // useIPv6: true, | ||
| - | |||
| - | // Enables / disables a data communication channel with the Videobridge. | ||
| - | // Values can be 'datachannel', 'websocket', true (treat it as | ||
| - | // 'datachannel'), undefined (treat it as 'datachannel') and false (don't | ||
| - | // open any channel). | ||
| - | // openBridgeChannel: true, | ||
| - | |||
| - | |||
| - | // UI | ||
| - | // | ||
| - | |||
| - | // Use display name as XMPP nickname. | ||
| - | // useNicks: false, | ||
| - | |||
| - | // Require users to always specify a display name. | ||
| - | // requireDisplayName: true, | ||
| - | |||
| - | // Whether to use a welcome page or not. In case it's false a random room | ||
| - | // will be joined when no room is specified. | ||
| - | enableWelcomePage: true, | ||
| - | |||
| - | // Enabling the close page will ignore the welcome page redirection when | ||
| - | // a call is hangup. | ||
| - | // enableClosePage: false, | ||
| - | |||
| - | // Disable hiding of remote thumbnails when in a 1-on-1 conference call. | ||
| - | // disable1On1Mode: false, | ||
| - | |||
| - | // Default language for the user interface. | ||
| - | // defaultLanguage: 'en', | ||
| - | |||
| - | // If true all users without a token will be considered guests and all users | ||
| - | // with token will be considered non-guests. Only guests will be allowed to | ||
| - | // edit their profile. | ||
| - | enableUserRolesBasedOnToken: false, | ||
| - | |||
| - | // Whether or not some features are checked based on token. | ||
| - | // enableFeaturesBasedOnToken: false, | ||
| - | |||
| - | // Enable lock room for all moderators, even when userRolesBasedOnToken is enabled and participants are guests. | ||
| - | // lockRoomGuestEnabled: false, | ||
| - | |||
| - | // When enabled the password used for locking a room is restricted to up to the number of digits specified | ||
| - | // roomPasswordNumberOfDigits: 10, | ||
| - | // default: roomPasswordNumberOfDigits: false, | ||
| - | |||
| - | // Message to show the users. Example: 'The service will be down for | ||
| - | // maintenance at 01:00 AM GMT, | ||
| - | // noticeMessage: '', | ||
| - | |||
| - | // Enables calendar integration, depends on googleApiApplicationClientID | ||
| - | // and microsoftApiApplicationClientID | ||
| - | // enableCalendarIntegration: false, | ||
| - | |||
| - | // Stats | ||
| - | // | ||
| - | |||
| - | // Whether to enable stats collection or not in the TraceablePeerConnection. | ||
| - | // This can be useful for debugging purposes (post-processing/analysis of | ||
| - | // the webrtc stats) as it is done in the jitsi-meet-torture bandwidth | ||
| - | // estimation tests. | ||
| - | // gatherStats: false, | ||
| - | |||
| - | // The interval at which PeerConnection.getStats() is called. Defaults to 10000 | ||
| - | // pcStatsInterval: 10000, | ||
| - | |||
| - | // To enable sending statistics to callstats.io you must provide the | ||
| - | // Application ID and Secret. | ||
| - | // callStatsID: '', | ||
| - | // callStatsSecret: '', | ||
| - | |||
| - | // enables sending participants display name to callstats | ||
| - | // enableDisplayNameInStats: false, | ||
| - | |||
| - | // enables sending participants email if available to callstats and other analytics | ||
| - | // enableEmailInStats: false, | ||
| - | |||
| - | // Privacy | ||
| - | // | ||
| - | |||
| - | // If third party requests are disabled, no other server will be contacted. | ||
| - | // This means avatars will be locally generated and callstats integration | ||
| - | // will not function. | ||
| - | // disableThirdPartyRequests: false, | ||
| - | |||
| - | |||
| - | // Peer-To-Peer mode: used (if enabled) when there are just 2 participants. | ||
| - | // | ||
| - | |||
| - | p2p: { | ||
| - | // Enables peer to peer mode. When enabled the system will try to | ||
| - | // establish a direct connection when there are exactly 2 participants | ||
| - | // in the room. If that succeeds the conference will stop sending data | ||
| - | // through the JVB and use the peer to peer connection instead. When a | ||
| - | // 3rd participant joins the conference will be moved back to the JVB | ||
| - | // connection. | ||
| - | enabled: true, | ||
| - | |||
| - | // Use XEP-0215 to fetch STUN and TURN servers. | ||
| - | useStunTurn: true, | ||
| - | |||
| - | // The STUN servers that will be used in the peer to peer connections | ||
| - | stunServers: [ | ||
| - | |||
| - | // { urls: 'stun:meet.cmnog.cm:443' }, | ||
| - | { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' } | ||
| - | ], | ||
| - | |||
| - | // Sets the ICE transport policy for the p2p connection. At the time | ||
| - | // of this writing the list of possible values are 'all' and 'relay', | ||
| - | // but that is subject to change in the future. The enum is defined in | ||
| - | // the WebRTC standard: | ||
| - | // https://www.w3.org/TR/webrtc/#rtcicetransportpolicy-enum. | ||
| - | // If not set, the effective value is 'all'. | ||
| - | // iceTransportPolicy: 'all', | ||
| - | |||
| - | // If set to true, it will prefer to use H.264 for P2P calls (if H.264 | ||
| - | // is supported). | ||
| - | preferH264: true | ||
| - | |||
| - | // If set to true, disable H.264 video codec by stripping it out of the | ||
| - | // SDP. | ||
| - | // disableH264: false, | ||
| - | |||
| - | // How long we're going to wait, before going back to P2P after the 3rd | ||
| - | // participant has left the conference (to filter out page reload). | ||
| - | // backToP2PDelay: 5 | ||
| - | }, | ||
| - | |||
| - | analytics: { | ||
| - | // The Google Analytics Tracking ID: | ||
| - | // googleAnalyticsTrackingId: 'your-tracking-id-UA-123456-1' | ||
| - | |||
| - | // The Amplitude APP Key: | ||
| - | // amplitudeAPPKey: '<APP_KEY>' | ||
| - | |||
| - | // Array of script URLs to load as lib-jitsi-meet "analytics handlers". | ||
| - | // scriptURLs: [ | ||
| - | // "libs/analytics-ga.min.js", // google-analytics | ||
| - | // "https://example.com/my-custom-analytics.js" | ||
| - | // ], | ||
| - | }, | ||
| - | // Allow all above example options to include a trailing comma and | ||
| - | // prevent fear when commenting out the last value. | ||
| - | |||
| - | makeJsonParserHappy: 'even if last key had a trailing comma' | ||
| - | |||
| - | // no configuration value should follow this line. | ||
| - | }; | ||
| - | |||
| - | /* eslint-enable no-unused-vars, no-var */ | ||
| - | </code> | ||
| - | * /etc/jitsi/videobridge/sip-communicator.properties | ||
| - | |||
| - | <code bash> | ||
| - | root@vps2:~# cat /etc/jitsi/videobridge/sip-communicator.properties | ||
| - | org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER=true | ||
| - | org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES=meet-jit-si-turnrelay.jitsi.net:443 | ||
| - | org.jitsi.videobridge.ENABLE_STATISTICS=true | ||
| - | org.jitsi.videobridge.STATISTICS_TRANSPORT=muc | ||
| - | org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=localhost | ||
| - | org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.meet.cmnog.cm | ||
| - | org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb | ||
| - | org.jitsi.videobridge.xmpp.user.shard.PASSWORD=oulalaaa | ||
| - | org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.auth.meet.cmnog.cm | ||
| - | org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME=29faf056-24c6-490b-95bc-94509ce532c9 | ||
| - | </code> | ||