IT 系パッケージメーカーの零細企業経営者場合

いつか書こうと思っていたので雑に書いていく。

要約

基本的に人の意見は参考にならない、聞く必要ない。自分の考えを信じたほうがいい。

ただし、IT 系の企業経営者で信頼できるなら人が身近にいるのであれば、意見交換はしたほうがいい。最近全く会えてないが、ヴェルクの田向さんSigfoss の森さんから頂いた意見はとても役に立った。

社外の人間の意見は参考にはならない

自分が起業したときに苦労したので、書いておくが、この記事も参考にならないと思ったほうがいい。

思い立ってすぐに起業したので、ほとんど知識がなかった。いろいろな人の意見を聞いてみたが、実際に経営してみると全く参考にならなかった。

助成金の話ばかりする人

これは最初に契約した税理士が良くなかっただけかもしれないが、基本的に助成金の話しかしてこない。助成金の仲介手数料が目当てなんだろう。

ちなみに助成金に関しては社員時代に一度助成金を使った事業のお手伝いをして本当に最悪な経験をしたので二度と関わるまいと決めていたので、助成金関連の事業には可能な限り関わらないようにしている。

ちなみに今の税理士は「高いサーバ買えば助成金が出る場合もあります」以外のことは一切言ってこない。よくわかっている。

カスタマイズしない自社製品なんて儲からないからやめろと言ってくる人

これはよく言われた。カスタマイズしたほうが儲かると。「別に儲ける必要はないんですよ」って言うと小バカにされた。

人は成功体験にしがみつくということを学んだ。

海外に目を向けろと言ってくる人

自分は英語がさっぱりできないので、日本国内だけでビジネスをやっているが「日本はオワコンなので、海外に打って出ないとダメ」と言われたた。

海外とビジネスするというのは自分には全く想像できないし、リスクしかないように思える。

正直、日本語ですらうまくやりとりができない日本の企業がいるのに海外とか無理だなと思っている。

資金調達しろといってくる人

なにをやるにしても「資金調達」ありきの話をしてくる。色々提案してくるが「そんなお金はない」っていっても「お金を稼ぐ時間なんて無駄だ、調達して攻めるべき」と言われた。

そもそも人とうまくやれないという、社会人不適合者ということで起業してるのに、調達して色々意見言われる時点で無理。

調達している人の意見は正直環境が違いすぎて何の参考にもならない。普通に世界線が違うので関わらないほうがいい。

銀行から借りろといってくる人

「無借金はだめ、お金を借りていることは大事」というのは年配の方に多かったが、お金借りる予定もないし銀行嫌いなので、受け入れられないという話をした。

「銀行は困った時に助けてくれる」と言われたが、むしろ困った時に厳しい話しか今まで聞いていないのなにを言ってるのかわからなかった。

あと別に IT 系は投資がほぼいらないのでそもそも借り入れ自体が不要。

営業を雇えと言ってくる人

自社製品が売れていないときに言われた。売れないのは営業を雇わないからだ。まず売り込みをしないとダメだと言われたが、「誰にでも売りたい製品」ではない時点で営業は別にいらないという説明をしたが「そんな甘い考えじゃ失敗する」と言われた。

ウェブサイト / Twitter / Discord / Gist で宣伝して売るという考えは受け入れられなかった。

人を増やせと言ってくる人

自分が結構忙しく働いてる時に言われた。今も忙しいが「人を増やすとコミュニケーションコストが高くなる」といっても理解してもらえなかった。

時雨堂は「ほっといてもなんかする人」だけを雇っているため管理コストがほぼ0なのだが、マネージャーを雇えと言われた。

実際、起業して見ると「売上を上げる=人を雇う」という考えの人がとても多いことに驚いた。皆、ほっといて売れるような製品をつくりたくはないらしい。

社会に還元しろと言ってくる人

一番めんどくさかった。一社だけで儲けるのはやめろといいながら、打ち合わせしようとしてきたりするし、自分に都合のいい話ばかりする人たち。

結局何がしたかったのかわからなかった。いい反面教師になった。

社員をもっと働かせろと言ってくる人

時雨堂が 6 時間労働になったあたりで言われた。社員は替えがきくとか意味がわからない事を言っていた。

たくさんの時間働いて成果をたくさん出せるのはそれは才能なので、誰もが真似できるものでもないと思っている。

