Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

プラグインでSymfony bundle利用時のアップデートについて #4960

Closed
okazy opened this issue Mar 11, 2021 · 23 comments
Closed

Comments

@okazy
Copy link
Contributor

okazy commented Mar 11, 2021

概要(Overview)

EC-CUBE 4.0 -> 4.1 へのアップデートについてこちらの Issue で議論していきます。

EC-CUBE 4.1 Roadmap #4603 にもある通り、4.0 を 4.1 へバージョンアップできるように互換性を考慮して開発が進められています。

期待する内容(Expect) or 要望 (Requirement)

4.0 でのマイナーバージョンアップと同様の難易度で 4.0 -> 4.1 のバージョンアップができる。

  • 手動およびバージョンアッププラグインでの2種類のバージョンアップ方法を用意する。
  • EC-CUBEのバージョンアップ前にプラグインおよび独自カスタマイズが EC-CUBE 4.1 対応されていることを前提とする。
  • バージョンアップは 4.0 系の最終バージョン(4.0.6の予定)からのバージョンアップとする。

技術面の補足(調査中)

  • composer.json の namebin/console eccube:composer:require-already-installed 内で小文字に変更する改修が必要。
  • package-api での EC-CUBE のバージョン判定方法はエンドポイントで良いか

環境 (environment)

  • EC-CUBE: 4.0.6 -> 4.1.0
  • PHP: 7.2 ~
  • DB:
    • PostgreSQL 9.6 ~
    • MySQL 5.7 ~

関連情報 (Ref)

EC-CUBE 4.1 Roadmap #4603
EC-CUBE 4.1 機能開発方針 #4901

@okazy okazy added this to the 4.1 milestone Mar 11, 2021
@okazy
Copy link
Contributor Author

okazy commented Mar 11, 2021

メモ(とりあえず考えを書いています)

無改造であればマイナーバージョンのバージョンアップと同様の手順でおおよそアップデート可能かと思います。
難しいのはカスタマイズされていた場合です。

