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

mixi tech note #04

mixi tech note #04

技術書典9に向けて作成した本のフルカラー電子版です

<< 目次 >>
第一章:Haskellで簡単にCLIツールを作るために
    by 松原 信忠 GitHub @matsubara0507
第二章:TIPSTARのアーキテクチャとCloud Spannerとの付き合い方
    by 川又 義照 Twitter @4cteru
第三章:機械学習とGCPで作るTIPSTARワイガヤ順位
    by 津田 恭平 Twitter @canoefishing
第四章:Behavior TreeでゲームAIに取り組んで思う
    by 田那辺 輝
第五章:Gitのindex treeとは結局なんなのか
    by 藤田 朱門 Twitter @shumon_84

<< 過去の tech note >>
mixi tech note #01
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-01

mixi tech note #02
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-02

mixi tech note #03
https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-03

XFLAG Tech Note Vol.01
https://speakerdeck.com/mixi_engineers/xflag-tech-note-vol-dot-01

XFLAG Tech Note vol.02
https://speakerdeck.com/mixi_engineers/xflag-tech-note-vol-dot-02

B16717ef4b7aab0b253d933c3934f280?s=128

mixi_engineers

December 08, 2020
Tweet

Transcript

  1. None
  2. mixi tech note #04 גࣜձࣾϛΫγΟ ༗ࢤɹஶ 2020-09-12 ൛ גࣜձࣾϛΫγΟ ൃߦ

  3. None
  4. ·͕͖͑ ຊॻʮmixi tech note #04ʯ͸ɺϛΫγΟάϧʔϓʹॴଐ͢Δ༗ࢤୡʹΑͬͯࣥචɾ੍࡞͞Εͨ ٕज़ॻͰ͢ɻ࣮ࡍͷϓϩμΫτ։ൃͷݱ৔Ͱ࢖༻͞Εٕͨज़ͷ࿩΍ɺ೔ʑͷۀ຿ͷ๣Βɺݸਓతʹௐ ΂ͨ͜ͱͳͲɺࢥ͍ࢥ͍ʹࣥච͍ͯ͠·͢ɻͦͷͨΊɺ֤ষͦΕͧΕͰ׬͍݁ͯ͠Δ಺༰ʹͳ͍ͬͯ ·͢ͷͰɺ޷͖ͳষ͔Β޷͖ͳॱ൪Ͱָ͓͠Έ͍ͩ͘͞ɻ ·ͨɺຊॻ͸ɺϛΫγΟάϧʔϓʹ͋Δٕज़త஌ݟ΍ΞΠσΞΛੵۃతʹڞ༗ɾެ։͍ͯ͘͜͠ͱ ͰɺੈͷதʹΑΓྑ͍αʔϏε͕ҲΕग़͢͜ͱΛئͬͯץߦ͞Ε͍ͯ·͢ɻܝࡌ͞Ε͍ͯΔ৘ใ͸ɺ

    ࣥචऀࣗ਎ͷ؀ڥͰݕূࣥ͠ච͞Εͨ΋ͷͰ͢ͷͰɺ͝ࢀߟʹ͞ΕΔࡍ͸ɺࣗ͝਎ͷ੹೚Ͱ൑அ͠ ͝׆༻͍ͩ͘͞ɻͳ͓ɺจষදݱʹ͖ͭ·ͯ͠΋ɺࣥචऀࣗ਎ͷݴ༿Ͱ఻͑ͨ͘ɺϑϥϯΫͳදݱͱ ͳ͓ͬͯΓ·͢͜ͱ͝ཧղ͍͚ͨͩΕ͹ͱࢥ͍·͢ɻ CTO ࣨ DevRel άϧʔϓ Ұಉ ˗ຊॻʹؔ͢Δ͓໰͍߹Θͤઌ ɹ https://twitter.com/mixi_engineers ˗ϛΫγΟάϧʔϓʹ͍ͭͯ ɹ https://mixi.co.jp/ ˞ʠϛΫγΟʡ ɺ ʠmixiʡ ɺ ʠmixi ϩΰʡ ͸ɺגࣜձࣾϛΫγΟͷ঎ඪ·ͨ͸ొ࿥঎ඪͰ͢ɻ·ͨɺ֤ ࣾͷձ໊ࣾɺαʔϏεٴͼ੡඼ͷ໊শ͸ɺͦΕͧΕͷॴ༗͢Δ঎ඪ·ͨ͸ొ࿥঎ඪͰ͢ɻ iii
  5. None
  6. ໨࣍ ·͕͖͑ iii ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ

    1 1.1 mix ύοέʔδ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 ୊ࡐɿstack-tpls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.3 Stack Template ͔Β࡞੒ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.4 ϦϙδτϦΛऩू . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.5 ऩू݁ՌΛอଘ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.6 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 19 2.1 ࢝Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.2 ΞʔΩςΫνϟ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.3 Cloud Spanner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.4 ऴΘΓʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 31 3.1 ϫΠΨϠॱҐͱ͸ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.2 ࡞੒͢Δ͜ͱʹͳͬͨഎܠ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.4 ϫΠΨϠॱҐʹͳΔ·Ͱ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 3.5 ػցֶशͷಋೖʹ͍ͭͯ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 45 4.1 ࢝Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 4.2 σβΠϯύλʔϯͰΈΔ State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 4.3 Behavior Tree ΛઃܭʹऔΓೖΕΔ . . . . . . . . . . . . . . . . . . . . . . . . . . 50 4.4 ҧ͍Λཧղͯ͠׆༻͢Δ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 4.5 ϏδϡΞϥΠζͰ͖ͨͱͯ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 4.6 Behavior Tree ͕࢘Δ΋ͷ͸ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 v
  7. ໨࣍ 4.7 ݁ͼ . . . . . . .

    . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 55 5.1 ࢝Ίʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 5.2 Git ͷ commit ʹ͍ͭͯ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 5.3 index tree ͸ࠩ෼؅ཧͰ͸ͳ͍ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5.4 index tree ͷ࣮ମͱߏ଄ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 5.5 index tree ͷಾͱͦͷ౴͑ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.6 ࠷ޙʹ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 ஶऀ঺հ 63 vi
  8. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞Δͨ Ίʹ චऀ͸Α͘ɺࢥ͍͍ͭͨπʔϧΛ Haskell

    Ͱ࣮૷͠·͢ɻͦͷͱ͖ʹɺίΞͷϩδοΫҎ֎ΛͰ͖ Δ͚ͩ؆୯ʹ࣮૷͢ΔͨΊͷ޻෉Λ͍ͯ͠·͢ɻCLI πʔϧΛ࡞Δͱ͖ʹඞཁʹͳΔίΞϩδοΫҎ ֎ͷ෦෼ͱ͍͏΋ͷ͸ɺͨͱ͑͹࣍ͷΑ͏ͳ΋ͷ͕ߟ͑ΒΕ·͢ɻ • ίϚϯυϥΠϯҾ਺ • άϩʔόϧͳઃఆͷ؅ཧ • ϩΪϯάʢग़ྗʣ • ֎෦αʔϏεͱͷ΍ΓͱΓ • σʔλετΞʢ؆қతͳʣ චऀ͸ɺ͜ΕΒΛ؆୯ʹѻ͑ΔΑ͏ʹ͢Δ͘͠Έͱͯ͠ mix ύοέʔδͱ͍͏ͷΛࣗ࡞ͯ͠ར༻ ͍ͯ͠·͢ɻຊষͰ͸ɺ͜ͷ mix ύοέʔδΛར༻ͯ͠εςοϓόΠεςοϓʹ CLI πʔϧΛ࡞Δ ͜ͱͰɺCLI πʔϧΛ؆୯ʹ࡞ΔͨΊͷ޻෉Λ঺հ͠·͢ɻ·ͨɺ͢΂ͯͷιʔείʔυ͸ GitHub ͷ matsubara0507/stack-tpls-demo*1 ϦϙδτϦʹ͋Γ·͢ɻ 1.1 mix ύοέʔδ ·ͣ͸ mix ύοέʔδʹ͍ͭͯ঺հ͠·͢*2ɻmix ύοέʔδͦΕࣗମ͸ɺ͋Δ 2 ͭͷύοέʔ δΛ૊Έ߹Θ͚ͤͨͩͷ؆୯ͳϥούʔϑϨʔϜϫʔΫͰ͢ɻ૊Έ߹Θͤͨύοέʔδ͸ extensible ύοέʔδͱ rio ύοέʔδͰ͢ɻॱʹ঺հ͠·͢ɻ *1 https://github.com/matsubara0507/stack-tpls-demo *2 https://github.com/matsubara0507/mix.hs 1
  9. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.1 mix ύοέʔδ

    extensible ύοέʔδ extensible*3 ύοέʔδ͸֦ுՄೳϨίʔυͷΑ͏ͳɺߴ֊ΧΠϯυͳσʔλܕΛ؆୯ʹѻ͑Δ ύοέʔδͰ͢ɻߴ֊ΧΠϯυʹ͍ͭͯ͸͜͜Ͱ͸ׂѪ͠·͕͢ɺͨͱ͑͹࣍ͷΑ͏ͳ ToDo ܕͰ؆ ୯ʹྫΛࣔ͠·͢ɻ ී௨ʹ Haskell ͷߏจͰهड़ͨ͠ ToDo ܕ data ToDo = ToDo { todoID :: Int , title :: Text , done :: Bool } ͜ΕΛ extensible Λ࢖͏͜ͱͰ࣍ͷΑ͏ʹهड़Ͱ͖·͢ɻ extensible ه๏ͷ ToDo ܕ import Data.Extensible type ToDo = Record ’[ "id" >: Int , "title" >: Text , "done" >: Bool ] ϑΟʔϧυʹΞΫηε͢Δ৔߹͸ person^.#name ͷΑ͏ʹͰ͖·͢*4ɻ͜Ε͚ͩͷ৔߹ɺΘ͟Θ ͟ extensible Λར༻͢Δར఺͸͋Γ·ͤΜɻextensible ه๏ʹΑΔϨίʔυܕͷେ͖ͳར఺ͷҰͭ ͸ɺϨίʔυϑΟʔϧυΛ഑ྻ΍Ϧετߏ଄ͷΑ͏ʹڞ௨ͷॲཧΛద༻ͨ͠͏͑Ͱ৞ΈࠐΊΔ఺Ͱ ͢ɻͨͱ͑͹ɺϑΟʔϧυ໊ʢจࣈྻʣͷϦετΛߏங͢Δؔ਺΍ɺ֤ϑΟʔϧυΛίϚϯυϥΠϯ Ҿ਺ͷΦϓγϣϯͱͯ͠ߏங͢Δؔ਺ΛఆٛͰ͖·͢ɻ ·ͨɺextensible ͷϨίʔυه๏͸ type એݴʹͳΔͷͰܕΫϥεͷΠϯελϯεΛݸผʹએݴ͢ Δඞཁ͕ͳ͘ͳΔͱ͍͏ར఺΋͋Γ·͢ɻ΋ͪΖΜɺཪΛฦͤ͹ݸʑͷϨίʔυʹରͯ͠ݸผʹએݴ Ͱ͖ͳ͘ͳΔͱ͍͏ܽ఺ͱ΋ߟ͑ΒΕ·͕͢ɻ *3 https://hackage.haskell.org/package/extensible-0.7 *4 ^ . ͸ lens ܥ ύ ο έ ʔ δ ͷ ؔ ਺ Ͱ ͢ https://hackage.haskell.org/package/lens-4.18.1/docs/ Control-Lens-Getter.html#v:-94-. 2
  10. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.1 mix ύοέʔδ

    rio ύοέʔδ rio ύοέʔδ*5͸͍ΘΏΔ alt. Prelude ͳύοέʔδͰ͢ɻalt. Prelude ͳύοέʔδͱ͸ɺ Haskell ͷඪ४ύοέʔδʹ͋ͨΔ Prelude Ϟδϡʔϧͷ୅ସʹͳΔύοέʔδͷ͜ͱΛࢦ͠·͢ɻ rio ͷ΄͔ʹ༗໊ͳ΋ͷͰɺclassy-prelude ύοέʔδ΍ universum ύοέʔδͳͲ͕͋Γ·͕͢ɺ චऀ͸࢖ͬͨ͜ͱ͕ͳ͍ͷͰൺֱͳͲΛ͜͜Ͱ͸͠·ͤΜɻPrelude Ϟδϡʔϧ͸҉໧తʹΠϯϙʔ τ͞Ε·͕͢ɺGHC ͷ NoImplicitPrelude ݴޠ֦ுΛ࢖͏͜ͱͰ҉໧తʹΠϯϙʔτ͞ΕΔͷΛͱ ΊΔ͜ͱ͕Ͱ͖·͢ɻ͜ͷػೳΛ૊Έ߹ΘͤΔ͜ͱͰ Prelude Ϟδϡʔϧͷ୅ΘΓʹผͷඪ४ύο έʔδͷΑ͏ͳύοέʔδΛΠϯϙʔτ͠·͢ɻ rio ύοέʔδ͸ɺϏϧυπʔϧ Stack *6Λ։ൃ͍ͯ͠ΔνʔϜ͕࡞੒͠·ͨ͠ɻrio ύοέʔδ ͸ ReaderT ύλʔϯͱݺ͹ΕΔσβΠϯύλʔϯ*7Λϕʔεʹͯ͠ઃܭ͞Ε͓ͯΓɺ࣍ͷΑ͏ͳ͜ ͱΛ؆୯ʹهड़Ͱ͖·͢ɻ • άϩʔόϧͳઃఆͷ؅ཧ • ϩΪϯά rio ύοέʔδʹ͸ RIO env ͱ͍͏ܕ͕͋Γ·͢ɻ͜ΕΛ IO ܕͷ୅ΘΓʹར༻͢Δ͜ͱͰʮά ϩʔόϧͳઃఆͷ؅ཧʯͱʮϩΪϯάʯΛ؆୯ʹهड़Ͱ͖ΔͷͰ͢ɻ rio Λར༻ͨ͠ϓϩάϥϜͷྫ import RIO main :: IO () main = do opt <- logOptionsHandle stdout False withLogFunc opt $ \logFunc -> runRIO (Env logFunc "Hoge") app data Env = Env { logFunc :: LogFunc -- ϩΪϯάͷͨΊʹඞཁ , getName :: Text } app :: RIO Env () app = do name <- asks getName logDebug $ display ("This is debug: " <> name) logInfo $ display ("This is info: " <> name) logWarn $ display ("This is warn: " <> name) logError $ display ("This is error: " <> name) *5 https://hackage.haskell.org/package/rio-0.1.18.0 *6 https://docs.haskellstack.org *7 ͜ ͜ Ͱ ͷ ղ આ ͸ ׂ Ѫ ͠ · ͢ ͕ ɺৄ ͠ ͘ ͸ https://www.fpcomplete.com/blog/2017/06/ readert-design-pattern Λࢀর͍ͯͩ͘͠͞ (rio ͷ࡞ऀͷهࣄͰ͢) 3
  11. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.1 mix ύοέʔδ

    ͪͳΈʹɺ͜ͷϓϩάϥϜͷ࣮ߦ݁Ռ͸࣍ͷΑ͏ʹͳΓ·͢ɻ $ stack runghc mix/sample/Main.hs 2020-09-07 22:33:49.378471: [debug] This is debug: Hoge @(mix/sample/Main.hs:23:3) 2020-09-07 22:33:49.381893: [info] This is info: Hoge @(mix/sample/Main.hs:24:3) 2020-09-07 22:33:49.381943: [warn] This is warn: Hoge @(mix/sample/Main.hs:25:3) 2020-09-07 22:33:49.382005: [error] This is error: Hoge @(mix/sample/Main.hs:26:3) extensible ͷຐ๏ rio ͷϩΪϯά͸ඇৗʹศརͰ͕ͪ͢ΐͬͱͨܽ͠఺͕ 2 ͭ͋Γ·͢ɻ 1. ܕΫϥεͷΠϯελϯεએݴ͕ඞཁ 2. withLogFunc ͷར༻͕ಛघ ࣮͸ɺલड़ͨ͠ϓϩάϥϜΛϏϧυ͢Δʹ͸ԼهͷΑ͏ͳܕΫϥεͷΠϯελϯεએݴ͕ඞཁ Ͱ͢ɻ rio ͷϩΪϯάΛ͢ΔͷʹඞཁͳΠϯελϯεએݴ instance HasLogFunc Env where logFuncL = lens logFunc (\x y -> x { logFunc = y }) ͜Ε͸ͨͩͷϘΠϥʔςϯϓϨʔτͰ͢Ͷɻmix Ͱ͸ RIO env ͷ env Λ extensible ͷϨίʔυ Ͱએݴ͢Δ͜ͱΛલఏʹ͢Δ͜ͱͰɺ͜ͷϘΠϥʔςϯϓϨʔτΛͳ͘͠·͢ɻલड़ͨ͠ϓϩάϥϜ ͷྫΛ mix Ͱهड़͢Δͱ࣍ͷΑ͏ʹͳΓ·͢ɻ mix Λར༻ͨ͠ϓϩάϥϜͷྫ import RIO import Data.Extensible import Mix import Mix.Plugin.Logger as MixLogger main :: IO () main = Mix.run plugin app where plugin :: Plugin () IO Env 4
  12. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.1 mix ύοέʔδ

    plugin = hsequence $ #logger <@=> MixLogger.buildPlugin logOpt <: #name <@=> pure "Hoge" <: nil logOpt = #handle @= stdout <: #verbose @= True <: nil type Env = Record ’[ "logger" >: MixLogger.LogFunc , "name" >: Text ] app :: IO () app = do name <- asks (view #name) logDebug $ display ("This is debug: " <> name) logInfo $ display ("This is info: " <> name) logWarn $ display ("This is warn: " <> name) logError $ display ("This is error: " <> name) withLogFunc ͷ୅ΘΓʹ Mix.run ͱ Plugin Λ࢖͍·͢ɻ͜ͷ Plugin ΋ extensible ͷ͘͠Έ Λར༻͍ͯ͠·͢ɻextensible ͷϨίʔυͷར఺͸ʮϨίʔυϑΟʔϧυΛ഑ྻ΍Ϧετߏ଄ͷΑ͏ ʹڞ௨ͷॲཧΛద༻ͨ͠͏͑Ͱ৞ΈࠐΊΔʯ఺ͱॻ͖·͕ͨ͠ɺ·͞ʹ͜ΕΛར༻͍ͯ͠·͢ʢhseq uence ͷ෦෼Ͱ͢ʣ ɻPlugin ͷத਎͸࣍ͷΑ͏ʹͳ͍ͬͯ·͢ɻ Plugin ܕͷத਎ type Plugin a m env = ContT a m env run :: MonadIO m => Plugin a m env -> RIO env a -> m a run plugin act = (‘runRIO‘ act) ‘withPlugin‘ plugin withPlugin :: (env -> m a) -> Plugin a m env -> m a withPlugin = flip runContT -- MixLogger.buildPlugin Ͱར༻͍ͯ͠·͢ toPlugin :: ((env -> m a) -> m a) -> Plugin a m env toPlugin = ContT -- Data.Extensible ͷؔ਺ʢf ͕ Plugin a m Ͱ͢ʣ hsequence :: Applicative f => (Comp f h :* xs) -> f (h :* xs) ContT ͱ͍͏ͷ͸ܧଓͱݺ͹ΕΔ΋ͷͰ͢ɻৄ͘͠͸ׂѪ͠·͕͢ɺwithLogFunc ͕·͞ʹܧଓ ʹͳ͍ͬͯ·͢ɻ withLogFunc ͱܧଓ withLogFunc :: MonadUnliftIO m => LogOptions -> (LogFunc -> m a) -> m a 5
  13. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.1 mix ύοέʔδ

    -- ܧଓ(Continuation)ͷϞφυτϥϯεϑΥʔϜ࢓༷ͷܕ newtype ContT r m a = ContT { runContT :: ((a -> m r) -> m r) } (a -> m r) -> m r ͷ෦෼͕ (LogFunc -> m a) -> m a ͱҰக͠·͢Ͷɻޙड़͢Δ mix ͷ ϓϥάΠϯ͸͢΂ͯ͜ͷܧଓͱͯ͠දݱ͓ͯ͠Γɺhsequence ͰͦΕΒΛ৞ΈࠐΜͰ env Λ࡞Γ ·͢ɻ ϓϥάΠϯγεςϜ mix ύοέʔδͷ͋Δ matsubara0507/mix.hs ϦϙδτϦʹ͸ɺ͍͔ͭ͘ϓϥάΠϯΛҰॹʹஔ ͍ͯ͋Γ·͢ɻݱࡏʢ2020 ೥ 9 ݄ʣ͋Δͷ͸ҎԼͷ௨ΓͰ͢ɻ • rio ͷϩΪϯά (mix ʹೖ͍ͬͯΔ) • ઃఆ༻ϑΟʔϧυΛ࣋ͭ (mix ʹೖ͍ͬͯΔ) • GitHub API ͷΫϥΠΞϯτʢmix-plugin-githubʣ • Drone API ͷΫϥΠΞϯτʢmix-plugin-droneʣ • Shell ͷ࣮ߦʢmix-plugin-shellʣ • SQLiteʢmix-plugin-persistent-sqliteʣ • XDG σΟϨΫτϦ΁ͷΩϟογϡʢmix-plugin-xdgcacheʣ ͪͳΈʹɺ͜ͷϓϥάΠϯγεςϜʢͱ rio ͷϥούʔϑϨʔϜϫʔΫʣ͸ tonatona ͱ͍͏ύο έʔδ*8ʹΠϯεύΠΞ͞Ε·ͨ͠ɻ ֤ύοέʔδͷόʔδϣϯͳͲ ຊ୊ʹೖΔલʹɺࠓճར༻ͨ͠ॲཧܥ΍ύοέʔδͷόʔδϣϯΛྻڍ͓͖ͯ͠·͢ɿ • GHCʢHaskell ͷॲཧܥʣ: 8.8.4 • StackʢHaskell ͷϏϧυπʔϧʣ: 2.3.1 • extensible : 0.8 • rio : 0.1.18.0 • aesonʢJSON Τϯίʔμɾσίʔμʣ: 1.4.7.1 • githashʢϓϩδΣΫτͷ.git Λղੳͯ͠ར༻Ͱ͖Δʣ: 0.1.4.0 • dotenvʢ.env ϑΝΠϧΛಡΈऔΔʣ: 0.8.0.6 *8 https://github.com/tonatona-project/tonatona 6
  14. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.2 ୊ࡐɿstack-tpls 1.2

    ୊ࡐɿstack-tpls ࠓճ͸ stack-tpls ͱ͍͏ CLI πʔϧΛ࡞Γ·͢ɻ͜Ε͸ GitHub ্ʹ͋Δ stack-templates ͱ͍ ͏ϦϙδτϦΛऩू͢ΔπʔϧͰ͢ɻ Stack Template Stack Template ͱ͸ɺHaskell ͷϏϧυπʔϧ Stack ͰॳظϑΝΠϧΛੜ੒͢Δʢstack new ί ϚϯυΛ࣮ߦʣͱ͖ʹੜ੒͢ΔϑΝΠϧͷͻͳܕΛΧελϚΠζͨ͠ςϯϓϨʔτͰ͢ɻίϚϯυ࣮ ߦ࣌ʹ࣍ͷΑ͏ʹࢦఆͰ͖·͢ɻ $ stack new project-name github:matsubara0507/mix-cli.hsfiles GitHubɾGitLabɾBitbucket ͷ͍ͣΕ͔ʹ stack-templates ͱ͍͏໊લͷϦϙδτϦΛ࡞Γɺͦ ͷϦϙδτϦʹ hsfiles ͱ͍͏֦ுࢠͷϑΝΠϧΛτοϓϨϕϧʹஔ͘͜ͱͰೝࣝ͞Ε·͢ʢ͜͜Ͱ ͸ .hsfiles ͷॻ͖ํࣗମ͸ׂѪ͠·͢ʣ ɻͨͱ͑͹ɺGitHub ্ʹ͋Δචऀͷ stack-templates Ϧϙ δτϦ͸࣍ͷΑ͏ʹͳ͍ͬͯ·͢ɻ ਤ 1.1: GitHub ͷ matsubara0507/stack-templates ϦϙδτϦ ຊߘͰ͸ GitHub ্ͷ Stack Template ΛूΊΔػೳ͚ͩΛ࣮૷͠·͢ɻ 7
  15. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.3 Stack Template

    ͔Β࡞੒ εςοϓόΠεςοϓ ࣍ͷεςοϓͰ࣮૷͍͖ͯ͠·͢ɻ 1. Stack Template ͔ΒϕʔεΛ࡞੒ 2. GitHub ͔ΒϦϙδτϦΛऩू͢Δ 3. ऩू݁ՌΛϩʔΧϧʹอଘ͢Δ ·ͣ͸ɺ Stack Template Λར༻ͯ͠ CLI πʔϧͷͻͳܕΛ࡞੒͠·͢ɻ࣍ʹɺ GitHub GraphQL API Λར༻ͯ͠ GitHub ্ʹ͋Δ Stack Template ϦϙδτϦΛूΊ·͢ɻGraphQL Λར༻͢Δ ͜ͱͰɺϦϙδτϦͱϦϙδτϦ্ʹ͋ΔϑΝΠϧΛ 1 ͭͷϦΫΤετͰूΊΔ͜ͱ͕Ͱ͖·͢ɻ GraphQL Ͱޮ཰ྑ͘ऩूͨ͠ͱͯ͠΋ɺίϚϯυΛͨͨͨ͘ͼʹϦΫΤετΛ౤͍͛ͯΔͱ஗͘ͳ Γ·͢ɻͦ͜Ͱ࠷ޙʹɺऩू݁ՌΛϩʔΧϧʹอଘ͢Δ͜ͱͰίϚϯυͷ࣮ߦΛߴ଎Խ͠ɺGitHub API Λ࢖ͬͯߋ৽͍ͨ͠৔߹͸ઐ༻ͷϑϥάΛ౉͢Α͏ʹ͠·͢ɻ 1.3 Stack Template ͔Β࡞੒ mix ύοέʔδΛར༻ͨ͠ CLI πʔϧΛ࡞Δ༻ʹ Stack Template Λ༻ҙ͍ͯ͠ΔͷͰɺͦΕΛ ར༻ͯ͠ stack new ͠·͢ɻ $ stack new stack-tpls-demo github:matsubara0507/mix-cli.hsfiles ࣮͸ stack new ͚ͨͩ͠Ͱ͸ɺstack build Ͱ͖·ͤΜɻ $ stack build ... [4 of 4] Compiling Main /path/to/stack-tpls-demo/app/Main.hs:3:29: error: parse error on input ʞ-ʟ | 3 | import Paths_stack-tpls-demo (version) | ^ .hsfiles ͷه๏Ͱɺ࡞੒͍ͨ͠ύοέʔδ໊ʢ͜͜Ͱ͸ stack-tpls-demoʣΛςϯϓϨʔτʹຒΊ ࠐΉ͜ͱ͕Ͱ͖·͢ɻPaths_xxx ͱ͍͏ͷ͸ϓϩδΣΫτʹؔͯࣗ͠ಈͰੜ੒͞ΕΔϞδϡʔϧͰɺ ϓϩδΣΫτϑΝΠϧʹهࡌͨ͠όʔδϣϯͳͲΛऔಘͰ͖·͢ɻCLI πʔϧͷ --version Φϓ γϣϯͳͲʹ࢖͏ͷͰ͕͢ɺxxx ͷ෦෼ʹ - ͕࢖͑ͳ͍ͷͰ͢ɻ͔͠͠ɺຒΊࠐΉʹ͸ - ͷ··Ͱ ͳ͍ͱ͍͚·ͤΜɻͳͷͰ - Λ _ ʹखͰஔ͖׵͑Δඞཁ͕͋Γ·͢ɻ 8
  16. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.3 Stack Template

    ͔Β࡞੒ ଞʹ΋ɺsrc/Lib ͱͳ͍ͬͯΔϞδϡʔϧͷωʔϜεϖʔεΛม͑ͨΓɺgit init Λͨ͠Γ͢Δ ඞཁ΋͋Γ·͢ɻͦ͏ͯ͠Ϗϧυͨ݁͠Ռɺ࣍ͷΑ͏ͳ CLI πʔϧ͕ͬͦ͘͞Ͱ͖͕͋Γ·ͨ͠ɻ $ stack exec -- stack-tpls-demo not yet implement command. $ stack exec -- stack-tpls-demo --help stack-tpls-demo [options] [input-file] -h --help Show this help text --version Show version -v --verbose Enable verbose mode: verbosity level "debug" $ stack exec -- stack-tpls-demo --version Version 0.1.0, Git revision Tue Sep 1 08:17:16 2020 +0900 (1 commits) ίϚϯυϥΠϯҾ਺ ίϚϯυϥΠϯҾ਺ͷ૊Έཱͯʹ͸ System.Console.GetOpt Λ࢖͍·͢ɻ͜Ε͸ඪ४ʹ૊Έࠐ ·Ε͍ͯΔίϚϯυϥΠϯҾ਺Λղऍ͢ΔػೳͰ͢ɻextensible ύοέʔδʹ͸ GetOpt Λ֦ுՄೳ ϨίʔυʹରԠͤͨ͞΋ͷ͕͋Γɺ࣮ࡍʹ͸͜ΕΛར༻͠·͢ɻ GetOpt ͷ֦ுՄೳϨίʔυ൛ withGetOpt :: MonadIO m => String -- usage Ͱදࣔ͞ΕΔ -> RecordOf (OptionDescr h) xs -- ίϚϯυϥΠϯҾ਺ͷઃఆ -> (RecordOf h xs -> [String] -> m a) -- ίϚϯυϥΠϯҾ਺Λ΋Βͬͯಈ࡞͍ͤͨؔ͞਺Λ౉͢ -> m a ͍ΘΏΔ usage ͬΆ͍ग़ྗ͸ίϚϯυϥΠϯҾ਺͕ؒҧ͍ͬͯΔͱ͖ʹදࣔ͞Ε·͢ɻͰ͖Ε͹ --help Φϓγϣϯ͕༩͑ΒΕͨͱ͖ʹ΋ද͍ࣔͨ͠ͷͰɺusage ༻ͷจࣈྻΛ΋Β͑ΔΑ͏ʹ֦ு ͨ͠ϞϊΛ༻ҙ͠·ͨ͠ʢwithGetOpt’ʣ ɻ͜ΕΛར༻͠·͢ɻ Main ؔ਺ͱίϚϯυϥΠϯҾ਺ -- Main.hs main :: IO () main = withGetOpt’ "[options] [input-file]" opts $ \r args usage -> do - MultiWayIf ͱ͍͏ݴޠ֦ு if | r ^. #help -> hPutBuilder stdout (fromString usage) | r ^. #version -> hPutBuilder stdout (Version.build version <> "\n") | otherwise -> runCmd r (listToMaybe args) where 9
  17. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.3 Stack Template

    ͔Β࡞੒ opts = #help @= helpOpt <: #version @= versionOpt <: #verbose @= verboseOpt <: nil type Options = Record ’[ "help" >: Bool , "version" >: Bool , "verbose" >: Bool ] -- ͜ͷΑ͏ͳؔ਺Λ֤ίϚϯυϥΠϯҾ਺෼༻ҙ͢Δ helpOpt :: OptDescr’ Bool helpOpt = optFlag [’h’] ["help"] "Show this help text" όʔδϣϯΦϓγϣϯ ίϛοτ਺ͳͲɺ Α͍ײ͡ʹόʔδϣϯͷ৘ใΛग़ྗ͢Δʹ͸ githash ύοέʔδ*9Λར༻͠·͢ɻ import Data.Version (Version) -- ͜Ε͸ඪ४ύοέʔδʹ͋Δ import qualified Data.Version as Version import qualified GitHash build :: Version -> Builder build v = encodeUtf8Builder . fromString $ unwords [ "Version" , Version.showVersion v ++ "," , "Git revision" , GitHash.giCommitDate gi , "(" ++ show (GitHash.giCommitCount gi) ++ " commits)" ] where gi = $$(GitHash.tGitInfoCwd) ͜ͷ build ؔ਺͸ Main ؔ਺Ͱ Version.build version ͰݺΜͰ͍Δ΋ͷͰ͢ɻҾ਺ͷ vers ion ͸લड़ͨ͠ Paths_xxx Ͱऔಘͨ͠΋ͷͰɺϓϩδΣΫτͷόʔδϣϯ৘ใʹͳΓ·͢ɻ$$(Gi tHash.tGitInfoCwd) ͸ Template Haskell ͱ͍͏ Haskell ͷϝλϓϩάϥϛϯάΛར༻ͨ͠΋ͷ ͰɺϏϧυ࣌ʹ .git ͷ৘ใΛूΊͯຒΊࠐΈ·͢ɻ *9 https://hackage.haskell.org/package/githash 10
  18. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.3 Stack Template

    ͔Β࡞੒ dotenv Λ࢖͏ GitHub τʔΫϯΛདͷ··ίϚϯυͱͯ͠ೖྗ͢Δͷ͸ؾ͕Ҿ͚ΔͷͰɺϫʔΫσΟϨΫτϦ΍ ϗʔϜσΟϨΫτϦʹ͋Δ .env ϑΝΠϧΛಡΈࠐΜͰ࢖ͬͯ͘ΕΔΑ͏ʹͯ͠Έ·͢ɻ͜Εʹ͸ dotenv ύοέʔδ*10Λ࢖͍·͢ɻ࢖͍ํ͸؆୯ͰɺMain ؔ਺ͷ๯಄ʹ਺ߦ௥Ճ͢Δ͚ͩͰ͢ɻ dotenv Λ࢖͏ -- Main.hs main :: IO () main = withGetOpt’ "[options] [input-file]" opts $ \r args usage -> do -- ҎԼ3ߦʢ಄2ߦ͸ϗʔϜσΟϨΫτϦ༻ɺ࠷ޙ͸ϫʔΫσΟϨΫτϦ༻ʣ homeDir <- getHomeDirectory _ <- tryIO $ loadFile defaultConfig { configPath = [homeDir </> ".env"] } _ <- tryIO $ loadFile defaultConfig { configOverride = True } if | r ^. #help -> hPutBuilder stdout (fromString usage) ... ίϚϯυຊମ ࠷ޙʹίϚϯυຊମΛࡌ͓͖ͤͯ·͢ɻ͜ΕΛϕʔεʹͯ͠ɺঃʑʹ֦ு͞Ε͍͖ͯ·͢ɻͪͳΈ ʹɺ_path Ҿ਺ʹ͸ίϚϯυͷΦϓγϣϯͳ͠ͷҾ਺͕དྷ·͢ɻࣗ෼͸Α͘ઃఆͷϑΝΠϧύεͳͲ ʹ࢖͍·͕͢ɺࠓճ͸ར༻͠ͳ͍ͷͰແࢹ͍ͯ͠·͢ɻ GitHub ϓϥάΠϯΛ૊ΈࠐΉ runCmd :: Options -> Maybe FilePath -> IO () runCmd opts _path = do -- ϓϥάΠϯΛ৞ΈࠐΈ·͢ʢ·ͩ̍ͭͰ͕͢ʣ let plugin = hsequence $ #logger <@=> MixLogger.buildPlugin logOpts <: nil Mix.run plugin cmd where logOpts = #handle @= stdout <: #verbose @= (opts ^. #verbose) <: nil *10 https://hackage.haskell.org/package/dotenv 11
  19. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.4 ϦϙδτϦΛऩू 1.4

    ϦϙδτϦΛऩू ͍Α͍ΑίΞͷ࣮૷Λ࢝Ί·͢ɻ͔͠͠ɺຊߘͷ໨త͸ίΞͷ࣮૷෦෼Ͱ͸ͳ͍ͷͰద౓ʹׂѪ͠ ·͢ɻ GraphQL API Λ࣮ߦ͢Δ GitHub GraphQL API *11Λར༻͢ΔͨΊʹ mix-plugin-github ϓϥάΠϯύοέʔδͷ Mix.P lugin.GitHub.GraphQL ϞδϡʔϧΛར༻͠·͢ɻ Mix.Plugin.GitHub.GraphQL ͷؔ਺ module Mix.Plugin.GitHub.GraphQL where fetch :: (HasGitHubToken env, FromJSON a) => Text -> RIO E a 1 Ҿ਺໨ͷ Text ܕ͸ΫΤϦจࣈྻͰ͢ɻ࢒೦ͳ͕Βɺྑͦ͞͏ͳ GitHub GraphQL API ΫϥΠ Ξϯτ͕ Haskell ʹ͸·ͩ͋Γ·ͤΜʢ2020 ೥ 9 ݄ݱࡏʣ ɻͳͷͰ fetch ؔ਺Ͱ͸ɺݺͼग़͠ଆ͕ Α͠ͳʹΫΤϦจࣈྻͰߏங͠ɺͦͷΫΤϦจࣈྻΛ POST ϦΫΤετʹؚΊΔͱ͜Ζ·ͰΛ΍Γ ·͢ɻ·ͨɺGraphQL API Λݺͼग़͢ʹ͸ GitHub ͷτʔΫϯ͕ඞཁͰ͢ɻHasGitHubToken en v ͸ RIO env ͷ؀ڥ env ͕ GitHub τʔΫϯΛ͍࣋ͬͯΔ͜ͱΛอূ͢ΔܕΫϥεͰ͢ɻ͜Εʹ ΑΓɺfetch ؔ਺Ͱͷ HTTP ϦΫΤετͰ GitHub τʔΫϯΛར༻Ͱ͖·͢ɻ ͯ͞ɺ͜ͷؔ਺Λ RIO Env ্Ͱ࢖͏ʹ͸ίϚϯυຊମʹϓϥάΠϯΛ૊ΈࠐΈ·͠ΐ͏ɻ GitHub ϓϥάΠϯΛ૊ΈࠐΉ import qualified Mix.Plugin.GitHub as MixGitHub -- Env.hs type Env = Record ’[ "logger" >: MixLogger.LogFunc , "github" >: MixGitHub.Token -- ௥Ճ ] -- Main.hs runCmd :: Options -> Maybe FilePath -> IO () runCmd opts _path = do gToken <- liftIO $ fromString <$> getEnv "GH_TOKEN" -- ௥Ճ let plugin = hsequence $ #logger <@=> MixLogger.buildPlugin logOpts <: #github <@=> MixGitHub.buildPlugin gToken -- ௥Ճ <: nil *11 https://docs.github.com/en/graphql 12
  20. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.4 ϦϙδτϦΛऩू Mix.run

    plugin cmd ࣮ࡍʹ͜ͷؔ਺Λݺͼग़͍ͯ͠Δ෦෼͸࣍ͷΑ͏ʹͳΓ·͢ɻ fetch ؔ਺Λݺͼग़͢ -- Cmd.hs fetchTplListFromGitHub :: [Repository] -> SearchOpts -> RIO Env [Repository] fetchTplListFromGitHub acc opts = do let query = searchRepositoryQuery "stack-templates in:name" opts logDebug $ "query: " <> display query resp <- GraphQL.fetch query :: RIO Env Response -- ίί let page = resp ^. #data ^. #search ^. #pageInfo repos = acc ++ map (view #node) (resp ^. #data ^. #search ^. #edges) opts’ = opts & #after ‘set‘ (page ^. #endCursor) if page ^. #hasNextPage then fetchTplListFromGitHub repos opts’ else pure repos searchRepositoryQuery :: Text -> SearchOpts -> Text searchRepositoryQuery query sOpt = ... type SearchOpts = Record ’[ "first" >: Int -- Կ݅औಘ͢Δ͔ , "after" >: Maybe Text -- ϖʔδωʔγϣϯͷઌ಄ ] searchRepositoryQuery ؔ਺͸ϦϙδτϦݕࡧ༻ͷΫΤϦͱϦϙδτϦݕࡧ༻ΦϓγϣϯΛࢦ ఆͯ͠ɺGraphQL ΫΤϦΛฦؔ͢਺Ͱ͢ɻ͜ΕΛͦͷ·· Mix.Plugin.GitHub.GraphQL.fetch ʹ౉͠·͢ɻ͜ͷͱ͖ʹɺܕ஫ऍ RIO Env Response ΛೖΕ͍ͯΔͷ͸ɺJSON Λσίʔυͨ͠ܕ ͕ఆ·Βͳ͍ͨΊͰ͢ɻResponse ܕ͸ɺ ࠓճͷ GraphQL ΫΤϦͷϨεϙϯε JSON Λ extensible ͷϨίʔυܕͰදݱͨ͠΋ͷͰɺͨͱ͑͹࣍ͷΑ͏ͳ JSON Λ૝ఆ͍ͯ͠·͢ɻ ࠓճͷ GraphQL ΫΤϦͷϨεϙϯεͱͯ͠ظ଴͢Δ JSON { "data" : { "search" : { "repositoryCount" : 1, "pageInfo" : { "endCursor" : null, "hasNextPage" : false }, "edges" : [ { "node" : { 13
  21. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.4 ϦϙδτϦΛऩू "name"

    : "stack-templates", "nameWithOwner" : "matsubara0507/stack-templates", "object" : { "tree" : { "entries" : [ {"name":"mix-cli.hsfiles", "type":"blob"}, ... ] } } } } ] } } } "pageInfo" ʹ͸ϖʔδωʔγϣϯͷ৘ใؚ͕·Ε͓ͯΓɺҰճͷϦΫΤετͰ্ݶ 100 ͔݅͠औ ಘͰ͖·ͤΜɻͰ͢ͷͰɺଓ͖͕͋Δ৔߹͸ "endCursor" Λ࣍ͷϦΫΤετʹ౉ͯ͠ϖʔδΛਐΊ ·͢ɻ"node" Ҏ͕߱ϦϙδτϦͷ৘ใʹͳΓ·͢ɻ .hsfiles Λྻڍ͢Δ ࠷ऴతʹཉ͍͠ͷ͸ stack-templates ϦϙδτϦʹ͋Δ .hsfiles ͷ৘ใͰ͢ɻͰ͢ͷͰɺϦϙδτ Ϧ৘ใΛར༻ͯ͠ .hsfiles Λྻڍ͠·͢ɻ ϦΫΤετ݁ՌΛϑΟϧλϦϯάͯ͠.hsfile Λྻڍ͢Δؔ਺ mapHsfilesWithFilter :: [Repository] -> [Hsfiles] mapHsfilesWithFilter = mconcat . map fromGitHubRepository . filter isStackTemplates isStackTemplates :: Repository -> Bool isStackTemplates repo = repo ^. #name == "stack-templates" type Hsfiles = Record ’[ "name" >: Text , "owner" >: Text , "domain" >: Domain -- GitHub or GitLab or BitBucket ] fromGitHubRepository :: Repository -> [Hsfiles] fromGitHubRepository repo = for files $ \file -> #name @= (file ^. #name) <: #owner @= getOwner repo <: #domain @= GitHub <: nil where -- "object" ͸ nullable files :: Repository -> [TreeEntry] 14
  22. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.4 ϦϙδτϦΛऩू files

    = filter isHsfiles $ maybe [] (\obj -> obj ^. #tree ^. #entries) (repo ^. #object) -- blob ΦϒδΣΫτͰ͔ͭϑΝΠϧ໊͕ .hsfiles ͰऴΘ͍ͬͯΔ isHsfiles :: TreeEntry -> Bool isHsfiles ent = isBlob ent && Text.isSuffixOf ".hsfiles" (ent ^. #name) ·ͣɺϦϙδτϦ໊ʢ"name"ʣ͕ stack-templates ͔Ͳ͏͔ΛνΣοΫ͠·͢ɻ"object" ͕Ϧ ϙδτϦͷτοϓϨϕϧͷϑΝΠϧ΍σΟϨΫτϦͷ৘ใʹͳΓɺ"type":"blob" ͳͲ͔Β෼͔Δ ͱ͓Γɺͨͩͷ git ΦϒδΣΫτͷ৘ใͰ͢ɻblob ΦϒδΣΫτͰ͋Γʢͭ·ΓσΟϨΫτϦ͡Ό ͳͯ͘ϑΝΠϧͰ͋Δ͜ͱʣ͔ͭɺϑΝΠϧ໊͕ .hsfiles ͰऴΘ͍ͬͯΔ৔߹͸ Stack Template ͷϑΝΠϧͰ͋Δͱ൑அ͍ͯ͠·͢ɻ ूΊͨ৘ใΛग़ྗ͢Δ ͜ΕΒͷؔ਺Λ૊Έ߹Θͤͯ .hsfiles ΛूΊͯɺ͞ΒʹͦΕΒͷ৘ใΛग़ྗ͠·͢ɻҎ্ͷؔ਺Λ ࣍ͷΑ͏ʹఆٛ͠·ͨ͠ɻ .hsfiles ΛूΊͯग़ྗ͢Δؔ਺ -- Cmd.hs cmd :: RIO Env () cmd = do logDebug "run: fetch hsfiles" tpls <- fetchTplList forM_ tpls $ \tpl -> logInfo (display $ toStackArg tpl) fetchTplList :: RIO Env [Hsfiles] fetchTplList = -- ࠓ·Ͱͷؔ਺Λ૊Έ߹ΘͤΔ mapHsfilesWithFilter <$> fetchTplListFromGitHub [] sOpts where sOpts = #first @= 100 <: #after @= Nothing <: nil ͜Μͳ;͏ʹग़ྗ͞Ε·͢ɻ $ stack exec -- stack-tpls-demo github:matsubara0507/get-opt-cli.hsfiles github:matsubara0507/lib-extensible.hsfiles github:matsubara0507/mix-cli.hsfiles github:matsubara0507/optparse-applicative-cli.hsfiles ... 15
  23. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.5 ऩू݁ՌΛอଘ 1.5

    ऩू݁ՌΛอଘ ຖճ GitHub API Λͨͨ͘ͷ͸ίετͳͷͰجຊ͸ϩʔΧϧϑΝΠϧʹอଘͯ͠ɺߋ৽͍ͨ͠ ৔߹͸ઐ༻ͷϑϥάΛ౉͢Α͏ʹ͠·͢ɻϩʔΧϧϑΝΠϧͷΩϟογϡ͸ XDG Base Directory Specification *12Ͱࢦఆ͞Ε͍ͯΔ΋ͷΛ࢖͍·͢ɻHaskell ͷ৔߹ɺdirectory ύοέʔδʹ͋Δ g etXdgDirectory *13Λ࢖͍·͢ʢrio ͷ৔߹͸ RIO.Directory Ϟδϡʔϧʹ͋Γ·͢ʣ ɻ ϑϥάΛ෇͚Δ ·ͣ͸ϑϥάΛ௥Ճ͠·͢ɻEnv ʹ with_update ͱ͍͏ϑΟʔϧυΛ௥Ճͯ͠ɺίϚϯυϥΠϯ Ҿ਺ʹ --update ϑϥάΛ௥Ճ͠·͢ɻͦͯ͠ɺ--update ͷ஋Λ with_update ʹ౉͚ͩ͢Ͱ͢ɻ ߋ৽ϑϥάΛ௥Ճ͢Δ -- Env.hs type Env = Record ’[ "logger" >: MixLogger.LogFunc , "github" >: MixGitHub.Token , "with_update" >: Bool -- ௥Ճ ] -- Main.hs main :: IO () main = withGetOpt’ "[options] [input-file]" opts $ \r args usage -> do ... where opts = #help @= helpOpt <: #version @= versionOpt <: #verbose @= verboseOpt <: #update @= updateOpt -- ௥Ճ <: nil type Options = Record ’[ "help" >: Bool , "version" >: Bool , "verbose" >: Bool , "update" >: Bool -- ௥Ճ ] updateOpt :: OptDescr’ Bool updateOpt = optFlag [] ["update"] "Update stack templates list in local cache" runCmd :: Options -> Maybe FilePath -> IO () runCmd opts _path = do *12 https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html *13 https://hackage.haskell.org/package/directory-1.3.6.1/docs/System-Directory.html#v: getHomeDirectory 16
  24. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.5 ऩू݁ՌΛอଘ gToken

    <- liftIO $ fromString <$> getEnv "GH_TOKEN" let plugin = hsequence $ #logger <@=> MixLogger.buildPlugin logOpts <: #github <@=> MixGitHub.buildPlugin gToken <: #with_update <@=> pure (opts ^. #update) -- ௥Ճ <: nil Mix.run plugin cmd mix-plugin-xdgcache ͯ͞ɺΩϟογϡͷ෦෼Λ࡞Γ·͢ɻ࣮͸ mix-plugin-xdgcache ϓϥάΠϯύοέʔδΛར༻͢ Δͱ؆୯ʹ࣮૷Ͱ͖·͢ɻϓϥάΠϯΛ࢖͏ʹ͸·ͣ Env Λ֦ு͠·͠ΐ͏ɻ mix-plugin-xdgcache ϓϥάΠϯΛΦϯʹ͢Δ import qualified Mix.Plugin.XdgCache as MixCache -- Env.hs type Env = Record ’[ "logger" >: MixLogger.LogFunc , "github" >: MixGitHub.Token , "xdgcache" >: MixCache.Config -- ௥Ճ , "with_update" >: Bool ] -- Main.hs runCmd :: Options -> Maybe FilePath -> IO () runCmd opts _path = do gToken <- liftIO $ fromString <$> getEnv "GH_TOKEN" let plugin = hsequence $ #logger <@=> MixLogger.buildPlugin logOpts <: #github <@=> MixGitHub.buildPlugin gToken <: #xdgcache <@=> MixCache.buildPlugin "stack-tpls" -- ௥Ճ <: #with_update <@=> pure (opts ^. #update) <: nil Mix.run plugin cmd ͜ΕͰ XDG σΟϨΫτϦͷΩϟογϡ෦෼ʢMac ͷ৔߹͸ ~/.cacheʣʹ stack-tpls ͱ͍͏ σΟϨΫτϦ͕࡞ΒΕͯɺstack-tpls-demo ͷΩϟογϡϑΝΠϧஔ͖৔ͱͯ͠ར༻͠·͢ɻ ͯ͞ɺ͋ͱ͸ΩϟογϡΛ࢖͏Α͏ʹΞϓϦέʔγϣϯΛ֦ு͠·͢ɻ࣮͸͘͢͝؆୯Ͱ͢ɻ Ωϟογϡ͕͋Ε͹ΩϟογϡΛ࢖͍ɺͳ͚Ε͹࠷ޙʹΩϟογϡΛอଘ͢Δؔ਺ withCacheOn Λ ࢖͏͚ͩͰ͢ɻͦͯ͠ɺߋ৽ϑϥά͕ਅͷ৔߹͸ΩϟογϡΛফ͢ expireCache ؔ਺Λ࢖͑͹ྑ͍ ͷͰ͢ɻ 17
  25. ୈ 1 ষ Haskell Ͱ؆୯ʹ CLI πʔϧΛ࡞ΔͨΊʹ 1.6 ऴΘΓʹ ΩϟογϡΛ௥Ճ͢Δ

    -- Cmd.hs cmd :: RIO Env () cmd = do logDebug "run: fetch hsfiles" -- ҎԼͷߦΛ௥Ճʢϑϥάͷ༗ແͰΩϟογϡΛ࡟আʣ whenM (asks $ view #with_update) $ MixCache.expireCache "stack-teplates" -- ‘withCacheOn‘ "stack-teplates" ΛޙΖʹ͚ͭΔ͚ͩ tpls <- fetchTplList ‘withCacheOn‘ "stack-teplates" forM_ tpls $ \tpl -> logInfo (display $ toStackArg tpl) ͍͢͝؆୯Ͱ͢Ͷɻ 1.6 ऴΘΓʹ stack-tpls ͸ 2018 ೥ 10 ݄͝Ζʢ໿ 2 ೥લʣʹ࡞Γ࢝ΊͨπʔϧͰ͢ɻstack new ͢Δͱ͖ʹί ϐʔ&ϖʔετͯ͠࢖͑Δʢຖճ๨ΕΔʣͷͰɺݸਓతʹ͸ׂͱॏๅ͍ͯ͠ΔπʔϧͰ͢ɻmix.hs ͸ ͦΕ͔Β͞Βʹ 1 ೥ޙʹ࡞ͬͨύοέʔδͰ͢ɻͰ͢ͷͰɺmix.hs ͸ޙ͔Β stack-tpls ʹಋೖ͠· ͨ͠ɻ͜ͷύοέʔδ΋ɺ࡞ͬͯҎ߱ຖճ࢖͍ͬͯΔ͓ؾʹೖΓͰ͢ɻͱ͍͏Θ͚Ͱɺ͓ؾʹೖΓͷ ঺հճͰͨ͠ɻ 18
  26. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.1 ࢝Ίʹ

    TIPSTAR ͱ͸ TIPSTAR ͱ͸ 3 ਓͷԋऀ͕νʔϜΛ૊ΈɺڝྠͷϨʔεΛ༧૝͍ͯ͠Δ༷ࢠΛϥΠϒ഑৴͢Δϛ ΫγΟͷαʔϏεͰ͢ɻνʔϜͷ༧૝ʹࢹௌऀ΋৐͔ͬͬͯಉ͡൪߸ʹౌ͚Δ͜ͱ͕Ͱ͖ΔͷͰɺڝ ྠʹৄ͘͠ͳͯ͘΋ͦͷ··৐͔ͬΔ͚ͩͰ༡Ϳ͜ͱ͕Ͱ͖ͯ͠·͍·͢ɻ͞Βʹݱ͚ۚͩͰ͸ͳ ͘ɺແྉίΠϯ΋࢖͑ΔΑ͏ʹͳ͍ͬͯΔͷͰɺָ͠͞ͷ෯΋޿͕͍ͬͯ·͢ɻ ਤ 2.1: TIPSTAR TIPSTAR ͷ໨ࢦ͢ͱ͜Ζ ϛΫγΟʹͱͬͯެӦڝٕͱ͍͏ࣄۀྖҬ͸৽͍͠νϟϨϯδͰͨ͠ɻͳͥ͜ͷࣄۀྖҬΛબ୒͠ ͯαʔϏεΛ࡞ͬͨͷ͔໰ΘΕΔ͜ͱ͕ଟ͍ͷͰɺνʔϜͱͯ͠໨ࢦ͍ͯ͠Δ͜ͱʹ͍ͭͯ৮Ε͓ͯ ͖͍ͨͱࢥ͍·͢ɻ 19
  27. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.1 ࢝Ίʹ

    ϛΫγΟ͸ίϛϡχέʔγϣϯαʔϏεΛ૑ग़͠ɺՈ଒΍༑ͩͪͱϫΠϫΠָ͘͠༡ΜͰ΋Β͑ Δ͜ͱΛ໨ࢦ͍ͯ͠·͢ɻఏڙ͍ͯ͠ΔαʔϏεʹ͸ SNSʮmixiʯ ɺεϚʔτϑΥϯΞϓϦʮϞϯε λʔετϥΠΫʯ ɺՈ଒ΞϧόϜʮΈͯͶʯͳͲ΋ؚ·Ε͓ͯΓɺ͝ଘ͡ͷํ΋͍Βͬ͠ΌΔ͔΋͠ Ε·ͤΜɻ SNSɺεϚʔτϑΥϯΞϓϦɺը૾ŋಈըڞ༗αʔϏεͱ͍ͬͨΑ͏ʹɺαʔϏεͷछྨ͸ҟͳΓ ·͕͢ɺίϛϡχέʔγϣϯΛ௨ͯ͠ਓʑͷੜ׆Λ๛͔ʹ͍ͨ͠ͱ͍͏૝͍͸ڞ௨͍ͯ͠·͢ɻՃ͑ ͯɺεϙʔπ͸ίϛϡχέʔγϣϯπʔϧͱͯ͠ඇৗʹڧྗͰ͢ɻڝྠ͸ΦϦϯϐοΫͷछ໨ͱͯ͠ ΋ KEIRIN ͱͯ͠࠾༻͞Ε͓ͯΓɺ೔ຊൃ঵ͷͱͯ΋͓΋͠Ζ͍εϙʔπͰ͢ɻ ڝྠͷ࣋ͭັྗʹΤϯλʔςΠϯϝϯτͷཁૉΛ߹ΘͤΔ͜ͱͰɺڧྗͳίϛϡχέʔγϣϯπʔ ϧͱͯ͠ఏڙͰ͖ΔͷͰ͸ͳ͍͔ͱߟ͑ɺTIPSTAR Λ௨ͯ͡ڝྠͷύʔηϓγϣϯνΣϯδΛى͜ ͦ͏ͱ͍ͯ͠·͢ɻ 20
  28. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.2 ΞʔΩςΫνϟ

    2.2 ΞʔΩςΫνϟ TIPSTAR Λࢧ͑ΔΞʔΩςΫνϟ ͯ͞ɺͦΜͳ TIPSTAR Λࢧ͑ΔΞʔΩςΫνϟͰ͕͢ɺ͢΂ͯΛ఻͑Δͷ͸೉͍͠ͷͰॏཁͳϙ ΠϯτΛ঺հ͠·͢ɻ ਤ 2.2: TIPSTAR ͷΞʔΩςΫνϟ (ུ֓) ࠾༻͍ͯ͠ΔΫϥ΢υαʔϏεɾݴޠΛྻڍ͢ΔͱҎԼ͕ڍ͛ΒΕ·͢ɻ • GCP – GKE Λར༻͠ API ͳͲͷαʔϏεΛ؅ཧ – σʔλϕʔεʹ Cloud Spanner Λར༻ • AWS – ө૾഑৴෦෼Λఏڙ – Media Services Λར༻ͯ͠ HLS ͰϨʔεө૾ɾTIPSTAR ͷ Live ө૾Λ഑৴ • Golang – API ΍֤छπʔϧ͸ go Λར༻ͯ͠։ൃ – echo + CleanArchitecture • CI/CD ʹ CircleCI + Cloud Build ࠓճ͸͜ͷதͷ Cloud Spanner Λར༻͢ΔͨΊͷऔΓ૊ΈʹϑΥʔΧε͠·͢ɻ 21
  29. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.2 ΞʔΩςΫνϟ

    Cloud Spanner ͱ͸ʁ GCP ͕ఏڙ͢ΔσʔλϕʔεαʔϏεͷҰͭͰߴ͍Մ༻ੑͱແஈ֊ͷεέʔϥϏϦςΟΛఏڙ͠ ͍ͯ·͢ɻσʔλϕʔεͷεέʔϦϯά͸ඇৗʹ࿑ྗ͕ඞཁͱ͞ΕΔ࡞ۀͷҰͭͰ͕͢ϊʔυͷ௥ ՃɺࣗಈγϟʔσΟϯάΛػೳͱͯ͠ఏڙ͍ͯ͠ΔͷͰ͔ͦ͜Βղ์͞ΕΔͷ͸ඇৗʹ͋Γ͕͍ͨͰ ͢ɻͨͩ͜͠ΕΒΛ࣮ݱ͢ΔͨΊʹ୯७ͳϨΠςϯγ͸ Cloud SQL ʹ͸ྼΓ·͢͠ൺֱతίετ͕ ߴ͍αʔϏεͰ͢ɻ࣮ࡍʹར༻͢Δʹ͸૝ఆن໛΍ඞཁͱ͞ΕΔཁ͔݅Β൑அ͢Δඞཁ͕͋Γ·͢ɻ Cloud Spanner ͷಋೖ·Ͱͷي੻ TIPSTAR ͸ͦΕͳΓʹେ͖ͳن໛ʹͳΔ͜ͱΛ૝ఆ͍ͯ͠Δ͜ͱͱߴՄ༻ੑͷඞཁੑͱεέʔϦ ϯάͷ࡞ۀ͔Βղ์͞Ε͍ͨ͜ͱ͔Β Cloud Spanner Λબ୒͠·ͨ͠ɻ ࣮͸ TIPSTAR ͸࠷ॳ͔Β Cloud Spanner Λར༻͍ͯͨ͠Θ͚Ͱ͸͋Γ·ͤΜͰͨ͠ɻॳظͷݕ ূஈ֊ͷϑΣʔζͰ͸ҧ͏σʔλϕʔεΛར༻͓ͯ͠Γ Cloud Spanner ʹ׬શʹҠߦͨ͠ͷ͸։ൃ த൫ʙޙ൒Ͱͨ͠ɻ࠷ॳظͷߏ੒͸ Cloud SQL ͱ Datastore Λར༻͍ͯ͠·ͨ͠ɻ͜Ε͸αʔϏε ͷݕূʹ͸े෼ͳߏ੒Ͱ͢ɻݕূޙɺϦϦʔεޙͷཁ݅ʹରԠ͢Δʹ͸͍͔ͭ͘ͷ՝୊͔Βมߋ͕ඞ ཁͱͳΓ·ͨ͠ɻ • ن໛͕େ͖͘ͳͬͯདྷͨ࣌ʹεέʔϧ͢ΔରԠ͕ඞཁʹͳΔ • Cloud SQL ͸ϝϯςφϯε࣌ʹΛμ΢ϯλΠϜ͕ൃੜ੍͠ޚͰ͖Δൣғ͕ڱ͍*1 ಛʹμ΢ϯλΠϜʹ͍ͭͯ͸ඇৗʹ೰·͘͠ɺࢥ͍੾ͬͯҠߦʹ౿Έ੾Γ·ͨ͠ɻ ਤ 2.3: ࠷ॳظͷߏ੒ ར༻͍ͯ͠ΔσʔλϕʔεΛมߋ͢Δʹ͸͕͔͔࣌ؒΔ͜ͱͱɺ͢ͰʹϓϩμΫτͷϢʔβʔςε τ΍഑৴ςετΛ࣮ࢪ͍ͯ͠Δঢ়گͷͳ͔ɺฒߦͯ͠ߏ੒Λมߋ͢Δʹ͸ஈ֊తʹߦ͏ඞཁ͕͋Γ· ͨ͠ɻ *1 ࣥච౰࣌ͷঢ়گͰ͋Γݱࡏ͸վળ͍ͯ͠ΔՄೳੑ͕͋Γ·͢ 22
  30. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.2 ΞʔΩςΫνϟ

    ίʔυͷमਖ਼͸ CleanArchitecture Λ࠾༻͍ͯͨ͠ͷͰ usecase ͳͲʹ͸खΛೖΕͣσʔλϕʔε ΛมߋͰ͖Δ༧ଌ͍ͯ͠·͕ͨ͠ɺޙड़͢Δ ID ൃ൪ͷػߏ͸ੑೳݕূ΋ඞཁͳͨΊ͜ͷ෦෼͚ͩΛ ࢒ͯ͠ҠߦΛ։࢝͠·ͨ͠ɻ ਤ 2.4: Cloud Spanner ΁ͷҠߦա౉ظ ༧ଌͷ௨Γίʔυमਖ਼͸େن໛ͳߏ੒มߋΛߟ͑Δͱൺֱతগͳ͍ίετͰ࣮ݱͰ͖·ͨ͠ɻID ൃ൪ͷػߏ͸େ෦෼ͷҠߦͱ͸ผͰߦ͍ɺ͍͔ͭ͘ͷύλʔϯΛࢼ͠ແࣄඞཁͱ͢ΔύϑΥʔϚϯε Λຬͨ͢͜ͱ͕Ͱ͖ɺ͸Εͯ׬શʹ Cloud Spanner ΁ͷҠߦΛ׬ྃ͠·ͨ͠ɻ ਤ 2.5: ࠷ऴతͳߏ੒ Ҡߦ͢Δʹ͸ඇৗʹίετ͕͔͔Γ·͕ͨ͠࠷ऴతͳߏ੒ʹΑΓɺ๊͍͑ͯͨଟ͘ͷ՝୊Λղফ ͠ɺಉ࣌ʹଟ͘ͷϝϦοτΛखʹೖΕΔ͜ͱ͕Ͱ͖·ͨ͠ɻ·ͨɺར༻σʔλϕʔεͷมԽʹରԠͰ ͖ͨ͜ͱͰ CleanArchitecture ͷԸܙΛड͚Δ͜ͱ͕Ͱ͖ͨͱࢥ͍·͢ɻ 23
  31. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.3 Cloud

    Spanner 2.3 Cloud Spanner Cloud Spanner ͱͷ෇͖߹͍ํ ඇৗʹେ͖ͳίετΛ͔͚ͯҠߦͨ͠ Cloud Spanner Ͱ͕͢ߏ੒มߋͷͨΊʹ͸ಛ༗ͷ՝୊ʹର Ԡ͢Δඞཁ͕͋Γ·ͨ͠ɻ • ϗοτεϙοτΛආ͚ΔͨΊʹ UUID Λར༻ • ιʔτͰ͖Δ ULID ͷར༻ • γʔέϯγϟϧͳ൪߸Λൃ൪͢Δʹ͸ಠࣗͷ ID ൃ൪͕ඞཁ • Ұׅߋ৽্ݶ΁ͷ഑ྀ • ϦτϥΠʹର͢Δႈ౳ੑ΁ͷ஫ҙ ͜ΕΒͷରԠํ๏͸͢Ͱʹར༻͞Ε͍ͯΔํ΍ϕετϓϥΫςΟεͱͯ͠هࣄʹͳ͍ͬͯΔ΋ͷ΋ ଟ͍ͷͰͦͪΒʹৡΔͱͯ͠ߏ੒มߋ࣌ʹಛʹ஫ྗͯ͠ղܾ͢Δඞཁͷ͋ͬͨγʔέϯγϟϧͳ൪߸ Λൃ൪͢Δ IDSequencer ͱݺΜͰ͍ΔػߏΛղઆ͠·͢ɻ γϯϓϧͳ ID ൃ൪ γϯϓϧʹγʔέϯγϟϧͳ ID Λൃ൪͠Α͏ͱ͢Δͱ͜ͷΑ͏ʹͳΔͱࢥ͍·͢ɻ Ϧετ 2.1: simple-sequencer 1: package sequencer 2: 3: import ( 4: "context" 5: 6: "cloud.google.com/go/spanner" 7: ) 8: 9: type SimpleSequencer struct { 10: SequencerKey string 11: Client *spanner.Client 12: } 13: 14: func (s *SimpleSequencer) Next(ctx context.Context) (int64, error) { 15: var next int64 16: 17: _, err := s.Client.ReadWriteTransaction(ctx, func(ctx context.Context, 18: txn *spanner.ReadWriteTransaction) error { 19: var current int64 20: row, err := txn.ReadRow(ctx, "Sequences", 21: spanner.Key{s.SequencerKey}, []string{"Id"}) 22: 23: if err != nil { 24
  32. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.3 Cloud

    Spanner 24: return err 25: } 26: if err := row.Column(0, &current); err != nil { 27: return err 28: } 29: 30: next = current + 1 31: m := spanner.Update("Sequences", 32: []string{"Key", "Id"}, []interface{}{s.SequencerKey, next}) 33: 34: return txn.BufferWrite([]*spanner.Mutation{m}) 35: }) 36: 37: return next, err 38: } ݱࡏൃ൪ࡁΈͷ ID Λऔಘ͠Ճࢉͨ͠ ID Λར༻͢ΔγϯϓϧͳܗͰ͢ɻऔಘ͔Βߋ৽·ͰΛτϥ ϯβΫγϣϯͱ͍ͯ͠·͢ɻ͜ͷܗͰ͸ಉ࣌ʹ ID ͷൃ൪Λཁٻ͞Εͯ͠·͏ͱൃ൪ͷͨͼʹϩοΫ ͕ൃੜ͢ΔͷͰཁ݅࣍ୈͰ͸ύϑΥʔϚϯεͰ໰୊͕ൃੜ͢ΔՄೳੑ͕͋Γ·͢ɻ όονʹΑΔ ID ൃ൪ γϯϓϧͳ ID ൃ൪Ͱ͸ڝ߹͕ߴස౓Ͱൃੜ͢ΔͨΊɺͦͷճ਺Λগͳ͘͢ΔΞϓϩʔνͱͯ͠ൃ ൪ࡁΈͷ ID Λߋ৽͢Δࡍʹࣄલʹେ͖͘Ճࢉ͢Δ͜ͱͰɺ·ͱΊͯ ID Λόονతʹൃ൪͢Δͱ͍ ͏ํ๏͕͋Γ·͢ɻ Ϧετ 2.2: batch-sequencer 1: package sequencer 2: 3: import ( 4: "context" 5: "sync" 6: 7: "cloud.google.com/go/spanner" 8: ) 9: 10: const BatchSequencerBatchSize = 10 11: 12: type BatchSequencer struct { 13: SequencerKey string 14: Client *spanner.Client 15: mu sync.Mutex 16: current int64 17: max int64 18: } 19: 20: func (s *BatchSequencer) Next(ctx context.Context) (int64, error) { 25
  33. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.3 Cloud

    Spanner 21: s.mu.Lock() 22: defer s.mu.Unlock() 23: 24: if s.current != 0 && s.current < s.max { 25: s.current += 1 26: return s.current, nil 27: } 28: 29: _, err := s.Client.ReadWriteTransaction(ctx, func(ctx context.Context, 30: txn *spanner.ReadWriteTransaction) error { 31: var current int64 32: row, err := txn.ReadRow(ctx, "Sequences", 33: spanner.Key{s.SequencerKey}, []string{"Id"}) 34: 35: if err != nil { 36: return err 37: } 38: if err := row.Column(0, &current); err != nil { 39: return err 40: } 41: 42: s.current = current + 1 43: s.max = current + BatchSequencerBatchSize 44: 45: m := spanner.Update("Sequences", 46: []string{"Key", "Id"}, []interface{}{s.SequencerKey, s.max}) 47: 48: return txn.BufferWrite([]*spanner.Mutation{m}) 49: }) 50: 51: if err != nil { 52: return 0, err 53: } 54: 55: return s.current, nil 56: } 57: γϯϓϧͳ ID ൃ൪ͱҟͳΓ·ͱΊͯൃ൪͢Δ ID ͕ރׇ͢Δ·Ͱ͸ Cloud Spanner ΁ͷΞ Ϋηε͕ෆཁͱͳΔͷͰҰ݅͋ͨΓͷ ID ൃߦʹ͔͔ΔύϑΥʔϚϯεͷվળ͕ݟࠐΊ·͢ɻ BatchSequencerBatchSize Λେ͖͘͢Ε͹ΑΓଟ͘ͷ ID ΛҰ౓ʹൃߦͰ͖ΔͷͰ͞ΒʹύϑΥʔ Ϛϯε͕ཁٻ͞ΕΔ৔߹͸͜ͷ਺ࣈΛେ͖͘͢Δ͜ͱͰղܾͰ͖ΔՄೳੑ͕͋Γ·͢ɻ όονʹΑΔ ID ൃߦ͸ൃ൪ͨ͠൪߸͕ඈΜͰ͠·͏Ϊϟοϓ͕ൃੜ͢Δ͜ͱ͕͋Γ·͢ɻ͜Ε ͸Ұ౓ʹൃߦ͢ΔόοναΠζΛେ͖͘͢Ε͹͢Δ΄Ͳൃੜ͢Δ൪߸͕૿͑ΔՄೳੑ͕͋Γ·͢ɻ Ϊϟοϓͷൃੜ͸֫ಘࡁΈ ID ͕شൃͨ͠৔߹ʹى͜Γߏ੒࣍ୈͰ͸σϓϩΠͳͲͰ༰қʹൃੜ͠ ·͢ɻ TIPSTAR Ͱ͸༗ݶͷ਺஋͕ཁٻ͞Ε͍ͯΔͨΊΪϟοϓͷൃੜ͸ͳΔ΂͘཈͍͑ͨͰ͢ɻ ΪϟοϓͷൃੜΛݮΒ͢ํ๏ͱͯ͠͸ 26
  34. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.3 Cloud

    Spanner • ൃ൪͢ΔόοναΠζΛখ͘͢͞Δ • ID ൃ൪ͷػߏʹؔ܎ͷͳ͍σϓϩΠ͕Өڹ͠ͳ͍ߏ੒ʹมߋ͢Δ ͳͲ͕ߟ͑ΒΕ·͕͢ TIPSTAR Ͱ͸࣍ʹ঺հ͢Δํ๏Ͱ ID ͷൃ൪Λ࣮ݱ͍ͯ͠·͢ɻ γϟʔυΛར༻ͨ͠ ID ൃ൪ ͜͜·Ͱॻ͍͖ͯͨ͜ͱ͸࣮͸ GCP ͷυΩϡϝϯτʹ΋هࡌ͞Ε͍ͯ·͢ͷͰΑΓৄ͘͠஌Γͨ ͍ํ͸ͪ͜ΒͷυΩϡϝϯτ*2Λࢀߟʹ͢Δͱྑ͍ͱࢥ͍·͢ɻ όονʹΑΔ ID ൃ൪ʹՃ͑ɺൃ൪ࡁΈ ID Λ؅ཧ͢ΔΩʔΛෳ਺࣋ͨͤͯ෼ࢄͤ͞Δ͜ͱͰڝ߹ ͷൃੜ཰ΛݮΒ͠·ͨ͠ɻ Ϧετ 2.3: shard-sequencer 1: package sequencer 2: 3: import ( 4: "context" 5: "fmt" 6: "math/rand" 7: "sync" 8: 9: "cloud.google.com/go/spanner" 10: ) 11: 12: const ShardSequencerShardSize = 10 13: const ShardSequencerBatchSize = 1 14: 15: type ShardSequencer struct { 16: SequencerKey string 17: Client *spanner.Client 18: mu sync.Mutex 19: current int64 20: max int64 21: } 22: 23: func (s *ShardSequencer) Next(ctx context.Context) (int64, error) { 24: s.mu.Lock() 25: defer s.mu.Unlock() 26: 27: if s.current != 0 && s.current < s.max { 28: s.current += 1 29: return s.current, nil 30: } 31: 32: shardNum := int64(rand.Intn(ShardSequencerShardSize) + 1) 33: _, err := s.Client.ReadWriteTransaction(ctx, func(ctx context.Context, 34: txn *spanner.ReadWriteTransaction) error { *2 https://cloud.google.com/solutions/sequence-generation-in-cloud-spanner?hl=ja 27
  35. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.3 Cloud

    Spanner 35: var current int64 36: shardKey := fmt.Sprintf("%s_%d", s.SequencerKey, shardNum) 37: row, err := txn.ReadRow(ctx, "Sequences", 38: spanner.Key{shardKey}, []string{"Id"}) 39: 40: if err != nil { 41: return err 42: } 43: if err := row.Column(0, &current); err != nil { 44: return err 45: } 46: 47: if current == 0 { 48: s.max = shardNum * ShardSequencerBatchSize 49: } else { 50: s.max = current + 51: (ShardSequencerShardSize * ShardSequencerBatchSize) 52: } 53: s.current = s.max - ShardSequencerBatchSize + 1 54: 55: m := spanner.Update("Sequences", 56: []string{"Key", "Id"}, []interface{}{shardKey, s.max}) 57: 58: return txn.BufferWrite([]*spanner.Mutation{m}) 59: }) 60: 61: if err != nil { 62: return 0, err 63: } 64: 65: return s.current, nil 66: } ඞཁͳγϟʔυ਺͚ͩ઀ඌޠΛ௥Ճ͢Δ͜ͱͰ෼ࢄΛ࣮ݱ͍ͯ͠·͢ɻ͜͜Ͱ͸όοναΠζΛ 1 ͱ͍ͯ͠·͕ͪ͢͜ΒΛௐ੔͢Δ͜ͱͰύϑΥʔϚϯεΛՔ͙͜ͱ͕Ͱ͖·͢ɻ͔͠͠όοναΠζ ͸؆୯ʹ૿΍ͤ·͕͢γϟʔυαΠζ͸؆୯ʹ૿΍ͤͳ͍ͷͰඞཁͳཁ݅Λ೺Ѳܾͯ͠ఆ͢Δඞཁ͕ ͋Γ·͢ɻ 28
  36. ୈ 2 ষ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํ 2.4 ऴΘΓʹ

    2.4 ऴΘΓʹ ࠓճ͸ TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ར༻͢ΔͨΊͷऔΓ૊ΈΛ঺հ͠·ͨ͠ɻ ଞʹ΋͜͜Ͱ͸঺հ͖͠Εͳ͔ͬͨΞʔΩςΫνϟʹؔ͢Δࢼߦࡨޡ΍ϥΠϒಈըΛ҆ఆͯ͠഑৴ ͢ΔͨΊʹߦ͖ͬͯͨ͞·͟·ͳٕज़తͳνϟϨϯδ͕͋Γ·͢ɻ TIPSTAR ͸ࠓޙେ͖͘ͳΔՄೳੑΛ࣋ͬͨαʔϏεͩͱࢥ͍·͢ɻαʔϏε͕εέʔϧ͍ͯ͘͠ ্Ͱ Cloud Spanner ΁ͷҠߦʹ΋ڍ͛ͨ௨Γܧଓͯ͠ΞʔΩςΫνϟͷมߋ͕ඞཁʹͳͬͯ͘Δͱ ࢥ͍ͬͯ·͢ɻ ՔಇதͷαʔϏεʹର͢ΔΞʔΩςΫνϟͷมߋͱ͍͏ͷ͸ಛʹϦεΫ͕͋Γίετ΋͔͔Γ· ͕͢ɺܧଓͯ͠औΓ૊ΜͰ͍͖ɺνϟϨϯδ͠ଓ͚ɺࠓޙ΋ϛΫγΟͷܝ͛ΔϢʔβʔαϓϥΠζ ϑΝʔετΛ೦಄ʹΑΓΑ͍αʔϏεΛఏڙ͍͖ͯ͠·͢ɻ 29
  37. None
  38. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠ ΨϠॱҐ લষɺ઒ຢٛরͷ

    TIPSTAR ͷΞʔΩςΫνϟͱ Cloud Spanner ͱͷ෇͖߹͍ํͰɺTIPSTAR ͷ঺հ͕͋Γ·ͨ͠ɻຊষͰ͸ TIPSTAR ͷಛ௃ͷ 1 ͭͰ͋ΔνʔϜͷ੝Γ্͕Γ౓Λࣔ͢ϫΠΨ ϠॱҐͷΞʔΩςΫνϟΛ঺հ͠·͢ɻࢲ͸ීஈ TIPSTAR ͷ API ։ൃΛ୲౰͓ͯ͠ΓɺϫΠΨϠ ॱҐ΋։ൃ୲౰ۀ຿ͷ 1 ͭͰͨ͠ɻࠓճϫΠΨϠॱҐͷ঺հΛ͍ͨ͠ͱࢥͬͨཧ༝͸ɺաڈʹ 2 ճ mixi tech note*1*2Ͱ௼Γʷػցֶशͱ͍ͬͨςʔϚͰ Google ͷػցֶशϓϩμΫτͷ঺հΛͨ͠ ͱ͓Γɺ͍͔ͭ͘ Google ͷػցֶशϓϩμΫτʹ৮Ε͖ͯ·͕ͨ͠ɺϦϦʔε༧ఆͷϓϩμΫτʹ ಋೖͨ͠ࣄྫΛ঺հͨ͜͠ͱ͕͋Γ·ͤΜͰͨ͠ɻ࣮ۀ຿ͰऔΓೖΕ͍ͯΔࣄྫΛ঺հ͍ͨ͠ͱࢥ ͍ɺࠓճϫΠΨϠॱҐͷ঺հΛ͢Δ͜ͱʹ͠·ͨ͠ɻ 3.1 ϫΠΨϠॱҐͱ͸ TIPSTAR ʹ͸֤ϧʔϜͷ੝Γ্͕Γ౓ͷ਺஋Λද͢ϫΠΨϠॱҐͱ͍͏΋ͷ͕͍͟͝·͢ɻ TIPSTAR ͸ A νʔϜ͔Β C νʔϜͷ߹ܭ 3 νʔϜ͋Γɺ੝Γ্͕Γ౓ʹ߹Θͤͯ 1~3 ҐͷॱҐ͕ ෇͖·͢ɻ1 ҐͷνʔϜ͸ΞϓϦͷϗʔϜը໘ͰҰ൪্ʹҠಈ͢ΔͨΊ஫໨ΛूΊ΍͘͢ͳΓ·͢ɻ ϫΠΨϠॱҐ্͕͕Δ͜ͱʹΑΓɺࢹௌ਺Λ্͛ͨΓɺ৐͔ͬΓϕοτΛͯ͘͠ΕΔਓ͕ଟ͘ͳΔ͜ ͱ͕ظ଴Ͱ͖ΔͨΊ֤νʔϜʹͱͬͯॏཁͳ਺஋ͷ 1 ͭͱͳ͍ͬͯ·͢ɻ *1 mixi tech note #02ɿ https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-02 *2 mixi tech note #03ɿ https://speakerdeck.com/mixi_engineers/mixi-tech-note-number-03 31
  39. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.2 ࡞੒͢Δ͜ͱʹͳͬͨഎܠ

    ਤ 3.1: ϫΠΨϠॱҐ͕̍ҐʹͳΔͱϗʔϜը໘্෦ʹදࣔ͞ΕΔ 3.2 ࡞੒͢Δ͜ͱʹͳͬͨഎܠ TIPSTAR ͸ϓϩδΣΫτൃ଍͔ΒϦϦʔε·Ͱ 1 ೥൒΄Ͳظ͕͍ؒ͟͝·͕ͨ͠ɺ࢝Ί͔ΒϫΠ ΨϠॱҐͷߏ૝͕͋ͬͨΘ͚Ͱ͸͋Γ·ͤΜɻචऀ͕ϓϩδΣΫτʹࢀըͨ͠ͷ͸ 2019 ೥ 10 ݄͜ ΖͰ͕ͨ͠ɺ౰࣌͸·ͩϫΠΨϠॱҐͷػೳ։ൃͷҊ͕ͳ͘ɺҊ͕ग़ͨͷ͸ཌ೥ͷ 1 ݄຤ͷࡱӨςε τޙͰͨ͠ɻԿ౓͔ࡱӨςετΛ܁Γฦ͍ͯ͠Δ͏ͪʹΤϯλʔςΠϝϯτͷཁૉΛڧ͍ͨ͘͠ɺग़ ԋऀͷϞνϕʔγϣϯΛ͍͋͛ͨͱ͍ͬͨཧ༝͔ΒνʔϜͷ੝Γ্͕Γ౓Λද͢ϫΠΨϠॱҐΛઃ͚ ͍ͨͱڧ͍ཁ๬͕͋Γ։ൃ͢Δ͜ͱʹͳΓ·ͨ͠ɻ·ͨɺϫΠΨϠॱҐʹԠͯ͡ϗʔϜը໘ͷදࣔॱ ͕มΘΔ͜ͱΛ঺հ͠·͕ͨ͠ɺͪ͜Β͸αʔϏεϦϦʔεޙʹೖͬͨػೳͰ͢ɻϦϦʔε౰ॳνʔ Ϝͷฒͼॱ͸ݻఆͩͬͨͷͰ͕͢ɺը໘্෦ʹදࣔ͞Ε͍ͯΔνʔϜʹࢹௌ਺͕ภΔ܏޲͕͋ͬͨͷ ͰϫΠΨϠॱҐʹԠͯ͡දࣔॱΛม͑ͯΈΔ͜ͱʹͳΓ·ͨ͠ɻ ϫΠΨϠॱҐ͸ 2 νʔϜͰ࡞੒ TIPSTAR ͷϓϩδΣΫτͰ͸ɺػցֶशΛ࢖͍ʮελʔτɺ࢒Γ˓˓पɺΰʔϧʯͱ͍ͬͨς ϩοϓ΍ BGM ΛࣗಈͰϨʔεө૾ʹૠೖ͢Δ͘͠ΈΛ࡞੒͍ͯ͠ΔνʔϜ͕͋Γ·͢ɻϫΠΨϠ ॱҐͰ࢖༻͢ΔείΞͷࢉग़͸ػցֶशΛख͕͚͍ͯΔνʔϜ͕࡞੒͠ɺචऀͷνʔϜͰ͸ϫΠΨϠ είΞΛ Cloud Pub/Sub ܦ༝Ͱड͚औΓɺΫϥΠΞϯτʹϫΠΨϠॱҐΛఏڙ͢Δ෦෼Λ୲౰͠· ͨ͠ɻ྆ํͷΞʔΩςΫνϟΛ؆୯ʹ঺հ͍ͨ͠ͱࢥ͍·͢ɻ 32
  40. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ

    ਤ 3.2: ػցֶशνʔϜ͕։ൃͨ͠ςϩοϓɻ࢒ΓʓʓपͳͲͷςϩοϓ͕ࣗಈͰදࣔ͞ΕΔ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ ϫΠΨϠείΞͷࢉग़ʹ͸ Cloud Pub/Subɺ Cloud Functionsɺ FFmpegɺ Cloud Schedulerɺ Cloud Vision APIɺCloud Natural Language APIɺSpeech-to-Text APIɺCloud SQL ͱ਺ଟ͘ͷ GCP ϓϩμΫτΛ࢖༻͍ͯ͠·͢ɻ1 ෼ຖʹ֤νʔϜͷ HLS ಈը͔Β੩ࢭըͱԻ੠ϑΝΠϧΛൈ͖ग़͠ ػցֶशͰϥϕϧ΍είΞΛݕग़͠ Cloud SQL ΁อଘ͠·͢ɻͦͯ͠ఆظతʹσʔλϕʔεʹอଘ ͨ͠είΞͷฏۉΛ TIPSTAR API ͷ GCP ϓϩδΣΫτͷ Cloud Pub/Sub ʹ Publish ͠·͢ɻ 33
  41. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ

    ਤ 3.3: ϫΠΨϠείΞͷࢉग़ 1 ෼ຖʹ֤νʔϜͷ HLS ಈը͔Β੩ࢭըͱԻ੠ϑΝΠϧൈ͖ग़͠ ֤νʔϜͷνʔϜ ID ͱ HLS URL ͸ݻఆͳͷͰ Scheduler ͷ message body ʹηοτ͠ɺఆظత ʹ Cloud Pub/Sub ͷ Topic ʹ Publish ͢ΔΑ͏εέδϡʔϦϯά͠·͢ // gcloudίϚϯυΛ࢖༻͠Cloud SchedulerͷjobΛηοτ gcloud scheduler jobs create pubsub Room1-1min --schedule "*/1 * * * *" --topic "waigaya-collector-schedule" --message-body "{\"hls\":\"https://team1.m3u8\",\ʡteam_id\":\"1\"}" --description "Room1:every 1minʡ HLS ͔Β੩ࢭըͱԻ੠ϑΝΠϧͷநग़͠είΞΛग़͢ τϐοΫʹϝοηʔδ͕ Publish ͞ΕΔͱɺͦΕΛτϦΨʹ͍ͯ͠Δ Cloud Functions ͕ىಈ͠· ͢ɻClooud Functions ಺Ͱ͸ ffmpeg ίϚϯυΛ࢖͍੩ࢭըͱԻ੠ϑΝΠϧͷநग़͠ Google Cloud Storage ʹอଘ͠·͢ɻ 34
  42. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ

    // Cloud Functions ͰffmpegίϚϯυΛ࣮ߦ࣮͠ߦ݁ՌΛGoogle Cloud Storageʹอଘ if err := exec.Command( "ffmpeg", "-i", h.URL, "-map", "0:0", "-r", "0.1", "-f", "image2", "-t", "59", fmt.Sprintf("%vimage_%v.jpg", h.tmpDir, "%05d"), "-map", "0:1", "-acodec", "pcm_s16le", "-ac", "1", "-ar", "16k", "-t", strconv.Itoa(periodTime), h.tmpDir+"audio.wav", ).Run(); err != nil { return err } if err := h.uploadGCS(); err != nil { return err } औΓग़ͨ͠੩ࢭը͔ΒɺGoogle Cloud Vision API Λ࢖͍ϥϕϧͷݕग़Λߦ͍·͢ɻ // VisionAPIΛ࢖͍إͷද৘Λݕग़ image, err := vision.NewImageFromReader(out) if err != nil { return score, err } // ը૾ϑΝΠϧ಺ͷإΛݕग़ faces, err := s.visionApi.DetectFaces(ctx, image, nil, 10) if err != nil { return score, err } for _, face := range faces { // faceΦϒδΣΫτ͔Β͸ౖ͍ͬͯΔ͔ɺָ͠ΜͰ͍Δ͔ɺڻ͍͍ͯΔ͔ͳͲͷද৘ͷείΞΛऔಘՄೳ } औΓग़ͨ͠Ի੠ϑΝΠϧ͸ Speech-to-Text API Λ࢖͍ςΩετϑΝΠϧΛऔಘ͠·͢ɻͦͷςΩ ετϑΝΠϧΛ Cloud Natural Language API Λ࢖༻͠ײ৘෼ੳΛߦ͍·͢ɻ 35
  43. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ

    // Speech-to-Text APIΛ࢖͍ςΩετϑΝΠϧΛऔಘ speechClient, err := speech.NewClient(context.Background()) if err != nil { return nil, err } data, err := ioutil.ReadFile(h.tmpDir + "audio.wav") if err != nil { return nil, err } // Ի੠ϑΝΠϧͷԻ੠Λݕग़ resp, err := speechClient.Recognize(context.Background(), &speechpb.RecognizeRequest{ Config: &speechpb.RecognitionConfig{ Encoding: speechpb.RecognitionConfig_LINEAR16, SampleRateHertz: 16000, LanguageCode: "ja-JP", }, Audio: &speechpb.RecognitionAudio{ AudioSource: &speechpb.RecognitionAudio_Content{Content: data}, }, }) for _, result := range resp.Results { for _, alt := range result.Alternatives { //alt.TranscriptͰςΩετऔಘ } } // ςΩετΛCloud Natural Language APIΛ࢖ͬͯײ৘Λ෼ੳ req := languagepb.AnalyzeSentimentRequest{ Document: &languagepb.Document{ Source: &languagepb.Document_Content{ Content: text, }, Type: languagepb.Document_PLAIN_TEXT, }, EncodingType: languagepb.EncodingType_UTF8, } sentiment, err := s.AudioApi.AnalyzeSentiment(context.Background(), &req) ࠷ޙʹϥϕϧͱײ৘෼ੳͷ݁Ռ͔ΒϫΠΨϠείΞΛܾఆ͠ɺCloud SQL ʹϫΠΨϠείΞΛอ ଘ͠·͢ɻ 36
  44. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ

    Google Cloud Vision API ͱ͸ Google ͕ఏڙ͍ͯ͠Δը૾ೝࣝ API*3Ͱɺը૾ΛΞοϓϩʔυ͢Δ͚ͩͰ෺ମͷϥϕϧݕग़ɺײ ৘ͷೝ஌ɺςΩετ෼ੳ͕Ͱ͖·͢ɻֶशࡁϞσϧΛ࢖༻͢ΔͷͰֶशΛ͢Δඞཁ͸ͳ͘ɺREST API ΍ RPC API ͕ఏڙ͞Ε͍ͯΔ΄͔ɺC#ɺGoɺJavaɺNode.jsɺPHPɺPythonɺRuby Λα ϙʔτͨ͠ΫϥΠΞϯτϥΠϒϥϦ΋ఏڙ͞Ε͍ͯ·͢ɻࠓճ͸ Go ͷΫϥΠΞϯτϥΠϒϥϦΛ࢖ ༻͠·ͨ͠ɻ·ͨ঺հϖʔδͰ͸ Vision API ΛࢼͤΔσϞπʔϧ͕ఏڙ͞Ε͍ͯ·͢ɻڵຯ͕͋Δ ํ͸ͥͻ೚ҙͷը૾Ͱ͓ࢼ͍ͩ͘͠͞ɻ·ͨࠓճ͸ׂѪ͠·͕͢ɺಠࣗͷը૾ೝࣝΛ࡞Γ͍ͨਓͷͨ Ίʹ AutoML Vsion ͱݺ͹ΕΔϓϩμΫτ΋͋Γ·͢ɻͪ͜Β͸ը૾ΛूΊͯϥϕϦϯά͢Δ͚ͩ ͰΧελϜϞσϧΛ࡞੒Ͱ͖ɺൺֱత༰қʹΦϦδφϧͷը૾ೝࣝ API Λ࡞Ε·͢ɻڵຯ͕͋Δํ ͸ͪ͜Β΋ͥͻ৮ͬͯΈ͍ͯͩ͘͞ɻ ਤ 3.4: Vision API ͷ঺հϖʔδͰσϞ͕Ͱ͖Δ Cloud Natural Language API ͱ͸ Cloud Natural Language API*4͸ςΩετΛ෼ੳ͢Δ API Ͱ͢ɻ೚ҙͷςΩετΛ API ʹΞο ϓϩʔυ͢Δͱਓɺ৔ॴɺιʔγϟϧϝσΟΞʹදΕΔײ৘ͳͲΛ෼ੳͰ͖ӳޠ΍೔ຊޠؚΊଟ͘ͷ ݴޠΛαϙʔτ͍ͯ͠·͢*5ɻͪ͜Βͷ API ΋ Vision API ಉ༷ʹ REST API ΍ΫϥΠΞϯτϥΠ *3 Vision APIɿ https://cloud.google.com/vision *4 Natural Language APIɿ https://cloud.google.com/natural-language *5 Language Supportɿ https://cloud.google.com/natural-language/docs/languages 37
  45. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ

    ϒϥϦ͕ఏڙ͞Ε͍ͯ·͢ɻNatural Language API ΋σϞπʔϧ͕ఏڙ͞Ε͍ͯΔͷͰɺͥͻ͓ࢼ ͍ͩ͘͠͞ɻ ਤ 3.5: Natural Language API ͷ঺հϖʔδͰσϞ͕Ͱ͖Δ AutoML Natural Language Λ࢖༻͢Ε͹ΦϦδφϧͷΧελϜϞσϧ΋࡞੒ՄೳͰ͢ɻ Speech-to-Text ͱ͸ Speech-to-Text*6͸ Google ͕ఏڙ͢Δ API ͰԻ੠ϑΝΠϧΛΞοϓϩʔυ͢Δ͚ͩͰจࣈى͜ ͠Λͯ͘͠Ε·͢ɻGoogle ࠷৽ͷσΟʔϓϥʔχϯάͷχϡʔϥϧωοτϫʔΫΞϧΰϦζϜΛར ༻͓ͯ͠Γ 125 Ҏ্ͷݴޠ΍ํݴͷԻ੠ೝࣝʹରԠ͍ͯ͠·͢ɻͪ͜Β΋ REST API ΍ΫϥΠΞϯ τϥΠϒϥϦɺϒϥ΢β্ͰࢼͤΔσϞπʔϧ͕ఏڙ͞Ε͍ͯΔͷͰͥͻ͓ࢼ͍ͩ͘͠͞ɻ *6 Speech-to-Textɿ https://cloud.google.com/speech-to-text 38
  46. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ

    ਤ 3.6: Speech-to-Text Google Cloud Vision API ΍ Cloud Natural Language API Λ࠾༻ͨ͠ཧ༝ ϫΠΨϠείΞͷ࣮૷Λͨ͠അ෵ढ़໻ (@raibo) ʹ࠾༻ͨ͠ཧ༝ΛਘͶͨͱ͜ΖҎԼͷճ౴͕͟͝ ͍·ͨ͠ɻ • ར༻ํ๏͕؆୯Ͱ͋Γɺ͙͢ʹར༻ՄೳͰ͋ͬͨ͜ͱ – Cloud Speech-to-Text Λ GCP ͕ϑϧϚωʔδυͰఏڙ͞Ε͍ͯΔ͓͔͛Ͱɺػցֶश είΞϦϯά෦෼͸ 1,2 Ӧۀ೔ఔ౓Ͱ׬੒ͨ͠ – ࠓճͷཁ݅Ͱ͸ɺϞσϧ͸Ұൠతͳ΋ͷͰ΋े෼ద༻Ͱ͖Δͱ൑அͨͨ͠Ίɺཁ݅ͱඇৗ ʹϚον͍ͯͨ͠ • Cloud Speech-to-Text ͷਫ਼౓͕ଞαʔϏεΑΓ΋ߴ͍ͱ͍͏఺ – ෳ਺ਓͷձ࿩΋͔ͬ͠Γͱ෼཭͞ΕΔͨΊɺείΞϦϯά͕ඇৗʹ͠΍͍͢ • ը૾ਪ࿦ͷਫ਼౓͕ඇৗʹߴ͘ɺମײͰײ৘ͷ Classification ͸΄ͱΜͲਓؒͷײ֮ͱͣΕ͍ͯ ͳ͔ͬͨ఺ – ϫΠΨϠͷείΞͱͯ͠΋ద౰ͩͱ൑அͰ͖ͨ ϫΠΨϠείΞΛ API ϓϩδΣΫτʹ Publish Cloud SQL ʹอଘ͍ͯͨ͠ϫΠΨϠείΞͷฏۉ఺Λఆظʹ TIPSTAR API ϓϩδΣΫτͷ Cloud Pub/Sub ͷτϐοΫʹ Publish ͠·͢ɻ 39
  47. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.3 ϫΠΨϠࢉग़ͷΞʔΩςΫνϟ

    ਤ 3.7: ϫΠΨϠείΞΛ TIPSTAR API ͷ GCP ϓϩδΣΫτʹ Publish // 30෼ʹҰ౓ϫΠΨϠείΞΛPublish͢ΔΑ͏ʹઃఆ gcloud scheduler jobs create pubsub WaigayaNotify --schedule "*/30 * * * *" --topic "waigaya-notify-schedule" --message-body "{\"room_numbers\":[1,2,3,4]}" --description "every 30min/notify" ্هͷ Cloud Pub/Sub Topic ʹϝοηʔδ͕ެ։͞ΕΔͱ Cloud Functions ͕ىಈ͠σʔλϕʔ ε͔ΒฏۉείΞΛࢉग़͠ TIPSTAR API ͷ Cloud Pub/Sub Topic ʹ Publish ͠·͢ // σʔλϕʔε͔Β஋Λऔಘ scoreList, err := getAccumulatedWaigayaScore(payload.RoomNumbers) if err != nil { return err } // औಘͨ͠஋ΛPublish client, err := pubsub.NewClient(ctx, destProject) if err != nil { return err } jsn, err := json.Marshal(scoreList) 40
  48. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.4 ϫΠΨϠॱҐʹͳΔ·Ͱ

    if err != nil { return err } _, err = client.Topic(destTopic).Publish(ctx, &pubsub.Message{Data: []byte(jsn)}).Get(ctx) if err != nil { return err } fmt.Printf("Waigaya Notify done.\n") 3.4 ϫΠΨϠॱҐʹͳΔ·Ͱ ্هͷϫΠΨϠείΞ͕ Publish ͞ΕΔͱɺτϦΨʹ͍ͯ͠Δ Cloud Functions ͕ىಈ͠ϫΠΨ ϠείΞΛ Cloud Spanner ʹอଘ͠·͢ɻͦͯ͠ TIPSTAR API Ͱ͸ Cloud Spanner ͔Β֤ϧʔ ϜͷϫΠΨϠείΞΛऔಘ͠ΫϥΠΞϯτʹϫΠΨϠॱҐΛฦ͠·͢ɻ ਤ 3.8: ϫΠΨϠείΞΛ Spanner ʹอଘ Cloud Pub/Sub ͱ Cloud Functions Λબ୒ͨ͠ཧ༝ Cloud Pub/Sub ͷτϐοΫΛ࢖͏͜ͱʹΑͬͯɺࠓޙػցֶशͷ͘͠ΈΛେ͖͘มߋ͢Δ͜ͱʹ ͳͬͨͱͯ͠΋֎ଆ͚ͩมߋ͢Ε͹ൺֱత༰қʹ੾Γସ͕͑Ͱ͖Δͱߟ͑ͨͨΊͰ͢ɻ 41
  49. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.4 ϫΠΨϠॱҐʹͳΔ·Ͱ

    Cloud Functions Λ࢖͏ʹ͋ͨΓؾΛ෇͚ͨ͜ͱ Cloud Functions σϓϩΠ࣌ʹ࠷େϦτϥΠճ਺Λࢦఆ͠ͳ͍৔߹͸λΠϜΞ΢τΛઃ͚ͯແݶϦ τϥΠ͕ى͖ͳ͍Α͏ʹ͠·ͨ͠ if time.Now().After(meta.Timestamp.Add(expiration)) { Infof("event timeout: halting retries for expired event ’%q’", meta.EventID) return nil } ҟͳΔ։ൃ؀ڥʹίϚϯυ 1 ͭͰ Cloud Functions ΛσϓϩΠͰ͖ΔΑ͏ʹ؀ڥม਺ͱؔ਺໊Λ ޻෉͠·ͨ͠ɻ // σϓϩΠίϚϯυ gcloud functions deploy $(FUNCTION_NAME)$(STAGE) --project $(GCP_PROJECT) --region $(REGION) --runtime $(RUNTIME) --trigger-topic $(TRIGGER_TOPIC) --retry --set-env-vars DB_SPANNER_URI=$(DB_SPANNER_URI) // ֤؀ڥͷؔ਺Λ༻ҙ͠ϝΠϯͷؔ਺ΛݺͿΑ͏ʹ͓ͯ͘͠ func UpdateWaigayaScorePrd(ctx context.Context, m PubSubMessage) error { return UpdateWaigayaScore(ctx, m) } func UpdateWaigayaScoreStg(ctx context.Context, m PubSubMessage) error { return UpdateWaigayaScore(ctx, m) } func UpdateWaigayaScoreDev(ctx context.Context, m PubSubMessage) error { return UpdateWaigayaScore(ctx, m) } func UpdateWaigayaScore(ctx context.Context, m PubSubMessage) error { // ͜͜ʹϝΠϯͷॲཧΛॻ͘ } 42
  50. ୈ 3 ষ ػցֶशͱ GCP Ͱ࡞Δ TIPSTAR ϫΠΨϠॱҐ 3.5 ػցֶशͷಋೖʹ͍ͭͯ

    3.5 ػցֶशͷಋೖʹ͍ͭͯ ػցֶश͸ۙ೥਎ۙʹͳͬͨ΋ͷͱ͸͍͑ɺ࣮ࡍͷϓϩμΫτʹಋೖ͢Δʹ͸ɺͦΕͳΓʹϋʔυ ϧ͕͋Δͱײ͡Δํ΋ଟ͍ͱࢥ͍·͢ɻ͔͠͠ࠓճͷΑ͏ʹɺGoogle ͕ؾܰʹػցֶशͷԸܙΛऔ ΓೖΕΒΕΔΑ͏ʹެ։ͨ͠ Google Cloud Vision API ΍ Google Cloud Natural Language API Λ࢖༻͢Ε͹ɺࣗΒػցֶशϞσϧΛ࡞੒͠ͳ͘ͱ΋ػցֶशΛ࣮ࡍͷϓϩμΫτʹಋೖ͢Δ͜ͱ͸ ՄೳͰ͢ɻmixi tech note#2 Ͱ΋঺հ͠·͕ͨ͠ɺػցֶशʹ͸͍͔ͭ͘Ϩϕϧ͕͋Γɺಋೖ͕೉ ͍͠΋ͷ΄Ͳࣗ༝౓͕ߴ͘ɺಋೖ͕༰қͳ΋ͷ΄Ͳࣗ༝౓͕௿͍܏޲͕͋Γ·͢ɻ͍͖ͳΓ೉͍͠ྖ Ҭͷ΋ͷΛೖΕΔΑΓ͸ɺ·ͣϓϩμΫτʹಋೖ༷͠ࢠΛݟͯඞཁ͕͋Δͱײͨ͡ΒঃʑʹϨϕϧͷ ߴ͍΋ͷʹ͍͚ͯ͠͹Α͍ͱචऀ͸ߟ͑·͢ɻϓϩμΫτϦϦʔε࣌͸ߴ౓ͳػցֶशϞσϧΛ࡞੒ ͢Δ࣮૷࣌ؒ΋ɺϞσϧ࡞੒ʹඞཁͳσʔλ΋े෼ʹͦΖ͍ͬͯͳ͍͜ͱ΋ଟ͍ͱࢥ͍·͢͠ɺߴ౓ ͳ΋ͷΛऔΓೖΕͯඞཁ͕ͳ͔ͬͨͱ͍͏൑அΛ͢Δ͜ͱʹͳΔ͔΋͠Εͳ͍͔ΒͰ͢ɻ·ͨಋೖʹ ͋ͨͬͯ͸ࠓճͷΑ͏ʹɺείΞͷड͚औΓʹ Cloud Pub/Sub Λར༻͍ͯ͠Ε͹ɺࠓޙߴ౓ͳػց ֶशʹ੾Γସ͑Δ࣌΋༰қʹͰ͖Δ͜ͱ͕ظ଴Ͱ͖ΔͷͰ͓קΊͰ͢ɻ 43
  51. None
  52. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊Μ Ͱࢥ͏ 4.1

    ࢝Ίʹ ιϑτ΢ΣΞ։ൃͷϞσϧ΍σβΠϯύλʔϯͳͲͳͲͷઃܭ͸͍ͨ΁Μଟ͘ͷؾ෇͖Λ༩͑ͯ͘ ΕΔ΋ͷͰ͋Δɻ·ٕͨज़΍؀ڥ͕೔ਐ݄าͰ͋ͬͯ΋ઃܭͷண૝ʹ͓͚Δఆ൪ύλʔϯʹ͸͍· ͩ৆ຯظݶ͸ͳ͍ͱݴ͑ΔͰ͠ΐ͏ɻࠓճ͸ઃܭͱͯ͠ͷࢹ఺Ͱܝ୊ͷʮήʔϜ AIʯΛʮBehavior TreeʯͰߏங͢Δ͜ͱʹऔΓ૊Έͭͭɺѻ͍ํΛݟग़͍͖͍ͯͨ͠ɻݕ౼͍ͯ͘͠ʹ͋ͨͬͯؔ࿈͢ Δख๏ͳͲަ͑ͯղઆ͢Δɻͦ͜ͰؔΘΓ͕ਂ͍ʮBehavior Treeʯ ʮState Machineʯͷ̎ͭͷղઆ Λத৺ʹ͍ͯ͘͠ɻ ʮBehavior Treeʯ͸΋͸΍։ൃπʔϧ UX ͱͯ͜͠ΕΒ͕࢖༻Ͱ͖ΔΑ͏૊Έࠐ·Ε͍ͯΔ͜ͱ ΋͋Δ͕ɺͳΜͰ΋Ͱ͖ͯ͠·͏൓໘ɺಛੑ΍Ϟσϧͱͯ͠ྑ͘೺Ѳͯ͠໨తΛૂͬͯར༻͠ͳ͍ͱ ࠞཚ͕ى͜Γ΍͍͢ɻ ʮState Machineʯ͸େੲ͔Β͋ΔϞσϧ͕ͩɺif จ swtch-case จ͕සग़ͯ͠ ঢ়ଶ؅ཧ͕͍͋·͍ͳίʔυͱͳͬͯ͠·͏Մೳੑ͕͋Δɻ ࠓճ͜ΕΒख๏Λ͋ΒͨΊͯݟͭΊ௚͠౿ऻͭͭ͠ɺήʔϜϓϩάϥϜͷதͰͷΩϟϥΫλΛ੍ޚ ͢ΔήʔϜ AI ͱͯ྆͠ऀΛ׆༻͢Δͱ͍͏͜ͱʹ͍ͭͯɺ࣮ફͯ͠Έͨ͜ͱΛৼΓฦΓͳ͕Βಡऀ ͷ͋ͳͨͱҰॹʹඥղ͖ɺ΄Μͷগ͠ཧղΛਂΊ͍͖͍ͯͨͱࢥ͏ɻͦͷͨΊຊষ͸࡞ͬͯΈͨܥͰ ͸ͳ͘ɺ࡞Δ্Ͱ஫ҙͨ͜͠ͱͷৼΓฦΓͱ͍͏·ͱΊʹͳ͍ͬͯΔɻ 45
  53. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.1 ࢝Ίʹ

    ͳ͓ࣥචʹ͋ͨΓࣄྫͱͳΔऔΓ૊Έͷ؀ڥͱͯ͠ɺήʔϜ։ൃΤϯδϯͷ Unity ʹͯɺBehavior Tree ͕άϥϑΟΧϧʹߏஙͰ͖ͯήʔϜ੍ޚͰ͖ΔγεςϜʢҎ߱ɺҰൠԽͯ͠ʮϏδϡΞϧΤσΟ λʯͱ͢Δʣ͝ͱ։ൃͨ͠ͷ͕ͩɺຊষͷจ຺ͱͯ͠ຊ࣭తʹ͸։ൃΤϯδϯ͸໰Θͳ͍΋ͷͰ͋Δɻ ͨͩͷͪʹड़΂͍ͯ͘஫ҙ఺Λ౿·͑ɺ։ൃ͠΍͍͢Τϯδϯ΋͘͠͸ϓϥάΠϯ͸Կ͔Λݟग़ͯ͠ ͍͚ͨͩͨΒ޾͍Ͱ͋Δɻ ຊষͷͶΒ͍ͱΰʔϧ ࠓճѻ͏ςʔϚɺBeahviour Tree ͱ State Machine Λཧղͯ͠ɺήʔϜ AI Λ૊ΈཱͯΔͱ͖ߟ ͓͖͍͑ͯͨ͜ͱΛऔΓ্͛ͯ఻͑Δɻ͜ͷςʔϚ͸໨৽͍͠΋ͷͰ͸ͳͦ͘ͷҰ෦͸ίϯϐϡʔλ ͕ൃల͢Δͦͷલ͔Β࢖ΘΕ͍ͯΔ਺े೥ͱ࢖͍ݹ͞ΕͯਐԽΛଓ͚͍ͯΔ෼໺Ͱ͋ΔɻͦͷՁ஋ͷ ࠶ೝࣝͱద੾ͳ࢖͍Ͳ͜Ζͷબ୒ʹͲ͔͜ͰߩݙͰ͖Ε͹ͱئ͍ɺຊষΛॻ͘ɻ ͦΕͰ͸ղઆʹਐΉɻ Behavior Tree Beahviour Tree ͱ͸ɺλεΫΛࢬ༿ͷΑ͏ʹ࿈Ͷෳࡶʹߏ੒͜ͱ͕Ͱ͖ΔɺߦಈͱҙࢥܾఆΛπ Ϧʔঢ়ʹ௻ΓԼ͛ͨϏδϡΞϧΠϝʔδͰ͋Δɻւ֎ͷ༗໊ϏσΦήʔϜ͔Β͜ͷख๏͕ൃ঵͠ϒʔ Ϝͱͳͬͨख๏Ͱ͋Δɻ ? ਤ 4.1: Behavior Tree πϦʔਤࣗମ͸ࢀߟʹॻ͍ͨద౰ͳ΋ͷ͕͓͓ͩΑͦ͜͏͍͏΋ͷͰ͋Δɻ໼ҹ΍ϋςφه߸͸ศ ্ٓ෇͚͍ͯΔ͕ɺͦ͜ʹϧʔϧͷࢦఆ͕͋Δͱ͍͏ҙຯؚ͕·ΕΔɻ State Machine State Machine ͱ͸ɺΑΓݹ͔͘Β͋ΔৼΔ෣͍ͷϞσϧͰ͋Γɺσδλϧճ࿏ઃܭͱϓϩάϥϜ Ͱ࢖ΘΕ͓ͯΓɺ༗ݶݸͷঢ়ଶͷத͔Β̍ͭͷঢ়ଶΛऔΓɺ·ͨঢ়ଶΛભҠ͢Δ৚݅Λ͍࣋ͬͯΔɻ 46
  54. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.1 ࢝Ίʹ

    1 2 3 OFF OFF ON ON ਤ 4.2: State Machine ϑϩʔਤ͸ద౰ʹॻ͍ͨ΋ͷ͕ͩɺ͜͏͍͏΋ͷͰؒҧ͍͸ͳ͍ɻจࣈΛఴ͍͑ͯΔ෦෼͕͋Δ͕ ͦͷΑ͏ʹભҠ৚͕݅෇͍͍ͯΔͱ͍͏ҙຯͰ͋Δɻ ۙͯ͘ԕ͍ ͜ΕΛΈͯɺ͍͔͕ͩΖ͏͔ɻલऀ͸॥؀͍ͯ͠ͳ͍ʁ ͨ·ͨ·ͩɻޙऀ͸ઢ͕͙ʹΌ͙ʹΌ͠ ͍ͯΔʁ ͨ·ͨ·ͩɻ ͦ͏ɺ̎ͭ͸ඇৗʹࣅ͓ͯΓࠞಉ͠΍͍͢ͷͩɻ·ͨ͞Βʹ͕̎ͭ Behavior Tree ͷϏδϡΞϧΤ σΟλ಺Ͱ֞ࠜͳ͘ར༻Ͱ͖ΔΑ͏ఏڙ͞Ε͍ͯΔɻ࣮ࡍͱͯ͠΋ɺBehavior Tree ͷߦಈΛͻͱͭ ͷ State ͱͰ͖ΔɻState Machine Ͱॴఆͷॲཧͷ࣮ߦΛ͢ΔͷͰʮߦಈʯͰ͖Δɻ ͔͠͠ɺ໨తʹ͓͍ܾͯఆతʹҧ͏͜ͱ͕͋ΔɻState Machine ͸ຊ࣭తʹ͸डಈతͰ͋Γ໨తͱ ͯ͠ड͚਎ɻBehavior Tree ͸ߦಈ໦ͱ༁ͤΔΑ͏ʹೳಈతͰ͋ΔɻͦΕ͸ɺBehavior Tree ͸ॱং ཱͯͨಓےͰҙࢥܾఆ͠ߦಈ͢ΔҙࢥͷΑ͏ͳ΋ͷ͕͋Δͷʹର͠ɺState Machine Ͱ͸ঢ়ଶఆٛͱ ͭͳ͕ΓΛࣔ͢෦෼͕த৺Ͱ͋Δͱ͍͏͜ͱɻ໨తΛ੔ཧ͢ΔͱਤͷΑ͏ͳߏ଄ͱͳΔɻ State Machine Behavior Tree 状態A 状態B ああしたい Aだったら Bだったら 行動 A 行動 B OKだったら OKだったら ਤ 4.3: Behavior tree ͱ State Machine 47
  55. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.1 ࢝Ίʹ

    ฒ΂Δͱ̎ͭͷؔ܎͸·ΔͰʮૹ৴ػͱड৴ػʯ ɺ·ͨ͸ʮϦϞίϯͱ૷ஔʯ ɺ ʮ೴ͱମʯͱ͍͏ؔ ܎ʹ͋Δͱݴ͑ΔͷͰ͸ͳ͍͔ɻ̍ͭͷπϦʔ಺Ͱ͜ͷͲͪΒ΋Λࠞͥͯ࢖͍ͬͯΔέʔε΋͖ͬͱ ͋Δͱࢥ͏͕ɺ໌֬ʹผਤͰ͋Δͱͯ͠ղऍͨ͠΄͏͕ऩ·Γ͕Α͍ɻͦΕ͸ࢥߟ AI Λஔ͖׵͑Δ ࡍʹঢ়ଶ؅ཧ͝ͱೖΕସ͑ͣҙࢥ͚ͩஔ͖׵͕͑Ͱ͖Δ͜ͱΛҙຯ͢Δɻ͍ͭͰʹݴ͑͹ήʔϜΤϯ δϯͷ Unity Λ࢖ͬͨͨΊɺΩϟϥΫλϞʔγϣϯ؅ཧͷʮStateMachineʯͱ͍͏Ξχϝʔγϣϯ πϦʔΛѻ͏ͱ͢Ε͹͞Βʹ 1 ͭπϦʔ͕૿͑ɺࡾॏͷπϦʔΛѻ͏ૄ݁߹؅ཧΈ͍ͨͳͱ͍͏͜ͱ ʹͳΔʢ͖ͬͱΑ͍ҙຯͰʣ ɻͦͷ৔߹ʹ͸ɺ೴ͱਆܦճ࿏ͱମɺͱ͍͏͜ͱʹͳΔ͔ɻ 目的 行動 状態 Animation ਤ 4.4: ࡾॏπϦʔ ͋͞ɺݕ౼։࢝ ͦΕͰ͸ɺ͔͜͜Βগ͠۩ମతʹήʔϜͷঢ়گΛΠϝʔδ͠ͳ͕ΒऔΓ্͍͛ͯ͘ɻΠϝʔδ͸ ʮΞΫγϣϯήʔϜʯ ɻ ͲΜͳͱ͖ΩϟϥΫλ͕ͲͷΑ͏ͳʮঢ়ଶʯΛͱΔͷ͔ɺࣗ཯తʹʮߦಈʯΛͱΔ৔߹ʹ͸ͲͷΑ ͏ͳಈػɾҙࢥΛ΋ͬͯಈ͘ͷ͔ΛϞσϧʹরΒ͠ͳ͕Βߟ͑ͯղઆ͍͖͍ͯͨ͠ɻ プレイヤー エネミー エネミー ਤ 4.5: Πϝʔδ 48
  56. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.2 σβΠϯύλʔϯͰΈΔ

    State 4.2 σβΠϯύλʔϯͰΈΔ State GoF Ͱ͓ೃછΈͷσβΠϯύλʔϯʹ͸ State ύλʔϯ͕ଘࡏ͢ΔɺState ผʹ೿ੜΫϥεΛઃ͚ ঢ়ଶʹԠͯ͡ΫϥεΦϒδΣΫτΛ੾Γସ͑ͯৼΔ෣͍Λม͑Δͱ͍͏ख๏Ͱ͋ΔɻৼΔ෣͍ʹؔ͠ ͯ State ຖʹΫϥε෼͚Ͱ͖ΔςΫχοΫͰ͋Δ͕ɺભҠ৚݅ʹؔͯ͠͸Ϟσϧͱͯ͠໌֬ʹ૊Έࠐ ·Ε͍ͯΔ΋ͷͰ͸ͳ͍ɻState ύλʔϯͰ͸ State ந৅ΫϥεͰৼΔ෣͍͝ͱͷ Method Λઃ͚ɺ State ผʹ೿ੜ࣮ͯ͠૷͠ɺ࣮ߦ࣌͸ݱࡏঢ়ଶʹ߹Θ࣮ͤͯߦΫϥεΦϒδΣΫτΛࠩ͠ସ͑Δɺͱ ͍͏ઃܭͱͳΔ΋ͷͰ͋Δɻ ࢲ͕Α͘࢖͏ State ࣮૷͸ɺ·ͣը໘ભҠͷγεςϜ͕ڍ͛ΒΕΔɻը໘ભҠͰ State Λߟ͑Δͱ ύλʔϯཧղͱͯ͠ͱͯ΋߹க͠΍͍͢ͷͩɻͨͱ͑͹ View() ϝιουͰදࣔɺBack() ϝιουͰ ը໘໭Δॲཧɺͱ͍ͬͨڞ௨ͨ͠ݺͼग़͠ʹ͍ͭͯந৅ؔ਺ͱͯ͠ઃఆ͠қ͘ɺState ࢦఆʹΑͬͯ ભҠݺͼग़͠ʹରͯ͠ͱͯ΋্खʹରԠͰ͖Δɻ ࠓճ͸ήʔϜΩϟϥΫλͷৼΔ෣͍ʹରͯ͠ந৅Խ࣮ͨ͠૷Λ͍ͨ͠ͷͰɺΩϟϥΫλͷ State ʹ ͍ͭͯߟ͍͑ͯ͘ɻ Attack Wait Damage Death Move Jump ਤ 4.6: State ͱભҠ৚݅ ਤͷΑ͏ʹࣗΩϟϥΫλͰ͋Ε͹Կ͔ͷΩʔʹԠͨ͡ڍಈ͔ɺ֎తͳύϥϝʔλཁҼʢμϝʔδͳ ͲʣΛड͚ͨͱ͖ʹ State ભҠ͕ى͜Δɻ ఢΩϟϥΫλͰ΋ಉ͡ϩδοΫͷ··Ωʔೖྗ෦෼Λผͷܦ࿏ͰࣗಈԽ͢Δɺͭ·Γຊষͷओ୊ Ͱ͋ΔήʔϜ AI ʹΑͬͯಈ͔͢͜ͱΛ໨࿦ΉɻͦΕ͸ͭ·ΓೖྗϞδϡʔϧͷஔ͖׵͕͑؆୯ʹ࣮ ݱͰ͖ΔΑ͏४උΛ͓͚ͯ͠͹ɺࣗΩϟϥͰ΋ఢΩϟϥͰ΋͸ͨ·ͨຯํ CPU Ωϟϥʢຯํ AIʣ Ͱ΋ɺҰ؏ͨ͠ΩϟϥΫλ੍ޚ࣮૷͕Ͱ͖Δͱ͍͏ૂ͍ͱͳΔɻ͍ͯͬͨ͞ΜɺΩϟϥΫλঢ়ଶΛ State ΫϥεϝιουͰ੔ཧ͢ΔͱදͷΑ͏ͳ΋ͷ͕ڍ͛ΒΕΔɻ ˙جຊతͳΩϟϥΫλঢ়ଶ • ଴ػ Wait() 49
  57. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.3 Behavior

    Tree ΛઃܭʹऔΓೖΕΔ • Ҡಈ Move() • δϟϯϓ Jump() • ߈ܸ Attack() • μϝʔδ Damage() • ࢮ๢ Death() ήʔϜͷಛੑʹԠͯ͡͞ΒʹछྨΛઃ͚͍͚ͯΔ͜ͱ͸༰қʹΠϝʔδͰ͖ΔͩΖ͏ɻ·ͨݟ͓ͯ ෼͔ΓͷΑ͏ʹɺ΄΅ಉ͡ State ໊ͰΩϟϥΫλϞʔγϣϯׂ͕Γ౰ͯͰ͖Δͱݴ͑Δɻ State Machine ΛઃܭʹऔΓೖΕΔ State Machine ͸ɺભҠ৚݅ͱৼΔ෣͍ʹؔ͢ΔϞσϧͰ͋Δ͕ɺιϑτ΢ΣΞ։ൃͷϑϨʔϜ ϫʔΫͱͯ͠Ͱ͸ͳ֓͘೦΍ઃܭͱͯ͠ͷར༻ͷํ͕ҰൠతͰɺৼΔ෣͍Λܭը͢ΔਤղࢿྉͰΑ͘ ໨ʹ͢Δ΋ͷͱࢥ͏͕ɺίʔυͰѻ͏৔߹ʹ͸ Switch-Case ʹཔΔ͜ͱʹͳΓ͕ͪͰ͋Δɻۙ೥Ͱ ͸πϦʔঢ়ʹλεΫΛઃఆͰ͖ΔϏδϡΞϥΠζ͞Εͨ։ൃπʔϧ͕ྲྀߦͯͦ͠ΕΛ༻͍Δ৔߹ʹ͸ ࢹ֮తʹ΋ར༻Ͱ͖ΔΑ͏ʹͳͬͨɻ ϏδϡΞϧΤσΟλ؀ڥ͸લ్ͨ͠ Behavior Tree ͷΞϓϩʔνͱ΄΅ಉٛͳͷͰ·ͱΊͯ࣍અ ͔Βॻ͍͍͖͍ͯͨɻ ͔͠͠ͳ͕ΒϏδϡΞϧΤσΟλͰ͋ͬͨͱͯ͠΋ɺߏ଄͕ෳࡶʹංେԽ͢Δͱ؅ཧͰ͖ͳ͘ͳΔ ڪΕ͕͋Γɺίʔυͱͯ͠ͲͷΑ͏ʹΞϓϩʔν͢Δ΂͖͔ͱ͍͏͜ͱ͸ߟ͍͖͍͑ͯͨɻ ංେԽڊେԽͨ͠ྫͱͯ͠౰ॳϏδϡΞϧΤσΟλ؅ཧ͞Ε͍ͯͨ௒େن໛ͳ։ൃձࣾͷϓϩδΣ ΫτͰ࠷ऴతʹൃಈભҠ৚͕݅ Excel ද؅ཧʹண஍ͨ͠ͱ͍͏͜ͱ͕͋Δͱ͍͏ɻ͜ͷహ຤͸ܦݧ ্ɺ։ൃݱ৔ͰΑ͘ى͜Γ͏Δ͋Δ͋ΔͰɺଟػೳπʔϧઆ͔Β࢝·Γɺ݁ہҰ൪௿࣍ݩʢϩʔϨϕ ϧʣͳํ๏Ͱղܾ͞ΕΔ༷ࢠͱॏͳΔͱ΋ࢥ͑ͨɻͳ͓͜Ε͸ঢ়گ࣍ୈͰɺͲͪΒ͕ຊ࣭తʹྑ͍ͱ ͍͏͜ͱͰ͸ͳ͍ɻ ͳ͓ίʔυͰѻ͏৔߹ͷঢ়ଶભҠ৚݅ͷந৅Խɺ͋Δ͍͸෼཭ͱ͍͏໘Ͱ͸ྑ͍Ϟσϧ͸ͪΐ͏Ͳ Α͍ܗͷ΋͸Կ͕͋ΔͩΖ͏͔ɻલ్༷ͨ͠ʹͳͬͨͷ΋ɺۙ୅తͳɺ͋Δ͍͸Α͘੔ཧͰ͖Δ࣮ݱ ํ๏͕ҙ֎ͱ೉͍͜͠ͱ͕ݱΕ͍ͯΔͷͰ͸ͱࢥ͏ɻ 4.3 Behavior Tree ΛઃܭʹऔΓೖΕΔ ࣍ʹߟ͍͑ͯ͘΋ͷ͸ɺBehavior Tree ΛͲͷΑ͏ʹਾ͑Δͷ͔ͱ͍͏͜ͱɻ໨తͱͯ͠؆қతʹ ੔ཧͨ͠ΩϟϥΫλͷߦಈτϦΨ͸͜ͷΑ͏ͳߏ଄ʹͳΔɻ 50
  58. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.3 Behavior

    Tree ΛઃܭʹऔΓೖΕΔ プレイヤーを探 す プレイヤーにダ メージを与える プレイヤーから 逃げる 条件 条件 条件 行動 行動 行動 走査 ਤ 4.7: ΩϟϥΫλͷߦಈτϦΨ ઀ଓઌʹߦಈΛ༩͑Δͱ͍͏΋ͷͩɻ༩͑ํ࣍ୈͰ͸ߦಈ͕ঢ়ଶͦͷ΋ͷʹͳΓ͏ΔͷͰɺ͋Β͔ ͡Ίܭը͕ඞཁʹͳΔͩΖ͏ɻ Behavior Tree ͷϏδϡΞϧΤσΟλͬͯͲΜͳ΋ͷ ʢ˞ʮϏδϡΞϧΤσΟλʯͱ͸ҰൠԽͨ͠ݺশͱͯࣔͨ͠͠΋ͷͰಛఆͷ঎඼͸ࢦ͠·ͤΜʣલ ܝͨ͠௨Γ৚݅ͱಈ࡞͕ϏδϡΞϥΠζ͞ΕͨπϦʔঢ়ͷ΋ͷ͕ͩɺࢹ֮తʹΘ͔Γ΍͍͢͜ͱ͔Β ήʔϜσβΠφʔͳΓ͕Ϛ΢εૢ࡞ͰσʔλΛ࡞੒͍ͯ͘͠πʔϧͱͯ͠΋ͬͺΒར༻͞Ε͍ͯΔɻ ͜ͷπϦʔʹొ࿥ͨ͠ϧʔϧʹԊͬͯҙࢥܾఆ͠ɺొ࿥ͨ͠ߦಈΛى͜͢ɻ Ұൠతʹ Behavior Tree ͷϊʔυछผ͸͜ͷ௨Γɻ ˙ҰൠతʹΑ͋͘Δϊʔυͷछྨ • Action ɹ࣮ࡍͷॲཧΛ࣮ߦʢDOʣ • Decorator ɹλεΫͷฦ٫஋ΛՃ޻͠৚݅൑ఆʹ໭͢ʢDOʣ • Conditional ɹ୯Ұ৚݅൑ఆʢIFʣ • Composite ɹෳ਺ࢠϊʔυΛ࣮ߦͯ͠൑ఆ஋Λ໭͢ • Sequence ɹ AND ͷ͜ͱ • Selector ɹ OR ͷ͜ͱ • Service ɹࢦఆͨ͠ස౓Ͱݺͼग़͢λεΫ • BlackBord ɹσʔλ ˞໾ׂͱ໊শ͸ͦΕͧΕͷγεςϜͰଟগ͹Β͖͕ͭ͋Δ ͜ͷΞϓϩʔνͷ୅໊ࢺͱ͍ͬͯաݴͰ΋ͳ͍ Unreal Engine 4 ͰͳΒɺΑΓ΋ͬͱଟ͘ͷϊʔυ छผ͕͋Δɻ ͜ΕΒΛ਺चͭͳ͗ɺλί଍഑ઢͯ͠ɺ৚݅ˠߦಈͷભҠΛߏங͍ͯ͘͠΋ͷͰ͋Δɻ ͜Ε͸͜ΕͰ͍ͨ΁Μ͢͹Β͘͠࡞ۀ෼୲͕Ͱ͖ͯཧ૝తͳͷ͕ͩɺ࢖͍ࠐΜͰ͍͘ʹ͋ͨͬͯ஫ ҙ͓͖͍ͯͨ͠ݒ೦΋͋Δɻͳ͓ɺΑ͋͘Δ੡඼֤छͷಈ࡞ൺֱ͸ผͷػձʹͱ͓ͬͯ͘ͱͯ͠ɺ࣍ 51
  59. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.4 ҧ͍Λཧղͯ͠׆༻͢Δ

    ͷΑ͏ͳ෦෼ͰϓϩδΣΫτͷ໰୊͕ى͖ͳ͍༷ʹऔΓѻ͑ͨΒͱࢥ͏ɻ ˙Behavior Tree ͷϏδϡΞϧΤσΟλ্Ͱͷ஫ҙ఺ • πϦʔ͕ڊେԽɾෳࡶԽ͠΍͍͢ • ڊେԽͨ͠ͱ͖݁ہίʔυͰ࣮૷͠௚͞ͳ͍ͱ࣮ߦίετ͕ߴ͍܏޲ • ͜ͷπϦʔσʔλΛߏஙͰ͖Δऀͱ͍͏ಛघεΩϧ͕ඞཁʹͳΔ • ݁ہΤϯδχΞ࡞ۀʹ໭ͬͯ͘ΔڪΕ • πϦʔσʔλͷଟਓ਺ฤूϚʔδʹিಥ͕ى͜Δ΋ͷ͕͋Δ • πϦʔσʔλͷ෇͚֎ࠩ͠͠ସ͕͑ޮ͔͘ • ඞͣ͠΋πϦʔঢ়͕؅ཧ͠΍͍͢ͱ͸ݶΒͳ͍ʢϚτϦοΫεදͰͳΒ؆ܿͳ৔߹ͳͲʣ ࢖͍ॴΛྑ͘ݟఆΊ্ͯखʹ෇͖߹͍ͬͯ͘ඞཁ͕͋Δ΋ͷͩɻ 4.4 ҧ͍Λཧղͯ͠׆༻͢Δ ઌ΄Ͳ΋ड़΂ͨΑ͏ʹɺݟͨ໨తʹ͜ͷ 2 ͭ͸ࣅ͍ͯΔ͔ɺ׬શʹಉ͡Ͱ͋Δɻπʔϧͱͯ͠΋Ͳ ͪΒ΋࣮ݱͰ͖ͯ߹Θͬͯ͞ѻΘΕ͍ͯΔɻ࢖͏ଆ͕ʮStateʯΛߏங͢Δͧͩͱ͔ʮBehaviorʯͩ ͧͱߟ͑Λ΋͍ͬͯͳ͍ͱ͏΍Ή΍ʹͳΓ΍͍͢ɻͦΕͰΑ͍৔߹΋͋Δ͕ɺલ్ͨ͠Α͏ͳݒ೦Λ ͋Β͔͡Ίߟྀ͓ͯ͘͠ͷͰ͋Ε͹ɺ͜ͷҧ͍ͱ࢖͍ॴΛཧղͯ͠औΓ૊ΜͰ͍͘͜ͱΛਪ঑͢Δɻ Ґஔ෇͚͸ɺBehavior Tree Ͱ͸จࣈ௨ΓߦಈΛఆٛ͢Δ͜ͱʹ௕͚ɺState Machine Ͱ͸ঢ়ଶͱ ભҠ৚݅Λఆٛ͢Δ͜ͱʹ௕͚͍ͯΔɻͭ·Γʮߦಈʯ΍ʮൃಈ৚݅ʯ͸όϦΤʔγϣϯΛ૿΍ͯ͠ ͍͘܏޲ʹ͋Γɺ ʮঢ়ଶʯ͸ෳࡶʹ޿͕͍ͬͯͯ΋ܥ౷ཱͯɺू໿͠ɺҰҙͰ͋Δ΂͖Ͱ͋Δͱ੔ཧ ͨ͠ɻ バリエーションを多くしたい 行動 状態 系統立てて整理し一意にしたい ਤ 4.8: ߦಈͱঢ়ଶͱભҠ৚݅ ͜ΕΛҙࣝ͠ͳ͍৔߹ɺ ʮߦಈʯΛ࣍ʑͱ૿΍ͨ͠ͱ͖ͷ઀ଓઌͷʮঢ়ଶʯ͸ɺͦͷઌʹͱΔҰ࿈ ͷ࣍ͷʮߦಈʯͱΛผͷϧʔτͱ෼͚Δ΂͘ɺ ʮঢ়ଶʯ͸͍ͭ͘΋ॏෳͯͦ͠ͷߦಈͷ਺͚ͩੜ੒͞ ΕΔڪΕ͕͋Δɻͨͱ͑͹͋Δঢ়گԼͰఢΩϟϥΫλ͕ϓϨΠϠʔΛݟ͚ͭΔʮߦಈʯͷ͍͔ͭ͘ͷ 52
  60. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.5 ϏδϡΞϥΠζͰ͖ͨͱͯ

    தʹ͸Ҡಈͱ͍͏ʮঢ়ଶʯؚ͕·ΕΔࣄʹͳΔɻ͜ͷঢ়ଶͰߦΘΕΔߦಈΛ Behavior ͷʮߦಈʯͱ ܾͯ͠Ίͨ৔߹͜Ε͸͜ͷҠಈ͸લޙͷҰ࿈ͷྲྀΕΛټΜͩࡧఢͷҠಈͱ͍͏༻్͕ݶఆ͞Ε͓ͯΓ ࠶ར༻ੑ͕௿͘ந৅౓͕௿͍ɻ൓ରʹ State ͷʮঢ়ଶʯͱͯ͠ҠಈͷߦಈΛܾΊͨ৔߹͸Ͳͷঢ়ଶ͔ ΒͰ͋ΕͲ๬Ί͹ಉ͡ߦಈ͕औΕΔͱͯ͠࠶ར༻ੑ͕ߴ͘ந৅౓͕ߴ͍ɻ ͜ͷΑ͏ͳ͜ͱ͔Βɺಉ݁͡ՌΛى͜͢΋ͷͱͯ͠Ͱ͋ͬͯ΋Ґஔ෇͚΍औΓճ͠ํ͕มΘͬͯ ͘Δɻ 索敵 待つ 見渡す 進む 振り向く 歩く 走る 見失う 待機 状態における行動 行動における状態 ਤ 4.9: Behavior Tree ͷߦಈͱ State Machine ͷঢ়ଶͷߦಈͷҧ͍ 4.5 ϏδϡΞϥΠζͰ͖ͨͱͯ ͦ͏͍ͬͨ࠶ར༻ੑ΍؅ཧ໘Λҙ͍ࣝͯ͘͠ͱɺͰ͖Δ͚ͩߴ͍࣍ݩͰந৅Խͨ͠ʮߦಈࢦࣔʯͱ ۩ମతͳʮݸผߦಈʯͱΛ෼཭ͯ͠อ͍ͬͯͳ͚Ε͹େྔͷѥछΛฏߦͰ؅ཧ͍͔ͯ͠ͳ͚Ε͹ͳΒ ͳ͍͜ͱ͕༧ݟͰ͖Δɻந৅Խͱ͸͍͑ɺͲͷ࣍ݩͰ΋ղऍͰ͖Δ΋ͷͰ͋ͬͯɺ੔ཧͷ͠ํͦΕͧ ΕͰࣗ༝౓͕͋Γ͗͢Δɻ౷Ұ͍ͨ͠΋ͷ࣍ୈͰ੔ཧ͢Δͷ͕Α͍ͩΖ͏ͱࢥΘΕΔɻͨͱ͑͹ɺ 1. ఢΩϟϥΫλΛछผͰ੔ཧ͢Δͱͨ͠৔߹ʹ͸ɺछผ͝ͱʹڞ௨ϞσϧΛٕ࣋ͬͯ΍ߦಈঢ়ଶ ϨϕϧͰ੔ཧ͢Δ΋ͷΛʮߦಈࢦࣔʯͱͨ͠ͱ͖ɺݸผΩϟϥΫλຖʹऔΓѻ͏࣌ؒ΍ڑ཭ͷ ҧ͍͋Δ͍͸߈ܸٕͳͲͷߦಈ಺༰ͷҧ͍ʹ͍ͭͯΛ۩ମతͳʮݸผߦಈʯͱͯ͠෼͚ͯ੔ཧ Ͱ͖Ε͹؅ཧ໘Ͱ͋ͱ͋ͱݒ೦͕গͳ͍ɻ 2. ͋Δ͍͸ɺཁૉͭ·ΓߦಈͷՌͨ͢໨త͝ͱʹந৅Խͨ͠Ϟδϡʔϧঢ়ʹͯ͠ɺ ʮݸผߦಈʯͱ ͯ͠ΩϟϥΫλ͝ͱʹ૊ΈཱͯΔߦಈࢦࣔΛͯ͠΋Α͍ɻߦಈϞδϡʔϧࢦఆπϦʔΛ࣋ͭɺ ͱ͍͏ܗʹͳΔɻ 3. ൃలϛοΫεͤͯ͞ɺΩϟϥछผ͝ͱʹڞ௨ͰߦಈϞδϡʔϧࢦఆπϦʔʢ2 ͷ΋ͷʣΛ࣋ͪɺ Ϟδϡʔϧ͸ྲྀΕͷఆٛͰ࣮͋ͬͯߦ͢Δ಺༰͸Ωϟϥݸผߦಈࢦఆ ʢ1 ͷ΋ͷʣͱͯ͠΋Α ͍ɻ͜ͷ৔߹͸ Behavior Tree Ͱࡾ૚ͱ͍͏۩߹ʹͳΔɻ ͜͏͍ͬͨ͜ͱΛݕ౼͓ͯ͘͜͠ͱͰ࡞ۀͱ؅ཧํ๏͕੔ཧ͞ΕΔɻͭ·ΓɺϏδϡΞϥΠζ͞Ε 53
  61. ୈ 4 ষ Behavior Tree ͰήʔϜ AI ʹऔΓ૊ΜͰࢥ͏ 4.6 Behavior

    Tree ͕࢘Δ΋ͷ͸ ͍ͯΔΤσΟλͰ͋Ε͹շదʹ؅ཧͰ͖Δʙͷ͸ૣܭͰɺগͳ͘ͱ΋͋Β͔͡Ίܭը͠ͳ͍ͱ͸·ͬ ͍ͯ͘ਂΈ͕ਂ͍ͷͰ͸ͱߟ͍͑ͯΔɻ 4.6 Behavior Tree ͕࢘Δ΋ͷ͸ Ͳ͜·Ͱ͕ରԠͰ͖Δπʔϧ΍؀ڥͰऔΓ૊ΜͰ͍Δ͔ʹΑΔͱ͜Ζ͕ͩɺ͜ΕΒΛ౿·͑ͨํ๏ Λ΋͠औΔͱ͢Ε͹... • Behavior Tree Ͱଟ૚తʹ؅ཧͯ͠Լ૚ʢݸผ૚ʣ͕ผϑΝΠϧʹͳ͍ͬͯΔ • Behavior Tree ͱ State Machine ͕ฒྻʹ͋Γ Behavior ͷߦಈͰ State τϦΨ͔͠ൃ͠ͳ͍ • ଟ૚؅ཧ͢Δͱ͖ͲͪΒ͔ͷ૚΋͘͠͸྆ํΛϏδϡΞϧπϦʔͰ͸ͳ͍΋ͷͰߏங͢Δ ͷ͍ͣΕ͔Ͱͳ͚Ε͹ɺ؅ཧ্ݫ͍͜͠ͱʹͳΔͷͰ͸ͳ͍͔ͱߟ͑Δɻͦ͏Ͱͳ͍৔߹ɺલ్͠ ͨ༧ݟͨ͠໰୊͸͙͢ʹൃੜ͢ΔͩΖ͏ɻͦͷ΄͔ʹ΋ɺͦ΋ͦ΋ϑΝΠϧԽ͞Εͳ͍ͳͲɺΑΓ໰ ୊͕ى͜Γ΍͍͢ঢ়گʹۙ͘ͳ͍͔Λબఆͷࡍʹ஫ҙ͍ͨ͠ɻ 4.7 ݁ͼ ιϑτ΢ΣΞ։ൃ͸ɺ಺༰ͷൃలʹΑͬͯඞͣෳࡶԽ͠ɺ࠷ॳ͔Βૂ͍͑ͯͨΒΑ͔ͬͨͱࢥ͏͜ ͱ͕Ͳͷ࣌΋ى͜ΔɻͲ͜ʹࣗ༝౓Λઃ͚Δ͔ɺͲΜͳεΩϧͷਓ͕ؒରԠͰ͖ΔΑ͏ʹ͢Δ͔ɺͲ ͷΑ͏ʹߋ৽͢Δ͔Λߟྀͨ͠ઃܭͱ͍͏΋ͷΛ৺͕͚͍ͨɻ ϏδϡΞϧΤσΟλͷ׆༻ͳͲΛਐΊɺྔ࢈࣌ͷোน͕௿͍ํ͕࡞ۀޮ཰Խͱ඼࣭޲্ʹد༩͢Δ ͜ͱ͸෼͔͍ͬͯΔɻಛੑΛཧղͯ͠͏·͘෇͖߹͍͚ͬͯͨΒɺίʔυ։ൃͱϊϯίʔυ։ൃΛద ٓ࢖͍෼͚ΒΕΔྑ͍ੈքʹͳΔͱߟ͍͑ͯΔɻ ͯ͞࠷ޙʹɺ͜ͷ։ൃख๏ͰऔΓ૊ΜͩৼΓฦΓͱͯ͠ Behavior Tree ͱ State Machine ͕Ͳ͏ ͋Ε͹ઃܭ໘Ͱྑ͍͔ΛࢲݟͰॻ͖௲ͬͨɻਓͦΕͧΕॏΜ͍ͨ͡෦෼͕ҟͳΔ͜ͱͱࢥ͏ͷͰɺࠓ ճड़΂ͨ͜ͱΑΓ΋΄͔ͷ఺Ͱڧ͘ҙࣝ͠ͳ͚Ε͹ͳΒͳ͍͜ͱ͕͋Δਓ΍ɺආ͚͍ͨͱड़΂ͨͱ͜ ΖΛޮՌతʹ׆༻Ͱ͖Δਓ΋͍Δ͔΋͠Εͳ͍ɻͦΜͳ࣌͸ɺͥͻͱ΋ͬ͘͡Γࢲʹڭ͍͑ͯͨͩ ͖ɺҙݟΛަΘ͍ͨ͠ͱئ͏ɻ 54
  62. ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 5.1 ࢝Ίʹ

    ίτμϚϯࣄۀ෦ͰΫϥΠΞϯτΤϯδχΞͱαʔόαΠυΤϯδχΞΛ݉೚͍ͯ͠Δ౻ాͰ͢ɻ ಥવͰ͕͢ɺΈͳ͞Μ͸৽ೖࣾһʹ࣍ͷΑ͏ͳ࣭໰Λ͞Εͯ΋౴͑ΒΕ·͔͢ʁ • ͳۭͥσΟϨΫτϦ͸ add Ͱ͖ͳ͍ͷ͔ • git status ͕ߴ଎ʹಈ࡞͢Δϫέ • ίϯϑϦΫτதʹͲ͏΍ͬͯ merge ઌͱ merge ݩΛ۠ผ͍ͯ͠Δͷ͔ ౴͑ΒΕͳ͔ͬͨਓ͸ɺຊষΛಡΊ͹ཧղͰ͖Δͱࢥ͍·͢ɻ ฐࣾͰ͸৽ଔΤϯδχΞࣾһ޲͚ͷٕज़ݚमͷ 1 ͭͱͯ͠ Git ݚमΛຖ೥ߦ͍ͬͯ·͢ɻࠓ೥౓ ͷ Git ݚम͸ࢲ͕ߨࢣΛ୲౰͍ͯͨ͠ͷͰ͕͢ɺݚम಺༰ΛݻΊΔաఔͰ Git ͷ index tree ʹ͍ͭ ͯਂ۷Γͯ͠ΈΔͱɺڵຯਂ͍ಛ௃͕ͨ͘͞Μ͋ͬͨͷͰɺຊষͰ͸ Git ͷ index tree ʹ͍ͭͯͷ ͋Ε͜ΕΛ঺հ͍ͨ͠ͱࢥ͍·͢ɻ 5.2 Git ͷ commit ʹ͍ͭͯ index tree ͷਂ͍࿩Λ͢Δલʹɺgit commit ͷڍಈʹ͍ͭͯ஌͓ͬͯ͘ඞཁ͕͋ΔͨΊɺ؆୯ʹ ͓͞Β͍͓͖ͯ͠·͢ɻ $ git commit Λ࣮ߦ͢Δͱ.git/objects/ҎԼʹ commit object ͕ੜ੒͞Ε·͢ɻ commit object ͸ɺҎԼͷ৘ใΛ࿈݁ͤͨ͞΋ͷΛɺzlib Ͱѹॖͯ͠࡞ΒΕ·͢ɻ • ࣝผࢠ (จࣈྻ"commit") • object ͷαΠζ 55
  63. ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 5.2 Git

    ͷ commit ʹ͍ͭͯ • tree object*1ͷ SHA-1 • ਌ commit ͷ SHA-1 • committer ͷ໊લɺϝʔϧΞυϨεɺίϛοτ࣌ࠁ • author ͷ໊લɺϝʔϧΞυϨεɺίϛοτ࣌ࠁ • ίϛοτϝοηʔδ ѹॖલͷঢ়ଶͷ SHA-1 ͕ͦͷ·· commit ͷϋογϡ஋ʹͳΓ·͢ɻ·ͨɺcommit ϋογϡ͸ ετϨʔδ಺ͷύεʹ΋ͳ͓ͬͯΓɺͨͱ͑͹ commit ϋογϡ͕ aff91e72719be31e58dd814a99 d8e6dc5103d731 ͷͱ͖ɺcommit ͷ࣮ମ͸.git/objects/af/f91e72719be31e58dd814a99d8e6 dc5103d731 ʹอଘ͞Ε͍ͯ·͢ɻ tree object ͸ϦϙδτϦͷঢ়ଶΛද͓ͯ͠Γɺ؆қతͳϑΝΠϧγεςϜͷΑ͏ͳߏ଄ʹͳͬͯ ͍·͢ɻtree object ʹ͸ɺͦͷσΟϨΫτϦʹؚ·Ε͍ͯΔϑΝΠϧͷ͞·͟·ͳ৘ใ͕ྻڍ͞Ε ͍ͯ·͢ɻ • ࣝผࢠ (จࣈྻ"tree") • object ͷαΠζ • ϑΝΠϧͷଐੑ (ϑΝΠϧͷछྨɺύʔϛογϣϯ) • ϑΝΠϧ (σΟϨΫτϦͷ৔߹͸ͦͷσΟϨτϦͷ tree object) ͷ SHA-1 • ϑΝΠϧ໊ commit object ͱಉ͘͡ɺ͜ΕΒͷ৘ใΛ࿈݁ͤͯ͞औͬͨ SHA-1 ͕ετϨʔδ಺ͷύεʹͳΓɺ zlib Ͱѹॖͨ͠΋ͷΛอଘ͠·͢ɻtree object ͕ࢦ͍ͯ͠ΔϑΝΠϧͷ SHA-1 ͸ Git Ͱ͸ blob ͱ ݺ͹ΕΔ object ͷϋογϡ஋Ͱ͢ɻblob ͸ϑΝΠϧͷ಺༰ͦͷ΋ͷΛ zlib Ͱѹॖͨ͠΋ͷͰɺ΄͔ ͷ object ͱಉ༷ʹอଘ͞Ε͍ͯ·͢ɻ ͦΕͧΕͷ object ͷத਎͸ɺҎԼͷίϚϯυͰ؆୯ʹ֬ೝͰ͖ΔͨΊɺҰ౓೷͍ͯΈΔͱ͓΋͠ Ζ͍ͱࢥ͍·͢ɻ $ git cat-file -p <ϋογϡ஋> Git ͷ object ʹ͍ͭͯ͸ɺ ʮPro Git - 10. Git ͷ಺ଆʯ *2Ͱ෼͔Γ΍͘͢ղઆ͞Ε͍ͯΔͨΊɺ͞ Βʹৄ͘͠஌Γ͍ͨ৔߹͸ࢀর͍ͯͩ͘͠͞ɻ *1 ৄ͘͠͸ޙड़͠·͕͢ɺtree object ͸ϦϙδτϦͷϑΝΠϧͷঢ়ଶΛอ͍࣋ͯ͠·͢ɻ *2 https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4- Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 56
  64. ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 5.3 index

    tree ͸ࠩ෼؅ཧͰ͸ͳ͍ 5.3 index tree ͸ࠩ෼؅ཧͰ͸ͳ͍ ৄ͘͠͸ޙड़͠·͕͢ɺindex tree ͷ࣮૷͸ git add ͳͲͷपลαϒίϚϯυͷڍಈ͔Βߟ͑Δ ͱɺ͋·Γ௚ײతͰ͸͋Γ·ͤΜɻͦͷ݁Ռɺindex tree ͸Α͘ޡղ͞Εͨ··࢖ΘΕ͍ͯ·͢ɻ࠷ ΋యܕతͳޡղͱ͍͑͹ɺindex tree ͕ࠩ෼Λ؅ཧ͍ͯ͠ΔͱࢥΘΕ͍ͯΔ͜ͱͰ͠ΐ͏ɻgit add ͢Δࡍɺࠩ෼ͷ͋ΔϑΝΠϧ͚ͩΛࢦఆͨ͠Γɺ-p ΦϓγϣϯͰಛఆͷࠩ෼͚ͩΛ index tree ʹొ ࿥ͨ͠ΓͰ͖ΔͨΊɺ͍͍ͭͭ index tree ͸ working directory ͷࠩ෼Λ͍࣋ͬͯΔͱࢥΘΕ͕ͪͰ ͕͢ɺ࣮ࡍ͸؅ཧ͍ͯ͠Δͷ͸ࠩ෼Ͱ͸ͳ͘ɺϑΝΠϧͦͷ΋ͷΛ؅ཧ͍ͯ͠·͢ɻ ϑΝΠϧͦͷ΋ͷΛ؅ཧ͢Δͱ͸ɺadd ͢Δͨͼʹͦͷ಺༰Ͱ blob Λੜ੒*3͠·͢ɻ ͦ͏ฉ͘ͱɺgit add ͕ϦϙδτϦ಺ͷ͢΂ͯͷϑΝΠϧͷ SHA-1 Λܭࢉͯ͠ zlib Ͱѹॖ͢Δͱ ͍͏ɺͱͯͭ΋ͳ͘ॏͨ͘ɺσΟεΫ༰ྔ΋େྔʹফඅ͢ΔॲཧΛ͍ͯ͠ΔΑ͏ʹฉ͑͜·͢ɻ͔͠ ࣮͠ࡍ͸ɺฤू͍ͯ͠ͳ͍ϑΝΠϧʹؔͯ͠͸ɺ౰વ blob ͷϋογϡ஋͸ಉ͡ʹͳΓɺ.git/objec ts/ҎԼʹಉ͡಺༰ͷϑΝΠϧ͕͢Ͱʹଘࡏ͢Δ͜ͱʹͳΔͨΊɺมߋ͕͋ͬͨϑΝΠϧҎ֎͸ zlib Ͱѹॖ͢Δॲཧ͸ল͔Ε৽ͨʹσΟεΫ༰ྔ΋ফඅ͠·ͤΜɻ ͱ͸͍͑ɺcommit ͢Δ·ͰʹϑΝΠϧΛमਖ਼ͯ͠ add Λ܁Γฦ͍ͯ͠Δͱɺແବͳ blob ͕૿͑ ͍͖ͯ·͢ɻ࣮ࡍʹ֬ೝͯ͠Έ·͠ΐ͏ɻ $ git init Initialized empty Git repository in /home/******/sample/.git/ $ touch hoge $ git add hoge $ echo "hoge" > hoge $ git add hoge $ git commit -m "first commit" [master (root-commit) c116179] first commit 1 file changed, 1 insertion(+) create mode 100644 hoge $ git fsck Checking object directories: 100% (256/256), done. dangling blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 git fsck ͸Ͳͷ commit object ͔Β΋ࢀর͞Ε͍ͯͳ͍ object Λ୳͢ίϚϯυͰɺdangling ͍ͯ͠Δ blob ͕ 1 ͭݟ͔ͭΓ·ͨ͠ɻdangling object ͸ɺ୯ମͰ͸େͨ͠αΠζͰ͸ͳͯ͘΋ɺ commit ͢Δؾ͕ͳͯ͘΋೔ৗతʹ add Λ͖ͨͨͳ͕Β࡞ۀΛਐΊΔਓ͸ɺ͔ͳΓͷྔͷ dangling object ͕ੜ੒͞Εͯ͠·͏ͨΊɺσΟεΫΛѹഭͯ͠͠·͍ͦ͏Ͱ͢ɻ ͔͠͠ɺ࣮ࡍʹ͸ dangling object ʹΑͬͯࡍݶͳ͘ফඅ͞ΕΔ͜ͱ͸͋Γ·ͤΜɻGit ͕͜ͷΑ *3 add ͨ͠ͱ͖ʹ࡞ΒΕΔ object ͸ blob object ͷΈͰɺtree object ͸ੜ੒͠·ͤΜɻ 57
  65. ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 5.4 index

    tree ͷ࣮ମͱߏ଄ ͏ͳϑΝΠϧΛ࡟আ͢ΔͨΊ*4ʹ git gc ͱ͍͏ίϚϯυΛఆظత*5ʹ࣮ߦ͢Δ͔ΒͰ͢ɻ 5.4 index tree ͷ࣮ମͱߏ଄ index tree ͕Ͳ͏͍ͬͨ໾ׂΛ͍࣋ͬͯΔͷ͔Λ֬ೝͨ͠ͱ͜ΖͰɺ͔͜͜Β͸ index tree ͷΑ Γ۩ମతͳϑΝΠϧϑΥʔϚοτͳͲʹ͍ͭͯ঺հ͍͖ͯ͠·͢ɻ͜͜Λཧղ͢Δ͜ͱͰ index tree ʹ·ͭΘΔɺ͞·͟·ͳෆՄղͳڍಈ΋ཧղͰ͖Δ͸ͣͰ͢ɻ ·ͣɺindex tree ͷ࣮ମ͸.git/index ʹ͋Γ·͢ɻindex tree ͷϑΝΠϧϑΥʔϚοτʹ͍ͭͯ ͸ɺެࣜϦϙδτϦͷ technical document*6ʹৄࡉʹهࡌ͞Ε͍ͯ·͢ɻͬ͟ͱ·ͱΊΔͱɺindex tree ͸ 2 छྨͷϒϩοΫͷू߹ମͰɺઌ಄ʹ 12byte ͷϔομ͕͋Γɺଓ͍ͯՄม௕ͷΤϯτϦ͕ొ ࿥͞Ε͍ͯΔϑΝΠϧ਺ʹ౳͍͠਺͚ͩଓ͘ͱ͍͏ɺϦετ 5.1 ͷΑ͏ͳߏ଄ʹͳ͍ͬͯ·͢ɻ Ϧετ 5.1: index tree ͷϑΝΠϧϑΥʔϚοτͷ֓ཁ ------------------------------------------------------------------------------- | 12byte - Header ------------------------------------------------------------------------------- | variable length - Entry 0 ------------------------------------------------------------------------------- | variable length - Entry 1 ------------------------------------------------------------------------------- | variable length - Entry 2 ------------------------------------------------------------------------------- | ... ------------------------------------------------------------------------------- | variable length - Entry N ------------------------------------------------------------------------------- ࣍ʹɺ֤ϒϩοΫͷϑΥʔϚοτʹ͍ͭͯݟ͍͖ͯ·͢ɻͥͻ͓खݩͷ index tree Λ hexdump Ͱ ோΊͳ͕ΒಡΈਐΊͯΈ͍ͯͩ͘͞ɻ·ͣɺ ϔομͷϑΝΠϧϑΥʔϚοτ͸Ϧετ 5.2 ͷ௨ΓͰ͢ɻ Ϧετ 5.2: ϔομͷϑΝΠϧϑΥʔϚοτ ------------------------------------------------------------------------------- | Header | 4byte - signature(’D’,’I’,’R’,’C’) | |=================================================================== | 12byte | 4byte - version number(2 or 3 or 4) | |=================================================================== | | 4byte - number of index entries ------------------------------------------------------------------------------- *4 Ճ͑ͯɺ׬શӬଓσʔλߏ଄ʹͳ͍ͬͯͯαΠζͷ໘Ͱޮ཰ͷѱ͍ object Λ൒Ӭଓσʔλߏ଄ʹͯ͠ pack file ͱݺ͹ ΕΔ΋ͷʹ·ͱΊΔ࡞ۀ΋ߦ͍·͢ɻ *5 ͍ͭ git gc ͕࣮ߦ͞ΕΔ͔͸ώϡʔϦεςΟΫεͰ൑அ͍ͯ͠·͢ɻৄ͘͠͸ https://git-scm.com/docs/git- gc#Documentation/git-gc.txt-gcauto Λࢀর͍ͯͩ͘͠͞ɻ *6 https://github.com/git/git/blob/master/Documentation/technical/index-format.txt 58
  66. ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 5.4 index

    tree ͷ࣮ମͱߏ଄ ઌ಄ 4byte ͸ϚδοΫφϯόʔͰɺඞͣ ASCII จࣈͰ"DIRC"Ͱ͢ɻଓ͘ 4byte ͸ index tree ͷ όʔδϣϯΛද͢੔਺Ͱɺݱࡏͷ࠷৽൛Ͱ͋Δ Git2.28 Ͱ͸ 2 ~ 4 ͷόʔδϣϯ͕ଘࡏ͠·͢ɻ஫ҙ ͓ͯ͘͠ඞཁ͕͋Γ·͕͢ɺindex tree ͷόʔδϣϯ͸࢖༻͍ͯ͠Δ Git ͷόʔδϣϯʹΑͬͯݻ ఆ͞Ε͍ͯΔΘ͚Ͱ͸͋Γ·ͤΜɻgit update-index ͷಛघͳΦϓγϣϯΛ࢖༻͢Δͱόʔδϣ ϯ͕มΘΓɺޙͷΤϯτϦͷߏ଄͕มԽ͠·͢ɻ؆୯ͷͨΊɺຊষͰ͸σϑΥϧτόʔδϣϯͰ͋Δ όʔδϣϯ 2 Λղઆ͠·͢ɻ࠷ޙʹΤϯτϦͷ਺͕ 4byte ੔਺Ͱೖ͍ͬͯ·͢ɻ1 ΤϯτϦ͸ 1 ϑΝ ΠϧʹରԠ͍ͯ͠ΔͨΊɺΤϯτϦ਺͸ݱࡏͷϦϙδτϦʹଘࡏ͢ΔϑΝΠϧ਺ʹ౳͘͠ͳΓ·͢ (ͨͩ͠ɺσΟϨΫτϦ͸আ͘)ɻ ΤϯτϦͷϑΝΠϧϑΥʔϚοτ͸Ϧετ 5.3 ͷ௨ΓͰ͢ɻ Ϧετ 5.3: ΤϯτϦͷϑΝΠϧϑΥʔϚοτ ------------------------------------------------------------------------------- | Entry | 4byte - ctime second | |=================================================================== | | 4byte - ctime nano second | |=================================================================== | | 4byte - mtime second | |=================================================================== | | 4byte - mtime nano second | |=================================================================== | | 4byte - device ID | |=================================================================== | | 4byte - inode number | |=================================================================== | | 4byte - mode | 16bit - unused | | |================================================== | | | 4bit - object type | | | 0x8 = regular file | | | 0xA = symbolic link | | | 0xE = git link | | |================================================== | | | 3bit - unused | | |================================================== | | | 9bit - unix like file permission | |=================================================================== | | 4byte - file owner’s user ID | |=================================================================== | | 4byte - file owner’s group ID | |=================================================================== | | 4byte - file size | |=================================================================== | | 20byte - SHA-1 digest | |=================================================================== | | 2byte - flags | 1bit - assume-valid flag | | | see bellow a command more about this flag | | | $ git update-index --assume-unchanged | | |================================================== 59
  67. ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 5.5 index

    tree ͷಾͱͦͷ౴͑ | | | 1bit - must be zero | | |================================================== | | | 2bit - conflict flag | | | 00 = no conflict | | | 01 = lowest common ancestor commit’s file | | | 10 = current commit’s file | | | 11 = another commit’s file | | |================================================== | | | 12bit - file name length | |=================================================================== | | $(file name length)byte - relative path from top level directory | |=================================================================== | | Fill in null bytes until file offset of next multiple of 8 ------------------------------------------------------------------------------- ઌ಄ 16byte Λ࢖ͬͯɺର৅ͷϑΝΠϧͷ ctime(ϝλσʔλͷ࠷ऴߋ৽࣌ࠁ) ͱ mtime(σʔλͷ ࠷ऴߋ৽࣌ࠁ) Λอ͍࣋ͯ͠·͢ɻ ͦͷޙ΋ 4byte ۠੾ΓͰɺσόΠε IDɺinode ൪߸ɺϞʔυ (ޙड़)ɺϢʔβʔ IDɺάϧʔϓ IDɺ ϑΝΠϧαΠζͱଓ͖·͢ɻ Ϟʔυ͸ɺ4byte Λࡉ੾Εʹͯ͠ɺ֤Ϗοτʹ໾ׂΛ༩͍͑ͯ·͢ɻৄ͘͠͸Ϧετ 5.3 ͷ௨ΓͰ ͕͢ɺobject type ͕ 0xE ͷ৔߹ɺgit link ͱ͍͏͋·Γฉ͖ೃછΈͷͳ͍୯ޠ͕ొ৔͍ͯ͠· ͢ɻຊষͰ͸ৄ͘͠ղઆ͠·ͤΜ͕ɺ͜Ε͸ submodule Λ࢖ͬͨࡍʹࢦఆ͞ΕΔ object type Ͱ ͢ɻ࢖༻ස౓͸ߴ͋͘Γ·ͤΜ͕ɺ಄ͷย۱ʹஔ͍͓ͯ͘ͱྑ͍͔΋͠Ε·ͤΜɻ ࣍ͷ 20byte ʹΑ͏΍͘ SHA-1 ͕ొ৔͠·͢ɻ͜ͷ SHA-1 ͸ීஈ 16 ਐ਺Ͱදه͞ΕΔϋογϡ ஋Λ 160bit ੔਺Ͱදݱͨ͠΋ͷͳͷͰ஫ҙ͍ͯͩ͘͠͞ɻ ͦͷ࣍ͷ 2byte ͸Ϟʔυͱಉ༷ʹ֤ϏοτͰ໾ׂ͕෼͔Ε͍ͯ·͢ɻassume-valid flag ͸ɺgi t update-index --assume-unchanged ͱ͍͏ίϚϯυΛ࢖༻ͨ͠ͱ͖ʹηοτ͞Ε·͢ɻ͜ͷϑ ϥά͕ηοτ͞Ε͍ͯΔͱɺ͜ͷϑΝΠϧͷ಺༰Λमਖ਼ͯ͠΋ git status ͰϑΝΠϧʹมߋ͕͋Δ ͔νΣοΫ͠ͳ͘ͳΓ·͢ɻҰݟ࢖͍ಓ͕ͳͦ͞͏ʹݟ͑·͕͢ɺେྔʹϑΝΠϧ͕͋Δ͕ɺcommit ʹؚΊΔ༧ఆ͕ͳ͍σΟϨΫτϦͳͲΛࢦఆ͓ͯ͘͠ͱɺgit status ͕ߴ଎ʹ࣮ߦͰ͖ΔΑ͏ʹͳ ΔͳͲͷϝϦοτ͕͋Γ·͢ɻconflict flag ͸ͦͷ໊ͷ௨ΓɺίϯϑϦΫτதʹ࢖༻͞ΕΔϑϥ άͰɺmerge ઌͷ commit ͷϑΝΠϧͳͷ͔ɺmerge ݩͷ commit ͷϑΝΠϧͳͷ͔ࣝผ͢ΔͨΊʹ ࢖͍·͢ɻ࠷ޙͷ 12bit ͸ϑΝΠϧ໊ͷ௕͞Ͱɺ࣍ʹԿόΠτಡΈࠐΊ͹ྑ͍͔͕෼͔Γ·͢ɻ ࠷ޙʹϑΝΠϧ໊ΛಡΈࠐΉͱɺ͜ͷΤϯτϦʹؚ·ΕΔ৘ใΛ͢΂ͯ͞Β͏͜ͱ͕Ͱ͖·͢ɻ ͦͯ࣍͠ͷΤϯτϦ͸ɺͦͷ࣍ͷ 8 ͷഒ਺ͷΞυϨε͔Β࢝·Γ·͢ɻ 5.5 index tree ͷಾͱͦͷ౴͑ index tree ͷߏ଄Λৄ͘͠ݟ͍ͯͬͨ͜ͱͰɺ๯಄Ͱ঺հͨ͠ɺindex tree ʹ·ͭΘΔ͞·͟·ͳ ಾʹ౴͑Δ͜ͱ͕Ͱ͖ΔΑ͏ʹͳΓ·ͨ͠ɻͦΕͰ͸ 1 ͭͣͭݟ͍͖ͯ·͠ΐ͏ɻ 60
  68. ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 5.5 index

    tree ͷಾͱͦͷ౴͑ Q. ͳۭͥσΟϨΫτϦ͸ add Ͱ͖ͳ͍ͷ͔ Git ͸ۭσΟϨΫτϦΛ࡞ͬͯ΋ add Ͱ͖ͣ commit ʹ΋ؚΊΒΕͳ͍ͷͰɺ.gitkeep ͱ͍͏ۭ ϑΝΠϧΛ࢖͓ͬͯ஡Λ୙͢Α͏ͳ͜ͱ͕Α͋͘Γ·͕͢ɺͲ͏ͯͦ͠΋ͦ΋ۭσΟϨΫτϦ͸ add Ͱ͖ͳ͍ͷͰ͠ΐ͏͔ɻ ͜͜·ͰಡΜͩ͋ͳͨͳΒɺ͜ͷ࣭໰ʹ౴͑Δ͜ͱ͕Ͱ͖ΔΑ͏ʹͳ͍ͬͯΔ͔ͱࢥ͍·͢ɻGit ͕ۭσΟϨΫτϦΛ add Ͱ͖ͳ͍ͷ͸ɺindex tree ͕ (ڱٛͷ) ϑΝΠϧ͔͠ѻ͍ͬͯͳ͍͔ΒͰ͢ɻ tree ΦϒδΣΫτ͸ɺindex tree Λݩʹ commit ࣌ʹॳΊͯੜ੒͞ΕΔͷͰɺindex tree ͔Β࡞Δͷ ʹ index tree ʹϑΝΠϧ͔͠ొ࿥Ͱ͖ͳ͍Ҏ্ɺۭͷ tree ΦϒδΣΫτ͕ੜ੒͞ΕΔ͜ͱ͸͋Γ· ͤΜɻ Q. git status ͕ߴ଎ʹಈ࡞͢Δϫέ git status ͸มߋ͕͋ͬͨϑΝΠϧΛྻڍͯ͘͠Ε·͢ɻ͜ͷڍಈΛφΠʔϒʹ࣮૷͠Α͏ͱ͢ ΔͱɺϦϙδτϦ಺ͷશϑΝΠϧΛ૸ࠪͯ͠ 1 ͭͣͭ SHA-1 Λൺֱ͍͖ͯ͠ɺSHA-1 ͕ҟͳͬͨ ϑΝΠϧΛྻڍ͠Α͏ͱ͢Δ͔ͱࢥ͍·͢ɻ͔͠͠ɺ͜ͷॲཧ͸શϑΝΠϧͷ SHA-1 Λ࠶ܭࢉ͢Δ ͨΊɺ͔ͳΓॏͦ͏ʹݟ͑·͕͢ɺ࣮ࡍʹ͸ڊେͳϦϙδτϦͰ΋ git status ͸ඇৗʹߴ଎ʹ࣮ߦ Ͱ͖·͢ɻ ͜Ε΋ index tree ͷߏ଄ΛಡΈղ͍ͨࠓͰ͸આ໌Ͱ͖·͢ͶɻSHA-1 Λܭࢉ͢Δલʹɺctimeɺ mtime Λൺֱͯ͠ߋ৽͕͔͋ͬͨͲ͏͔Λ֬ೝ͍ͯ͠Δ͔ΒͰ͢ɻצͷӶ͍ಡऀ͸ؾ෇͍͔ͨ΋͠ Ε·ͤΜ͕ɺҰݟ͢Δͱ Git Ͱ؅ཧ͢Δඞཁ͕ͳͦ͞͏ͳ৘ใ͕ɺindex tree ʹ͸ؚ·Ε͍ͯ·ͨ͠ ͶɻctimeɺmtimeɺσόΠε IDɺinode ൪߸ͱ͍ͬͨϑΝΠϧͷϝλ৘ใͰ͢ɻ࣮͸͜ΕΒͷ৘ใ ͸ git status Ͱ࢖༻͢Δ΋ͷͰͨ͠ɻ git status Λ࣮ߦ͢Δͱ͍͖ͳΓ SHA-1 Λൺֱ͢Δલʹɺctimeɺmtime Λൺֱͯ͠ɺߋ৽͋ͬ ͨ৔߹ʹ͚ͩ SHA-1 Λܭࢉ͍ͯ͠·͢ɻ௨ৗɺ1commit ͰେྔͷϑΝΠϧΛߋ৽͢Δ͜ͱ͸ͳ͔ͳ ͔ͳ͍ͨΊɺGit Λ࢖͍ͬͯͯ git status ͕஗͍ͱײ͡Δ͜ͱ͕গͳ͍ͷ΋͏ͳ͚ͣ·͢Ͷɻ ·ͨɺctime ͱ mtime ͕ߋ৽͞Ε͍ͯͨ৔߹͸ɺindex tree ͷ ctime ͱ mtime Λߋ৽ͯ͠ϝλ৘ ใ͚ͩมԽͨ͠ϑΝΠϧ͕େྔʹͨ·Βͳ͍Α͏ʹ΋ͳ͍ͬͯ·͢ɻ ͞Βʹɺ͔͜͜Βݴ͑Δ͜ͱͱͯ͠ɺgit status ͕ index tree ಺ͷ ctime ͱ mtime Λมߋ͢ Δ͜ͱ͕͋ΔͷͰɺ ʮgit status ͸ഁյతมߋΛՃ͑ΔίϚϯυͰ͋Δʯͱ͍͏ڻዼͷࣄ࣮͕͋Γ ·͢ɻ Q. ίϯϑϦΫτதʹͲ͏΍ͬͯ merge ݩͱ merge ઌΛ۠ผ͍ͯ͠Δͷ͔ Git ͰίϯϑϦΫτ͢ΔͱɺίϯϑϦΫτՕॴʹ merge ݩͱ merge ઌͦΕͧΕͷमਖ਼಺༰͕ࠩ͠ ࠐ·Ε·͢ɻ͜ͷͱ͖ɺίϯϑϦΫτղফͷҰ؀ͱͯ࣍͠ͷΑ͏ͳίϚϯυΛ࢖͏͜ͱ͕͋Δ͔ͱࢥ ͍·͢ɻ 61
  69. ୈ 5 ষ Git ͷ index tree ͱ͸݁ہͳΜͳͷ͔ 5.6 ࠷ޙʹ

    $ git checkout --thirs $ git checkout --ours ͜ΕΒͷίϚϯυ͸ɺͦΕͧΕڧ੍తʹ merge ઌ·ͨ͸ merge ݩͷঢ়ଶʹϑΝΠϧΛ্ॻ͖͢Δ ίϚϯυͰ͢ɻ͔͠͠ɺίϯϑϦΫτத͸౰વ merge commit Λ࡞੒͢ΔલͰ͢ͷͰɺmerge ݩ΍ merge ઌͱ͍ͬͨ৘ใ͸Ͳ͜Ͱ͍࣋ͬͯΔͷͰ͠ΐ͏͔ɻ ͜ͷ౴͑΋ index tree ͷߏ଄ʹ͋Γ·ͨ͠ɻindex tree ͸ίϯϑϦΫτத͸ɺmerge ઌͱ merge ݩͷϑΝΠϧΛ conflict flag Ͱ۠ผͯ͠ɺ྆ϑΝΠϧͱ΋อ͍࣋ͯ͠Δ͔ΒͰͨ͠ɻcommit Λ ݟʹߦ͘ͷͰ͸ͳ͘ɺindex tree ͔Β௚઀ର৅ͷ blob ʹඈ΂Δͱ͍͏ͷ͸ɺ͔ͳΓҙ֎Ͱ͢Ͷɻ 5.6 ࠷ޙʹ index tree ͸Ԟ͕ਂ͍Ͱ͢Ͷɻࠓճ͸ॻ͖͖Ε·ͤΜͰ͕ͨ͠ɺindex tree ͷόʔδϣϯ 3 ΍ 4 Ͱ ͸ɺ͞Βʹ͓΋͠Ζ͍ػೳ͕௥Ճ͞Ε͍ͯ·͢ɻ චऀ͸ Git ͕େ޷͖Ͱɺࣾ಺ LT ձͰ͸සൟʹ Git ͷ࿩Λ͍ͯ͠ΔͷͰɺࣾ಺Ͱ΋͋Δఔ౓ Git ޷ ͖ͱͯ͠ೝ஌͞Ε͍ͯΔͷͰ͕͢ɺ࣮͸ೖࣾલ͸πʔϧͱͯ͠ͷ Git ͷ࢖͍ํҎ্ͷ͜ͱ͸શવ஌Γ ·ͤΜͰͨ͠ɻ౰࣌ͷ৽ଔݚमͰɺGit ͷ಺෦ߏ଄ʹ͍ͭͯৄ͘͠ฉ͍ͯڵຯ͕༙͍ͨͷ͕࢝·ΓͰ ͨ͠ɻ Git ʹ͸ index tree ͚ͩͰͳ͘ɺ·ͩ·͓ͩ΋͠Ζ͍࿩͕ͨ͘͞Μ࢒͍ͬͯΔͷͰɺগ͠Ͱ΋ଟ͘ ͷਓʹ Git ʹڵຯΛ࣋ͬͯ΋Β͑ͨΒͳͱࢥ͍ͬͯ·͢ɻ ·ͨɺ࣮ࡍͷݚमͰ͸͜ΕҎ্ʹೱͯ͘ৄࡉͳ Git ͷ࿩Λ͍ͯ͠ΔͷͰɺ΋͜͠ΕΛಡΜͰ Git ʹ ڵຯΛ࣋ͬͯ͘Εֶͨੜ͕͍ͨΒɺͥͻฐࣾͷ࠾༻Λड͚ͯΈ͍ͯͩ͘͞ʂ ͓଴͍ͪͯ͠·͢ɻ 62
  70. ஶऀ঺հ দݪ ৴஧ (ୈ 1 ষ୲౰, GitHub: matsubara0507) ॴଐ͸ϞϯεταʔόνʔϜͰ Ruby

    Λॻ͍ͯΔɻϓϩάϥϛϯά͕޷͖Ͱɺීஈ͸ਪ͠ݴ ޠͷ Haskell Ͱ༡ΜͩΓɺ৽͍͠ϓϩάϥϛϯάݴޠΛษڧͨ͠Γ͍ͯ͠ΔɻHaskell-jp ΍ Elm-jp Ͱͪΐͪ͜ΐ͜׆ಈ΋͍ͯ͠Δɻ ઒ຢ ٛর (ୈ 2 ষ୲౰, GitHub: m4cteru, Twitter: @4cteru) ϥΠϒಈըϓϩμΫτ։ൃࣨͰ TIPSTAR ͷ։ൃΛߦͳ͍ͬͯ·͢ɻΞ΢τυΞ (ข͖Ր) ͕ ޷͖ͰΑ͘Ωϟϯϓ৔΍Տݪʹग़͔͚ͯ༡ΜͰ͍·͢ɻCHUMS ͱ͍͏Ξ΢τυΞϒϥϯυ ͕޷͖ɻ ௡ా ګฏ (ୈ 3 ষ୲౰, GitHub,Medium,Qiita: flatfisher, Twitter: @canoefishing) TIPSTAR ͷαʔόʔαΠυΤϯδχΞɺGCP ͱ Go ݴޠΛ࢖ͬͨ API ։ൃ΍ϓϩδΣΫτ ϦʔυΛ͍ͯ͠·͢ɻ௼Γ͕झຯͳͷͰʮ௼ΓʷςΫϊϩδʔʯͱ͍ͬͨςʔϚʹऔΓ૊Ήͷ ͕޷͖Ͱ͢ɻ ాಹล ً (ୈ 4 ষ୲౰) ։ൃຊ෦ CTO ࣨॴଐɻΤϯδχΞͱͯ͠εϚϗήʔϜ։ൃͱӡӦɺͦΕ͔Βऩӹੑ΍ήʔϜ ੑͱ UX ໘ͷΫϦΤΠςΟϒʹܞΘ͖ͬͯͨɻࠓ͸ϓϩάϥϛϯάڭҭʹ͍ͭͯͷֶशιϑ τͱΧϦΩϡϥϜΛࣗࣾ಺Ͱ୯ಠͰ࡞Γɺதɾߴߍੜʹ޲͚ͯϓϩάϥϛϯάߨ࠲ͷߨࢣ΋͠ ͍ͯΔɻ ౻ా ग໳ (ୈ 5 ষ୲౰, Github: shumoon84, Twitter: @shumon_84) ίτμϚϯࣄۀ෦Ͱ Unity ͱ Java Λॻ͍͍ͯΔ৽ଔ 2 ೥໨ΤϯδχΞͰ͢ɻ޷͖ͳ΋ͷ͸ ϘʔυήʔϜͱ Git ͱ Go Ͱ͢ɻ ԕ౻ ѯ ʢσβΠφʔ, noteɿ en_akaʣ σβΠφʔͱͯ͠ΞϓϦͷ UI ʗ UX σβΠϯΛϝΠϯʹ୲౰ɺ৽نࣄۀͷ্ཱͪ͛ʹ΋௅ઓ ͨ͠Γ͠·ͨ͠ɻࠓ͸ɺσβΠϯઓུࣨͰ૊৫ࢧԉ΍৽ଔ࠾༻ͷΠϕϯτاըͳͲΛߦͳͬͯ ͍·͢ɻ ਿా ֆඒ (੍࡞ਐߦ, GitHub: esugita, Twitter: @semisemi7) ݩʑ͸ΤϯδχΞͰɺαʔόαΠυ͔ΒεϚϗΞϓϦ·Ͱ෯޿͘ܦݧ͍ͯ͠·͕͢ɺࠓ͸ɺ DevRel ͱͯ͠ɺࣾ಺֎ͷٕज़ऀίϛϡχςΟͷࢧԉΛߦͬͨΓɺٕज़޿ใΛ͍ͯ͠·͢ɻ 63
  71. mixi tech note #04 2020 ೥ 9 ݄ 12 ೔ɹॳ൛ୈ

    1 ࡮ɹൃߦ ஶɹऀ גࣜձࣾϛΫγΟ ༗ࢤ ൃߦॴ גࣜձࣾϛΫγΟ ҹ࡮ॴ ೔ޫاը ɹ ˜ mixi, Inc.
  72. None