経営者がコード書くなと言ってくる人

想像以上に言われる。自分が好き勝手にコードを書いて生きていくために起業したのに何を言ってるのか。

うまくいくとなにも言われなくなる

面白いもので、時雨堂コトハジメとかである程度うまくいってることをオープンにするとなにも言われなくなる。

社員の意見はとても重要

基本的に自分で方針は決めるが、悩んでるときは必ず社員たちに相談することにしてる。自分の考えが良くないことも多々あった。相談できる社員を雇うことが大事。

まとめ

結構なにも考えず上からの意見を言われることが多いので聞かないほうがいい。成功経験に引っ張られている考えがほとんどだった。

自分の考えを信じたほうがいい。もちろん、この記事の意見も参考にするべきではない。

terurou はどうなんだろうとふったら書いてくれたので紹介。


この記事は宣伝です

時雨堂の CTO である SUZUKI Tetsuya による ネイティブライブラリガイド for iOS and Android という解説書が Zenn にて公開されました。

価格は 5000 円しますが、継続的な更新が前提での価格ですし、ここまで網羅されている内容は世界的にみてもほとんど無いと思いますのでお買い得です。

まとめ

ノウハウしか詰まってないから買うべき。

色々まとまりなく書いてみました。

CTO の立ち位置

SUZUKI Tetsuya は現在、時雨堂で働くほぼ全ての時間で Sora iOS / Android SDK 開発、または React Native WebRTC Kit の開発を行っています。ほぼというのはたまに Erlang のライブラリを作らされたりしています。

WebRTC SFU Sora がでて今年の 12 月でちょうど 5 年立ちますが、 CTO は殆どの時間をモバイル 向け SDK の開発をしています。この経験をしている人は世界を見てもほとんどいないのではないでしょうか。ちなみに、SDK だけではなく社内で使うモバイル用のテストツールなども開発しています。

libwebrtc の iOS / Android SDK は力が入れられていない

実は libwebrtc の iOS / Android 向けの SDK はあまりリソースが注ぎ込まれていません。バグがあったとしても放置されることが多いです。

そのため時雨堂では色々 libwebrtc にパッチを当てたりもしています。これらのノウハウは全てオープンソースとして公開していますが、ソースが公開されているだけじゃわからないはずです。

そもそも libwebrtc だってソースが公開されていますが、詳しい人はほとんどいないでしょう。

SDK は難しい

そもそも libwebrtc を利用した モバイル向けの SDK 開発はとても難しいです。libwebrtc がしんどい、さらに libwebrtc の iOS / Android SDK がしんどい、そして SDK 開発がしんどいという 3 重苦です。正直バッドノウハウしかない世界です。

Sora のモバイル SDK を開発するには libwebrtc の知識、libwebrtc の iOS / Android SDK の知識、iOS / Android の知識、さらに WebRTC SFU Sora の知識が必要になります。

OSS

Sora iOS SDK と Android SDK、React Native WebRTC Kit は Apache Licesne 2.0 としてオープンソースで公開されています。そのためノウハウもへったくれもありません。

仕事が OSS 前提だと、隠すことがなくて楽ですね。

獣道を歩く

今回の WebRTC ネイティブライブラリガイド for iOS and Android はそんな「獣道」をあるき続けている人が継続的に更新していく解説書です。

継続的に更新していくというのは実はとても重要です。CTO も書いていますが libwebrtc は積極的には快適変更をしてきます。一つ前のバージョンで利用できたライブラリが使えなくなるなんてよくある話です。

libwebrtc と iOS と Android を同時に追いかけるのは相当大変です。専任でやっている CTO ですら、しんどそうにしているときが多々あります。これを片手間でやるのは無理でしょう。

蛇足

今回は CTO が個人として解説書を書いてくれたのをとても感謝しています。

本来は会社としてやるべきなのでしょうが、残念ながら会社として専門的な書籍を業務として行い、売上を上げるというのはとても難しいです。

個人の臨時収入としては良いが企業の売上としては見合わないというのが現状だと思っています。


これは、こんな事がやれたら楽しそうだなという話でどうするかとかはまだ決まっておりません。

要約

  • Momo に WebAssembly Runtime を載せたい
  • WebAssembly でエンコード前とエンコード後の音声と映像を操作できるようにしたい

