$30 off During Our Annual Pro Sale. View Details »
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
NestJSのDIコンテナで作るクリーンなレイヤー境界
Search
kimutyam
May 20, 2022
Technology
3
2.3k
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
2.2k
セプテーニで分析基盤(Treasure Data)を導入した話
kimutyam
0
1.5k
Reactive Messaging Patternsを使った境界づけられたコンテキストの統合
kimutyam
3
1.4k
アジャイルでのドメイン・ユースケースモデリング
kimutyam
5
2.3k
Introduction of ScalaTest
kimutyam
3
2.3k
Scalaで学ぶヘキサゴナルアーキテクチャ実践入門
kimutyam
15
6.9k
Other Decks in Technology
See All in Technology
MAP-7thplaceSolution
yukichi0403
2
250
プロダクトマネジメントの分業が生む「デリバリーの渋滞」を解消するTPMの越境
recruitengineers
PRO
3
430
Ryzen NPUにおけるAI Engineプログラミング
anjn
0
210
小さな判断で育つ、大きな意思決定力 / 20251204 Takahiro Kinjo
shift_evolve
PRO
1
300
モバイルゲーム開発におけるエージェント技術活用への試行錯誤 ~開発効率化へのアプローチの紹介と未来に向けた展望~
qualiarts
0
280
原理から解き明かす AIと人間の成長 - Progate BAR
teba_eleven
2
300
Capture Checking / Separation Checking 入門
tanishiking
0
110
Introduction to Sansan, inc / Sansan Global Development Center, Inc.
sansan33
PRO
0
2.9k
Microsoft Agent 365 を 30 分でなんとなく理解する
skmkzyk
1
290
Design System Documentation Tooling 2025
takanorip
1
930
ML PM Talk #1 - ML PMの分類に関する考察
lycorptech_jp
PRO
1
490
Noを伝える技術2025: 爆速合意形成のためのNICOフレームワーク速習 #pmconf2025
aki_iinuma
2
1k
Featured
See All Featured
Writing Fast Ruby
sferik
630
62k
Fireside Chat
paigeccino
41
3.7k
Why Our Code Smells
bkeepers
PRO
340
57k
GraphQLとの向き合い方2022年版
quramy
50
14k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
jQuery: Nuts, Bolts and Bling
dougneiner
65
8.1k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
A Tale of Four Properties
chriscoyier
162
23k
Java REST API Framework Comparison - PWX 2021
mraible
34
9k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.3k
Statistics for Hackers
jakevdp
799
230k
Done Done
chrislema
186
16k
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 ˞ొஃ࣌ͰͷٻਓใͰ͢ɻ