ããªãã¯ãããããã®ãã¬ã°ã©ã ãèããããšãããã§ããã
倧èŠæš¡ãªãããã¯ãã§ãŒã³ ãããžã§ã¯ãã®éçºã«è±å¯ãªçµéšãæ〠Serokell ããŒã ã¯ãå芳ããããšãã§ããŸããã§ããã ç§ãã¡ã¯ XNUMX 人ã®åŸæ¥å¡ãã³ã³ãã¹ãã«åå ãããXNUMX é±éåŸã圌ãã¯ã»ã¯ã·ãŒ ã«ã¡ã¬ãªã³ãšããæ§ãããªã©ã³ãã ãªããã¯ããŒã ã§åªåããŸããã ãã®èšäºã§ã¯ã圌ããã©ã®ããã«ãããè¡ã£ããã«ã€ããŠèª¬æããŸãã ããããã® XNUMX åéã§ãå°ãªããšãèå³æ·±ãç©èªãèªãã§ããã ããå€ããŠããã®äžã§èªåã®ä»äºã«å¿çšã§ããæçãªäœããèŠã€ããŠããã ããã°å¹žãã§ãã
ããããå°ãæèããå§ããŸãããã
競äºãšãã®æ¡ä»¶
ãããã£ãŠãåå è ã®äž»ãªã¿ã¹ã¯ã¯ãææ¡ãããã¹ããŒã ã³ã³ãã©ã¯ãã® 24 ã€ä»¥äžãå®è£ ããããšãšãTON ãšã³ã·ã¹ãã ãæ¹åããããã®ææ¡ãè¡ãããšã§ããã ã³ã³ãã¹ãã¯15æ15æ¥ããXNUMXæXNUMXæ¥ãŸã§å®æœãããçµæã¯XNUMXæXNUMXæ¥ã«ã®ã¿çºè¡šãããã ãã®éãTelegram 㯠Telegram ã§ã® VoIP é話ã®å質ããã¹ãããã³è©äŸ¡ããããã«ãC++ ã§ã®ã¢ããªã±ãŒã·ã§ã³ã®èšèšãšéçºã«é¢ããã³ã³ãã¹ããéå¬ããçµæãçºè¡šã§ããããšãèãããšãããªãé·ãæéãããããŸããã
äž»å¬è ãææ¡ãããªã¹ããã XNUMX ã€ã®ã¹ããŒãã³ã³ãã©ã¯ããéžæããŸããã ãã®ãã¡ã® XNUMX ã€ã¯ TON ã§é åžãããŠããããŒã«ã䜿çšããXNUMX ã€ç®ã¯åœç€Ÿã®ãšã³ãžãã¢ã TON å°çšã«éçºããHaskell ã«çµã¿èŸŒãŸããæ°ããèšèªã§å®è£ ããŸããã
é¢æ°åããã°ã©ãã³ã°èšèªã®éžæã¯å¶ç¶ã§ã¯ãããŸããã ç§ãã¡ã®äžã§
ãªãåå ããããšæã£ãã®ã§ããããïŒ
ã€ãŸããç§ãã¡ã®å°éåéã¯ç¹æ®ãªã¹ãã«ãå¿ èŠãšããéæšæºçã§è€éãªãããžã§ã¯ãã§ãããå€ãã®å Žå IT ã³ãã¥ããã£ã«ãšã£ãŠç§åŠç䟡å€ãããããã§ãã ç§ãã¡ã¯ãªãŒãã³ãœãŒã¹éçºã匷åã«ãµããŒããããã®æ®åã«åãçµãã§ãããã³ã³ãã¥ãŒã¿ãµã€ãšã³ã¹ãšæ°åŠã®åéã§ãã·ã¢ã®æå倧åŠãšãååããŠããŸãã
ã³ã³ãã¹ãã®èå³æ·±ã課é¡ãšãç§ãã¡ãæãã Telegram ãããžã§ã¯ããžã®åå ã¯ãããèªäœã倧ããªåæ©ãšãªããŸããããè³éã¯ãããªãã€ã³ã»ã³ãã£ããšãªããŸããã ð
TONãããã¯ãã§ãŒã³ç 究
ç§ãã¡ã¯ãããã¯ãã§ãŒã³ã人工ç¥èœãæ©æ¢°åŠç¿ã®æ°ããªéçºã泚ææ·±ãç£èŠããç§ãã¡ãåãçµãã§ããååéã§ã®éèŠãªãªãªãŒã¹ãèŠéããªãããã«åªããŠããŸãã ãããã£ãŠãã³ã³ãã¹ããéå§ããããŸã§ã«ãç§ãã¡ã®ããŒã ã¯ãã§ã«æ¬¡ã®ã¢ã€ãã¢ã«ç²ŸéããŠããŸããã
ã³ã³ãã¹ããå§ãŸããŸã§ã«ã³ãŒãã¯ãã§ã«å ¬éãããŠãããããæéãç¯çŽããããã«ã次ã®èè ãæžããã¬ã€ããŸãã¯æŠèŠãæ¢ãããšã«ããŸããã ãŠãŒã¶ãŒã«ããã æ®å¿µãªãããããã§ã¯çµæã¯åŸãããŸããã§ãããUbuntu ã§ãã©ãããã©ãŒã ãçµã¿ç«ãŠãæé 以å€ã«ãä»ã®è³æã¯èŠã€ãããŸããã§ããã
СаЌа ЎПкÑЌеМÑаÑÐžÑ ÐŸÐºÐ°Ð·Ð°Ð»Ð°ÑÑ ÑÑаÑелÑМП пÑПÑабПÑаММПй, МП ÑОÑаÑÑ ÐµÐµ в МекПÑПÑÑÑ ÐŒÐŸÐŒÐµÐœÑÐ°Ñ Ð±ÑлП ÑлПжМП. ÐПвПлÑМП ÑаÑÑП МаЌ пÑÐžÑ ÐŸÐŽÐžÐ»ÐŸÑÑ Ð²ÐŸÐ·Ð²ÑаÑаÑÑÑÑ Ðº ÑеЌ ОлО ОМÑÐŒ пÑМкÑаЌ О пеÑеклÑÑаÑÑÑÑ Ñ Ð²ÑÑПкПÑÑПвМевÑÑ ÐŸÐ¿ÐžÑаМОй абÑÑÑакÑÐœÑÑ ÐžÐŽÐµÐ¹ Ма МОзкПÑÑПвМевÑе ЎеÑалО ÑеалОзаÑОО.
ä»æ§ã«å®è£ ã®è©³çŽ°ãªèª¬æããŸã£ããå«ãŸããŠããªãæ¹ãç°¡åã§ãã ä»®æ³ãã·ã³ããã®ã¹ã¿ãã¯ãã©ã®ããã«è¡šçŸãããã«é¢ããæ å ±ã¯ãTON ãã©ãããã©ãŒã çšã®ã¹ããŒã ã³ã³ãã©ã¯ããäœæããéçºè ã®å©ãã«ãªããšããããããéçºè ã®æ³šæããããå¯èœæ§ãé«ããªããŸãã
ããã¯ã¹: ãããžã§ã¯ãããŸãšãã
ã»ãã±ã«ã§ã¯ç§ãã¡ã¯å€§ãã¡ã³ã§ã
ããã§ç§ãã¡ã¯äœæããããšããå§ããŸãã
$ cd ~/.config/nixpkgs/overlays && git clone https://github.com/serokell/ton.nix
$ cd /path/to/ton/repo && nix-shell
[nix-shell]$ cmakeConfigurePhase && make
äŸåé¢ä¿ãã€ã³ã¹ããŒã«ããå¿ èŠããªãããšã«æ³šæããŠãã ããã NixOSãUbuntuããŸã㯠macOS ã®ãããã䜿çšããŠãããã«é¢ä¿ãªããNix ã¯éæ³ã®ããã«ãã¹ãŠãå®è¡ããŸãã
TONã®ããã°ã©ãã³ã°
TON ãããã¯ãŒã¯ã®ã¹ããŒã ã³ã³ãã©ã¯ã ã³ãŒãã¯ãTON ä»®æ³ãã·ã³ (TVM) äžã§å®è¡ãããŸãã TVM ã¯ä»ã®ã»ãšãã©ã®ä»®æ³ãã·ã³ãããè€éã§ãéåžžã«èå³æ·±ãæ©èœãåããŠããŸãã ç¶ã О ããŒã¿ãžã®ãªã³ã¯.
ããã«ãTON ã®ã¡ã³ããŒã¯ XNUMX ã€ã®æ°ããããã°ã©ãã³ã°èšèªãäœæããŸããã
ãã£ãã ã¯ã次ã®ãããªãŠãããŒãµã« ã¹ã¿ã㯠ããã°ã©ãã³ã°èšèªã§ãã
ãã¡ã³ã·ãŒ ã«äŒŒãã¹ããŒã ã³ã³ãã©ã¯ã ããã°ã©ãã³ã°èšèªã§ãã
XNUMX çªç®ã®ã¢ã»ã³ãã© â TVM çšã®ãã€ããªå®è¡å¯èœã³ãŒããçæããããã® XNUMX ã€ã®ã©ã€ãã©ãªã Fifth ã¢ã»ã³ãã©ã«ã¯ã³ã³ãã€ã©ããããŸããã ãã
ç§ãã¡ã®ç«¶äºã¯ããŸããããŸã
æåŸã«ãç§ãã¡ã®åãçµã¿ã®çµæãèŠãŠã¿ãŸãããã
éåæ決æžãã£ãã«
æ¯æããã£ãã«ã¯ãXNUMX 人ã®ãŠãŒã¶ãŒããããã¯ãã§ãŒã³ã®å€éšã«æ¯æããéä¿¡ã§ããããã«ããã¹ããŒã ã³ã³ãã©ã¯ãã§ãã ãã®çµæããé (ææ°æãããããªã) ã ãã§ãªããæéãç¯çŽã§ããŸã (次ã®ãããã¯ãåŠçããããŸã§åŸ ã€å¿ èŠããããŸãã)ã æ¯æãã¯å¿ èŠãªã ãå°é¡ã§ãå¿ èŠãªåæ°ã ãè¡ãããšãã§ããŸãã ãã®å Žåãæçµçãªæ±ºæžã®å ¬å¹³æ§ã¯ã¹ããŒãã³ã³ãã©ã¯ãã«ãã£ãŠä¿èšŒãããŠãããããåœäºè ã¯ãäºããä¿¡é Œããå¿ èŠã¯ãããŸããã
ç§ãã¡ã¯ãã®åé¡ã«å¯Ÿããéåžžã«ç°¡åãªè§£æ±ºçãèŠã€ããŸããã XNUMX ã€ã®åœäºè
ã¯ãããããã« XNUMX ã€ã®çªå· (ååœäºè
ãæ¯æã£ãå
šé¡) ãå«ã眲åä»ãã¡ãã»ãŒãžã亀æã§ããŸãã ããã XNUMX ã€ã®æ°å€ã¯æ¬¡ã®ããã«æ©èœããŸã
å®éããã®ã¢ã€ãã¢ãå®è£ ããã«ã¯ XNUMX ã€ã®æ°å€ã§ååã§ããããã®æ¹æ³ã®æ¹ããã䟿å©ãªãŠãŒã¶ãŒ ã€ã³ã¿ãŒãã§ã€ã¹ãäœæã§ãããããäž¡æ¹ãæ®ããŸããã ãŸããåã¡ãã»ãŒãžã«ãæ¯æãéé¡ãèšèŒããããšã«ããŸããã ããããªããšãäœããã®çç±ã§ã¡ãã»ãŒãžã倱ãããå Žåããã¹ãŠã®éé¡ãšæçµèšç®ã¯æ£ãããŠãããŠãŒã¶ãŒã¯æ倱ã«æ°ä»ããªãå¯èœæ§ããããŸãã
ç§ãã¡ã®ã¢ã€ãã¢ããã¹ãããããã«ããã®ãããªã·ã³ãã«ã§ç°¡æœãªæ¯æããã£ãã« ãããã³ã«ã®äœ¿çšäŸãæ¢ããŸããã é©ããããšã«ãèŠã€ãã£ãã®ã¯æ¬¡ã® XNUMX ã€ã ãã§ããã
説æ åæ§ã®ã¢ãããŒãã§ãããåæ¹åãã£ãã«ã®å Žåã®ã¿ã§ãããã¥ãŒããªã¢ã« ãããã¯ç§ãã¡ã®èããšåãèãã説æããŠããŸãããäžè¬çãªæ£ç¢ºæ§ã競å解決æé ãªã©ã®å€ãã®éèŠãªè©³çŽ°ã«ã€ããŠã¯èª¬æããŠããŸããã
ãã®æ£ç¢ºãã«ç¹ã«æ³šæãæããªããããããã³ã«ã詳现ã«èª¬æããããšãåççã§ããããšãæããã«ãªããŸããã æ°åã®ç¹°ãè¿ãã®åŸãä»æ§ãå®æããŸãããããã§ãããªããä»æ§ãäœæã§ããããã«ãªããŸããã
äž»å¬è ã®æšå¥šã«åŸã£ãŠãã³ã³ãã©ã¯ãã FunC ã§å®è£ ããã³ã³ãã©ã¯ããæäœããããã®ã³ãã³ã ã©ã€ã³ ãŠãŒãã£ãªãã£ããã¹ãŠ Fift ã§äœæããŸããã CLI ã«ã¯ä»ã®èšèªãéžæããããšãã§ããŸããããFit ãè©ŠããŠå®éã®ããã©ãŒãã³ã¹ã確èªããããšã«èå³ããããŸããã
æ£çŽã«èšããšãFift ãšååããåŸãéçºãããããŒã«ãã©ã€ãã©ãªãåãã人æ°ãããç©æ¥µçã«äœ¿çšãããŠããèšèªãããããã®èšèªãåªå ãã説åŸåã®ããçç±ã¯èŠã€ãããŸããã§ããã ã¹ã¿ãã¯ããŒã¹ã®èšèªã§ã®ããã°ã©ãã³ã°ã¯ãã¹ã¿ãã¯äžã«ãããã®ãåžžã«é ã®äžã«å ¥ããŠããå¿ èŠããããã³ã³ãã€ã©ã¯ãããå©ããŠãããªããããéåžžã«äžå¿«ã§ãã
ãããã£ãŠãç§ãã¡ã®æèŠã§ã¯ãFift ã®ååšãæ£åœåããå¯äžã®çç±ã¯ãFift Assembler ã®ãã¹ãèšèªãšããŠã®åœ¹å²ã§ãã ãããããã®æ¬è³ªçã«å¯äžã®ç®çã®ããã«æ°ãããã®ãçºæããããããTVM ã¢ã»ã³ãã©ãæ¢åã®èšèªã«åã蟌ãã æ¹ãè¯ãã®ã§ã¯ãªãã ããã?
TVM Haskell eDSL
ä»åºŠã¯ XNUMX çªç®ã®ã¹ããŒã ã³ã³ãã©ã¯ãã«ã€ããŠèª¬æããŸãã ç§ãã¡ã¯ãã«ãã·ã°ããã£ãŠã©ã¬ãããéçºããããšã«ããŸããããFunC ã§å¥ã®ã¹ããŒãã³ã³ãã©ã¯ããæžãã®ã¯éå±ãããŸãã ããã€ãã®ãã¬ãŒããŒãè¿œå ãããã£ãã®ã§ãããããã TVM çšã®ç¬èªã®ã¢ã»ã³ããªèšèªã§ããã
Fift ã¢ã»ã³ãã©ãŒãšåæ§ã«ãæ°ããèšèªã¯åã蟌ãŸããŠããŸããããã¹ããšã㊠Fift ã§ã¯ãªã Haskell ãéžæãããã®é«åºŠãªåã·ã¹ãã ãæ倧éã«æŽ»çšã§ããããã«ããŸããã ã¹ããŒã ã³ã³ãã©ã¯ããæ±ãå Žåãå°ããªãšã©ãŒã§ãã³ã¹ããéåžžã«é«ããªãå¯èœæ§ããããããéçåä»ãã¯å€§ããªå©ç¹ã§ãããšç§ãã¡ã¯èããŠããŸãã
Haskell ã«åã蟌ãŸãã TVM ã¢ã»ã³ãã©ãŒãã©ã®ãããªãã®ãã瀺ãããã«ãããã«æšæºã®ãŠã©ã¬ãããå®è£ ããŸããã 泚æãã¹ãç¹ãããã€ããããŸãã
- ãã®å¥çŽã¯ XNUMX ã€ã®æ©èœã§æ§æãããŠããŸãããå¿ èŠã«å¿ããŠè€æ°ã®æ©èœã䜿çšã§ããŸãã ãã¹ãèšèª (Haskell ãªã©) ã§æ°ããé¢æ°ãå®çŸ©ããå ŽåãeDSL ã䜿çšãããšãããã TVM ã®å¥åã®ã«ãŒãã³ã«ããããåŒã³åºãæç¹ã§åã«ã€ã³ã©ã€ã³åããããéžæã§ããŸãã
- Haskell ãšåæ§ãé¢æ°ã«ã¯ã³ã³ãã€ã«æã«ãã§ãã¯ãããåããããŸãã eDSL ã§ã¯ãé¢æ°ã®å ¥åã¿ã€ãã¯é¢æ°ãäºæããã¹ã¿ãã¯ã®ã¿ã€ãã§ãããçµæã¿ã€ãã¯åŒã³åºãåŸã«çæãããã¹ã¿ãã¯ã®ã¿ã€ãã§ãã
- ã³ãŒãã«ã¯æ³šéãä»ããŠããŸã
stacktype
ãåŒã³åºããã€ã³ãã§äºæ³ãããã¹ã¿ã㯠ã¿ã€ãã説æããŸãã å ã®ãŠã©ã¬ããå¥çŽã§ã¯ããããã¯åãªãã³ã¡ã³ãã§ããããeDSL ã§ã¯å®éã«ã¯ã³ãŒãã®äžéšã§ãããã³ã³ãã€ã«æã«ãã§ãã¯ãããŸãã ãããã¯ãã³ãŒããå€æŽããã¹ã¿ã㯠ã¿ã€ããå€æŽãããå Žåã«ãéçºè ãåé¡ãçºèŠããã®ã«åœ¹ç«ã€ããã¥ã¡ã³ããŸãã¯ã¹ããŒãã¡ã³ããšããŠæ©èœããŸãã ãã¡ããããã®ãããªã¢ãããŒã·ã§ã³ã¯ TVM ã³ãŒããçæãããªããããå®è¡æã®ããã©ãŒãã³ã¹ã«ã¯åœ±é¿ããŸããã - ããã¯ãŸã XNUMX é±éã§æžããããããã¿ã€ããªã®ã§ããã®ãããžã§ã¯ãã«ã¯ãŸã ããã¹ãããšããããããããŸãã ããšãã°ã以äžã®ã³ãŒãã«ããã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã¯ãã¹ãŠèªåçã«çæãããå¿ èŠããããŸãã
eDSL ã§ã®ãã«ãã·ã° ãŠã©ã¬ããã®å®è£ ã¯æ¬¡ã®ããã«ãªããŸãã
main :: IO ()
main = putText $ pretty $ declProgram procedures methods
where
procedures =
[ ("recv_external", decl recvExternal)
, ("recv_internal", decl recvInternal)
]
methods =
[ ("seqno", declMethod getSeqno)
]
data Storage = Storage
{ sCnt :: Word32
, sPubKey :: PublicKey
}
instance DecodeSlice Storage where
type DecodeSliceFields Storage = [PublicKey, Word32]
decodeFromSliceImpl = do
decodeFromSliceImpl @Word32
decodeFromSliceImpl @PublicKey
instance EncodeBuilder Storage where
encodeToBuilder = do
encodeToBuilder @Word32
encodeToBuilder @PublicKey
data WalletError
= SeqNoMismatch
| SignatureMismatch
deriving (Eq, Ord, Show, Generic)
instance Exception WalletError
instance Enum WalletError where
toEnum 33 = SeqNoMismatch
toEnum 34 = SignatureMismatch
toEnum _ = error "Uknown MultiSigError id"
fromEnum SeqNoMismatch = 33
fromEnum SignatureMismatch = 34
recvInternal :: '[Slice] :-> '[]
recvInternal = drop
recvExternal :: '[Slice] :-> '[]
recvExternal = do
decodeFromSlice @Signature
dup
preloadFromSlice @Word32
stacktype @[Word32, Slice, Signature]
-- cnt cs sign
pushRoot
decodeFromCell @Storage
stacktype @[PublicKey, Word32, Word32, Slice, Signature]
-- pk cnt' cnt cs sign
xcpu @1 @2
stacktype @[Word32, Word32, PublicKey, Word32, Slice, Signature]
-- cnt cnt' pk cnt cs sign
equalInt >> throwIfNot SeqNoMismatch
push @2
sliceHash
stacktype @[Hash Slice, PublicKey, Word32, Slice, Signature]
-- hash pk cnt cs sign
xc2pu @0 @4 @4
stacktype @[PublicKey, Signature, Hash Slice, Word32, Slice, PublicKey]
-- pubk sign hash cnt cs pubk
chkSignU
stacktype @[Bool, Word32, Slice, PublicKey]
-- ? cnt cs pubk
throwIfNot SignatureMismatch
accept
swap
decodeFromSlice @Word32
nip
dup
srefs @Word8
pushInt 0
if IsEq
then ignore
else do
decodeFromSlice @Word8
decodeFromSlice @(Cell MessageObject)
stacktype @[Slice, Cell MessageObject, Word8, Word32, PublicKey]
xchg @2
sendRawMsg
stacktype @[Slice, Word32, PublicKey]
endS
inc
encodeToCell @Storage
popRoot
getSeqno :: '[] :-> '[Word32]
getSeqno = do
pushRoot
cToS
preloadFromSlice @Word32
eDSL ããã³ãã«ãã·ã°ãã㣠ãŠã©ã¬ãã ã³ã³ãã©ã¯ãã®å®å
šãªãœãŒã¹ ã³ãŒãã¯ã次ã®å Žæã«ãããŸãã
ã³ã³ãã¹ããš TON ã«é¢ããçµè«
ç§ãã¡ã®äœæ¥ã«ã¯åèš 380 æéããããŸãã (ããã¥ã¡ã³ãã®äœæãäŒè°ãå®éã®éçºãå«ã)ã ã³ã³ãã¹ã ãããžã§ã¯ãã«ã¯ãCTOãããŒã ãªãŒããŒããããã¯ãã§ãŒã³ ãã©ãããã©ãŒã ã®ã¹ãã·ã£ãªã¹ããHaskell ãœãããŠã§ã¢éçºè ã® XNUMX 人ã®éçºè ãåå ããŸããã
ããã«ãœã³ã®ç²Ÿç¥ãç·å¯ãªããŒã ã¯ãŒã¯ããããŠæ°ãããã¯ãããžãŒã®åŽé¢ã«çŽ æ©ã没é ããå¿ èŠæ§ã¯åžžã«åºæ¿çãªãã®ã§ãããããç§ãã¡ã¯ã³ã³ãã¹ãã«ç°¡åã«åå ã§ãããªãœãŒã¹ãèŠã€ããŸããã éãããè³æºã®äžã§æ倧éã®ææãéæããããã«æ°æ©ç ãã¬å€ãéããããšããŠããããã¯è²ŽéãªçµéšãšçŽ æŽãããæãåºã«ãã£ãŠè£ãããŸãã ããã«ããã®ãããªã¿ã¹ã¯ã«åãçµãããšã¯ãåžžã«äŒç€Ÿã®ããã»ã¹ãè©Šãè¯ããã¹ããšãªããŸãã瀟å ã®çžäºäœçšãé©åã«æ©èœããªããã°ãçã«é©åãªçµæãéæããããšã¯éåžžã«å°é£ã ããã§ãã
æè©ã¯ããŠãããç§ãã¡ã¯ TON ããŒã ãè²»ãããåŽåã«æéãåããŸããã 圌ãã¯ãè€éã§çŸããããããŠæãéèŠãªããšã«ãæ©èœããã·ã¹ãã ãæ§ç¯ããããšã«æåããŸããã TON ã¯ã倧ããªå¯èœæ§ãç§ãããã©ãããã©ãŒã ã§ããããšã蚌æãããŠããŸãã ãã ãããã®ãšã³ã·ã¹ãã ãçºå±ããã«ã¯ããããã¯ãã§ãŒã³ ãããžã§ã¯ãã§ã®äœ¿çšãšéçºããŒã«ã®æ¹åã®äž¡æ¹ã®ç¹ã§ãããã«å€ãã®ããšãè¡ãå¿ èŠããããŸãã ç§ãã¡ã¯ä»ããã®ããã»ã¹ã«åå ã§ããããšãèªãã«æã£ãŠããŸãã
ãã®èšäºãèªãã§ããŸã 質åãããå ŽåããŸã㯠TON ã䜿çšããŠåé¡ã解決ããæ¹æ³ã«ã€ããŠã¢ã€ãã¢ãããå Žåã¯ã
åºæïŒ habr.com