カスタマイズ方法による対応方法の違い

  • 本体のコードを直接変更いただいている場合
    • Git OR 手動でのマージ
  • Customizeディレクトリ、 `app/template' でカスタマイズをされている場合
    • Customizeディレクトリを EC-CUBE 4.1 対応していただいた後に本体のバージョンアップを行う。
    • 本体のロジックをオーバーライドしている場合は、手作業でマージする必要あり
    • app/template 以下の twig テンプレートも必要に応じてマージする必要あり
  • プラグインを利用いただいていた場合
    • 利用いただいているプラグインが全て EC-CUBE 4.1 対応していないとバージョンアップができない
    • 通常の手順でプラグインのバージョンアップを行ったのち、本体のバージョンアップを行う。
    • composer.json の name は EC-CUBE 4.0/4.1 で互換性がないので、対策をする必要がある
      • 案1: 4.0 -> 4.1 のバージョンアップ時に全て小文字に書き換える
      • 案2: 4.0.6 では name が小文字でも動作するように改修する(要検証)
        • 4.0.5 以下のバージョンでは name 小文字には対応できないため現実的ではないか・・・

バージョン

  • 4.0 系は次にリリースされるであろう 4.0.6 が最終バージョンになるかと思われる。(セキュリティFIXを除く)
  • 4.0.6 に含まれる修正は 4.1.0 にも取り込まれた状態でリリースされる。
    • これらの差分は「フレームワークのアップデート(Symfonyなど)」と「いくつかの機能追加 ( EC-CUBE 4.1 機能開発方針 #4901 ) 」が含まれる。
  • EC-CUBE 4.0.5 以下のバージョンアップからのアップデートは「4.0.x -> 4.0.6」「4.0.6 -> 4.1.0」の2段階のバージョンアップが必要。

package-api (オーナーズストア側) の改修

  • composer.json の name は EC-CUBE 4.0/4.1 で互換性がない
    • 4.0 ではキャメルケース ec-cube/PluginCode
    • 4.1 では全て小文字 ec-cube/plugincode
  • オーナーズストアでは 4.0/4.1 のプラグインを同一のプラグインとして扱う。
  • EC-CUBE にインストール時に package-api で EC-CUBE のバージョンを確認して composer.json を切り替えて配信する
    • バージョンの確認方法
      • 現状 package-api へ EC-CUBE のバージョンは送信していないので判定できない
      • EC-CUBE 内で定義しているバージョンはカスタマイズ可能なため、こちらを送信して判定するのは得策ではない
      • 4.0/4.1 でエンドポイントを分けて配信するのが良いか

@okazy
Copy link
Contributor Author

okazy commented Mar 11, 2021

具体的なバージョンアップ手順(暫定)

前準備(順不同)

  • 独自カスタマイズの 4.1 対応
  • プラグインを 4.1 対応バージョンへバージョンアップ
  • 4.0.6 へのバージョンアップ

4.0.6 -> 4.1.0 へのバージョンアップ

  1. サイトのバックアップ
  2. メンテナンスモードを有効にする
  3. EC-CUBEのソースファイルを 4.1.0 に置き換え
  4. 個別ファイル差し替え
  5. composer.json/composer.lockの更新
  6. スキーマ更新/マイグレーション
  7. テンプレートファイルの更新
  8. メンテナンスモードを無効にする
EC-CUBEのソースファイルを 4.1.0 に置き換え

マイナーバージョンと変更なし

[root]
  │
  ├──[app/config/eccube]
  ├──[app/DoctrineMigrations]
  ├──[bin]
  ├──[src]
  ├──[html]
  ├──[vendor]
  │
個別ファイル差し替え(暫定)
composer.json
composer.lock
.htaccess
composer.json/composer.lockの更新

以下のコマンドをプラグインコードが小文字になるように対応すればいける(気がする)

bin/console eccube:composer:require-already-installed

@nanasess
Copy link
Contributor

  • 本体のコードを直接変更いただいている場合
    • 手動でのマージするしかない。

Git を利用できる方は、 Git でのバージョンアップがおすすめです
https://qiita.com/nanasess/items/7ad3592073458adae09d

  • Customizeディレクトリでカスタマイズをされている場合
    • Customizeディレクトリを EC-CUBE 4.1 対応していただいた後に本体のバージョンアップを行う。

本体のロジックをオーバーライドしている場合は、手作業でマージする必要があります

追加で、 app/template 以下の twig テンプレートも必要に応じてマージする必要があります

@okazy
Copy link
Contributor Author

okazy commented Mar 22, 2021

コメントありがとうございます!
確かに対応が必要です。

@okazy
Copy link
Contributor Author

okazy commented Apr 8, 2021

検証手順のメモです。

WebApiプラグインを準備

  1. 4.1 対応のWebApiプラグインをパッケージング https://github.com/EC-CUBE/eccube-api4/tree/4.1
  2. Mockサーバ起動 https://doc4.ec-cube.net/plugin_mock_package_api
  3. tgzの拡張子にしておく mv Api-41.tar.gz repos/Api-41.tgz

ファイル差し替え後にbundle がないためコマンドが使えなくなる

➜  ec-cube40-41 git:(4.1-beta2) bin/console cache:clear --no-warmup
PHP Fatal error:  Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "TrikoderOAuth2Bundle" from namespace "Trikoder\Bundle\OAuth2Bundle".
Did you forget a "use" statement for another namespace? in /ec-cube40-41/src/Eccube/Kernel.php:96
Stack trace:
#0 /ec-cube40-41/vendor/symfony/http-kernel/Kernel.php(446): Eccube\Kernel->registerBundles()
#1 /ec-cube40-41/vendor/symfony/http-kernel/Kernel.php(133): Symfony\Component\HttpKernel\Kernel->initializeBundles()
#2 /ec-cube40-41/src/Eccube/Kernel.php(113): Symfony\Component\HttpKernel\Kernel->boot()
#3 /ec-cube40-41/vendor/symfony/framework-bundle/Console/Application.php(169): Eccube\Kernel->boot()
#4 /ec-cube40-41/vendor/symfony/framework-bundle/Console/Application.php(75): Symfony\Bundle\FrameworkBundle\Console\Application->registerCommands()
#5  in /ec-cube40-41/src/Eccube/Kernel.php on line 96

関連商品プラグインを準備

  1. clone
  2. checkout 4.1
  3. tar
  4. mv

EC-CUBE 4.0 をインストール

composer1 の composer.phar を準備しておく

php composer.phar -V
Composer version 1.10.17 2020-10-30 22:31:58
  1. git clone https://github.com/EC-CUBE/ec-cube.git ec-cube40-41
  2. php composer.phar install
  3. DBの設定 vi .env
  4. bin/console eccube:install --no-interaction
  5. echo ECCUBE_PACKAGE_API_URL=http://127.0.0.1:9999 >> .env
  6. psql eccubedb -h 127.0.0.1 -U postgres -c "update dtb_base_info set authentication_key='test';" / mysql -u root -p -h 127.0.0.1 eccube -e "update dtb_base_info set authentication_key='test';"
  7. bin/console s:run --env=dev
  8. 管理画面からプラグインをインストール・有効化
  9. 動作確認
  10. プラグインを無効化

EC-CUBE 4.1 へのアップデート

別ディレクトリに EC-CUBE 4.1 を準備しておく
composer2 の composer も準備しておく

ファイルの差し替え

  1. git checkout composer.json composer.lock
  2. git checkout refs/tags/4.1-beta2 -b 4.1-beta2
  3. rm -rf vendor AND composer install cp -rf ../ec-cube_41/vendor ./
  4. bin/console cache:clear --no-warmup
  5. bin/console eccube:composer:require-already-installed
  6. bin/console doctrine:schema:update --force --dump-sql
  7. bin/console doctrine:migrations:migrate
  8. rm -rf app/proxy/entity/*
  9. composer dump-autoload
  10. bin/console eccube:generate:proxies
  11. bin/console cache:warmup --env=dev
  12. bin/console s:run --env=dev
  13. 動作確認

残課題

  • bundleを利用している場合のアップデート
  • composer.json の name に大文字が入っている場合のアップデート

@okazy
Copy link
Contributor Author

okazy commented Apr 12, 2021

bundleを利用している場合のアップデート

vendorの差し替え時に削除ではなく、上書きにする。

bin/console eccube:composer:require-already-installed

こちらの実行時に不要なファイルはこちらで削除される想定。

composer.json の name に大文字が入っている場合のアップデート

composer 自体が動かないと思うので、事前に手動で変更 or アップデートプラグインの冒頭で変更

@okazy
Copy link
Contributor Author

okazy commented Apr 12, 2021

作業中

cp -rf ../ec-cube41/vendor ./

@okazy okazy changed the title EC-CUBE 4.0 -> 4.1 へのアップデートについて Symfony bundle利用時のアップデートについて Jun 2, 2021
@okazy okazy changed the title Symfony bundle利用時のアップデートについて プラグインでSymfony bundle利用時のアップデートについて Jun 2, 2021
@okazy
Copy link
Contributor Author

okazy commented Jun 3, 2021

マイナーバージョンアップの場合は vendor を上書きする方法でバージョンアップが可能でした。
ドキュメントにプルリクを送りました。
EC-CUBE/doc4.ec-cube.net#196

@okazy
Copy link
Contributor Author

okazy commented Jun 24, 2021

メジャーバージョンアップの際はプラグインを無効化してから実施する手順とする

@okazy
Copy link
Contributor Author

okazy commented Jun 24, 2021

プラグインを無効にしてからアップデートをしてみましたが、同じエラーが発生しました。

Symfony bundle の読み込みが早すぎて registerBundles() 時点でプラグインが有効化されているかの判定ができません。
無効なプラグインの Symfony bundle の読み込みを回避するのは困難です。

public function registerBundles()

https://github.com/symfony/symfony/blob/ef06f338f22d6624e24bc54cc1952d14e71cd75e/src/Symfony/Component/HttpKernel/Kernel.php#L132

@okazy
Copy link
Contributor Author

okazy commented Jun 24, 2021

Symfony bundle の読み込みを回避してみましたが、 services.yaml の読み込みでエラーとなりました。

Eccube/Kernel::registerBundles()

        foreach ($plugins as $code) {
            $pluginBundles = $pluginDir.'/'.$code.'/Resource/config/bundles.php';
            if (file_exists($pluginBundles)) {
                $contents = require $pluginBundles;
                foreach ($contents as $class => $envs) {
                    if (isset($envs['all']) || isset($envs[$this->environment])) {
+                        if (class_exists($class)) {
                            yield new $class();
+                        }
                    }
                }
            }
        }
In FileLoader.php line 180:

  There is no extension able to load the configuration for "trikoder_oauth2" (in "/app/Plugin/Api/Resource/config/services.yaml"). Looked for namespace "trikoder_oauth2", found ""framework", "security", "
  doctrine_cache", "doctrine", "doctrine_migrations", "doctrine_fixtures", "sensio_framework_extra", "monolog", "swiftmailer", "twig"
  , "debug", "web_server", "web_profiler", "maker", "mobile_detect", "knp_paginator", "api", "eccube"" in /app/Plugin/Api/Resource/config/services.yaml (which is loaded in resource "/app/Plugin/Api/Resource/config/services.yaml").


In YamlFileLoader.php line 721:

  There is no extension able to load the configuration for "trikoder_oauth2" (in "/app/Plugin/Api/Resource/config/services.yaml"). Looked for namespace "trikoder_oauth2", found ""framework", "security", "
  doctrine_cache", "doctrine", "doctrine_migrations", "doctrine_fixtures", "sensio_framework_extra", "monolog", "swiftmailer", "twig"
  , "debug", "web_server", "web_profiler", "maker", "mobile_detect", "knp_paginator", "api", "eccube"".

@okazy
Copy link
Contributor Author

okazy commented Jun 24, 2021

無効になっているプラグインのbundleとconfigを読み込まないようにしてみましたが、
okazy@468414e

In ArrayNode.php line 327:

  Unrecognized option "oauth2" under "security.firewalls.api". Available options are "access_denied_handler", "access_denied_url", "a
  nonymous", "context", "entry_point", "form_login", "form_login_ldap", "guard", "host", "http_basic", "http_basic_ldap", "json_login
  ", "json_login_ldap", "logout", "logout_on_user_change", "methods", "pattern", "provider", "remember_me", "remote_user", "request_m
  atcher", "security", "simple_form", "simple_preauth", "stateless", "switch_user", "user_checker", "x509".

app/Plugin/Api/DependencyInjection/ApiExtension.phpsecurity.firewalls を設定しているところをコメントアウトしてみましたが以下のエラーが発生しました。

PHP Fatal error:  Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load interface "ClientAware" from namespace "GraphQL\Error".
Did you forget a "use" statement for another namespace? in /app/Plugin/Api/GraphQL/Error/InvalidArgumentException.php:18
Stack trace:
#0 /vendor/composer/ClassLoader.php(480): include()
#1 /vendor/composer/ClassLoader.php(346): Composer\Autoload\includeFile()
#2 /vendor/symfony/debug/DebugClassLoader.php(167): Composer\Autoload\ClassLoader->loadClass()
#3 [internal function]: Symfony\Component\Debug\DebugClassLoader->loadClass()
#4 [internal function]: spl_autoload_call()
#5 /src/Eccube/DependencyInjection/Compiler/AutoConfigurationTagPass.php(42): is_subclass_of()
#6 /app/Plugin/Api/GraphQL/Error/InvalidArgumentException.php on line 18

rm -rf var/cache/* しても症状は変わりません

助けてください 😢

@nanasess
Copy link
Contributor

@okazy この状態で composer dumpautoload を実行してみるとどうでしょうか?

@okazy
Copy link
Contributor Author

okazy commented Jun 24, 2021

ありがとうございます。
composer dumpautoload を実行してみましたが、上記エラーは解決せずでした。。。

@okazy
Copy link
Contributor Author

okazy commented Jun 24, 2021

APP_ENV=prod で実行すると少しエラーが変わりました。

PHP Fatal error:  Uncaught Error: Interface 'GraphQL\Error\ClientAware' not found in /app/Plugin/Api/GraphQL/Error/InvalidArgumentException.php:18
Stack trace:
#0 /vendor/composer/ClassLoader.php(480): include()
#1 /vendor/composer/ClassLoader.php(346): Composer\Autoload\includeFile()
#2 [internal function]: Composer\Autoload\ClassLoader->loadClass()
#3 [internal function]: spl_autoload_call()
#4 /src/Eccube/DependencyInjection/Compiler/AutoConfigurationTagPass.php(42): is_subclass_of()
#5 /src/Eccube/DependencyInjection/Compiler/AutoConfigurationTagPass.php(35): Eccube\DependencyInjection\Compiler\AutoConfigurationTagPass->configureDoctrineEventSubscriberTag()
#6 /vendor/s in /app/Plugin/Api/GraphQL/Error/InvalidArgumentException.php on line 18

@nanasess
Copy link
Contributor

@okazy composer の classloader に登録されているはずのファイルが見つからないって言っているので、以下の手順でどうでしょう?

プラグインは無効化しておく

  1. git checkout composer.json composer.lock
  2. git checkout refs/tags/4.1-beta2 -b 4.1-beta2
  3. cp -rf ../ec-cube_41/vendor ./
  4. rm -rf var/cache # キャッシュを明示的に削除
  5. composer dumpautoload # classmap を再生成
  6. bin/console eccube:composer:require-already-installed

@okazy
Copy link
Contributor Author

okazy commented Jun 25, 2021

@nanasess
いただいた手順でも同様のエラーが発生しました。

➜  ec-cube_40-41_rm git:(4.1-beta2) ✗ bin/console eccube:composer:require-already-installed
PHP Fatal error:  Uncaught Error: Class 'Trikoder\Bundle\OAuth2Bundle\TrikoderOAuth2Bundle' not found in /src/Eccube/Kernel.php:96
Stack trace:
#0 /vendor/symfony/http-kernel/Kernel.php(446): Eccube\Kernel->registerBundles()
#1 /vendor/symfony/http-kernel/Kernel.php(133): Symfony\Component\HttpKernel\Kernel->initializeBundles()
#2 /src/Eccube/Kernel.php(113): Symfony\Component\HttpKernel\Kernel->boot()
#3 /vendor/symfony/framework-bundle/Console/Application.php(169): Eccube\Kernel->boot()
#4 /vendor/symfony/framework-bundle/Console/Application.php(75): Symfony\Bundle\FrameworkBundle\Console\Application->registerCommands()
#5 /ve in /src/Eccube/Kernel.php on line 96

Trikoder の bundle と services.yaml 読み込み回避した結果が以下です。

➜  ec-cube_40-41_rm git:(4.1-beta2) ✗ git checkout okazy/dev-bundle-update  -b dev-bundle-update
Branch 'dev-bundle-update' set up to track remote branch 'dev-bundle-update' from 'okazy'.
Switched to a new branch 'dev-bundle-update'
➜  ec-cube_40-41_rm git:(dev-bundle-update) ✗ bin/console eccube:composer:require-already-installed

In ArrayNode.php line 327:

  Unrecognized option "oauth2" under "security.firewalls.api". Available options are "access_denied_handler", "access_denied_url", "a
  nonymous", "context", "entry_point", "form_login", "form_login_ldap", "guard", "host", "http_basic", "http_basic_ldap", "json_login
  ", "json_login_ldap", "logout", "logout_on_user_change", "methods", "pattern", "provider", "remember_me", "remote_user", "request_m
  atcher", "security", "simple_form", "simple_preauth", "stateless", "switch_user", "user_checker", "x509".

@okazy
Copy link
Contributor Author

okazy commented Jun 25, 2021

アップデートプラグインで回避されていたので、真似してやってみます。
EC-CUBE/eccube-update-plugin@bfa1154

@okazy
Copy link
Contributor Author

okazy commented Jun 25, 2021

次は Symfony 4 で追加された interface でエラーとなりました。
Symfony のメジャーバージョンアップを cp コマンドで実施するのに限界を感じています。

git checkout composer.json composer.lock
git checkout refs/tags/4.1-beta2 -b 4.1-beta2
cp -rf ../ec-cube_41/vendor ./

cp -f ../ec-cube_40/vendor/autoload.php ./vendor/
cp -f ../ec-cube_40/vendor/composer/autoload_classmap.php ./vendor/composer/
cp -f ../ec-cube_40/vendor/composer/autoload_files.php ./vendor/composer/
cp -f ../ec-cube_40/vendor/composer/autoload_namespaces.php ./vendor/composer/
cp -f ../ec-cube_40/vendor/composer/autoload_psr4.php ./vendor/composer/
cp -f ../ec-cube_40/vendor/composer/autoload_real.php ./vendor/composer/
cp -f ../ec-cube_40/vendor/composer/autoload_static.php ./vendor/composer/
cp -f ../ec-cube_40/vendor/composer/installed.json ./vendor/composer/

rm -rf var/cache # キャッシュを明示的に削除
bin/console eccube:composer:require-already-installed
➜  ec-cube_40-41 git:(4.1-beta2) bin/console eccube:composer:require-already-installed
PHP Fatal error:  Uncaught Error: Interface 'Symfony\Contracts\Service\ResetInterface' not found in /vendor/symfony/console/Application.php:65
Stack trace:
#0 /vendor/composer/ClassLoader.php(480): include()
#1 /vendor/composer/ClassLoader.php(346): Composer\Autoload\includeFile()
#2 [internal function]: Composer\Autoload\ClassLoader->loadClass()
#3 /vendor/symfony/framework-bundle/Console/Application.php(31): spl_autoload_call()
#4 /vendor/composer/ClassLoader.php(480): include('/Users/hideki_o...')
#5 /vendor/composer/ClassLoader.php(346): Composer\Autoload\includeFile()
#6 [internal function]: Composer\Autoload\ClassLoader->loadClass()
#7 [internal function]: spl_autoload_call()
#8 /vendor/symfony/console/Application.php on line 65

@okazy
Copy link
Contributor Author

okazy commented Jun 25, 2021

回避方法案

  • bundle入りのプラグインは削除してからアップデート
  • EC-CUBE 4.1 で bundleプラグイン入りの vendor を用意する

いずれの場合もアップデートの難易度はかなり上がる。

@okazy
Copy link
Contributor Author

okazy commented Jun 25, 2021

API プラグインが同梱されている 4.1-beta2 のパッケージから vendor をコピーすることでバージョンアップが可能なことを確かめました。

@chihiro-adachi
Copy link
Contributor

@okazy
doc4の手順どおりで特にトラブルなくアップデートできました。

# 4.0.6-p1のセットアップ

unzip eccube-4.0.6-p1.zip

cd eccube-4.0.6-p1

bin/console e:i

echo >> .env
echo ECCUBE_PACKAGE_API_URL=http://127.0.0.1:9999 >> .env

mkdir repos
cp ~/path/to/eccube-api4.tar.gz repos/api.tgz

sqlite3 var/eccube.db;
update dtb_base_info set authentication_key='test';

docker run --rm -v ${PWD}/repos:/repos -e MOCK_REPO_DIR=/repos -p 9999:8080 eccube/mock-package-api

bin/console eccube:composer:require ec-cube/Api
bin/console e:p:e --code Api

# アップデート

unzip eccube-4.1-beta2.zip 

rm -rf eccube-4.0.6-p1/html        
rm -rf eccube-4.0.6-p1/src                           
rm -rf eccube-4.0.6-p1/bin                           
rm -rf eccube-4.0.6-p1/app/DoctrineMigrations        
rm -rf eccube-4.0.6-p1/app/config/eccube    

cp -r eccube-4.1-beta2/html eccube-4.0.6-p1/
cp -r eccube-4.1-beta2/src eccube-4.0.6-p1/   
cp -r eccube-4.1-beta2/bin eccube-4.0.6-p1/          
cp -r eccube-4.1-beta2/app/DoctrineMigrations eccube-4.0.6-p1/app/
cp -r eccube-4.1-beta2/app/config/eccube eccube-4.0.6-p1/app/config

cp -r eccube-4.1-beta2/vendor eccube-4.0.6-p1/ 
cp  eccube-4.1-beta2/composer.json eccube-4.0.6-p1/
cp  eccube-4.1-beta2/composer.lock eccube-4.0.6-p1/

bin/console c:c --no-warmup

bin/console eccube:composer:require-already-installed
bin/console doctrine:schema:update --force --dump-sql
bin/console doctrine:migrations:migrate
bin/console eccube:generate:proxies
bin/console cache:warmup

@chihiro-adachi
Copy link
Contributor

bundleを使っているプラグインがある場合の手順を記載しました
https://github.com/EC-CUBE/doc4.ec-cube.net/pull/215/files#diff-fef4cbe15ac80014b4f840d2ac79b8e974d83edd95b87e64d0f4cc1e4e84ab1aR145

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants