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
Introduction of Jooby. DevIO2016
Search
komuro-sapporo
October 08, 2016
Technology
0
1.3k
Introduction of Jooby. DevIO2016
Developers IO 2016 in Fukuoka
komuro-sapporo
October 08, 2016
Tweet
Share
More Decks by komuro-sapporo
See All by komuro-sapporo
How To 脆弱性対応
komurosappro
0
740
内容は話せないけどGamedayのススメ
komurosappro
0
550
ゲンバのサービス運用
komurosappro
2
1.4k
大阪勉強会_第5回.pdf
komurosappro
0
5
運用事件簿
komurosappro
0
2.6k
Other Decks in Technology
See All in Technology
モバイルアプリ研修
recruitengineers
PRO
5
1.7k
実践アプリケーション設計 ③ドメイン駆動設計
recruitengineers
PRO
13
4.1k
Grafana Meetup Japan Vol. 6
kaedemalu
1
200
Bye-Bye Query Spaghetti: Write Queries You'll Actually Understand Using Pipelined SQL Syntax
tobiaslampertlotum
0
120
退屈なことはDevinにやらせよう〜〜Devin APIを使ったVisual Regression Testの自動追加〜
kawamataryo
4
1.2k
DuckDB-Wasmを使って ブラウザ上でRDBMSを動かす
hacusk
1
140
AI エージェントとはそもそも何か? - 技術背景から Amazon Bedrock AgentCore での実装まで- / AI Agent Unicorn Day 2025
hariby
3
610
スプリントレトロスペクティブはチーム観察の宝庫? 〜チームの衝突レベルに合わせたアプローチ仮説!〜
electricsatie
1
150
進捗
ydah
2
230
「魔法少女まどか☆マギカ Magia Exedra」での負荷試験の実践と学び
gree_tech
PRO
0
450
事業価値と Engineering
recruitengineers
PRO
8
5.4k
制約理論(ToC)入門
recruitengineers
PRO
9
3.7k
Featured
See All Featured
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3.1k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
21k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
11
1.1k
RailsConf 2023
tenderlove
30
1.2k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.4k
Build The Right Thing And Hit Your Dates
maggiecrowley
37
2.8k
Why You Should Never Use an ORM
jnunemaker
PRO
59
9.5k
Building Applications with DynamoDB
mza
96
6.6k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
Six Lessons from altMBA
skipperchong
28
4k
Transcript
%FWFMPQFST*0 " খࣨܒ ϞόΠϧΞϓϦαʔϏε෦ DMBTTNFUIPEJOD ⡥$MBTTNFUIPE *OD ݄ /FX/FYU8FC"QQMJDBUJPO 'SBNFXPSL
ʮ+PPCZʯ
⡥$MBTTNFUIPE *OD ࣗݾհ w খࣨܒ w ϞόΠϧΞϓϦαʔϏε෦όοΫΤϯυάϧʔϓ w ։ൃऀ 1-
ࡳຈΦϑΟεϚωʔδϟ w ࡛ۄݝग़࡛ۄҭͪ Կނ͔ࠓւಓࡳຈࢢࡏॅ w ϞόΠϧΞϓϦ(ͷํΦϑΟε্ཱͪ͛෦ୂʢࣗশ w 5XJUUFS!DPNED
+BWB 1ZUIPO "OESPJE "84 6OSFBM &OHJOF 4QSJOH ,PUMJO
+BWB 4QSJOH#PPU ࢭΉʹࢭ·Εͣ࣌ʑ1MBZGPS4DBMB
ւಓࡳຈࢢ͔Βདྷ·ͨ͠ɻ
None
ւಓͱ͍͑ɾɾɾ
None
None
ઇ
None
Նྋͯ͘͠ͱͯշదͰ ͢ɻ ౙനͯ͘ ۃΊͯ פ͍Ͱ͢ ʢͨͩ͠෦ͷதॵ͍ʣ
,"/8",:6%"*
⡥$MBTTNFUIPE *OD N @@ N w ͜ͷࢿྉɺ+PPCZ$3Λରʹॻ͍ͯ͋Γ ·͢ w +PPCZͷϦϦʔε͕ૣ͍ͨΊɺॻ͍ͯΔ్தͰόʔ
δϣϯ্͕͕Γ·ͨ͠ w ݱࡏ$3͕ϦϦʔεࡁΈ
+PPCZͲ͏Ͱ͠ΐ͏
⡥$MBTTNFUIPE *OD ͡Ίʹ w 8FCΞϓϦέʔγϣϯ։ൃͷϑϨʔϜϫʔΫʹඞཁ ͳཁૉͱͲΜͳͷͰ͠ΐ͏͔ʁ %* 8FC4FSWFS 4DBMBCJMJUZ
.PEVMF "TTFUT ๛ͳ֎෦ϥΠϒϥϦ
⡥$MBTTNFUIPE *OD ஶ໊ͳ8FCΞϓϦ։ൃϑϨʔϜϫʔΫ
KPPCZͱ w ࡞ऀ&EHBS&TQJOB !KLOBDL ͞Μ w +BWBωΠςΟϒ w .JDSP8FCΞϓϦέʔγϣϯ։ൃͷϑϨʔϜϫʔΫ
w ར༻ՄೳͳϞδϡʔϧ͕ެࣜͰ݁ߏ༻ҙ͞ΕͯΔ w طଘͷ+BWBϥΠϒϥϦΛ͍·ΘͤΔ w εςʔτϨεͳͷͰεέʔϧ͍͢͠ w /FUUZ +FUUZ VOEFSUPX ਖ਼֬ͳൃԻෆ໌ɾɾ
⡥$MBTTNFUIPE *OD 8FC'SBNFXPSL#FODINBSL IUUQTXXXUFDIFNQPXFSDPNCFODINBSLT TFDUJPOEBUBSIXQFBLUFTUKTPO
,JMMFSGFBUVSF w+BWB/BUJWF w4DBMBCMF wNPEVMBS wNVMUJMBOHVBHF +BWB +BWBTDSJQU wNJDSPXFCGSBNFXPSL
+BWB/BUJWF
⡥$MBTTNFUIPE *OD +BWB/BUJWF w ಈ࡞࠷͕݅+BWBҎ্ w +BWBҎ্ NBWFOYҎ্ w ϥϜμࣜΛͬͨهड़͕ެࣜͷελϯμʔυ
w ίϯύΫτʹॻ͚Δ w ܕਪͱϥϜμࣜͷԸܙʹ༩Γ·͠ΐ͏ w +BWBҎ߱ͷ+7.͕ಈ࡞ج൫ w IUUQPUOEOMEPSBDMFDPKQPOEFNBOEKBWBEBZ QEG$+BWB%BZQEG
⡥$MBTTNFUIPE *OD 4DBMBCMF w εςʔτϨε w ࢄڥʹͯεέʔϧ͍ͤ͢͞ w "84ͷڥ͕εέʔϧ͢Δͷͱɺ૬ੑ͕ྑ͍
ͣ w ະݕূ
'BTU
⡥$MBTTNFUIPE *OD 'BTU w ىಈ͕ૣ͍ w σϑΥϧτͷαʔόʔ/FUUZ w IUUQOFUUZJP w
ͦͷଞαϙʔτ w +FUUZ IUUQXXXFDMJQTFPSHKFUUZ w VOEFSUPX IUUQVOEFSUPXJP w 5PNDBUͳ͍ IUUQKPPCZPSHEPDTFSWFST
⡥$MBTTNFUIPE *OD ىಈ͕ૣ͍ͷਖ਼ٛ
⡥$MBTTNFUIPE *OD $PEF w ίʔυ͕εοΩϦ ίϯύΫτʹ public class App
extends Jooby { Logger log = LoggerFactory.getLogger(App.class); { get("/", request -> "Hello jooby"); } public static void main(final String[] args) throws Throwable { run(App::new, args); } } ͜Ε͚ͩ
⡥$MBTTNFUIPE *OD $PNQBSF @Controller public class SimpleController { @RequestMapping("/simple") public
@ResponseBody String simple() { return "Hello world!"; } } { get("/simple", () -> "Hello World!"); } 4QSJOH.7$ +PPCZ ͪΐͬͱଇؾຯɾɾʁ
⡥$MBTTNFUIPE *OD ಛ w SPVUFTίʔυͰॻ͘ w 4JOBUSBFYQSFTTKT͔ΒΠϯεύΠΞ w εΫϦϓτͬΆ͘ॻ͚ΔߏจΛ༻ҙ w
جຊϥϜμࣜ w 'VODUJPOབྷΈͷγϯλοΫεγϡΨʔʹΑͬͯɺѹతʹه ड़ྔ͕গͳ͍ɻϥϜμࣜͱܕਪڧྗɻ w ܕਪʹΑΓهड़͕লུ͞ΕΔ͕ɺ*%&ͷྗʹཔΔͱಛʹࠔΒ ͳ͍ɻ w ΠϯελϯεΠχγϟϥΠβ w ίϯετϥΫλͰهड़͢ΔΑΓݟ௨͕͠ྑ͍ ڧ੍Ͱͳ͍
⡥$MBTTNFUIPE *OD ڧྗͳػೳΛհ wϞδϡʔϧͰػೳͷ֦ு wΠϯλʔηϓτͰϑΟϧλɺϩά wઃఆϑΝΠϧϨεʢඞཁ࠷খݶʣ
࡞ͨ͠ΞϓϦέʔγϣϯ NPEVMF NPEVMF NPEVMF NPEVMF .PEVMBS
⡥$MBTTNFUIPE *OD Ϟδϡʔϧͱʁ w +PPCZͷಛͷҰͭɻऔΓࠐΈɺऔΓ֎ָ͕͠ w +PPCZʹ͓͍ͯͷϞδϡʔϧͱɺ+PPCZʹΈࠐ Ή͜ͱͷͰ͖Δίϯϙʔωϯτʢ࣮ࡍʹΠϯλϑΣʔ ε
w +PPCZ.PEVMFͱ͍͏ΠϯλϑΣʔεΛ࣮ɺϒ Ϧοδͯ͋͛͠ΕطଘͷϥΠϒϥϦΛऔΓࠐΉͷ ͱͯ؆୯ w ͪΐͬͱ಄ͷྑ͍ϑΝΫτϦͷΑ͏ͳΠϝʔδ
⡥$MBTTNFUIPE *OD ϞδϡʔϧͷΠϝʔδ +PPCZ طଘͷϥΠϒϥϦ ͜ͷ··ͩͱऔΓࠐΊͳ͍ʂ
⡥$MBTTNFUIPE *OD ϞδϡʔϧͷΠϝʔδ +PPCZ +PPCZ.PEVMF طଘͷϥΠϒϥϦ +PPCZ.PEVMFΠϯλϑΣʔε Ͱϥοϓ͢Δ͚ͩͰ ؆୯ʹϞδϡʔϧԽ
⡥$MBTTNFUIPE *OD ϞδϡʔϧͷಡΈࠐΈ ΞϓϦέʔγϣϯ؆୯ʹΈࠐΊΔ public class App extends Jooby
{ { use(new MyModule()); } { get("/", req -> { MyService service = req.require(MyService.class); return service.doSomething(); }); } } ϞδϡʔϧΛϩʔυ ϞδϡʔϧͰϩʔυ͞ΕͨΫ ϥεΛΠϯελϯεԽ Ϟδϡʔϧ͕ϩʔυ͞Εͯͳ͍ ͱ/VMM1PJOUFS&YDFQUJPO ϞδϡʔϧͰ४උ͞Εͨ αʔϏεΫϥε
⡥$MBTTNFUIPE *OD .PEVMFΛՃ͢Δ ࡞ͨ͠ΞϓϦέʔγϣϯ "84.PEVMF -PHCBDL "844%,͕ ͍͍ͨ
⡥$MBTTNFUIPE *OD .PEVMFͷ४උ <dependency> <groupId>org.jooby</groupId> <artifactId>jooby-aws</artifactId> <version>1.0.0.CR7</version> </dependency> QPNYNMʹґଘՃ
aws.accessKey = ACCCESSSSSSSSSKEYYYYYYYYYYYYYYYY aws.secretKey = seeeeeCreeeeeeetKeeeyyyyyyyyyyy BQQMJDBUJPODPOGʹઃఆՃ IUUQTHJUIVCDPNKPPCZQSPKFDUKPPCZUSFFNBTUFSKPPCZBXT
⡥$MBTTNFUIPE *OD "84.PEVMFΛϩʔυ public class App extends Jooby {
{ use(new Aws() .with(creds -> new AmazonS3Client(creds)) ); } } ϞδϡʔϧՃ "NB[PO4Λ͏߹ public class App extends Jooby { { get("/", req -> { AmazonS3Client s3Client = req.require(AmazonS3Client.class); log.info("get s3Client. {}”, s3Client); return “AmazonS3Client"; }); } } ඞཁͳΠϯελϯεऔಘ
⡥$MBTTNFUIPE *OD "84.PEVMFͷதΛ͍ͯΈΔ private Builder<BiFunction<AWSCredentialsProvider, Config, AmazonWebServiceClient>> callbacks =
ImmutableList.builder(); public Aws with( final BiFunction<AWSCredentialsProvider, Config, AmazonWebServiceClient> callback) { requireNonNull(callback, "Callback is required."); callbacks.add(callback); return this; } public Aws with(final Function<AWSCredentialsProvider, AmazonWebServiceClient> callback) { return with((creds, conf) -> callback.apply(creds)); } "XTϞδϡʔϧXJUIϝιουΛͬͯ$BMMCBDLΛొ ͠·͢ɻSFUVSOUIJTͰࣗΛฦ٫͍ͯ͠ΔͨΊCVJMEFS ͱͯ͠ར༻Ͱ͖·͢ɻ
⡥$MBTTNFUIPE *OD ॳظԽॲཧ @Override public void configure(final Env env,
final Config config, final Binder binder) { callbacks.build().forEach(it -> { ConfigCredentialsProvider creds = new ConfigCredentialsProvider(config); AmazonWebServiceClient service = it.apply(creds, config); creds.service(service.getServiceName()); Class serviceType = service.getClass(); Class[] interfaces = serviceType.getInterfaces(); if (interfaces.length > 0) { // pick first binder.bind(interfaces[0]).toInstance(service); } binder.bind(serviceType).toInstance(service); env.onStop(new AwsShutdownSupport(service)); after(env, binder, config, service); }); } DPOpHVSF.PEVMF͕ϩʔυ͞ΕͨࡍʹॳظԽॲཧΛ࣮ߦ͠·͢ɻ ඞཁͳ$MJFOUͷΫϥεΛDBMMCBDLT͔ΒऔΓग़͠ɺ$SFEFOUJBMͱڞʹॳ ظԽͭͭ͠ɺΫϥεʹରͯ͠ͷΠϯελϯεΛొ͍͖ͯ͠·͢ɻ
⡥$MBTTNFUIPE *OD ϞδϡʔϧϥΠϑαΠΫϧ .PEVMF Πϯελϯεੜ ΞϓϦέʔγϣϯ ॳظԽ ΞϓϦέʔγϣϯ ऴྃ
.PEVMF ऴྃ .PEVMFDPOpHVSF &OWPO4UBSU &OWPO4UPQ .PEVMFͰඞཁͳॳظઃఆͳͲDPOpHVSFͰ࣮ߦɻ PO4UBSU PO4UPQͷఆٛͪ͜ΒͰߦ͓͚ͬͯྑ͍ɻ
⡥$MBTTNFUIPE *OD +BDLTPO.PEVMF ࡞ͨ͠ΞϓϦέʔγϣϯ "84.PEVMF -PHCBDL ϨεϙϯεΛ+40/ ʹ͍ͨ͠ +BDLTPO
.PEVMF
⡥$MBTTNFUIPE *OD .PEVMFͷ४උ <dependency> <groupId>org.jooby</groupId> <artifactId>jooby-jackson</artifactId> <version>1.0.0.CR7</version> </dependency> QPNYNMʹґଘՃ
IUUQTHJUIVCDPNKPPCZQSPKFDUKPPCZUSFFNBTUFSKPPCZKBDLTPO public class App extends Jooby { { use(new Jackson()); } } ϞδϡʔϧՃ
⡥$MBTTNFUIPE *OD +BDLTPOϞδϡʔϧՃͷ#FGPSFͱ"GUFS IUUQTHJUIVCDPNKPPCZQSPKFDUKPPCZUSFFNBTUFSKPPCZKBDLTPO public class User { public
User(String name, boolean steamer) { this.name = name; this.steamer = steamer; } public String name; public boolean steamer; } get("/user/{name}", (req) -> { return new User(req.param("name").value(), true); }); Ϩεϙϯεʹ6TFSΛฦ٫͢Δ
⡥$MBTTNFUIPE *OD +BDLTPOϞδϡʔϧՃͷ#FGPSFͱ"GUFS jp.classmethod.User@d719ea9 #FGPSF IUUQTHJUIVCDPNKPPCZQSPKFDUKPPCZUSFFNBTUFSKPPCZKBDLTPO {"name":"komuro","steamer":true} "GUFS
⡥$MBTTNFUIPE *OD Ϟδϡʔϧಈ࡞·ͱΊ wΠϝʔδͱͯ͠ΠϯελϯεΛੜͯ͠ฦ٫͢Δ಄ ͷྑ͍ϑΝΫτϦʹΠϝʔδ͕͍ۙ wϞδϡʔϧʹϥΠϑαΠΫϧ͕͋Γɺϩʔυ࣌ʹϥ ΠϒϥϦͷॳظԽॲཧΛهड़͠ɺΞϓϦέʔγϣϯऴ ྃ࣌ʹഁغͷͨΊͷॲཧͳͲΛهड़Ͱ͖Δ wϞδϡʔϧͰར༻͢Δ͜ͱͷͰ͖Δࢦఆ͞ΕͨΫϥε ʹରͯ͠ͷ࣮ʢΠϯελϯεʣΛఆٛ͢Δ
⡥$MBTTNFUIPE *OD ͦͷଞ༻ҙ͞ΕͯΔϞδϡʔϧ w KPPCZBLLB w KPPCZBTTFUTMFTTK w KPPCZBTTFUTOPEFKT w
KPPCZDBTTBOESB w KPPCZDPVDICBTF w KPPCZFMBTUJDTFBSDI w KPPCZKBDLTPO w KPPCZNPOHPEC w KPPCZTXBHHFS IUUQTHJUIVCDPNKPPCZQSPKFDUKPPCZ
&SSPS)BOEMJOH
⡥$MBTTNFUIPE *OD ΤϥʔϋϯυϦϯάʹ͍ͭͯ +PPCZʹ͓͍ͯͷΤϥʔϋϯυϦϯάҎԼͷछྨͰ ॲཧ͢Δ͜ͱ͕Ͱ͖·͢ɻ w)551εςʔλείʔυΛϋϯυϦϯά w&YDFQUJPOΫϥεΛϋϯυϦϯά wͦͷଞྫ֎ΛϋϯυϦϯά
⡥$MBTTNFUIPE *OD εςʔλείʔυ err(400, (req, rsp, ex) -> {
logger.error("Bad Request“, ex); rsp.send("Bad Request"); }); +PPCZ શͯͷύεʹରͯ͠ɺΤϥʔ͕ൃੜͨ͠߹ͷॲཧΛهड़͠·͢ɻ͜ͷ ߹ɺจࣈྻΛϨεϙϯεͰฦ٫
⡥$MBTTNFUIPE *OD &YDFQUJPOΫϥε err(NullPointerException.class, (req, rsp, ex) -> {
Map<String, String> messageMap = new HashMap<>(); messageMap.put("reaction", "Ψο"); messageMap.put("cause", "͵ΔΆʂ"); logger.error(“null pointer exception”, ex); rsp.send(messageMap.get(“reaction")); // ΤϥʔΛฦ٫ }); +PPCZ શͯͷύεʹରͯ͠ɺ/VMM1PJUFS&YDFQUJPO͕ൃੜͨ͠߹ͷॲཧΛهड़͠· ͢ɻ
⡥$MBTTNFUIPE *OD ͦͷଞྫ֎ public class App extends Jooby {
{ err((req, rsp, ex) -> { logger.error("ex: {}", ex); rsp.send("other error"); }); } } +PPCZ 3PVUFTFSS &SS)BOEMFSFSS ͷγϯλοΫεγϡΨʔͰ͢ɻ IUUQKPPCZPSHBQJEPDTPSHKPPCZ3PVUFTIUNMFSS PSHKPPCZ&SS)BOEMFS Ҿʹ͍ͭͯɺΠϯλϑΣʔε&SS)BOEMFSͷIBOEMFϝιουͰ֬ೝͰ͖ ·͢ɻ IUUQKPPCZPSHBQJEPDTPSHKPPCZ&SS)BOEMFSIUNM
*OUFSDFQUPST
⡥$MBTTNFUIPE *OD *OUFSDFQUPST w+PPCZͰͭͷ*OUFSDFQUPS͕༻ҙ͞Ε͍ͯ·͢ɻ wSFRVFTUॲཧલʹ࣮ߦ͞ΕΔ#FGPSF wSFTQPOTFΛฦ٫͢Δલʹ࣮ߦ͞ΕΔ"GUFS wSFTQPOTFฦ٫ޙʹ࣮ߦ͞ΕΔ$PNQMFUF 3FRVFTU 4FSWJDF
#FGPSF 3FTQPOTF "GUFS $PNQMFUF 4QSJOHͰݴ͏)BOEMFS*OUFSDFQUPS "TQFDU+૬ʁ
⡥$MBTTNFUIPE *OD #FGPSF before("/simple", (req, rsp) -> { logger.info("Header
: {}", req.headers()); }); TJNQMFʹϦΫΤετ͢ΔͱॲཧલʹΠϯλʔηϓτ͠·͢ɻϦΫΤετͷό ϦσʔγϣϯϑΟϧλʔ࣮ʹ༗ޮͰ͠ΐ͏͔ɻ $ curl http://localhost:8080/simple Hello World! [2016-10-06 17:51:23,524]-[netty task-3-4] INFO jp.classmethod.App - Header : {Host=[localhost:8080], Connection=[keep-alive], Cache-Control=[max-age=0], Upgrade-Insecure-Requests=[1], User-Agent=[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/ 537.36], Accept=[text/html,application/xhtml+xml,application/xml;q=0.9,image/ webp,*/*;q=0.8], Accept-Encoding=[gzip, deflate, sdch], Accept-Language=[ja,en- US;q=0.8,en;q=0.6], content-length=[0]} ग़ྗ
⡥$MBTTNFUIPE *OD "GUFS after("*", (req, rsp, result) -> {
logger.info("after process"); return result; }); ग़ྗ શͯͷύεʹରͯ͠ϨεϙϯεΛฦ٫͢ΔલʹΠϯλʔηϓτɻ Τϥʔ͕ൃੜͨ͠߹࣮ߦ͞Εͳ͍ͷͰҙɻ $ curl http://localhost:8080/simple/revisited revisited [2016-10-06 18:38:17,360]-[netty task-3-2] INFO jp.classmethod.App - after process [2016-10-06 18:38:17,361]-[netty task-3-2] INFO jp.classmethod.App - Call path: / simple/revisited
⡥$MBTTNFUIPE *OD $PNQMFUF complete("*", (req, rsp, cause) -> {
// intercept log logger.info("Call path: {}", req.path()); }); ग़ྗ શͯͷύεʹରͯ͠3FTQPOTFฦ٫ޙʹ࣮ߦ͞Ε·͢ɻϩάͱ͔ʹར༻Ͱ͖ͦ ͏ɻͪ͜Βਖ਼ৗɾΤϥʔؔͳ͘ඞ࣮ͣߦ͞Ε·͢ɻ [2016-10-06 18:42:21,520]-[netty task-3-6] INFO jp.classmethod.App - after process [2016-10-06 18:42:21,520]-[netty task-3-6] INFO jp.classmethod.App - Call path: / simple/revisited
⡥$MBTTNFUIPE *OD ·ͱΊ wܰྔ͔ͭಈ࡞͕ૣ͍ҹ wઃఆϑΝΠϧ͕ΑΓগͳ͘ίʔυͰهड़ wεέʔϧ͘͢͠ɺػೳͷΈࠐΈ͍͢͠ w4XBHHFSͷग़ྗͳͲ͋Γ㽂 wখ࢝͘͞ΊΔ8FCΞϓϦέʔγϣϯͷ։ൃϑϨʔϜ ϫʔΫ wͦΖͦΖ4QSJOHͷ࣍Λ୳ͦ͏
⡥$MBTTNFUIPE *OD ࢀরϦϯΫ w IUUQXXXJOGPXPSMEDPNBSUJDMFKBWBKPPCZGSBNFXPSL TJNQMJpFTKBWBXFCEFWFMPQNFOUIUNM w IUUQKBNFTXBSOFSCMPHMPHEPXODPNQPTUTKPPCZ GSBNFXPSLFBTZUPIBOEMFKBWBXFCEFWFMPQNFOU w
IUUQKPPCZPSH w IUUQTHJUIVCDPNKPPCZQSPKFDUKPPCZ w IUUQRJJUBDPNLB[VLJ[PPJUFNTCDGDDEC w IUUQXXXJSBTVUPZBDPN
%FWFMPQFST*0 " ⡥$MBTTNFUIPE *OD #cmdevio2016 ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ ϒϩάͰҾ͖ଓ͖ใൃ৴͍͖ͯ͠·͢ɻ