PHP Conference Japan 2019での発表資料(25分発表エディション)です
https://fortee.jp/phpcon-2019/proposal/80fe2e57-a35d-48cd-9c78-4af5000cbeac
© - BASE, Inc.Composerって何? どう動くの? 読んでみました!. . - PHP Conference Japan
View Slide
© - BASE, Inc.⾃⼰紹介• ۚलथ / ͖Μ͡ΐ͏ͻͰ͖• GitHub: @o0h / Twitter: @o0h_• BASE, Inc. (2019.10) / ج൫νʔϜ• ex Connehito Inc.(2015.04-)• ͖ͳFWCakePHP• ΞΠίϯ ඒຯ͍͠ࡪࢠကͷࣸਅͰ͢
© - BASE, Inc.本⽇は Composerのお話です!Composer\Console\Application::$logo
© - BASE, Inc.Composer、 使った事ありますか?
© - BASE, Inc.では、 Composerで 困った事ありませんか?
• install͕͍• ίϯϑϦΫτʁʁͳΜౖ͔ΒΕͨʂ• Φϓγϣϯ͕Α͔͘ΒΜ• ίϯϑΟάΑʔΘ͔ΒΜ• .lockߋ৽ͰPR͛ΒΕͯwww
© - BASE, Inc.いつもあんなにお世話になってるのに、彼(⼥)が困っている時に何もしてあげられない。
© - BASE, Inc.それって、 とても切なくないですか?
© - BASE, Inc.よし、 じゃあ腹割って話をしてみよう!
© - BASE, Inc.Composerって どういう仕組みで 動いているのかな? みたいな話をしますお話することcomposer installΛྫʹ
© - BASE, Inc.Composerの 「使い⽅」については 触れません!お話しないこと
© - BASE, Inc.この発表を機に、「Composer怖くないよ!」と 感じてくれる⼈を増やしたい今回のゴール
© - BASE, Inc.Composerはあくまで⼀例。「普段使っているツール」について、 その中⾝に興味を持ってみるのは楽しいよ!というのを感じてもらえたら幸いです。今回の(裏)ゴール
© - BASE, Inc.ΑΖ͓͘͠Ͷ͕͍͠·͢ʂͱ͍͏͜ͱͰʂ
© - BASE, Inc.おしながきInstallコマンドの全体感‧概要の整理初めてのComposerInstallコマンドの中⾝を⾒てみる
© - BASE, Inc.ComposerͱԿ͔ʁ
© - BASE, Inc.ComposerͱԿ͔ʁ=>ComposerύοέʔδཧγεςϜ※ެࣜαΠτͰʮComposer is a tool for dependency management in PHP.ʯͱઆ໌͍ͯ͠·͢ɻ Introduction - Composer https://getcomposer.org/doc/00-intro.md
パッケージ管理システム?© - BASE, Inc.• ϨϙδτϦͷߪಡ• ύοέʔδͷΠϯετʔϧɾআ• ґଘؔͷղܾ• ઃఆཧhttps://ja.wikipedia.org/wiki/ύοέʔδཧγεςϜ
パッケージ管理とComposer© - BASE, Inc.• PackagistͱΓͱΓͨ͠Γ <= ϨϙδτϦͷߪಡ• GitHub͔Βguzzlehttp/clientΛऔಘͯ͠ஔͨ͠Γ <= ύοέʔδͷΠϯετʔϧɾআ• ^1.2ͱ~1.2ʹର͠1.3.0Ͱͳ͘1.2.9ΛऔͬͨΓ <= ґଘؔͷղܾ• composer.jsonͷதΛղऍͨ͠Γ <= ઃఆཧ
パッケージ管理の「PHP実装」© - BASE, Inc.ґଘཧͷେม͞ΑʂύοέʔδཧͩʂComposerരʂ՝ղ๏࣮
抽象の解釈としての実装© - BASE, Inc.• ϨϙδτϦͷߪಡ• ύοέʔδͷΠϯετʔϧɾআ• ґଘؔͷղܾ• ઃఆཧݱ࣮ɾந ιϑτΣΞɾ࣮• \Composer\Repository\• \Composer\Installer\• \Composer\Package\• \Composer\DependencyResolver\
\Composer\Repository\© - BASE, Inc.• ϨϙδτϦใͷཧ–repositories[].typeͷ෦ʹରԠ͢ΔΠϝʔδ• ex:–ComposerRepository: packagistϨϙ–VcsRepository: GitHubSVNͳͲͷϨϙ–PathRepository: ϩʔΧϧϑΝΠϧRepositories - Composer https://getcomposer.org/doc/05-repositories.md
\Composer\Installer\© - BASE, Inc.• Πϯετʔϧͷཧ–ύοέʔδDLͷىಈͱ͔औಘϑΝΠϧͷஔͱ͔• ex:–LibraryInstaller: packageͷΠϯετʔϧ–ProjectInstaller: root projectͷΠϯετʔϧ–PluginInstaller: plugin packageͷΠϯετʔϧ–PearInstaller: pear packageͷΠϯετʔϧ
\Composer\Package\© - BASE, Inc.• ύοέʔδใͷཧ–composer.jsonΛղऍͨ͠Γ• ex:–RootPackage: root projectͷཧ–Locker: composer.lockͷཧ–Link: packageؒͷ(ґଘ)ؔ
\Composer\DependencyResolver\© - BASE, Inc.• ґଘؔͷཧ–ෳϨϙ͔ΒύοέʔδใΛ౷߹ͨ͠Γ–install͢Δ͔ʁupdate͢Δ͔?ͦͷ··͔?ΛܾΊͨΓ• ex:–Solver: ґଘؔΛཧ͠ύοέʔδͷѻ͍ΛܾΊΔ–Pool: ϨϙδτϦύοέʔδใͷू–Operation: install,update,removeͳͲͷૢ࡞Λࣔ͢
© - BASE, Inc.ίί·Ͱୈ1ষʂ
初めてのComposer: まとめ© - BASE, Inc.• ύοέʔδཧʹඞཁͳཁૉ–ϨϙδτϦ,Πϯετʔϥ,ґଘղܾ,ઃఆཧ• Composerύοέʔδཧͷʮ࣮ʯ–্هͷ4֓೦ʹ͍ͭͯɺ ͦΕͧΕରԠ͢Δnamespace͕ଘࡏ͢Δ
$ composer instal -vvv
͜ͷը໘ͷҙຯ͕͔ΔΑ͏ʹ͢Δͧʂ
© - BASE, Inc.コードの「⼊り⼝」を捉えるinstallίϚϯυͷىಈ·ͰͷྲྀΕΛΔ·ͣ
ApplicationとしてのComposer© - BASE, Inc.Composerͷຊମͱ͍͑ίΠπͰ͕͢
ApplicationとしてのComposer© - BASE, Inc.தΛݟͯΔͱɺ࣮ଶConsole\Application
symfony/console© - BASE, Inc.• Composersymfony/consoleΛར༻• CLIπʔϧΛ؆୯ʹ࡞ΕΔύοέʔδ• CommandΫϥεͱ͍͏୯ҐΛ࡞Γ• Applicationͷதʹొ͢Δ※ symfony/consoleʹ͍ͭͯίνϥͷهࣄͳͲΛͲ͏ͦ Container(PSR-11)ͱsymfony/consoleͰ؆୯ͳίϚϯυϥΠϯΞϓϦέʔγϣϯΛ࡞ͬͯΈΑ͏ - istyle Tech Blog https://techblog.istyle.co.jp/archives/97
Composer\Command© - BASE, Inc.$composer about$composer config$composer check-platform-
installってどこにあるの?© - BASE, Inc.InstallCommandΫϥε
© - BASE, Inc.InstallCommand::execute()ͷେ·͔ͳΠϝʔδ
© - BASE, Inc.InstallCommand::execute()ͷେ·͔ͳΠϝʔδfactoryͯ͠
© - BASE, Inc.InstallCommand::execute()ͷେ·͔ͳΠϝʔδઃఆͯ͠
© - BASE, Inc.InstallCommand::execute()ͷେ·͔ͳΠϝʔδ࣮ߦʂ
© - BASE, Inc.(༨ஊ)ΫϥεʮComposer\Installerʯͱ໊લۭؒʮComposer\Installer\*ʯ͕͋Γ·͕͢ผͰ͢ɻClass namespace
© - BASE, Inc.֓؍
© - BASE, Inc.ΊͬͪΌ؆୯Μ͚ʂʂ
© - BASE, Inc.ຊʹͦ͏͔ʂʁ
© - BASE, Inc.メインとなる仕事の中⾝を追うInstallCommandͷࣄ ≒ Installerͷࣄ=>͡Ό͋InstallerಡΊྑ͍͔
Installerを開くと‧‧© - BASE, Inc.ίϯετϥΫλ͔Βͯ͠طʹେมͦ͏…
© - BASE, Inc.ෳࡶͦ͏ͳίʔυɺ۩ମతʹಡΈ࢝ΊΔલʹ ࣄ༰ͷΠϝʔδͱ ʮίίͲ͏ͳͬͯΔΜͩʁʯΛཧ͓ͯ͘͠ਤΛඳ͘
installの⼤まかな流れ© - BASE, Inc.1.PJใ(RootPackage)ͷಡΈࠐΈ2.ϨϙδτϦใͷಡΈࠐΈ3.ߋ৽༰ͷࢉग़(ґଘੑͷཧ)4.ύοέʔδͷऔಘɾஔ5..lockϑΝΠϧͷߋ৽6.autoloadϑΝΠϧͷੜࣄલॲཧґଘղܾࣄޙॲཧ
© - BASE, Inc.͜ͷลΓΛ೦಄ʹஔ͖ͭͭ ࣮ࡍͷྲྀΕΛݟͯΈΔʂʂ
Installer::run()の全体像© - BASE, Inc.functionͷத ͜Μͳײ͡
Installer::run()の全体像© - BASE, Inc.ΠϯετʔϧࡁΈͷύοέʔδใΛ औಘͯ͠
Installer::run()の全体像© - BASE, Inc.ґଘੑͷղܾ ύοέʔδͷऔಘ &ஔΛͯ͠
Installer::run()の全体像© - BASE, Inc..lockϑΝΠϧΛ ߋ৽ͯ͠
Installer::run()の全体像© - BASE, Inc.autoloadϑΝΠϧͷ ग़ྗʂ
© - BASE, Inc.͜Ε͕installͷਖ਼ମʂʂʙୈ2ষɾfinʙ
Installコマンドの全体感‧概要の整理: まとめ© - BASE, Inc.• جຊతͳίϚϯυ src/Composer/Commandʹ Ϋϥεͱ࣮ͯ͠͞Ε͍ͯΔ• Installॲཧͷ࣮ଶɺ InstallCommand->Installer::run()ʹ͋Δ
installの⼤まかな流れ© - BASE, Inc.1.PJใ(RootPackage)ͷಡΈࠐΈ2.ϨϙδτϦใͷಡΈࠐΈ3.ߋ৽༰ͷࢉग़(ґଘੑͷཧ)4.ύοέʔδͷऔಘɾஔ5..lockϑΝΠϧͷߋ৽6.autoloadϑΝΠϧͷੜࣄલॲཧґଘղܾࣄޙॲཧ࠶ܝ
© - BASE, Inc.PJ情報の読み込み事前処理①
PJの読み込み?© - BASE, Inc.• ϓϩδΣΫτ(PJ)ύοέʔδͷҰܗଶ• ύοέʔδ ͕ࣗґଘ͍ͯ͠ΔϞϊͷใΛ࣋ͭ• ͳͷͰґଘղܾͷ࠷ॳͷҰา ʮPJͷใΛಡΈࠐΉʯ͜ͱ
RootPackage© - BASE, Inc.• ComposerͷੈքͰɺ 1ͭͷcomposer.jsonʹରԠͯ͠ 1ͭͷPackageΠϯελϯε͕࡞ΕΔ• ͦͷதͰɺ PJࣗ = rootͱͳΔPackage RootPackageΠϯελϯε͕࡞ΒΕΔ
Package© - BASE, Inc.• ͭ·Γ `composer install` ࣮ߦͱ RootPackageͷґଘੑͷղܾͱݴ͑Δ• Packageͷதʹɺࣗͷόʔδϣϯใґଘ͢Δύοέʔδͷใetcؚ͕·Ε͍ͯΔ
RootPackageの取得© - BASE, Inc.Installer::create()Composer::getPackage()
© - BASE, Inc.レポジトリ情報の読み込み事前処理②
[定義]レポジトリってなんだ?© - BASE, Inc.• (ར༻Մೳͳ)ύοέʔδใΛཧ͢Δ–໊લ–όʔδϣϯ–औಘઌ
レポジトリ情報の読み込み© - BASE, Inc.• ࢦఆ͞Εͨͷ͕ଘࡏ͢Δ͔ʁ Ͳ͜ʹ͋Δ͔ʁΛΒͳ͍ͱ ύοέʔδͷDL͕Ͱ͖ͳ͍• ϨϙδτϦ͕ͦΕΛཧ͢Δɻ ʮԿͷύοέʔδ͕༗Δ͔ʯͷใΛ Ѳ͠ɺϢʔβʔʹఏڙ͢Δ
Repository(Interface)© - BASE, Inc.• ComposerͷੈքͰɺ ϨϙδτϦRepositoryInterfaceͷ࣮Ͱදݱ͞ΕΔ• RepositoryʮύοέʔδใͷҰཡʯΛಡΈࠐΈɺཧ͢Δ• ʮऔಘʯʮݕࡧʯͷػೳΛఏڙ͢Δ
composer installͰɺ ϩʔΧϧٴͼϦϞʔτͷใ͕ؔΘΔ基本的なレポジトリ3つ© - BASE, Inc.ϩʔΧϧInstalledFilesystemRepoPlatformRepo(΄΅) vendorσΟϨΫτϦPHPͷγεςϜใϦϞʔτ ComposerRepo Packagist
InstalledFilesystemRepo© - BASE, Inc.• ΠϯετʔϧࡁΈύοέʔδͷཧ–༰ `vendor/composer/installed.json`• ʮطʹ͋ΔPackageʯͷղܾ ͜ͷϨϙδτϦΛૢ࡞͢Δ͜ͱͰ࣮ݱ
InstalledFilesystemRepoの様⼦© - BASE, Inc.$composer show —tree
• γεςϜཁ݅ͷཧ–phpͷόʔδϣϯ༗ޮͳ֦ுͳͲ• requireʹ'php””ext-XXX”͕هड़͞Εͨ࣌ʹར༻͞ΕΔPlatformRepository© - BASE, Inc.composer.json
PlatformRepositoryの様⼦© - BASE, Inc.$composer show —platform
ComposerRepository© - BASE, Inc.• Packagist্ͷύοέʔδͷཧ–༰ `https://packagist.org/packages.json`• indexϑΝΠϧ–͜͜ʹه͞Ε͍ͯΔιʔεΛϑΣον͢Δ• ࠷ॳʮύοέʔδ໊ͷҰཡʯͷΈ–ͨͩ͠ɺͦΕࣗମԆॲཧ͞ΕΔ–ղܾ͕ඞཁͳύοέʔδ͕ग़͖ͯͨ࣌ʹ ύοέʔδݸผͷใΛऔΓʹߦ͘
ComposerRepositoryのリスト更新© - BASE, Inc.ϦετΛऔಘ͍ͯ͠Δ༷ࢠ$ composer install
© - BASE, Inc.isntallʹ͓͍ͯɺ͜ΕΒͲ͏ѻΘΕΔ͔ʁ
Poolの作成とRepoの登録© - BASE, Inc.• Pool–ϨϙδτϦύοέʔδΛཧ͢Δ–ҎޙɺϨϙδτϦʹର͢Δύοέʔδͷ͍߹Θͤ(جຊతʹ)PoolΛհͯ͠ߦΘΕΔ• ґଘੑͷղܾʹਐΉલʹɺ ࡞͞Ε͍ͯΔ3ͭͷRepositoryΠϯελϯεΛPoolʹొ͢Δ
Poolの作成とRepoの登録© - BASE, Inc.Installer::doInstall
Poolの作成とRepoの登録© - BASE, Inc.Poolͷ࡞
Poolの作成とRepoの登録© - BASE, Inc.ϩʔΧϧRepoͷొ
Poolの作成とRepoの登録© - BASE, Inc.ଞͷRepoͷొ
© - BASE, Inc.ίί·Ͱࣄલॲཧ
installの事前処理: まとめ© - BASE, Inc.• PJใRootPackageͱͯ͠ΠϯελϯεԽ͞ΕΔ• installʹ͓͍ͯϩʔΧϧͱϦϞʔτͷRepository͕ಡΈࠐ·ΕΔ–InstalledFilesystem, Platform, Composer• ಡΈࠐ·ΕͨRepositoryPoolʹՃ͞Εɺ౷߹తʹղܾ͢Δͷʹར༻͞ΕΔ
© - BASE, Inc.更新内容の算出(依存性の整理)依存解決①
更新内容の算出(依存性の整理)?© - BASE, Inc.• (rootΛؚΉ)ෳͷύοέʔδ͕ɺ ͦΕͧΕʹෳͷύοέʔδʹґଘ͍ͯ͠Δ• ͦΕΒͷใΛ౷߹͢Δඞཁ͕͋Δ–֤ύοέʔδ͕Կʹґଘ͍ͯ͠Δ͔Λ࠶ؼతʹѲ͢Δ–ચ͍ग़͞Εͨґଘʹ͍ͭͯɺڞ༗Ͱ͖Δͷিಥ͕ͳ͍͔ΛௐΔ• ࠷ऴతʹʮԿ͕΄͍͔͠ʯΛѲ͢Δ
© - BASE, Inc.ߟ͑ͳ͚Ε͍͚ͳ͍ͷɺ Packageͷrequireใ͔Βελʔτͯ͠ ґଘઌͷґଘ͋ΔதͰ શͯͷ݅(ࢦఆver.)Λຬͨ͢ʹ ԿΛऔಘ͢Εྑ͍ͷ͔ʁͷ ʮਖ਼ղʯΛݟ͚ͭΔɺͱ͍͏͜ͱ
© - BASE, Inc.ߟ͑ͳ͚Ε͍͚ͳ͍ͷɺ Packageͷrequireใ͔Βελʔτͯ͠ ґଘઌͷґଘ͋ΔதͰ શͯͷ݅(ࢦఆver.)Λຬͨ͢ʹ ԿΛऔಘ͢Εྑ͍ͷ͔ʁͷ ʮਖ਼ղʯΛݟ͚ͭΔɺͱ͍͏͜ͱͬ͘͟ΓͱॲཧखॱͷΠϝʔδ͚ͩઆ໌ෳࡶͩͶʂ
PackageとRequest© - BASE, Inc.• Package->requiresͷใΛ࿈Ͷ͍ͯ͘ʮཉ͍͠ʯͷΩϡʔΛଋͶΔΫϥε͕ཉ͍͠• ͦΕ͕RequestΫϥε• require1ߦ͝ͱʹjob͕1ݸͰ͖ΔΠϝʔδ(=job)Packagephpunit/phpunit:^8.4Requestjobs
RequestとJob© - BASE, Inc.Requestjobs job୯७ͳ࿈ྻ• jobͷ࣋ͭใ–cmd• install|update|remove–packageName–constraint• ver.ࢦఆ
RequestとSolver© - BASE, Inc.• Solver::solve()ʹ RequestΛ͢• ͜ͷதͰڝ߹݅ɾڞ௨෦͕ߟྀ͞ΕΔ• jobsΛݩʹɺ ʮԿΛ͢Ε͍͍͔ʯΛInstallerʹฦͯ͘͠ΕΔSolverRequestOperation[]
Operation© - BASE, Inc.• job͕ղܾ͞Εɺ࠷ऴతʹߋ৽ૢ࡞͕ඞཁͳͷ͚͕ͩฦ͞ΕΔ• ྫ͑”Nothing toinstall or update”ͳΒɺ`solve()`ͷฦΓۭྻSolverOperationjobs Operationjobs Operation
© - BASE, Inc.パッケージの取得‧配置依存解決②
パッケージの取得‧配置?© - BASE, Inc.• ʮͲͷύοέʔδΛऔಘ(ߋ৽ɺআ)͢Εྑ͍͔ʯͱ͍͏ใΛಘͨ• ͦΕͧΕʹ͍ͭͯɺదͳॴ͔Βऔಘ͢Δ• ඞཁʹԠͯ͡ղౚमਖ਼ͳͲͷॲཧ͞Έͭͭɺ࠷ऴతʹنଇతͳॴஔ͢Δ
実際にパッケージをDLしてくる© - BASE, Inc.• ύοέʔδͷΠϯετʔϧɺInstallationManager::execute()ʹΑͬͯߦΘΕΔ• औಘݩPackage͕͍ͬͯΔ• DLઌΛܾఆ͢ΔͷInstallerͷࣄ• DLΛ͢ΔͷDownloaderͷࣄ
© - BASE, Inc.Operation[]ΛInstallationManagerʹ͢໘Installer::doInstall()
流れ© - BASE, Inc.
流れ© - BASE, Inc.ݟ͑ͳ͍ͷͰૡ͍ఠΉߏ͕ਂ͍ͥʂ
流れ(ざっくり)①© - BASE, Inc.InstallerInstallationManageroperation͔ΒpackageΛरͬͯpackageͷtypeʹԠͨ͡installerΛ༻ҙLibraryInstallerlocaRepo, operationlocaRepo, operation
流れ(ざっくり)②© - BASE, Inc.DownloadManagerpackage͔ΒtypeʹԠͨ͡ downloaderΛऔಘpackage, downloadPathpackage, downloadPathLibraryInstallerDownloaderpackageͷใΛಡΈऔͬͯ downloadPathʹల։
流れ(ざっくり)③© - BASE, Inc.localRepoΠϯετʔϧࡁΈύοέʔδͷ ใ(ΦϯϝϞϦ)Λߋ৽packageLibraryInstallerInstallerinstalled.jsonͷߋ৽
© - BASE, Inc.ίί·Ͱґଘղܾ
installの依存解決: まとめ© - BASE, Inc.• RootΛؚΉؔ࿈PackageͷrequireΛશͯྻڍ͠(Request/job)ɺSolverʹΑ࣮ͬͯߦ͖͢ૢ࡞ΛߜΓࠐΜͰ͍Δ• Package͝ͱʹInstallerɾDownloaderΛىಈ͠ɺવΔ͖ιʔείʔυΛDL͢Δ
© - BASE, Inc..lockファイルの更新事後処理①
.lockファイルに載せる情報は?© - BASE, Inc.• .lockϑΝΠϧɺʮίί·ͰʹΠϯετʔϧͨ͠ͷʯͷࣸ૾–औಘ͞ΕͨPackage: localRepoͷσʔλ–ϓϥοτϑΥʔϜͷใ: composer.json +PlatformReqRepoͷσʔλ–ͦͷଞɺstabilityϑϥάͳͲ: RootPackageͷσʔλ
必要な情報を合成してdumpする© - BASE, Inc.• Composer\Package\Locker–ʮ.lockϑΝΠϧͷΠϯελϯεʯͳΠϝʔδ• Locker::setLockData()ʹ ඞཁͳใΛͨ͠Βɺ jsonσʔλΛΈཱͯͯϑΝΠϧʹग़ྗ͜͜·ͰͷRepo/PackageͷΠϝʔδΛ௫Ί͍ͯΕɺ .lockσʔλͷࢉग़γϯϓϧͰ͢Ͷʂ
© - BASE, Inc.autoloadファイルの更新事後処理②
autoloadファイルに載せる情報は?© - BASE, Inc.• ༰localRepoʹྻڍ͞Ε͍ͯΔͷ• ઃఆใͱͯ͠ɺ–RootPackageͷ༰–Composer\Configͷ༰–etc
各ファイルの出⼒© - BASE, Inc.• autoloadϑΝΠϧෳͷ༰͔ΒΔ–ΫϥεϚοϓ–includeϑΝΠϧ–Composer\Autoload\ClassLoader–etc.• ͜ΕΒΛ`vendor/composer`ҎԼʹग़ྗ–※ઃఆʹΑͬͯҟͳΔ
© - BASE, Inc.おしながきComposerのcommandとは何か実装からみる「Composerとは何か」`install`を深堀りしてみる
© - BASE, Inc.まとめ
まとめ© - BASE, Inc.• installҰݟ ෳࡶͦ͏͚ͩͲෳࡶͩͥʂ• ෳࡶͳϞϊɺʮԿΛղܾ͢Δͷ͔ʁʯΛҙࣝ͢ΔͱྲྀΕ͕௫Έͦ͢͏˕
© - BASE, Inc.※આ໌͢͠͞ॏࢹͰɺ ͍ͩͿ؆ུԽͯ͠͠·ͨ͠ɻൃදͷதͰ৮Ε͍ͯͳ͍෦ଟʑ͋ΔͷͰɺ ͦ͜ੋඇίʔυΛಡΜͰΈ͍ͯͩ͘͞ʂ
© - BASE, Inc.いつも触っているものが なぜ動くのか?を知れると 楽しいです!!!
© - BASE, Inc.、やっていきましょう!
© - BASE, Inc.࣭͝ͳͲʂ ※งғؾճʹͳͬͨΒ͢Έ·ͤΜʂ
© - BASE, Inc.お付き合いいただき ありがとうございました!