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
【Go活用事例】 安全運転支援サービスを支える 運用管理システム
Search
Hirotaka Suzuki
November 01, 2019
Technology
3
1.4k
【Go活用事例】 安全運転支援サービスを支える 運用管理システム
2019/11/1 の、DeNA.go #3 の発表資料です。
Hirotaka Suzuki
November 01, 2019
Tweet
Share
More Decks by Hirotaka Suzuki
See All by Hirotaka Suzuki
サーバーエンジニアがFlutterに挑戦している話
suhirotaka
0
110
Other Decks in Technology
See All in Technology
会社もクラウドも違うけど 通じたコスト削減テクニック/Cost optimization strategies effective regardless of company or cloud provider
aeonpeople
2
410
地域コミュニティへの「感謝」と「恩返し」 / 20250726jawsug-tochigi
kasacchiful
0
110
データエンジニアがクラシルでやりたいことの現在地
gappy50
3
780
[MIRU25] NaiLIA: Multimodal Retrieval of Nail Designs Based on Dense Intent Descriptions
keio_smilab
PRO
1
160
Mambaで物体検出 完全に理解した
shirarei24
2
140
MCPと認可まわりの話 / mcp_and_authorization
convto
2
330
ユーザー理解の爆速化とPdMの価値
kakehashi
PRO
1
110
Power Automate のパフォーマンス改善レシピ / Power Automate Performance Improvement Recipes
karamem0
0
280
大規模組織にAIエージェントを迅速に導入するためのセキュリティの勘所 / AI agents for large-scale organizations
i35_267
6
360
興味の胞子を育て 業務と技術に広がる”きのこ力”
fumiyasac0921
0
440
AI コードレビューが面倒すぎるのでテスト駆動開発で解決しようとして読んだら、根本的に俺の勘違いだった
mutsumix
0
120
【Λ(らむだ)】最近のアプデ情報 / RPALT20250729
lambda
0
170
Featured
See All Featured
BBQ
matthewcrist
89
9.8k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
Become a Pro
speakerdeck
PRO
29
5.4k
Code Reviewing Like a Champion
maltzj
524
40k
Adopting Sorbet at Scale
ufuk
77
9.5k
How to Ace a Technical Interview
jacobian
278
23k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
Building Adaptive Systems
keathley
43
2.7k
Build The Right Thing And Hit Your Dates
maggiecrowley
37
2.8k
Statistics for Hackers
jakevdp
799
220k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
283
13k
Code Review Best Practice
trishagee
69
19k
Transcript
ʲ(P׆༻ࣄྫʳ ҆શӡసࢧԉαʔϏεΛࢧ͑Δ ӡ༻ཧγεςϜ ླ༟ਸ!TVIJSPUBLB ΦʔτϞʔςΟϒࣄۀຊ෦εϚʔτυϥΠϏϯά෦γεςϜ։ൃάϧʔϓ גࣜձࣾσΟʔɾΤψɾΤʔ The Go
gopher was designed by Renee French.
ࣗݾհ ླ༟ਸ!TVIJSPUBLB ϑϦʔϥϯεɾϔϧεςοΫܥελʔτΞοϓΛܦͯɺ %F/"ೖࣾɻ ަ௨ࣄނݮαʔϏε%3*7&$)"35ͷαʔόʔΞϓϦ έʔγϣϯ։ൃΛ͍ͬͯ·͢ɻ 8FCͷਐԽͱͱʹಈըαΠτ͔ΒϞϏϦςΟαʔϏε ·ͰؔΘ͖ͬͯͯɺͬͱͬͱ8FC͕׆༂͢Δࣾձʹ
͍͖͍ͯͨ͠ɻ
ຊͷΞδΣϯμ (PΛͬͨ։ൃͷݱͷงғؾΛ͓͍͑ͨ͠ʂ • (PΛͬͯͳʹΛͭͬͨ͘ͷʁ • ͳΜͰ(PΛ࠾༻ͨ͠ͷʁ • ͲΜͳϥΠϒϥϦΛͬͯΔͷʁ • ۩ମతͳ࣮ʹ͍ͭͯ
• 3BJMTͱͷซ༻ͷίπ • ։ൃͰۤ࿑ͨͯ͠͠Δ͜ͱʁ
(PͰͳʹΛ͍ͭͬͯ͘Δ͔
%3*7&$)"35ͱʁ
%3*7&$)"35ͱ 4 A2 DRIVE CHART
%3*7&$)"35ͷ࣮ূޮՌ 5 A3 DRIVE CHART
ं֎ΧϝϥͷΑ͏͢ 㾎ंؒڑෆ 㾎Ұ࣌ෆఀࢭ 㾎ա
ंΧϝϥͷΑ͏͢ 㾎ݟ 㾎ډΓ
ʑͷӡసϨϙʔτ 9 A7 ӡసͷΫηΛݟ͑ΔԽ͠ɺةݥͳಈը͚ͩϐοΫΞοϓɻ
%3*7&$)"35ͷӡ༻ཧ͕Ͱ͖Δ 8&#γεςϜΛͭ͘Γ·ͨ͠
ͨͱ͑ɺ͜Μͳ͜ͱ͕Ͱ͖·͢ ✓ ֤ςʔϒϧʢҎ্ʣͷ$36%ૢ࡞ΠϯϙʔτɾΤΫεϙʔτ ✓ ंࡌثͷ෦Λൃͯ͠ɺൃॻͷ1%'Λμϯϩʔυ͢Δ ✓ ෦͕ೲ͞Εͨͱ͖෦͕༻͞Εͨͱ͖ʹɺࡏݿΛਖ਼͘͠อͭ ✓ ͰͷंࡌثͷΈཱ͔ͯΒൃૹ·ͰΛτϥοΩϯά͢Δ ✓
Ͳͷंࡌث͕Ͳͷं྆ʹऔΓ͚ΒΕ͍ͯΔ͔ཧ͢Δ ✓ ंࡌثʹ৴͢ΔΞϓϦέʔγϣϯΛΞοϓϩʔυ͢Δ ✓ "*ʹΑΔϢʔβʔͷإೝূͷਖ਼֬ੑΛνΣοΫ͢Δ ✓ Ϣʔβʔ͔ΒͷϑΟʔυόοΫΛ֬ೝͯ͠ɺϝʔϧฦ৴͢Δ ✓ ϢʔβʔͷݖݶΛΘ͔Γ͍͢(6*Ͱ֬ೝɾมߋ͢Δ ✓ ंࡌثͷՔಇঢ়گΛϦΞϧλΠϜͰूܭ͢Δ ɾɾɾɾɾɾ
ը໘հ
ं྆Ұཡը໘
ं྆Ұཡը໘ʢ֦େʣ $47Πϯϙʔτ $47ΤΫεϙʔτ ϑΟϧλʢΠϯΫϦϝϯλϧαʔνʣ ϑΟϧλʢϓϧμϯʣ ৄࡉදࣔϘλϯ আϘλϯ ҹϘλϯ
෦ൃը໘
ंࡌثऔΓ͚ը໘
ंࡌثΞϓϦέʔγϣϯ৴ը໘
Ϣʔβʔཧը໘
(PΛ࠾༻͢Δ·ͰͷಓͷΓ
ΞʔΩςΫνϟ
ΞʔΩςΫνϟʢ֦େʣ (P 3BJMT ֤ίϯϙʔωϯτ ϚΠΫϩαʔϏεԽ
(PͰॻ͔Ε͍ͯΔͷ • ӡ༻ཧγεςϜͷ"1*ɾϏϡʔ 3BJMTͰॻ͔Ε͍ͯΔͷ • ंࡌثͱͷ௨৴"1* • ंࡌث͔ΒͷϑΝΠϧΞοϓϩʔυ"1* • 8&#ΫϥΠΞϯτͱͷ௨৴"1*
• ఆظόονσʔϞϯ 3BJMT͕ଟ͍ ΞʔΩςΫνϟʢݴޠผʣ
%3*7&$)"35ࣄۀԽ·ͰͷಓͷΓ ࣮ূ࣮ݧʢ̎ʣ ύʔτφʔ༷ͱ࣮ݧతʹαʔϏεΛӡ༻ͯ͠ɺຊʹަ௨ࣄނݮޮՌ͕͋Δͷ͔Λݕূ ‑ ࣄۀԽ0,͔ͷஅ ͠/(Ͱ͋Εɺ࣮ূ࣮ݧதͷιʔείʔυ͓ଂೖΓʹɾɾɾ ‑ ຊαʔϏε։࢝ ظؒͷαʔϏεΛܧଓΛલఏʹɺεέʔϥϏϦςΟΛߟྀͨ͠γεςϜߏங͕ඞཁ
(PPS3BJMT ˒࣮ূ࣮ݧ࣌ɺεϐʔυॏࢹͰ3BJMT 8FC։ൃʹඞཁͳϥΠϒϥϦ͕ͦΖ͍ͬͯͯɺͳΜͱ͍ͬͯ։ൃ͕͍ w ࣮ূ࣮ݧதසൟʹ༷มߋ͕ൃੜ͠ɺεϐʔυউෛ ˒ຊαʔϏεɺύϑΥʔϚϯεॏࢹͰ(P ࣮ߦͷ͞ • ͕̎ഒʹͳΕαʔόʔ͕ͰࡁΉʢίετϝϦοτʣ ੩తܕ͚
• ظؒͷӡ༻Λߟ͑Δͱɺܕ͕͋Δ͜ͱͰେنͳϦϑΝΫλϦϯάָ͕ʹͳΔ ʢӡ༻ϝϦοτʣ
(PͰॻ͔Ε͍ͯΔͷ • ӡ༻ཧγεςϜͷ"1*ɾϏϡʔ 3BJMTͰॻ͔Ε͍ͯΔͷ • ंࡌثͱͷ௨৴"1* • ंࡌث͔ΒͷϑΝΠϧΞοϓϩʔυ"1* • 8&#ΫϥΠΞϯτͱͷ௨৴"1*
• ఆظόονσʔϞϯ 3BJMT͕ଟ͍ ΞʔΩςΫνϟʢݴޠผʣ ࣮ূ࣮ݧதʹ ͳ͔ͬͨαʔϏε ࣮ূ࣮ݧத͔Β ͋ͬͨαʔϏε
ӡ༻ཧγεςϜ͔Β(PΛ࠾༻͠ɺ ͦͷଞͷαʔϏε ॱ࣍(PʹϦϓϨΠε༧ఆ
(PΛ͞Θͬͯ࠷ॳʹײͨ͜͡ͱ • ίϯύΠϧ͕௨Εɺ͍͍ͩͨҙਤ௨Γʹਖ਼͘͠ಈ͍͍ͯΔɻݴޠઃ ܭ͕लҳͳͷͩͱࢥ͏ • ܕ·ΘΓ͕ॊೈͳͷͰɺಈతܕ͚ͷݴޠ͔ΒͰۤ࿑͠ͳ͍ • "5PVSPG(PΛҰ௨Γऴ͑Εɺ044ͷιʔείʔυಡΊΔ • ιʔε͕͍ɾɾɾ
• จࣈྻૢ࡞େมɾɾɾ
͍ͬͯΔϥΠϒϥϦ
8"'ʢϑϨʔϜϫʔΫʣ ˒(PͷϑϨʔϜϫʔΫΛίϯηϓτ͔Βେࡶʹ̎ͭʹେผ͢Δͱɾɾ ϑϧελοΫɾ.7$WTϛχϚϧɾߴ ˒ͳͥͳΒɾɾ w యܕతͳ8FCγεςϜͷͨΊɺϑϧελοΫϑϨʔϜϫʔΫͷԸܙʹ͔͋ͣΓ͍ͨ w ӡ༻ཧγεςϜ͕ߴʹಈ࡞͢Δඞཁੑ͏͍͢
ݕ౼ͨ͠ϑϨʔϜϫʔΫ #FFHP ˕ 3FWFM ͻͱͱ͓ΓͷػೳͦΖ͍ͬͯΔ͕ɺఀؾຯ *SJT ϓϩδΣΫτͷӡӦ໘ͰΛ๊͍͑ͯΔΑ͏ ࠓճͬͪ͜ʂ
#FFHPʹ͍ͭͯ • ϑϧελοΫͷ.7$ϑϨʔϜϫʔΫ • தࠃͰਓؾ͕͋ΓɺΤϯλʔϓϥΠζͰͷ࣮๛ʢςϯηϯτɾϑΝʔΣΠɾɾɾʣ • 8FC։ൃ͚ͷػೳҰ௨ΓͦΖ͍ͬͯΔ •
֤ػೳϞδϡʔϧԽ͞Ε͓ͯΓɺ͖ͳϥΠϒϥϦʹೖΕସ͑ΒΕΔ • ηογϣϯɾΩϟογϡɾϩΨʔɾJOɺɺɺ03.·Ͱ͍͍ͭͯΔ • ϑϧελοΫϑϨʔϜϫʔΫͷΘΓʹɺϕϯνϚʔΫ͍ͦͦ͜͜ • 3BJMTಉ༷ʹɺCFFͱ͍͏$-*πʔϧ͕͋Δ • ίʔυࣗಈੜʢTDBGGPMEJOHʣͰ͖Δ
ϥΠϒϥϦհ 03. (03. কདྷͷ3BJMT͔ΒͷϦϓϨΠεͷͨΊɺ"DUJWF3FDPSEʹ ࣅͨػೳ͕΄͍͠ ϩΨʔ MPHSVT #FFHPͷMPHTϞδϡʔϧ༻ҙ͞Ε͍ͯΔ͕ɺMPHSVTΛ
༻͍ͯ͠Δ ڥઃఆ $POpHPS ڥ͝ͱʹઃఆϑΝΠϧΛ࡞Ͱ͖Δ ύοέʔδཧ HMJEFˠ (P.PEVMFT HMJEFΛ͍͕ͬͯͨɺ(P.PEVMFTͷಋೖޙʹҠߦ ߦऔಘ XIFSFBNJ ࣮ߦதͷιʔείʔυͷߦΛऔಘͰ͖ΔɻΤϥʔ௨ ࣌ʹ༻
ϥΠϒϥϦհ ߏମͷൺֱ HPDNQ ߏମͳͲͷҰகΛྑ͍ײ͡ʹൺֱͯ͘͠ΕΔ *%ੜ YJE ϢχʔΫ*%Λੜ͢ΔɻΞηοτͷμΠδΣετ༩ ͳͲͰ༻
1%'ੜ HPQEG ຊޠ͖Ε͍ʹ1%'ग़ྗͯ͘͠ΕΔɺ͋Γ͕͍ͨϥ ΠϒϥϦ ը૾ੜ HH ͖ͳϑΥϯτΛϩʔυͯ͠ςΩετΛը૾ԽͰ͖Δ όʔίʔυੜ #BSDPEF 23ίʔυͷ࡞ʹ༻
࣮ʹ͍ͭͯ
#FFHPΛͬͯ ࣮͍͖ͯ͠·͢
࣮ʢ$POUSPMMFSʣ ˒ϕʔεͷίϯτϩʔϥߏମΛఆٛ͢Δ • ϨεϙϯεͷϑΥʔϚοτʢ)5.-+40/ʣͰɺߏମΛ͚Δ // controllers/html/base.go type HTMLController
struct { beego.Controller accesslog *logger.AccessLog } // controllers/api/base.go type APIController struct { beego.Controller accesslog *logger.AccessLog }
࣮ʢ$POUSPMMFSʣ ˒ϧʔςΟϯάΛఆٛ͢Δ // routers.go // ϩάΠϯ༻ΤϯυϙΠϯτ beego.Router("/login", &opshtml.HTMLController{},
"get:LoginIndex") beego.Router("/api/login", &opsapi.APIController{}, "post:LoginIndex")
࣮ʢ$POUSPMMFSʣ ˒ίϯτϩʔϥڞ௨ॲཧΛ࣮͢Δ • 1SFQBSF Ͱίϯτϩʔϥͷલॲཧɺ'JOJTI Ͱίϯτϩʔϥͷޙॲཧ͕ॻ͚Δʢ3BJMT ͷCFGPSF@BDUJPOɾBGUFS@BDUJPOͷΑ͏ͳͷʣ //
controllers/api/base.go func (c *APIController) Prepare() { // ΫοΩʔೝূݖݶνΣοΫͳͲ } func (c *APIController) Finish() { // ϩάͷॻ͖ग़͠ͳͲ }
࣮ʢ$POUSPMMFSʣ ˒ίϯτϩʔϥݸผॲཧΛ࣮͢Δ // controllers/api/login.go func (c *APIController) LoginIndex()
{ // ϩάΠϯॲཧΛͯ͠ɺJSONΛฦ͢ c.ServeJSON() } // controllers/html/login.go func (c *HTMLController) LoginIndex() { // ϩάΠϯϖʔδͷϏϡʔΛฦ͢ c.TplName = "ops/login/index.tpl" }
࣮ʢ.PEFMʣ ˒%#εΩʔϚʹରԠ͢ΔߏମΛఆٛ͢Δ // models/car_schema.go type Car struct {
ID int `gorm:"column:id;primary_key" json:"id" csv:"id" chart:"display:ID;sortable:true;filterable:true;type:number;formable:f alse;listable:true"` Name *string `gorm:"column:name" json:"name" csv:"name" chart:"display:ं྆ ໊;sortable:true;filterable:true;type:text;formable:true;listable:true "` // ...... }
࣮ʢ.PEFMʣ ˒Ϩίʔυͷݕࡧ݁ՌΛ֨ೲ͢ΔߏମΛఆٛ͢Δ // models/car_schema.go type Cars struct {
Cars []Car `json:"data"` CountTotal int `json:"recordsTotal"` // ...... }
࣮ʢ.PEFMʣ ˒ϞσϧϩδοΫΛ࣮͢Δ • ϝιου໊ɺ"DUJWF3FDPSEͷϝιου໊Λҙࣝ͢Δ • (03.ͷϑοΫʢ#FGPSF$SFBUFɾ"GUFS$SFBUFʣ͕͑Δ // models/car.go
func (car *Car) FindBy() error { // ̍݅औಘ } func (cars *Cars) Where() error { // ෳ݅औಘ } func (car *Car) Update() error { // ̍݅ߋ৽ } func (cars *Cars) UpdateAll() error { // ෳ݅ߋ৽ }
࣮ʢ7JFXʣ ˒ϏϡʔςϯϓϨʔτΛ࣮͢Δ • HPͷςϯϓϨʔτύοέʔδΛ͏ • +40/ϏϡʔΛΘͣʹɺϞσϧͷߏମͰϨεϙϯεΛఆٛ͢Δ {{/* views/login/index.tpl
*/}} <div> <img src="{{ .baseURL }}/logo.png" width="100" height="100"> </div>
// main.go beego.Run()
্࣮ͷ
εΩʔϚߏମ ˒ςʔϒϧ͝ͱʹɺ%#ͷεΩʔϚఆٛΛөͨ͠εΩʔϚߏମΛͭ͘Δ ˒ܕͱWBMJEBUFλάͰεΩʔϚΛදݱ͢Δ w (03.ͷ্༷ɺ/6--ڐՄͷΧϥϜϙΠϯλܕʹ͢Δඞཁ͕͋Δ type TableExample struct
{ // int unsigned (NOT NULL) DeviceID int `validate:"min=0"` // int unsigned (NOT NULL DEFAULT 0) UserCertBy *int `validate:"min=0"` // int unsigned UserID *int // varchar (NOT NULL) Result string `validate:"required"` // varchar Name *string }
εΩʔϚߏମ ˒ΫϥΠΞϯταΠυͰͷڍಈΛߏମͷλάʹఆٛ͢Δ • +BWB4DSJQUʹλάͷ༰Λ+40/Ͱฦ٫͢Δ • ʢྫʣ͋ΔΧϥϜʹରͯ͠ɺιʔτػೳΛ༗ޮʹ͢Δ͔Ͳ͏͔ • ʢྫʣ͋ΔΧϥϜΛɺ$47ͷग़ྗରʹ͢Δ͔Ͳ͏͔
type TableExample struct { Name *string `gorm:"column:name" json:"name" csv:"name" chart:”display:Name;sortable:true;filterable:true;type:text;formab le:true;listable:true"` UpdatedByUserName string `gorm:"-" json:"updated_by_user_name" csv:"-" chart:"display:ߋ৽ ऀ;sortable:false;filterable:false;type:text;formable:false"` }
࣮ͷڞ௨Խ ˒ଟͷςʔϒϧʹରͯ͠ɺڞ௨ͷػೳΛ࣮͍ͨ͠ • ʢྫʣDBSTʹର͢Δ$SFBUFͷϩδοΫͱɺVTFSTʹର͢Δ$SFBUFͷϩδοΫಉ͡ ˒͔͕͠͠ɾɾ • ςʔϒϧ͕ଟ͍ͷͰɺಉ͡ϩδοΫ࣮Λڞ௨Խ͍ͨ͠ • (PʹδΣωϦΫε͕ͳ͍ʢ˞࣮࣌࣌ʣͷͰɺڞ௨ϝιουΛͭ͘Δ͜ͱ͍͠ •
·ͨڞ௨ϝιουʹͯ͠͠·͏ͱɺ༷ͷॊೈੑ͕ࣦΘΕΔ ‑ ϞσϧɾίϯτϩʔϥɾϏϡʔͷܗΛࣗಈੜͰ͖ΔΑ͏ʹ͢ΔʢಠࣗͷTDBGGPMEJOHػೳʣ
ͱ͍͑ɺଞͷαʔϏε 3BJMTͰಈ͍͍ͯΔɾɾ
3BJMTαʔϏεͱͷซଘ ˒%#·ΘΓͷఆٛͷڞ௨Խ • (PͷαʔϏεͱ3BJMTͷαʔϏε͕ಉ͡%#Λࢀর͍ͯ͠Δ߹ɺ%#·ΘΓͷఆٛͷ ߋ৽͕ࠩόάͷԹচʹͳΔ • Ͱ͖Δ͚ͩೋॏཧΛආ͚ΔΑ͏ʹ͢Δ ڞ௨ԽͷҰྫ
%#εΩʔϚఆٛ 3VCZ SJEHFQPMF ͰҰݩཧ εΩʔϚߏମ %#εΩʔϚ͔ΒεΩʔϚߏମΛࣗಈੜɻ·ͨɺ%#εΩʔ Ϛͱͷ͕ࠩൃੜ͍ͯ͠ͳ͍͔ΛνΣοΫ͢ΔπʔϧΛ༻ҙ FOVNఆٛ ZBNMʹFOVNͷఆٛΛॻ͖ग़͠ɺ྆γεςϜ͔ΒಡΈࠐΉ
3BJMTαʔϏεͱͷซଘ ˒҉߸Խ·ΘΓͷڞ௨Խ • ҰํͷαʔϏεͰ҉߸Խͨ͠Λ͏ҰํͷαʔϏεͰࢀর͍ͨ͠߹ɺ҉߸Խํࣜ 伴Λ߹ΘͤΔඞཁ͕͋Δ • ʢྫʣγϯάϧαΠϯΦϯ • ෳͷαʔϏεͰɺಉ͡Ϣʔβʔ໊ɾύεϫʔυͰϩάΠϯ͍ͨ͠ •
3VCZͷ%FWJTFɺϢʔβʔύεϫʔυͷ҉߸Խʹ#$SZQUΛ༻͢Δ • (PଆͰ#$SZQU·ΘΓͷॲཧΛ࣮͢Δඞཁ͕͋Δ • 伴ͷཧ͕໘ʹͳΔ • 伴ͷߋ৽λΠϛϯάΛͦΖ͑ΔͳͲͷ • ΫϥυαʔϏεΛ͏ͱָʢ"844FDSFUT.BOBHFSͳͲʣ
3BJMTαʔϏεͱͷซଘ ˒ϢʔςΟϦςΟػೳͷڞ௨Խ • ൚༻తͳϢʔςΟϦςΟΛͲͪΒଆͷαʔϏεʹ࣮͢Δ͔ʁ • ϝʔϧૹ৴ɾ௨γεςϜɾ֎෦"1*࿈ܞɾɾɾ • ͲͪΒ͔ҰํʹدͤΔʁ • αʔϏεؒͷ௨৴͕ൃੜ͢Δʢ3&45"1*PSH31$ʁʣ
• υΩϡϝϯτඋͷඞཁੑ্͕͕Δ • ྆αʔϏεͰ࣮͢Δʁ • ࣮ίετ͕ΒΉ • ߋ৽͕ࠩόάͷԹচʹͳΔ
͜Ε͔Β(PΛ ͕Μ͕Μ͍͖ͬͯ·͢