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
cm-komuro
October 08, 2016
Technology
0
1.2k
Introduction of Jooby. DevIO2016
Developers IO 2016 in Fukuoka
cm-komuro
October 08, 2016
Tweet
Share
More Decks by cm-komuro
See All by cm-komuro
How To 脆弱性対応
cmkomuro
0
610
内容は話せないけどGamedayのススメ
cmkomuro
0
460
ゲンバのサービス運用
cmkomuro
2
1.3k
運用事件簿
cmkomuro
0
2.4k
Other Decks in Technology
See All in Technology
家族アルバム みてねにおけるGrafana活用術 / Grafana Meetup Japan Vol.1 LT
isaoshimizu
1
600
ここが嬉しいABAC ここが辛いよABAC #再解説+補足編
masahirokawahara
1
270
開発生産性向上サービスを作るFindyが自分たちで開発生産性を爆上げした組織づくりの歩み / Findy's path to boosting its own development productivity 2024-04-17
ma3tk
3
650
Next'24 事例セッションの紹介とクラウド資格を活用したキャリア形成について語りMuscle
yasumuusan
1
440
一生覚えておきたい「システム開発=コミュニケーション」〜初めての実務案件振り返りLT〜
maimyyym
0
130
20分で完全に理解するGrafanaダッシュボード
hamadakoji
3
460
コードを書く隙間を見つけて生きていく技術/Findy 思考の現在地
fujiwara3
27
5.9k
アクセシビリティを考慮したUI/CSSフレームワーク・ライブラリ選定
yajihum
2
1k
VS CodeでAWSを操作しよう
smt7174
7
1.6k
Janus
bkuhlmann
1
490
On Your Data を超えていく!
hirotomotaguchi
2
670
DevOpsメトリクスとアウトカムの接続にトライ!開発プロセスを通して計測できるメトリクスの活用方法
ham0215
2
240
Featured
See All Featured
Learning to Love Humans: Emotional Interface Design
aarron
267
39k
Fireside Chat
paigeccino
21
2.6k
Automating Front-end Workflow
addyosmani
1356
200k
A Tale of Four Properties
chriscoyier
151
22k
Intergalactic Javascript Robots from Outer Space
tanoku
266
26k
Designing on Purpose - Digital PM Summit 2013
jponch
110
6.5k
Statistics for Hackers
jakevdp
789
220k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
7
1k
The Language of Interfaces
destraynor
151
23k
The Illustrated Children's Guide to Kubernetes
chrisshort
31
46k
Happy Clients
brianwarren
92
6.4k
StorybookのUI Testing Handbookを読んだ
zakiyama
13
4.6k
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 ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ ϒϩάͰҾ͖ଓ͖ใൃ৴͍͖ͯ͠·͢ɻ