課題

Momo は libwebrtc を利用した WebRTC クライアントです。様々な環境で動き、とても軽いのでいろいろなところで利用いただいています。

ただ課題として基本的に Momo が対応していないことをやろうとすると自分でカスタマイズする必要があります。これは体力のある企業でやる場合はいいと思うのですがスタートアップなどでは厳しいのが現状です。

たとえば …

  • Momo が配信する映像にぼかしフィルターをかけたい
  • Momo が投げてる SDP をカスタマイズしたい
  • Momo が受信したパケットの映像部分をダンプしたい
  • Momo の Sora シグナリング時に投げてる JSON を加工したい

これらをやるには必ず Momo のコードに手を入れ自前でビルドする必要があります。

これらをなんとかして Momo に手を入れないで利用できるようにできないかとずっと考えていましたが、思いついたのは LuaJIT を使ってフックポイントからフックして処理できるような感じにするかという OpenResty 的な思考でした。

ただ Lua はまぁ、良い言語で自分も好きなのですが残念ながら流行っているとは言い難いですし、書きたい人もそんなにいません。

実際 Erlang VM 上で動作する Luerl を使った商用システムを何個か作りましたが、刺さるところには刺さるくらいでした。

なんどか めるぽん に「C++ でプラグインの仕組みはやっぱりしんどい?」という相談をしたこともありますが、厳しそうなのでやめました。

WebAssembly

Momo とはあまり関係ないWebRTC における End to End Encryption をブラウザ上で実現するために Go で書いたコードを WebAssembly に出力して利用するというのを実装して、かなりうまく動いたという経験をしました。

このとき思ったのが、Momo に WebAssembly Runtime を載せて WebAssembly 用のフックポイントを Momo に用意して、誰もが気軽に Momo のプラグイン的なものを WebAssembly…


定期的にやるやつ。前書いたのが 2020–06なので 5ヶ月でどうなったか。

Erlang/OTP

設計やリリース、調整などであまり Erlang/OTP は書かなかった。OTP 23.1 になった。なにより Erlang/OTP に AsmJit による JIT が OTP 24 で入ることになった。最大 40% の高速化が見込めるとのことで期待。

また、顧客から Erlang/OTP を利用した自社製品の性能検証報告をいただき信じられない性能がでており、衝撃を受けた。自分が作りたいものは今後も Erlang/OTP でいけると確信した。

Go

Wasm 向けの Go と自社サービス向けの Gin を利用した Go の両方を書いた。自分にとっては Go はミドルウェアよりもライブラリやウェブサービスに適してそう。

zerolog や sqlx や squirrel といった便利ライブラリはありがたい。

WebAssembly (Wasm)

Go から初めて利用したがとても便利だった。ただ自分が Wasm を利用する言語を増やしたくはないので Rust や AssemblyScript には手を出さず Go 一本に絞りたいと考えている。なので適用範囲はとても狭いという認識。

WASI はとても楽しみにしており、wasmtime-go も良さそう。

Vim

erlang-ls を設定してもらったので、大変快適。Erlang/OTP とドキュメントは Vim で書いている。erlang-ls も定期的にアップデートしている。

VSCode

Go を書くときは VSCode を利用している。Go についてはいたれりつくせり。Vim モードもいい感じ。

WebRTC

メインのお仕事。E2EE 向けのライブラリを Go で書いたりしていた。

やることが無限にでてきているが、機能追加というよりは改善がほとんどなので、気は楽。徹底的に良いものを作っていくという方針。

WebRTC 界隈は動きがそんなに無いが、やろうとしていることは巨大なので、プロトコルに絞って追いかけている。

QUIC / WebTransport

ちょっと調べては、まだ大丈夫の繰り返し。2021 年は本格的に取り組んでいきたい。

E2EE

たくさんの知識と経験を得た。今後も色々やっていきたい。自分がとても興味を持てる分野ということがわかった。

まとめ

分野的には WebRTC と E2EE の2つを中心に広げていきたいと考えてる。自分にとって興味の範囲を狭めるのは集中できている証拠なのでとても良い。

来年から QUIC / WebTrasnport に取り組みたい。この分野は先人がたくさんいるので苦労があまりなさそうで今から楽しみだ。


オンラインイベントで聞かれて、ツイッターにつぶやいたら思った以上に反響があったので、もう少し詳細に書いてみます。

思ったより反響があった

まとめ

  • 信頼できる暗号ライブラリがある
  • 自分が TypeScript より Go のほうが書ける
  • Go の Wasm バイナリサイズを気にする必要がない

WebCrypto にない暗号が必要

自社の WebRTC SFU において End to End Encryption (E2EE) をブラウザ上で実現するためにはいくつかの壁がありました。

一つは WebCrypto が提供していない暗号を利用したいというものです。

今回 E2EE を実装するにあたり採用した Signal プロトコルでは公開鍵暗号に Curve25519 を採用しています。残念ながら WebCrypto では Curve25519 に対応していません。この時点で「暗号ライブラリをどこからもってくる」というのが必要になりました。

一つ思いついたのが Emscripten を利用した何かしらの信頼できる暗号ライブラリを引っ張ってくるということです。libsodium あたりを利用するというのも一瞬考えましたが、Curve25519 を使うだけにしてはオーバキルだと判断しました。

ただそれはそれで JavaScript 側で Signal プロトコルを実装するということになり、しんどそうだなと判断しました。

そこで考えたのが Go です。Go の暗号ライブラリは Go で書かれています。一部 CPU 専用命令が有効になるのもあります、それを使わず Wasm 化は可能でした。

Go の暗号ライブラリは「標準」で用意されているもののため信頼性がとても高いです。そのためこのライブラリをそのまま Wasm 化できるのはとても大きいと判断しました。

どうでもいいですがプロトコル実装者には暗号ライブラリを自作するのは学習以外ではやってはならぬという鉄の掟が存在します。

Signal プロトコルを TypeScript で実装したくなかった

Go の暗号ライブラリを使うと判断したタイミングで Wasm 側で Signal プロトコルの状態管理までしたいと考えていました。

Signal プロトコルはシンプルではありますが、状態を管理するものが多いため、可能な限り Go で書いて、テストをガッツリ書いておきたいと考えたからです。

また自分が TypeScript で Signal プロトコルを実装できる能力がないと判断したというのもあります。

実際 Go で状態管理は思った以上によく書けました。テストもガッツリ書いたおかげでミスも減りました。

JavaScript と Go のグルー部分は自分ではなく JavaScript に慣れている社員に書いてもらいました。

Go の生成した Wasm バイナリサイズを気にする必要がない

WebRTC SFU で利用するため、2.6 MiB (圧縮して 700KiB) のバイナリは正直全く気にならないレベルです。E2EE 自体が CPU を食べますし、音声と映像を送受信するだけで 2.6MiB なんて一瞬です。

容量を気にする必要がないというのも大きな判断材料になりました。

雑感

信頼できる暗号ライブラリと慣れている言語での状態管理実装はとてもマッチしました。コード自体もとても短く書けて、テストも充実させられることができました。

今回のような暗号ライブラリの利用とプロトコルの詰め込みという天で WebAssembly を利用する場合は C/C++ か Rust が本命だと思いますが、今回は Go を採用したことで暗号ライブラリをサクッと利用でき、状態管理もさくっと実装できました。

今後は Wasm 側のテストも Go で chromedp を利用して書いていければと考えています。

今回は用途にピッタリハマったから良いと思いますが、Go での Wasm 生成は何かしら明確な理由がない限りは選択するのはおすすめできません。

適材適所です、ほんとに。

ちなみに Sora Labo にて WebAssembly を利用した E2EE のサンプル、E2EE (WebAssembly 版) マルチストリームが試せますのでもしよければどうぞ。

おまけ

Twitter でツッコミいただいたので、せっかくだから TinyGo で試してみたらビルドはできました。動かすために wasm_exec.js を TinyGo のものに変更してみましたが、残念ながら “syscall/js.finalizeRef not implemented” というエラーがでて動きませんでした。どこかで追いかけようと思います。もしこれを読んでなにかヒント持ってる方は是非コメントください。

追記


Sora JavaScript SDK では正式リリース前に定期的に Canary リリースをはじめました。GitHub リポジトリのタグにも npm にも登録しています。

npm で canary というタグがセットできるのでそれを利用しています。

Image for post
Image for post

Canary リリースの目的

Sora デモ機能での利用と Sora Labo での利用が主な目的です。また新しい機能を試しやすくしたいというのもあります。

