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
690
内容は話せないけどGamedayのススメ
komurosappro
0
530
ゲンバのサービス運用
komurosappro
2
1.3k
大阪勉強会_第5回.pdf
komurosappro
0
4
運用事件簿
komurosappro
0
2.5k
Other Decks in Technology
See All in Technology
C++26 エラー性動作
faithandbrave
2
870
ヤプリQA課題の見える化
gu3
0
140
DUSt3R, MASt3R, MASt3R-SfM にみる3D基盤モデル
spatial_ai_network
3
470
Storage Browser for Amazon S3
miu_crescent
1
340
非機能品質を作り込むための実践アーキテクチャ
knih
6
1.8k
信頼されるためにやったこと、 やらなかったこと。/What we did to be trusted, What we did not do.
bitkey
PRO
0
1.1k
[トレノケ雲の会 mod.13] 3回目のre:Inventで気づいたこと -CloudOperationsを添えて-
shintaro_fukatsu
0
120
Wantedly での Datadog 活用事例
bgpat
2
1.1k
サイバー攻撃を想定したセキュリティガイドライン 策定とASM及びCNAPPの活用方法
syoshie
3
1.7k
プロダクト組織で取り組むアドベントカレンダー/Advent Calendar in Product Teams
mixplace
0
640
サーバーなしでWordPress運用、できますよ。
sogaoh
PRO
0
170
mixi2 の技術スタックを探ってみる (アプリ編)
ichiki1023
0
110
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
GitHub's CSS Performance
jonrohan
1030
460k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
It's Worth the Effort
3n
183
28k
Docker and Python
trallard
43
3.2k
Practical Orchestrator
shlominoach
186
10k
Into the Great Unknown - MozCon
thekraken
34
1.6k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
Reflections from 52 weeks, 52 projects
jeffersonlam
348
20k
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 ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ ϒϩάͰҾ͖ଓ͖ใൃ৴͍͖ͯ͠·͢ɻ