Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Mojoliciousではじめるマイクロサービスアーキテクチャ

 Mojoliciousではじめるマイクロサービスアーキテクチャ

モノリシックに配置されたアプリに限界を感じてませんか?
各アプリにいくつも出てくる共通ロジック。
「そろそろコピペではダメだ!」
そこで今話題の「マイクロサービス」化しよう!と思うわけです。
しかし、マイクロサービス自体、複雑なもので、私(たち)程度の
小規模では逆に導入障壁が高く、ミドルウェアにやられてしまう、
そう思われている事でしょう。
ここに、Perl Mojoliciousベースで小さくマイクロサービスを構築する方法があります!
サービスの規模に合わせて、マイクロサービス化やっていきましょう。
それと少しOkinawa.pmのご紹介。

9f91ab0a03349df998bfecf7e213cd66?s=128

Masaaki Saito

March 04, 2017
Tweet

Transcript

  1. .PKPMJDJPVTͰ͸͡ΊΔ
 ϚΠΫϩαʔϏεΞʔΩςΫνϟ NBTBLZTU
 ͍͞ͱ͏·͖͋͞

  2. w ͍͞ͱ͏·͖͋͞
 !NBTBLZTU w 0LJOBXBQNͷਓ w 8FCϋϧαʔΤϯδχΞ w ೶ۀɺ໦଄ݐங w

    ԭೄݝಡ୩ଜࡏॅ
 ʢ೔ຊҰਓޱͷଟ͍ଜʂʣ ࣗݾ঺հ
  3. ΋͘͡  ετʔϦʔ  .PKPMJDJPVTͱ͸  "1*Λ࡞੒͢Δ  "1*Λू໿͢Δ 

    ηΩϡϦςΟೝূ  0LJOBXBQNͷ͝঺հ
  4. ετʔϦʔ

  5. ετʔϦʔ w ϞϊϦγοΫʹ·ΈΕͨγεςϜΛɺঃʑʹɺ
 ϚΠΫϩαʔϏεԽ͍ͯͬͨ͠ͻͱͭͷ࿩Ͱ͢ɻ w 1)1 1FSM 1ZUIPOͳͲͰߏங͞ΕͨϞϊϦγοΫΞϓϦ܈ w ֤ΞϓϦ͕௚઀σʔλϕʔεʹ઀ଓͯ͠σʔλΛऔಘߋ৽

    w ΞϓϦؒͰɺࣅ༷ͨͳςʔϒϧ͕࡞ΒΕ͍ͯͨ
  6. ετʔϦʔ 8FCTFSWFS ΞϓϦ1)1$PEF*HOJUFS ΞϓϦ1)14ZNGPOZ ΞϓϦ1ZUIPO%KBOHP ΞϓϦ1)1$PEF*HOJUFS ΞϓϦ1)1$PEF*HOJUFS ΞϓϦ1)14ZNGPOZ %#TFSWFS 8FCTFSWFS

    8FCTFSWFS ΞϓϦ1FSM"NPO ΞϓϦ1)18PSE1SFTT 3FEJT ΞϓϦ1)1$PEF*HOJUFS %#TFSWFS
  7. ετʔϦʔ ͯ͞Ͳ͏෼ׂ͢Δ͔ʜ ෼ׂ̍ɿ൚༻తͳ"1*Λ෼͚Δ w ༣ศ൪߸ॅॴ"1*
 w ϝʔϧ഑৴"1* ֤ϑΥʔϜͰ%#͔ΒҾ͍͖ͯͯΔɻ,&/@"--͕ෳ਺͋Δɻ όοΫΤϯυͷ.5"Λ੾Γସ͑Մʹɻ
 QPTUpY

    KPCRVFVF.JOJPO $POP)B 4FOE(SJE "NB[PO4&4
 w νϟοτ௨஌"1* Τϥʔ௨஌ํ๏ɺϑΥʔϚοτ͕όϥόϥͩͬͨͷͰɺ౷Ұͯ͠)JQ$IBU΁ྲྀ͢
 ϏδωεϩδοΫʹӨڹ͕ͳ͍ҝ΍Γ΍͍͢
  8. ετʔϦʔ ͯ͞Ͳ͏෼ׂ͢Δ͔ʜ ෼ׂ̎ɿऔಘܥͷ"1*Λ෼͚Δ σʔλͷഁյͷ৺഑͕ͳ͍ҝ΍Γ΍͍͢ ෼ׂ̏ɿڞ༻͢Δߋ৽ܥͷ"1* ਃ͠ࠐΈ"1*ʜͳͲɺڞ༻͠ͳ͍ΞϓϦ୯ಠͳ෦෼͸ɺ
 ༏ઌͯ͠"1*ʹ͢Δඞཁੑ͕গͳ͍ͷͰɺޙճ͠ʹɻ
 ݺͼग़͠ଆͷґଘΛͳ͘͠ɺγϯϓϧʹ͢Δʹ͸΋ͪΖΜඞཁɻ ʢૄ݁߹ʣ w

    ళฮ৘ใ"1* w ձһ৘ใ"1* w ΞϑΟϦΤΠτ؅ཧ"1*
  9. ετʔϦʔ ԿͰ"1*Λ࡞Δ͔ʜ w ޙํޓ׵ʹ༏Ε͍ͯΔ1FSM͕͍͍ w খ͞ͳ"1*͕ଟ͍ͷͰɺNJDSPGSBNFXPSL͕͍͍ w ґଘϞδϡʔϧ͸গͳ͍ํ͕͍͍͔ͳʁ .PKPMJDJPVT

  10. .PKPMJDJPVTͱ͸

  11. .PKPMJDJPVTͱ͸ w ඪ४ϞδϡʔϧͷΈͰ࣮૷ 1FSMҎ্ͷ৔߹ w 8FCͰ։ൃ͢Δπʔϧ͕ἧͬͯΔ w ϚΠΫϩϑϨʔϜϫʔΫ͕෇ଐ w ༷ʑͳ8FCαʔόΛαϙʔτ

    αʔό෇ଐɺ14(*ରԠ
  12. 1 #!/usr/bin/env perl 2 use Mojolicious::Lite; 3 4 get '/'

    => sub { 5 my $c = shift; 6 $c->render(json => {yapc => 'kansai!!'}); 7 }; 8 9 app->start; % curl --dump-header - 'http://localhost:3000/' HTTP/1.1 200 OK Content-Length: 19 Date: Tue, 21 Feb 2017 01:54:25 GMT Content-Type: application/json;charset=UTF-8 Server: Mojolicious (Perl) {"yapc":"kansai!!"} .PKPMJDJPVTͱ͸ ϚΠΫϩϑϨʔϜϫʔΫͷ࠷খߏ੒
  13. "1*Λ࡞੒͢Δ

  14. helper mysql => sub { state $mysql = Mojo::mysql->new($CONFIG->{database}->{dsn}); };

    get '/:code' => [code => qr/(\d){7}/] => sub { my $c = shift; my $code = $c->param('code'); my $city = $c->mysql->db->query('SELECT * FROM ken_all WHERE code = ?', $code)->hash; unless ($city) { $city = {}; } $c->render(json => $city); }; ྫ͑͹ɺ༣ศ൪߸͔ΒॅॴΛݕࡧ͢Δ"1* % curl --dump-header - 'http://localhost:3000/9040322' HTTP/1.1 200 OK Server: Mojolicious (Perl) Content-Length: 183 Date: Tue, 21 Feb 2017 07:01:23 GMT Content-Type: application/json;charset=UTF-8 {"code":"9040322","kana1":"ΦΩφϫέϯ","kana2":"φΧΨϛάϯϤϛλϯιϯ","kana3":"φϛώϥ","name1":"ԭೄݝ ","name2":"த಄܊ಡ୩ଜ","name3":"೾ฏ"} "1*Λ࡞੒͢Δ
  15. use utf8; use t::Util; use Test::More; use Test::Mojo; use FindBin;

    require “$FindBin::Bin/../ken_all.pl"; my $t = Test::Mojo->new; $t->get_ok('/9040322') ->status_is(200) ->json_has('/9040322') ->json_is('/9040322/name1' => 'ԭೄݝ') ->json_is('/9040322/kana1' => 'ΦΩφϫέϯ'); +40/ͷςετ ok 1 - GET /9040322 ok 2 - 200 OK ok 3 - has value for JSON Pointer "/9040322" ok 4 - exact match for JSON Pointer "/9040322/name1" ok 5 - exact match for JSON Pointer "/9040322/kana1" 1..5 ok 3034 ms ( 0.00 usr 0.00 sys + 0.44 cusr 0.43 csys = 0.87 CPU) [12:44:50] All tests successful. "1*Λ࡞੒͢Δ { "9040322": { "kana1": "ΦΩφϫέϯ", "kana2": "φΧΨϛάϯϤϛλϯιϯ", "kana3": "φϛώϥ", "name1": "ԭೄݝ", "name2": "த಄܊ಡ୩ଜ", "name3": "೾ฏ" } }
  16. $c->delay( # ฒྻϦΫΤετ sub { my $delay = shift; $c->ua->get('127.0.0.1:5000/affiliate/list'

    => $delay->begin); $c->ua->get('127.0.0.1:5000/course/112345' => $delay->begin); $c->ua->get('127.0.0.1:5000/member/masakyst' => $delay->begin); }, # ݁ՌΛશͯड͚͔ͯΒϨϯμϦϯά sub { my ($delay, $affiliate, $course, $member) = @_; $c->stash({ affiliate => $affiliate->res->json, course => $course->res->json, member => $member->res->json, }); $c->render(template => 'index'); } ); ෳ਺ͷ"1*ݺͼग़͠Λฒྻʹ͢Δ "1*Λ࡞੒͢Δ ˞IZPOPUPBE NPSCPͰͳ͍ͱಈ͖·ͤΜ ˞಺෦"1*ݺͼग़͠ͷྫ
  17. "1*Λू໿͢Δ

  18. "1*Λू໿͢Δ w ී௨ͳΒ֤"1*ຖʹαʔόΠϯελϯεΛݐͯΔ w ϑϩϯτͷ8FCαʔό͔ΒϦόʔεϓϩΩγ w ֤"1*ʹࢮ׆؂ࢹ ෮چʢ4VQFSWJTPSEʜ ͯ͞ɺ"1*͸୔ࢁͰ͖ͨɺͲ͏΍ͬͯ഑ஔ͠Α͏ʜ ͜ͷล͕খن໛ͩͱඇৗʹΊΜͲ͍ʂʂ

  19. ํ๏̍ɿ.PVOUʹΑΔ"1*ͷू໿ "1*Λू໿͢Δ "1*ήʔτ΢ΣΠ ༣ศ൪߸ݕࡧ"1* ϝʔϧૹ৴"1* ձһ؅ཧ"1* ళฮ؅ཧ"1* LFO@BMM NBJMTFOEFS NFNCFST

    TUPSFT όοΫΤϯυͷ"1*ΛϚ΢ϯτ
  20. ํ๏̍ɿ.PVOUʹΑΔ"1*ͷू໿ use Mojolicious::Lite; plugin Mount => {'/ken_all' => 'ken_all.pl' };

    plugin Mount => {'/keystone' => 'keystone.pl' }; plugin Mount => {'/mailsender' => 'mailsender.pl' }; plugin Mount => {'/alert' => 'alert.pl' }; plugin Mount => {'/store_info' => 'store_info.pl' }; plugin Mount => {'/members' => 'members.pl' }; app->start; "1*Λू໿͢Δ % carmel exec -- ./api-gateway.pl get -M GET /ken_all/9040322 (git)-[master] [Fri Feb 24 13:44:08 2017] [debug] Your secret passphrase needs to be changed [Fri Feb 24 13:44:08 2017] [debug] GET "/ken_all/9040322" [Fri Feb 24 13:44:08 2017] [debug] Routing to application "Mojolicious::Lite" [Fri Feb 24 13:44:08 2017] [debug] Routing to a callback [Fri Feb 24 13:44:08 2017] [debug] 200 OK (0.007251s, 137.912/s) {"code":"9040322","kana1":"ΦΩφϫέϯ","kana2":"φΧΨϛάϯϤϛλϯιϯ","kana3":"φϛώϥ","name1":"ԭೄݝ ","name2":"த಄܊ಡ୩ଜ","name3":"೾ฏ"} Ϛοϐϯά͍ͨ͠63-ɹɹϑΝΠϧ΁ͷύεʢ"1*͸ผʹ։ൃՄʣ BQJHBUFXBZQM
  21. "1*Λू໿͢Δ w ϝϦοτ w "1*ຖʹผͰ։ൃͯ͠౷߹Ͱ͖Δ w "1*ຖʹϓϩηεىಈ͍ͯ͠ͳ͍ͷͰɺݸʑͷ؂ࢹ෮چ͕ෆཁ w σϝϦοτ w

    ̍ͭͷΞϓϦʹͳΔͷͰɺϓϩηε͕େ͖͘ͳΔ w ಉ͡Ϟδϡʔϧͷผόʔδϣϯ͕࢖༻Ͱ͖ͳ͍ ํ๏̍ɿ.PVOUʹΑΔ"1*ͷू໿ ˞Ұ൪ͷσϝϦοτͰ͕͢ɺখن໛ͩͱͦΜͳʹ໰୊ʹͳΒͳ͍Ͱ͢
  22. "1*Λू໿͢Δ "1*ήʔτ΢ΣΠ ༣ศ൪߸ݕࡧ"1* ϝʔϧૹ৴"1* ձһ؅ཧ"1* ೝূ"1* LFO@BMM ํ๏̎ɿ1MBDL"QQ1SPYZʹΑΔ"1*ͷू໿ NBJMTFOEFS NFNCFST

    LFZTUPOF όοΫΤϯυͷ"1*ʹϦόʔεϓϩΩγ
  23. "1*Λू໿͢Δ ํ๏̎ɿ1MBDL"QQ1SPYZʹΑΔ"1*ͷू໿ 14(MԽ use Plack::Builder; use Plack::App::Proxy; sub proxy {

    Plack::App::Proxy->new(remote => $_[0])->to_app; } builder { enable 'Proxy::RewriteLocation'; mount "/ken_all" => proxy(‘http://127.0.0.1:8810'); mount "/keystone" => proxy(‘http://127.0.0.1:8820'); mount "/members" => proxy(‘http://127.0.0.1:8860'); # ... }; όοΫΤϯυͷ"1*ϓϩηε΁3FWFSTF1SPYZ͢Δ
  24. % cat Procfile API Gateway: plackup -a api-gateway.psgi ken all

    API : morbo ./ken_all.pl -l http://*:8810 keystone API : morbo ./keystone.pl -l http://*:8820 members API : morbo ./members.pl -l http://*:8830 "1*Λू໿͢Δ ํ๏̎ɿ1MBDL"QQ1SPYZʹΑΔ"1*ͷू໿ 1SPDMFUʹΑΔ"1*ىಈͷ؅ཧ 14:38:21 keystone API .1 | Server available at http://127.0.0.1:8820 14:38:21 mailsender API .1 | Server available at http://127.0.0.1:8830 14:38:21 ken all API .1 | Server available at http://127.0.0.1:8810 14:38:21 members API .1 | Server available at http://127.0.0.1:8850 14:38:21 store service API .1 | Server available at http://127.0.0.1:8860 14:38:21 hipchat API .1 | Server available at http://127.0.0.1:8840 14:38:21 API Gateway.1 | HTTP::Server::PSGI: Accepting connections at http://0:5000/ w ෳ਺ͷ"1*ϓϩηεͷҰ੪ىಈ w "1*ϓϩηεͷࢮ׆؂ࢹɺࣗಈ෮چ 'JMF3PUBUF-PHTͰϩά΋ू໿Մೳ
  25. "1*Λू໿͢Δ w ϝϦοτ w "1*ຖʹɺ׬શʹಠཱͨ͠ϓϩηεϞδϡʔϧͰ։ൃͰ͖Δ w ̍୆ͷαʔό͔Β࢝Ίͯɺ෦෼తʹผαʔόʹ෼ࢄ͠΍͍͢ w 1SPDMFUͷ͓͔͛Ͱɺ"1*ϓϩηεىಈ෮چͷख͕ؒͳ͘ͳΔ w

    1SPDMFU͸ɺຊ൪؀ڥͰ΋࢖͏ͱศར w σϝϦοτ w 1FSMʹΑΔ3FWFSTF1SPYZͳͷͰ/HJOYͳͲͱൺ΂ͯগ͠஗͍ ํ๏̎ɿ1MBDL"QQ1SPYZʹΑΔ"1*ͷू໿ "1*ήʔτ΢ΣΠ͸5XJHHZ͕͍͍Ͱ͢
  26. ηΩϡϦςΟೝূ

  27. ηΩϡϦςΟೝূ w *%ύεϫʔυೝূ w 5PLFOೝূʢ"DDFTT5PLFOΛൃߦʣ w γϯϓϧͳ΋ͷΛࣗ࡞Ͱ΋͍͍ w 0"VUI w

    +40/8FC5PLFO "1*ݺͼग़͠ʹೝূΛ͔͚͍ͨ .PKPMJDJPVT1MVHJO0"VUI .PKPMJDJPVT1MVHJO0"VUI4FSWFS
  28. ηΩϡϦςΟೝূ w +40/8FC5PLFO +85 δϣοτͱಡΉ w ॺ໊ͷग़དྷΔ+40/ΛؚΜͩ63-4BGFͳτʔΫϯ w ҉߸ԽͰ͸ͳ͍ͷͰɺ+40/ͷத਎͸ݟΒΕΔ w

    Ͱ͕͢ɺվ͟Μ͢Δͱݕূʹࣦഊ͢ΔͷͰجຊతʹ҆શ w %#ͳͲͰͷτʔΫϯ؅ཧ͕ʢγϯϓϧͳ৔߹ʣෆཁ +40/8FC5PLFOʹΑΔೝূ IUUQTKXUJP
  29. use Crypt::JWT qw(encode_jwt decode_jwt); 
 $router->add("/authorize", sub { my ($req,

    $env) = @_; my $id = $req->body_parameters->{login_id}; my $pass = $req->body_parameters->{password}; ## DB઀ଓͯ͠ೝূ my $user = $db->query('SELECT * FROM users WHERE login_id = ? AND password = ?', $id, $pass)->hash; unless ($user) { die; } # JSON TokenԽ͢Δσʔλߏ଄Λ࡞੒ my $payload = { iss => ‘υϝΠϯ’, # ൃߦݩURL sub => $user->{app_id}, # Ϣʔβࣝผࢠ / ΞϓϦID iat => time, # τʔΫϯੜ੒࣌ࠁ exp => time + (60 * 60), # ༗ޮظݶ }; # ൿີ伴ͰJSONΛॺ໊ my $jws_token = encode_jwt(payload => $payload, alg => 'HS256', key => 'ൿີʂ'); return ["200", ["Content-Type" => "application/json"], [encode_json({token => $jws_token})]]; }); +85ʹΑΔೝূαʔό ηΩϡϦςΟೝূ
  30. enable sub { my $app = shift; my $unauthorized =

    sub { my $body = 'Authorization required jwt'; return [401, ['Content-Type' => 'text/plain', 'Content-Length' => length $body, 'WWW-Authenticate' => 'Bearer realm="invalid_token"'], [ $body ] ]; }; my $authenticator = sub { my $token = shift; my $data = decode_jwt(token => $token, key => 'ൿີ'); # ͜ΕͰtokenͷjsonσʔλ͕෮ݩͰ͖·ͨ͠ʂ }; sub { my $env = shift; if ($env->{PATH_INFO} =~ /^\/authorize$/) { return $app->($env); } my $token = $env->{HTTP_AUTHORIZATION} or return $unauthorized->(); if ($token =~ /^Bearer (.*)$/i) { if ($authenticator->($1, $env)) { return $app->($env); } } return $unauthorized->(); }; }; ηΩϡϦςΟೝূ +85ʹΑΔೝূϓϩΩγ
  31. ηΩϡϦςΟೝূ w .PKPMJDJPVT1MVHJO"$.& w "$.&ϓϩτίϧ %7ূ໌ൃߦͷࣗಈԽ  w 5XJHHZ5-4 w

    5XJHHZʹ5-4TVQQPSU ଞɺศརͳ44-ؔ܎ͷπʔϧͷ঺հ ೝূہ $" -FU`T&ODSZQU
  32. ηΩϡϦςΟೝূ .PKPMJDJPVT1MVHJO"$.& #!/usr/bin/env perl use Mojolicious::Lite; plugin 'ACME'; get '/'

    => {text => 'I ♥ YAPC!'}; app->start; $ sudo ./myapp.pl daemon -l http://*:80 [Tue Feb 28 11:34:06 2017] [info] Listening at "http://*:80" Server available at http://127.0.0.1:80 $ ./myapp.pl acme account register [Tue Feb 28 11:13:32 2017] [debug] Your secret passphrase needs to be changed Account Created Writing account.key $ ./myapp.pl acme cert generate υϝΠϯ [Tue Feb 28 11:21:03 2017] [debug] Your secret passphrase needs to be changed Writing myapp.key Writing myapp.crt requires 'Mojolicious'; requires 'Mojolicious::Plugin::ACME'; requires 'IO::Socket::SSL'; DQBOpMF NZBQQQM 5FSNJOBM
  33. ηΩϡϦςΟೝূ 5XJHHZ5-4 #!/usr/bin/env perl use Mojolicious::Lite; # plugin 'ACME'; get

    '/' => {text => 'I ♥ YAPC!'}; app->start; $ plackup -a ./myapp.pl psgi -s Twiggy::TLS --tls-key myapp.key --tls-cert myapp.crt Twiggy: Accepting connections at https://0.0.0.0:5000/ requires 'Plack'; requires 'Twiggy::TLS'; DQBOpMF NZBQQQM 5FSNJOBM $ curl --dump-header - https://api.υϝΠϯ.com:5000/ HTTP/1.0 200 OK Content-Type: text/html;charset=UTF-8 Date: Tue, 28 Feb 2017 03:05:49 GMT Content-Length: 11 I ♥ YAPC!
  34. ·ͱΊ w "1*࡞੒͸ɺ.PKPMJDJPVTͰॻ͘ͱָʂ w "1*ήʔ΢ΣΠ΋1FSMͰॻ͘ͱָʂ w ϓϩηε؅ཧ΋1FSM 1SPDMFU Ͱָʂ w

    ೝূ44-ؔ܎΋1FSMͰָʂ શ෦1FSMͷΈͰͰ͖·͢ʂ ϛυϧ΢ΣΞʹ΍ΒΕͳ͍ʂʂ
  35. 0LJOBXBQNͷ͝঺հ

  36. 0LJOBXBQNͷ͝঺հ 0LJOBXBQNʢެࣜʣઃཱ͠·ͨ͠ʂ ˞ਅΜத͸఻આͷϋοΧʔNJZBHBXB͞Μ पΓͷਓ͕ίΞϝϯόʔͰ͢

  37. 0LJOBXBQNͷ͝঺հ લ਎͸ɺ೥͔Β։࢝ͨ͠ඇެࣜ:PNJUBOQN 5XJUUFSͰ֦ࢄ͚ͨͩͩͬͨ͠ͷͰ͕͢ɺ
 Ͳ͔͜Βͱ΋ͳ͘1FSMϢʔβʔ͕ू·Δʜ

  38. 0LJOBXBQNͷ͝঺հ ԭೄͷ*5ίϛϡχςΟ૯߹ΠϕϯτʮϋοΧʔζνϟϯϓϧʔʯ ͳΜͱ͋ͷ1FSMϋοΧʔ஄͞Μ͕ԭೄʹʂʂ ࠓ೥ͷϋοΧʔζνϟϯϓϧʔ݄Լ०༧ఆͰ͢ʂ

  39. 0LJOBXBQNͷ͝঺հ +"846(ԭೄ͞Μͱձ৔߹ಉͰษڧձ ճ໨͘Β͍ʹͳΔͱू·ΔϢʔβʔͷ਺ ΋҆ఆ͢ΔΑ͏ʹͳΓ·ͨ͠ ͦΖͦΖɺ0LJOBXBQNʹ͠Α͏͔ʂ

  40. 0LJOBXBQNͷ͝঺հ ެࣜQNͷ࡞Γํ IUUQHJIZPKQEFWTFSJBMNPEFSOQFSM ʮୈճ1FSM.POHFSTإͷݟ͑Δ஥ؒΛ૿΍ͦ͏ʯΛख़ಡ XXXQNPSHͷʮQFSM@NPOHFSTYNMʯʹQNΛ௥هͯ͠QVMMSFR IUUQTHJUIVCDPNQFSMPSHXXXQNPSH Ϛʔδ͞ΕͨΒ։࠵͢Δʂ

  41. 0LJOBXBQNͷ͝঺հ QNΛ΍Δͱɺ৭ʑͳਓ͕༡ͼʹ͖ͯ͘Ε·͢ʂ w ීஈձ͑ͳ͍Α͏ͳϋοΧʔͷਓ͕͖ͯ͘ΕͨΓ w ۀքཪଆͷ࿩͕͖͚ͨΓ w ओ࠵͢ΔࣄͰɺࣗ෼ࣗ਎େ͖ͳษڧʹͳͬͨΓ w ѹ౗తʹֶͼ͕͋Γ·͢ɻ޿͕Γ·͢ɻ

  42. 0LJOBXBQNͷ͝঺հ QNΛ΍Δͱɺ৭ʑͳਓ͕༡ͼʹ͖ͯ͘Ε·͢ʂ ͢͝ʔ͍ʂͨʔͷ͠ʔʂ

  43. 0LJOBXBQNͷ͝঺հ QN࡞ͬͯΈ·ͤΜ͔ʁ Ҏ্Ͱ͢ɻ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