もしよければ使ってみてください。

Canary リリースと Lerna は Next.js から

今回 Canary リリースは Next.js を参考にさせていただきました。Next.js は積極的に Canary リリースをしていて、とても参考になります。色々自動化されているのも流石です。

Sora JavaScript SDK のリポジトリ構成も Next.js を参考にし Lerna を採用しました。E2EE ライブラリが入ってくるため、複雑になってしまうのをきれいにパッケージとして分割できるようにするためです。


WebRTC SFU の課題である録画ファイルの合成を簡単に実現する Hisui をリリースしました。

「なぜ開発しているのか」は別にまとめてあるのでどうぞ。

Hisui 2020.1 はとにかくシンプルに、最低限の機能を提供するというのを目的にリリースを行いました。

  • インプットもアウトプットも WebM に統一する
  • 映像コーデックは VP8/VP9 に統一する
  • 音声コーデックは Opus に統一する
  • 1 バイナリで利用可能にする
  • Docker 経由で利用可能にする
  • Ubuntu 20.04 固定する (Docker 経由なので気にする必要はない)

H.264 関連はすべてライセンスの扱いが存在するため今回は省きました。今後は対応していく予定です。MP4 対応は次のリリースで対応してく予定です。

Image for post
Image for post
合成した WebM

合成後の解像度は 320x240 に合わせています。今後は細かく指定可能にしていく予定です。

録画された WebM ファイルと recording.report で出力されるファイルを同じフォルダに置いて実行すればあとは処理が走ります。

まず動くものをということでリリースしました。Discord にてフィードバックをお待ちしております。

ヘルプ

こんな感じのヘルプです。

$ docker run ghcr.io/shiguredo/hisui:2020.1 hisui --help
hisui
Usage: /usr/local/bin/hisui [OPTIONS]
Options:
-h,--help Print this help message and exit
-f,--in-metadata-file Metadata filename (REQUIED)
--out-video-codec Video codec (VP8/VP9) default: VP9
--out-video-frame-rate Video frame rate (INTEGER/RATIONAL) default: 25)
--out-webm-file Output filename
--max-columns Max columns (POSITIVE INTEGER) default: 3
--libvpx-cq-level libvpx Constrained Quality level (NON NAGATIVE INTEGER) default: 10
--libvpx-min-q libvpx minimum (best) quantizer (NON NEGATIVE INTEGER) default: 3
--libvpx-max-q libvpx maximum (worst) quantizer (NON NEGATIVE INTEGER) default: 40
--verbose Verbose mode
--show-progress-bar Toggle to show progress bar. default: true

WebRTC Signaling Server Ayame を利用した Ayame Lite というサービスをβ版として公開しておりましたが、今回名前を Ayame Labo として正式リリースしました。

要約

  • Ayame Lite 同様、無料で使える
  • サインアップしなくても利用できる
  • Ayame Lite から仕様変更はほとんどない
  • ルーム認証を利用すれば商用や法人での利用化
  • Erlang で書かれた Ayame で動いている

Ayame Labo

Ayame Lite と Sora Labo のコードをベースにほぼ 1 から書き直しました。 開発は tnamao にお願いしました。自分は設計だけして終わりです。

デプロイなども簡単になったので、ほんとありがたいです。

シンプル

ウェブサイト自体はシグナリング URL とシグナリングキーだけで、あとはちょっとしたログが見れる程度です。ログインも GitHub アカウントを持っていればすぐです。

サインアップなしでも利用できる

Ayame Labo は Ayame を気軽に使ってほしいという思いから、サインアップ無しで利用できるのを継続しました。ただし個人での利用限定です。法人で使う場合はかならずルーム認証を使って下さい。

STUN/TURN はルーム認証利用限定にした

Ayame Labo では STUN/TURN を利用するにはルーム認証を利用する必要があります。ローカルでの利用以外はサインアップして使ってほしいという思いからです。

接続ログを直近 24 時間にした

Sora Labo で良かったことを取り入れました。

Erlang 版の Ayame が動いている

Ayame 完全互換の Erlang で書かれた Ayame が動いています。単に自分が Go のミドルウェアを運用するのに慣れていないというのが理由です。実装自体は 1 日でできました。

実は Ayame Lite もここ数ヶ月は Erlang 版で動いており、安定して稼働しておりました。

