Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
NestJSのDIコンテナで作るクリーンなレイヤー境界
Search
kimutyam
May 20, 2022
Technology
2
1.7k
NestJSのDIコンテナで作るクリーンなレイヤー境界
NestJS Meetup Online #2 にて発表した内容です。
https://nest-jp.connpass.com/event/244015/
kimutyam
May 20, 2022
Tweet
Share
More Decks by kimutyam
See All by kimutyam
Embulk / Presto / Sparkを用いたETL事情
kimutyam
4
2k
セプテーニで分析基盤(Treasure Data)を導入した話
kimutyam
0
1.4k
Reactive Messaging Patternsを使った境界づけられたコンテキストの統合
kimutyam
3
1.2k
アジャイルでのドメイン・ユースケースモデリング
kimutyam
5
2.1k
Introduction of ScalaTest
kimutyam
3
2.1k
Scalaで学ぶヘキサゴナルアーキテクチャ実践入門
kimutyam
15
6.5k
Other Decks in Technology
See All in Technology
分析者起点の企画を成功させた連携面の工夫
lycorptech_jp
PRO
1
250
Low Latency Join Method for Distributed DBMS
yugabytejapan
0
180
令和最新版 Perlコーディングガイド
anatofuz
4
3.7k
Oracle Database 23ai 新機能#4 Real Application Clusters
oracle4engineer
PRO
0
160
UE5の雑多なテク
ryuichikawano
0
400
Strict Concurrencyにしたらdeinitでクラッシュする話
0si43
0
130
普通の Web エンジニアのための様相論理入門 #yapcjapan / YAPC Hakodate 2024
ytaka23
5
1.4k
I tried the newly introduced certification "Applied Skills" on Microsoft Learn
mappie_kochi
0
150
Azure Verified Moduleを触って分かった注目ポイント/azure-verified-module-begin
mhrtech
1
390
入門 バックアップ
ryuichi1208
18
6.7k
Databricks Appのご紹介
databricksjapan
0
250
【shownet.conf_】ShowNet 2024 ~ Inter * Network ~
shownet
PRO
0
520
Featured
See All Featured
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
92
16k
Fashionably flexible responsive web design (full day workshop)
malarkey
404
65k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
355
29k
Building Your Own Lightsaber
phodgson
102
6k
A Philosophy of Restraint
colly
203
16k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
46
4.9k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
41
9.2k
Making the Leap to Tech Lead
cromwellryan
131
8.8k
What's new in Ruby 2.0
geeforr
341
31k
What's in a price? How to price your products and services
michaelherold
243
11k
Fontdeck: Realign not Redesign
paulrobertlloyd
81
5.2k
How To Stay Up To Date on Web Technology
chriscoyier
787
250k
Transcript
גࣜձࣾΧέϋγɹଜজ /FTU+4ͷ%*ίϯςφͰ࡞ΔΫϦʔϯͳϨ ΠϠʔڥք /FTU+4NFFUVQ0OMJOFɹ
ࢹௌऀɾಡऀͷఆ w ҎԼͷ͍ͣΕ͔ʹ֘ w /FTU+4Ͱ8FCΞϓϦέʔγϣϯΛΜͩ͜ͱ͕͋Δ w /FTU+4ͷ1SPWJEFS.PEVMFΛ৮ͬͨ͜ͱ͕͋Δ w ΦϒδΣΫτࢦͰͷઃܭɾ։ൃܦݧ͕͋Δ
ࣗݾհ w גࣜձࣾΧέϋγ d w ҩྍൃɾཧ࠷దԽྖҬͷ৽نࣄۀͷ্ཱͪ͛Λ୲த w ιϑτΣΞΤϯδχΞσʔλΤϯδχΞΞʔΩςΫτ w
Χέϋγͱ5ZQF4DSJQU w גࣜձࣾΧέϋγY5ZQF4DSJQU"EWFOU$BMFOEBS w ͳͥόοΫΤϯυ5ZQF4DSJQU͔ʁٕज़બఆഎܠͱ࣮ફྫΛհ͠·͢ ଜজ ͖ΉΒ͖͋ͻΖ ˞ܦྺͷৄࡉ/FTU+4.FFUVQ0OMJOFͷΠϕϯτϖʔδʹهࡌ͍ͯ͠·͢
5XJUUFSIUUQTUXJUUFSDPNLJNVUZBN .FEJVNIUUQTLJNVUZBNNFEJVNDPN 4QFBLFS%FDLIUUQTTQFBLFSEFDLDPNLJNVUZBN (JUIVCIUUQTHJUIVCDPNLJNVUZBN 'PMMPX.F
ΞδΣϯμ ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ /FTU+4ͷ%*ίϯςφͷΈ ϨΠϠʔڥքΛߏ͢Δ औΓѻΘͳ͍͜ͱ w ΫϦʔϯΞʔΩςΫνϟͷਂ͍આ໌
w υϝΠϯϞσϦϯάͷํ ηΫγϣϯ
ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ ͑ํ ηΫγϣϯ
w ΫϦʔϯΞʔΩςΫνϟͰ༗໊ͳਤͰ͢ɻ w ͜ΕΒͷಉ৺ԁͷଆʹ͍͘΄ͲιϑτΣΞͱ ্ͯ͠ҐϞδϡʔϧʹͳΔ͜ͱ͕ࣔ͞Ε͍ͯ·͢ɻ w υϝΠϯۦಈઃܭͷจ຺ͩͱɺ&OUJUJFTศ্ٓυ ϝΠϯϞσϧͱදݱ͢Δ߹͕͋Γ·͢ɻ w ಉ৺ԁͷΛϨΠϠʔڥքͱݺͼ·͢ɻ
w ಉ৺ԁͷΛԣஅ͢ΔʮˠʯґଘؔͰ͢ɻ ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ ΫϦʔϯΞʔΩςΫνϟ IUUQTCMPHDMFBODPEFSDPNVODMFCPCUIFDMFBOBSDIJUFDUVSFIUNM
ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ ґଘؔٯసͷݪଇ %FQFOEFODZ*OWFSTJPO1SJODJQMF l্ҐϞδϡʔϧ͍͔ͳΔͷԼҐϞδϡʔϧ ͔Β࣋ͪࠐΜͰͳΒͳ͍ɻํͱநʢྫͱ͠ ͯΠϯλʔϑΣʔεʣʹґଘ͢Δ͖Ͱ͋Δɻz˞ lநৄࡉʹґଘͯ͠ͳΒͳ͍ɻৄࡉʢ۩త ͳ࣮༰ʣ͕நʹґଘ͢Δ͖Ͱ͋Δɻz˞ ґଘؔٯసύλʔϯͰɺΠϯλʔϑΣʔεΛհ ͤ͞Δ͜ͱͰ্ҐϞδϡʔϧͷґଘΛճආ͍ͯ͠·
͢ɻ ,MPESߘऀࣗʹΑΔஶ࡞ $$දࣔܧঝ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJEʹΑΔ ,MPESߘऀࣗʹΑΔஶ࡞ $$දࣔܧঝ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJEʹΑΔ ӈ্ը૾ ӈԼը૾ ˞ IUUQTKBXJLJQFEJBPSHXJLJґଘੑٯసͷݪଇ ैདྷͷϨΠϠʔύλʔϯ ґଘؔٯసύλʔϯ
w ґଘؔٯసͷݪଇʹैͬͨઃܭΛ͢Δͱɺ࠷ऴ తʹΠϯλʔϑΣʔεͷ࣮Λඥ͚Δඞཁ͕ग़ͯ ͖·͢ɻͦ͜Ͱɺґଘੑͷೖ %* Λߦ͍·͢ɻ w ্ͷίʔυɺίϯετϥΫλͰґଘੑΛೖ͢ ΔྫͰ͢ ίϯετϥΫλ%*
ɻ w %*ͱɺґଘؔΛΫϥεؔͷ֎͔Β͢͜ͱ Ͱ͢ɻ w ͳ͓ɺԼͷίʔυɺ.FDIBOJTN෦Ͱ1PMJDZͷ ۩Ϋϥε͕ґଘͯ͠ɺґଘੑͷzೖzʹͳͬͯ ͍·ͤΜɻ ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ ґଘੑͷೖ %FQFOEFODZ*OKFDUJPO export class MechanismService { constructor(private policyService: IPolicyService) { } // ུ } export class MechanismService { private policyService: IPolicyService = new PolicyService( ) // ུ }
w %*ΛͬͨΫϥεઃܭΛਐΊΔͱɺґଘؔΛղ ܾ͢ΔӈͷΑ͏ͳίʔυ͕ੜ·Ε·͢ɻ w Ϋϥε͕গͳ͍͏ͪʹͳΓ·ͤΜ͕ɺ૿͑ ͖ͯͨ࣌ෆཁͳෳࡶੑΛੜΉ߹͕͋Γ·͢ɻ w %*ίϯςφӈͷίʔυΛॻ͔ͣʹґଘؔͷϏ δωεϩδοΫͷ֎ଆͰཧ͢Δ͜ͱ͕Ͱ͖· ͢ɻ
w ͦͯ͠ɺ%*ίϯςφ/FTU+4ͷओཁͳػೳͷͭ Ͱ͢ɻ ΫϦʔϯͳϨΠϠʔڥքΛΉͨΊͷߟ͑ํ %*ίϯςφԿΛղܾ͢Δ͔ʁ new UtilityService ( new MechanismService ( new PolicyService( ) ) )
/FTU+4ͷ%*ίϯςφͷΈ ηΫγϣϯ
w ·ͣ؆୯ͳྫ͔Βɻ w $BUT4FSWJDFͷґଘؔɺ!.PEVMFΛӈͷΑ͏ ʹఆٛ͢Ε%*Ͱ͖·͢ɻ w ͜ͷྫɺ$BUT4FSWJDFzΫϥεzΛ$BUT$POUSPMMFS ͰίϯετϥΫλ%*͍ͯ͠·͢ɻ /FTU+4ͷ%*ίϯςφͷΈ 1SPWJEFS
@Controlle r class CatsService { } @Controller("cats") class CatsController { constructor(private catsService: CatsService) { } // ུ } @Module( { controllers: [CatsController] , providers: [CatsService] , } ) export class AppModule {}
w ΠϯλʔϑΣʔεͷ߹ɺ͕ඞཁͰ͢ɻ w +BWB4DSJQUΠϯλʔϑΣʔεΛαϙʔτͯ͠ ͍ͳ͍ͨΊɺ5ZQF4DSJQUΛ+BWB4DSJQUʹίϯ ύΠϧ͢ΔͱɺΠϯλʔϑΣʔεͷఆٛফࣦ ͠·͢ɻ w τʔΫϯ ྫͰ$"54@4&37*$&@50,&/
Ͱ /FTU+4ͷ*OKFDUFSͰࣝผՄೳͳঢ়ଶʹ͢Δඞཁ͕ ͋Γ·͢ɻ /FTU+4ͷ%*ίϯςφͷΈ 1SPWJEFS interface ICatsService { } class CatsService implements ICatsService { } const CATS_SERVICE_TOKEN = "CATS_SERVICE_TOKEN" ; class CatsController { constructor ( @Inject(CATS_SERVICE_TOKEN ) private catsService: ICatsServic e ) { } // ུ } export const CatServiceProvider: Provider = { provide: CAT_SERVICE_TOKEN , useClass: CatsService , } ; @Module( { controllers: [CatsController] , providers: [CatServiceProvider] , } ) export class AppModule { }
/FTU+4ͷ%*ίϯςφͷΈ !.PEVMFͱԿ͔ʁ .PEVMF# .PEVMF" FYQPSUT JNQPSUT JNQPSUT 1SPWJEFS 1SPWJEFS $POUSPMMFS
QSPWJEFST /FTU+4ͷΠϯδΣΫλʹΑͬͯΠϯελϯ εԽ͞Εɺগͳ͘ͱϞδϡʔϧͰڞ༗ ͞ΕΔ DPOUSPMMFST .PEVMFͷΠϯελϯεԽ͢Δඞཁ͕͋Δ $POUSPMMFSҰཡ JNQPSUT ͜ͷϞδϡʔϧʹFYQPSU͢ΔผͷϞδϡʔ ϧͷҰཡ FYQPSUT ผͷϞδϡʔϧͰ͜ͷϞδϡʔϧΛJNQPSU ͢ΔͨΊͷɺެ։͢ΔϓϩόΠμٴͼτʔ ΫϯͷϦετ
ϨΠϠʔڥքΛߏ͢Δ ηΫγϣϯ
ϨΠϠʔڥքΛߏ͢Δ IUUQTCMPHDMFBODPEFSDPNVODMFCPCUIFDMFBOBSDIJUFDUVSFIUNM ߏ͢ΔΫϥεਤ
ϨΠϠʔڥքΛߏ͢Δ ߏ͢ΔΫϥεਤ w ֤ϨΠϠʔຖ EPNBJOVTF$BTF QSJNBSZ"EBQUPSTFDPOEBSZ"EBQUPS ʹͦΕͧ Ε.PEVMFΛ࡞͠·͢ w ͦΕΒΛ࠷ऴతʹ.PEVMFΛଋͶ·͢ɻ
w <ิ>QSJNBSZͱTFDPOEBSZͱʁ w ΫϦʔϯΞʔΩςΫνϟͷલਐͱͳͬͨ 1PSUT"EBQUPSTΞʔΩςΫνϟͷ༻ޠͰ ͢ɻ w QSJNBSZʮۦಈ͢ΔʯΞμϓλ w TFDPOEBSZʮۦಈ͞ΕΔʯΞμϓλ
w 3FQPTJUPSZ3FRVFTUFS*'ͷΈͰ͢ɻ w ۩ମతͳ࣮Λ͢ΔͱΞμϓλٴͼͦΕΑ Γ֎ͷԁʹґଘͯ͠͠·͏ͨΊͰ͢ɻ w Ұ൪্ҐϞδϡʔϧʹͳΔͨΊzೖz͢Δґଘ ͳ͍ͨΊɺ.PEVMF͋Γ·ͤΜɻ w ͳ͓ɺτʔΫϯϢʔεέʔεͷ࣮Ͱ͏ͨ
Ίɺ͜͜ʹஔ͍ͯ͠·͢ɻ ϨΠϠʔڥքΛߏ͢Δ υϝΠϯ EPNBJO export type Cat = Readonly< { id: CatId ; name: CatName ; age: CatAge ; }> ; export const CAT_REPOSITORY_TOKEN = 'CAT_REPOSITORY_TOKEN' ; export interface ICatRepository { store(cat: Cat): Promise<void> ; } export const CAT_REQUESTER_TOKEN = 'CAT_REQUESTER_TOKEN' ; export interface ICatRequester { get(catId: CatId): Promise<Cat | undefined> ; }
w ʮೣΛड͚औΔʯͱ͍͏ϢʔεέʔεΛఆͨ͠ ࣮Ͱ͢ɻ w 6TF$BTF*'Ͱɺͦͷ࣮Ϋϥε *OUFSBDUPS Ͱ͢ɻ w *OUFSBDUPSͰυϝΠϯͰఆٛͨ͠*'Λίϯε τϥΫλͷҾʹఆ͍ٛͯ͠·͢ɻ
ϨΠϠʔڥքΛߏ͢Δ Ϣʔεέʔε 6TF$BTF export interface UseCase<In, Out> { run(input: In): Promise<Out> ; } export type Input = Readonly< { catId: CatId ; }> ; export type Output = Omit<Cat, 'id'> ; export type ReceiveCatUseCase = UseCase<Input, Output> ; export const RECEIVE_CAT_USECASE_TOKEN = 'RECEIVE_CAT_USECASE_TOKEN' ; @Injectable( ) export class ReceiveCatInteractor implements ReceiveCatUseCase { constructor ( @Inject(CAT_REPOSITORY_TOKEN ) private catRepository: ICatRepository , @Inject(CAT_REQUESTER_TOKEN ) private catRequester: ICatRequester , ) { } async run({ catId }: Input): Promise<Output> { const cat = await this.catRequester.get(catId); // ུ } }
ϨΠϠʔڥքΛߏ͢Δ Ϣʔεέʔε 6TF$BTF w ηΧϯμϦʔΞμϓλͷΫϥε Λ࣮ͱͯ͠ ࠾༻͢Δ͜ͱʹ͢Δ߹ɺηΧϯμϦΞμϓλ ͷ.PEVMFΛJNQPSU͠·͢ɻ w
͜ΕΛ౿·͑ͯ࣍ͷϖʔδͰ.PEVMFΛ࡞͠ ·͢ɻ
w ηΧϯμϦʔΞμϓλͷ.PEVMF ޙड़ ΛJNQPSU ͍ͯ͠·͢ w ϢʔεέʔεΛଞͷ.PEVMFͰར༻Ͱ͖ΔΑ͏ʹ ϓϩόΠμΛFYQPSU͍ͯ͠·͢ w ϓϥΠϚϦΞμϓλͷ.PEVMF
ޙड़ ͰJNQPSU ͠·͢ɻ w <ิ>6TF$BTF.PEVMFΠϯλʔϑΣʔεΞμ ϓλʹґଘ͍ͯ͠·͕͢ɺϩδοΫ͕ґଘ͍ͯ͠ ΔΘ͚Ͱ͋Γ·ͤΜɻ ϨΠϠʔڥքΛߏ͢Δ Ϣʔεέʔε 6TF$BTF export const ReceiveCatUseCaseProvider: Provider = { provide: RECEIVE_CAT_USECASE_TOKEN , useClass: ReceiveCatInteractor , } ; @Module( { imports: [AdaptorMemoryStoreModule, AdaptorPetShopApiModule] , providers: [ReceiveCatUseCaseProvider] , exports: [ReceiveCatUseCaseProvider] , } ) export class UseCaseModule { }
w υϝΠϯͷϦϙδτϦͷ*'Λ࣮͍ͯ͠·͢ɻ w ϦϙδτϦͷϓϩόΠμΛଞͷ.PEVMFͰ׆༻Ͱ ͖ΔΑ͏ʹFYQPSU͍ͯ͠·͢ɻ w Ϣʔεέʔεͷ.PEVMFͰJNQPSU͠·͢ɻ ϨΠϠʔڥքΛߏ͢Δ ΠϯλʔϑΣʔεΞμϓλ 4FDPOEBSZ"EBQUPS
@Injectable( ) export class CatRepository implements ICatRepository { store(cat: Cat): Promise<void> { // ུ } } export const CatRepositoryProvider: Provider = { provide: CAT_REPOSITORY_TOKEN , useClass: CatRepository , } ; @Module( { providers: [CatRepositoryProvider] , exports: [CatRepositoryProvider] , } ) export class AdaptorMemoryStoreModule { }
w $BU$POUSPMMFSͷ࣮Ͱ͢ɻ w 6TF$BTF*'ͱ1SFTFOUFSͷΫϥεΛίϯετ ϥΫλͰఆ͍ٛͯ͠·͢ɻ ϨΠϠʔڥքΛߏ͢Δ ΠϯλʔϑΣʔεΞμϓλ 1SJNBSZ"EBQUPS @Injector( )
export class CatPresenter { } @Controller('/cat' ) export class CatController { constructor ( @Inject(RECEIVE_CAT_USECASE_TOKEN ) private receiveCatUseCase: ReceiveCatUseCase , private catPresenter: CatPresenter , ) { } @Put(':id' ) async receive(@Param('id') id: string): Promise<CatViewModel> { // ུ } }
ϨΠϠʔڥքΛߏ͢Δ ΠϯλʔϑΣʔεΞμϓλ 1SJNBSZ"EBQUPS w $POUSPMMFS ੨ ͷґଘؔΛղܾ͢ΔͨΊʹɺ *OUFSBDUPSͷϓϩόΠμʔΛؚΉϢʔεέʔεͷ .PEVMF͕ඞཁʹͳΓ·͢ɻ w
·ͨɺ͜ͷྫͰ1SFTFOUFSͷґଘؔղܾ͢ Δඞཁ͕͋Γ·͢ɻ w ͜ΕΛ౿·͑ͯ࣍ͷϖʔδͰ.PEVMFΛ࡞͠ ·͢ɻ
w Ϣʔεέʔεͷ.PEVMFΛJNQPSUͯ͠ɺ $POUSPMMFSͷίϯετϥΫλ%*͍ͯ͠·͢ɻ w DPOUSPMMFSTʹίϯτϩʔϥʔͷࢦఆΛ͍ͯ͠· ͢ɻ w 1SFTFOUFSΫϥεΛQSPWJEFSTʹࢦఆ͍͠·͢ɻ w <ิ>͜͜ͰϢʔεέʔεͷ*'ʹґଘ͍ͯ͠·
͕͢ɺϢʔεέʔεͷ*'ΛΒͣʹ۩Ϋϥεͷ ࢦఆͰ͋Γ·ͤΜɻ w *'ʹґଘ͍ͤͯ͞Δͷ$POUSPMMFSͷςελ ϏϦςΟΛ্ͤ͞ΔͨΊͰ͢ɻ ϨΠϠʔڥքΛߏ͢Δ ΠϯλʔϑΣʔεΞμϓλ 1SJNBSZ"EBQUPS @Module( { imports: [UseCaseModule] , controllers: [CatController] , providers: [CatPresenter] , } ) export class AdaptorWebApiModule { }
w ࠷ऴతʹ"QQ.PEVMFͰࠓ·Ͱ࡞ͨ͠.PEVMF ΛJNQPSU͠·͢ w ηΧϯμϦʔΞμϓλ6TF$BTF.PEVMFͰ JNQPSU͞Ε͍ͯΔͨΊ͜͜ͰෆཁͰ͢ɻ w "QQ.PEVMFΛ/FTU'BDUPSZDSFBUFʹͯ͠ Ͱ͢ɻ ϨΠϠʔڥքΛߏ͢Δ
"QQ.PEVMF @Module( { imports: [UseCaseModule, AdaptorWebApiModule] , } ) export class AppModule { } export async function main() { const app = await NestFactory.create(AppModule) ; await app.listen(80, '0.0.0.0') ; }
࠷ޙʹ
࠷ޙʹ w ΫϦʔϯͳϨΠϠʔڥքΛ࡞ΔͨΊʹɺґଘؔٯసͷݪଇΛ׆༻͠ґଘؔΛೖ͠·͢ɻ w %*ίϯςφΛ͏ͱɺ࣮ͱઃఆΛ͚ͯґଘؔͷઢ͕Ͱ͖·͢ɻ w /FTU+4ͷ.PEVMFTΛ͑ґଘؔͷೖͷׂ౷࣏͕ՄೳͰ͢ɻ w ࠓճϨΠϠʔผʹઢͷׂ౷࣏Λ͠·ͨ͠ɻ w
αϯϓϧίʔυҎԼ w IUUQTHJUIVCDPNLJNVUZBNOFTUKTDMFBOBSDIJUFDUVSFUSFF ·ͱΊ
࠷ޙʹ w Έํͷߟ͑ํಉ͡Ͱ͕͢ɺ͜͜Ͱઆ໌ͨ͠ͷύλʔϯͰ͢ɻ w ϓϩδΣΫτͷঢ়گϓϩμΫτͷಛʹΑͬͯͲ͏͍͏ߏʹ͢Δ͔ݕ౼͠·͠ΐ͏ɻ w ͨͩ͠ɺߏΛΉ্Ͱͷߟ͑ํಉ͡Ͱ͢ɻ w lΞʔΩςΫνϟͷϧʔϧͲΕಉ͡Ͱ͋Δʂz˞ ҙॻ͖
˞3PCFSU$.BSUJO ʰ$MFBO"SDIJUFDUVSFୡਓʹֶͿιϑτΣΞͷߏͱઃܭʱʮংจʯΑΓ
࠷ޙʹ 8FBSF)JSJOH w ΤϯδχΞʹؔͯ͠ଟ͘ͷٻਓ͕͍͟͝·͢ɻ˞ w όοΫΤϯυʹؔͯ͠5ZQF4DSJQUΛओཁݴޠͱ ͨ͠ืू͋Γ·͢ɻ˞ w 8FCͷϑϩϯτΤϯυ5ZQF4DSJQUΛར༻͍ͯ͠ ·͢ɻ˞
IUUQTIFSQDBSFFSTWLBLFIBTIJ ˞ొஃ࣌ͰͷٻਓใͰ͢ɻ