法人や商用での利用を可能にした

ルーム認証を利用する事で法人や商用での利用も可能にしました。これは WebRTC の P2P 利用がもっと広がってほしいという思いからです。

Ayame Lite について

年内でクローズしますので、Ayame Labo への移行をお願いします。

今後

バグフィックスや使いづらいところを修正していきます。Ayame (Erlang 版) も少しずつ改善していく予定です。

将来的にこの Ayame (Erlang 版) はパッケージとして提供するのもありかも?と思っています。ただ、ソースコードの公開はする予定はありません。


WebRTC SFU Sora 向けの E2EE ライブラリ Sora E2EE の 2020.1 をリリースしました。このライブラリは WebAssembly での利用を想定して開発されたものです。

要約

  • WebAssembly (WASM) での利用を前提としたライブラリ
  • Go の syscall/js をしている
  • X3DH / Double Ratchet / SFrame ライブラリ

リポジトリ

解説

このライブラリは Go で書かれていますが Go の syscall/js を利用することで WASM に変換しブラウザで利用することを想定しています。

なぜ Go なのか

そもそも WASM を利用している理由は 2 つです。

  • WebCrypto にないライブラリを利用したい
  • 複雑な状態管理を WASM に押し付けたい

WebCrypto にないライブラリですが、主に Curve25519 と Ed25519 になります。これを標準ライブラリとして搭載している事が Go でチャレンジすることの一番の理由です。

また、Double Ratchet をさすがに JavaScript で実装するのは自分のスキル的に難しいと判断したというのもあります。

実装

SFrame で利用する状態管理以外はすべて WASM で行っています。メッセージングプロトコルは Signal では決められていないので独自のものを採用しています。

X3DH / Double Ratchet に関しては教科書どおりの実装をしていますので、面白みはありません。

WASM つまり JavaScript と Go の変換はすべて wasm.go に追いやっています。

例外をうまく挙げられないため多値を返すという方式を選択しました。Go っぽい戻り値を JS に持ち込んだのでもしかすると気持ち悪いと思われる方もいるかも知れません。

利用

このライブラリはこれだけでは利用できません。SFrame の鍵管理を JavaScript 側で実装する必要があります。これは Insertable Streams API や WebCrypto と Web Worker を使うために仕方なくそうしていますが、将来的に WASM…


2020 年 10 月版

WebRTC 関連でどんなことをやっているか、やっていこうかというのを書いていこうと思います。時雨堂が WebRTC で何をやろうとしているのかの可視化です。

毎月書いていこうと考えています。時雨堂の WebRTC 製品に興味がある方は読んでみていただけると嬉しいです。

今後 WebRTC SFU Sora は独立して書くことにしました。WebRTC SFU Sora については以下をご確認ください。

おしらせ

時雨堂の CTO である SUZUKI Tetsuya が個人で WebRTC の本を書いているそうです。主に libwebrtc をモバイルで活用するという内容になるとのことです。 CTO は WebRTC SFU Sora の iOS / Andoird SDK のメイン開発者であり、React Native WebRTC Kit のメイン設計者です。libwebrtc をモバイルで使うノウハウを多く持っています。

Image for post
Image for post

最近流行りの Zenn にて有料で公開されるとのことなので、公開されたらもし興味あれば買ってみてください。公開日は今の所未定です。

WebRTC Native Client Momo

詳細については OpenMomo プロジェクト をご確認下さい。

方針

WebRTC Native Client Momo はビルドの簡易化、libwebrtc への追従、単体で完結する事がメインです。

様々な OS やアーキテクチャーに対応しており、それらを簡易化し、誰もが簡単にビルドできるようにしています。また libwebrtc の最新バージョンに追従することで最新の技術を積極的に使えます。

ハードウェアエンコーダーへの対応も積極的にすすめています。現時点では Raspberry Pi と macOS 、Jetson Nano 、NVIDIA ビデオカードに搭載されているハードウェアエンコーダに対応しています。

libwebrtc M87 対応

対応予定です

Jetson Nano の VP8 HWA 対応

対応済みです

今後

Momo は一通り欲しい機能は実装した状態になったため、今後はメンテナンスフェーズとする予定です。libwebrtc のアップデートや AV1…

About

V

Erlang/OTP / 時雨堂 / WebRTC / E2EE

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store