wardite 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Steepfile +1 -0
- data/examples/grayscale.rb +64 -0
- data/exe/wardite +11 -5
- data/lib/wardite/instruction.rb +10 -9
- data/lib/wardite/load.rb +20 -10
- data/lib/wardite/revisitor.rb +92 -0
- data/lib/wardite/value.rb +6 -22
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite/wasi/consts.rb +129 -0
- data/lib/wardite/wasi.rb +268 -7
- data/lib/wardite/wasm_module.rb +53 -0
- data/lib/wardite.rb +74 -105
- data/misc/proposals/rubykaigi2025.md +46 -0
- data/misc/slides/fib.c +4 -0
- data/misc/slides/fib.html +13 -0
- data/misc/slides/image-1.png +0 -0
- data/misc/slides/image-2.png +0 -0
- data/misc/slides/image.png +0 -0
- data/misc/slides/tokyo12.html +614 -0
- data/misc/slides/tokyo12.md +624 -0
- data/sig/fcntl.rbs +7 -0
- data/sig/generated/wardite/instruction.rbs +2 -0
- data/sig/generated/wardite/load.rbs +2 -3
- data/sig/generated/wardite/revisitor.rbs +25 -0
- data/sig/generated/wardite/value.rbs +3 -10
- data/sig/generated/wardite/wasi/consts.rbs +137 -0
- data/sig/generated/wardite/wasi.rbs +62 -5
- data/sig/generated/wardite/wasm_module.rbs +42 -0
- data/sig/generated/wardite.rbs +24 -19
- metadata +18 -3
- data/examples/add.wasm +0 -0
@@ -0,0 +1,614 @@
|
|
1
|
+
<!DOCTYPE html><html lang="ja-JP"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,height=device-height,initial-scale=1.0"><meta name="apple-mobile-web-app-capable" content="yes"><meta http-equiv="X-UA-Compatible" content="ie=edge"><meta property="og:type" content="website"><meta name="twitter:card" content="summary"><style>@media screen{body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button{appearance:none;background-color:initial;border:0;color:inherit;cursor:pointer;font-size:inherit;opacity:.8;outline:none;padding:0;transition:opacity .2s linear;-webkit-tap-highlight-color:transparent}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:disabled,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:disabled,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:disabled,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:disabled{cursor:not-allowed;opacity:.15!important}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover{opacity:1}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:active,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:active,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover:active,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover:active{opacity:.6}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:not(:disabled),body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:not(:disabled),body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover:not(:disabled),body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover:not(:disabled){transition:none}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=prev],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=prev],body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button.bespoke-marp-presenter-info-page-prev{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJNNjggOTAgMjggNTBsNDAtNDAiLz48L3N2Zz4=") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=next],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=next],body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button.bespoke-marp-presenter-info-page-next{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJtMzIgOTAgNDAtNDAtNDAtNDAiLz48L3N2Zz4=") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=fullscreen],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=fullscreen]{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48ZGVmcz48c3R5bGU+LmF7ZmlsbDpub25lO3N0cm9rZTojZmZmO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6NXB4fTwvc3R5bGU+PC9kZWZzPjxyZWN0IHdpZHRoPSI4MCIgaGVpZ2h0PSI2MCIgeD0iMTAiIHk9IjIwIiBjbGFzcz0iYSIgcng9IjUuNjciLz48cGF0aCBkPSJNNDAgNzBIMjBWNTBtMjAgMEwyMCA3MG00MC00MGgyMHYyMG0tMjAgMCAyMC0yMCIgY2xhc3M9ImEiLz48L3N2Zz4=") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button.exit[data-bespoke-marp-osc=fullscreen],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button.exit[data-bespoke-marp-osc=fullscreen]{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48ZGVmcz48c3R5bGU+LmF7ZmlsbDpub25lO3N0cm9rZTojZmZmO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6NXB4fTwvc3R5bGU+PC9kZWZzPjxyZWN0IHdpZHRoPSI4MCIgaGVpZ2h0PSI2MCIgeD0iMTAiIHk9IjIwIiBjbGFzcz0iYSIgcng9IjUuNjciLz48cGF0aCBkPSJNMjAgNTBoMjB2MjBtLTIwIDAgMjAtMjBtNDAgMEg2MFYzMG0yMCAwTDYwIDUwIiBjbGFzcz0iYSIvPjwvc3ZnPg==")}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=presenter],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=presenter]{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJNODcuOCA0Ny41Qzg5IDUwIDg3LjcgNTIgODUgNTJIMzVhOC43IDguNyAwIDAgMS03LjItNC41bC0xNS42LTMxQzExIDE0IDEyLjIgMTIgMTUgMTJoNTBhOC44IDguOCAwIDAgMSA3LjIgNC41ek02MCA1MnYzNm0tMTAgMGgyME00NSA0MmgyMCIvPjwvc3ZnPg==") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button.bespoke-marp-presenter-note-bigger{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJNMTIgNTBoODBNNTIgOTBWMTAiLz48L3N2Zz4=") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button.bespoke-marp-presenter-note-smaller{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJNMTIgNTBoODAiLz48L3N2Zz4=") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}}@keyframes __bespoke_marp_transition_reduced_outgoing__{0%{opacity:1}to{opacity:0}}@keyframes __bespoke_marp_transition_reduced_incoming__{0%{mix-blend-mode:plus-lighter;opacity:0}to{mix-blend-mode:plus-lighter;opacity:1}}.bespoke-marp-note,.bespoke-marp-osc,.bespoke-progress-parent{display:none;transition:none}@media screen{::view-transition-group(*){animation-duration:var(--marp-bespoke-transition-animation-duration,.5s);animation-timing-function:ease}::view-transition-new(*),::view-transition-old(*){animation-delay:0s;animation-direction:var(--marp-bespoke-transition-animation-direction,normal);animation-duration:var(--marp-bespoke-transition-animation-duration,.5s);animation-fill-mode:both;animation-name:var(--marp-bespoke-transition-animation-name,var(--marp-bespoke-transition-animation-name-fallback,__bespoke_marp_transition_no_animation__));mix-blend-mode:normal}::view-transition-old(*){--marp-bespoke-transition-animation-name-fallback:__bespoke_marp_transition_reduced_outgoing__;animation-timing-function:ease}::view-transition-new(*){--marp-bespoke-transition-animation-name-fallback:__bespoke_marp_transition_reduced_incoming__;animation-timing-function:ease}::view-transition-new(root),::view-transition-old(root){animation-timing-function:linear}::view-transition-new(__bespoke_marp_transition_osc__),::view-transition-old(__bespoke_marp_transition_osc__){animation-duration:0s!important;animation-name:__bespoke_marp_transition_osc__!important}::view-transition-new(__bespoke_marp_transition_osc__){opacity:0!important}.bespoke-marp-transition-warming-up::view-transition-group(*),.bespoke-marp-transition-warming-up::view-transition-new(*),.bespoke-marp-transition-warming-up::view-transition-old(*){animation-play-state:paused!important}body,html{height:100%;margin:0}body{background:#000;overflow:hidden}svg.bespoke-marp-slide{content-visibility:hidden;opacity:0;pointer-events:none;z-index:-1}svg.bespoke-marp-slide:not(.bespoke-marp-active) *{view-transition-name:none!important}svg.bespoke-marp-slide.bespoke-marp-active{content-visibility:visible;opacity:1;pointer-events:auto;z-index:0}svg.bespoke-marp-slide.bespoke-marp-active.bespoke-marp-active-ready *{animation-name:__bespoke_marp__!important}@supports not (content-visibility:hidden){svg.bespoke-marp-slide[data-bespoke-marp-load=hideable]{display:none}svg.bespoke-marp-slide[data-bespoke-marp-load=hideable].bespoke-marp-active{display:block}}}@media screen and (prefers-reduced-motion:reduce){svg.bespoke-marp-slide *{view-transition-name:none!important}}@media screen{[data-bespoke-marp-fragment=inactive]{visibility:hidden}body[data-bespoke-view=""] .bespoke-marp-parent,body[data-bespoke-view=next] .bespoke-marp-parent{inset:0;position:absolute}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc{background:#000000a6;border-radius:7px;bottom:50px;color:#fff;contain:paint;display:block;font-family:Helvetica,Arial,sans-serif;font-size:16px;left:50%;line-height:0;opacity:1;padding:12px;position:absolute;touch-action:manipulation;transform:translateX(-50%);transition:opacity .2s linear;-webkit-user-select:none;user-select:none;white-space:nowrap;will-change:transform;z-index:1;view-transition-name:__bespoke_marp_transition_osc__}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>*,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>*{margin-left:6px}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>:first-child,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>:first-child{margin-left:0}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>span,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>span{opacity:.8}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>span[data-bespoke-marp-osc=page],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>span[data-bespoke-marp-osc=page]{display:inline-block;min-width:140px;text-align:center}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=fullscreen],body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=next],body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=presenter],body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=prev],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=fullscreen],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=next],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=presenter],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=prev]{height:32px;line-height:32px;width:32px}body[data-bespoke-view=""] .bespoke-marp-parent.bespoke-marp-inactive,body[data-bespoke-view=next] .bespoke-marp-parent.bespoke-marp-inactive{cursor:none}body[data-bespoke-view=""] .bespoke-marp-parent.bespoke-marp-inactive>.bespoke-marp-osc,body[data-bespoke-view=next] .bespoke-marp-parent.bespoke-marp-inactive>.bespoke-marp-osc{opacity:0;pointer-events:none}body[data-bespoke-view=""] svg.bespoke-marp-slide,body[data-bespoke-view=next] svg.bespoke-marp-slide{height:100%;left:0;position:absolute;top:0;width:100%}body[data-bespoke-view=""] .bespoke-progress-parent{background:#222;display:flex;height:5px;width:100%}body[data-bespoke-view=""] .bespoke-progress-parent+.bespoke-marp-parent{top:5px}body[data-bespoke-view=""] .bespoke-progress-parent .bespoke-progress-bar{background:#0288d1;flex:0 0 0;transition:flex-basis .2s cubic-bezier(0,1,1,1)}body[data-bespoke-view=next]{background:#0000}body[data-bespoke-view=presenter]{background:#161616}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container{display:grid;font-family:Helvetica,Arial,sans-serif;grid-template:"current dragbar next" minmax(140px,1fr) "current dragbar note" 2fr "info dragbar note" 3em;grid-template-columns:minmax(3px,var(--bespoke-marp-presenter-split-ratio,66%)) 0 minmax(3px,1fr);height:100%;left:0;position:absolute;top:0;width:100%}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-parent{grid-area:current;overflow:hidden;position:relative}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-parent svg.bespoke-marp-slide{height:calc(100% - 40px);left:20px;pointer-events:none;position:absolute;top:20px;-webkit-user-select:none;user-select:none;width:calc(100% - 40px)}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-parent svg.bespoke-marp-slide.bespoke-marp-active{filter:drop-shadow(0 3px 10px rgba(0,0,0,.5))}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-dragbar-container{background:#0288d1;cursor:col-resize;grid-area:dragbar;margin-left:-3px;opacity:0;position:relative;transition:opacity .4s linear .1s;width:6px;z-index:10}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-dragbar-container:hover{opacity:1}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-dragbar-container.active{opacity:1;transition-delay:0s}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-next-container{background:#222;cursor:pointer;display:none;grid-area:next;overflow:hidden;position:relative}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-next-container.active{display:block}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-next-container iframe.bespoke-marp-presenter-next{background:#0000;border:0;display:block;filter:drop-shadow(0 3px 10px rgba(0,0,0,.5));height:calc(100% - 40px);left:20px;pointer-events:none;position:absolute;top:20px;-webkit-user-select:none;user-select:none;width:calc(100% - 40px)}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container{background:#222;color:#eee;grid-area:note;position:relative;z-index:1}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button{height:1.5em;line-height:1.5em;width:1.5em}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-presenter-note-wrapper{display:block;inset:0;position:absolute}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-presenter-note-buttons{background:#000000a6;border-radius:4px;bottom:0;display:flex;gap:4px;margin:12px;opacity:0;padding:6px;pointer-events:none;position:absolute;right:0;transition:opacity .2s linear}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-presenter-note-buttons:focus-within,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-presenter-note-wrapper:focus-within+.bespoke-marp-presenter-note-buttons,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container:hover .bespoke-marp-presenter-note-buttons{opacity:1;pointer-events:auto}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-note{box-sizing:border-box;font-size:calc(1.1em*var(--bespoke-marp-note-font-scale, 1));height:calc(100% - 40px);margin:20px;overflow:auto;padding-right:3px;white-space:pre-wrap;width:calc(100% - 40px);word-wrap:break-word;scrollbar-color:#eeeeee80 #0000;scrollbar-width:thin}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-note::-webkit-scrollbar{width:6px}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-note::-webkit-scrollbar-track{background:#0000}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-note::-webkit-scrollbar-thumb{background:#eeeeee80;border-radius:6px}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-note:empty{pointer-events:none}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-note.active{display:block}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-note p:first-child{margin-top:0}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container .bespoke-marp-note p:last-child{margin-bottom:0}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container{align-items:center;box-sizing:border-box;color:#eee;display:flex;flex-wrap:nowrap;grid-area:info;justify-content:center;overflow:hidden;padding:0 10px}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container .bespoke-marp-presenter-info-page,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container .bespoke-marp-presenter-info-time,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container .bespoke-marp-presenter-info-timer{box-sizing:border-box;display:block;padding:0 10px;white-space:nowrap;width:100%}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button{height:1.5em;line-height:1.5em;width:1.5em}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container .bespoke-marp-presenter-info-page{order:2;text-align:center}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container .bespoke-marp-presenter-info-page .bespoke-marp-presenter-info-page-text{display:inline-block;min-width:120px;text-align:center}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container .bespoke-marp-presenter-info-time{color:#999;order:1;text-align:left}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container .bespoke-marp-presenter-info-timer{color:#999;order:3;text-align:right}body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container .bespoke-marp-presenter-info-timer:hover{cursor:pointer}}@media print{.bespoke-marp-presenter-info-container,.bespoke-marp-presenter-next-container,.bespoke-marp-presenter-note-container{display:none}}</style><style>div#\:\$p > svg > foreignObject > section{width:1280px;height:720px;box-sizing:border-box;overflow:hidden;position:relative;scroll-snap-align:center center;-webkit-text-size-adjust:100%;text-size-adjust:100%}div#\:\$p > svg > foreignObject > section::after{bottom:0;content:attr(data-marpit-pagination);padding:inherit;pointer-events:none;position:absolute;right:0}div#\:\$p > svg > foreignObject > section:not([data-marpit-pagination])::after{display:none}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){font-size:2em;margin:0.67em 0}div#\:\$p > svg > foreignObject > section video::-webkit-media-controls{will-change:transform}@page {size:1280px 720px;margin:0}@media print{html, body{background-color:#fff;margin:0;page-break-inside:avoid;break-inside:avoid-page}div#\:\$p > svg > foreignObject > section{page-break-before:always;break-before:page}div#\:\$p > svg > foreignObject > section, div#\:\$p > svg > foreignObject > section *{-webkit-print-color-adjust:exact!important;animation-delay:0s!important;animation-duration:0s!important;color-adjust:exact!important;transition:none!important}div#\:\$p > svg[data-marpit-svg]{display:block;height:100vh;width:100vw}}div#\:\$p > svg > foreignObject > :where(section){container-type:size}div#\:\$p > svg > foreignObject > section img[data-marp-twemoji]{background:transparent;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em;width:1em}/*!
|
2
|
+
* Marp default theme.
|
3
|
+
*
|
4
|
+
* @theme default
|
5
|
+
* @author Yuki Hattori
|
6
|
+
*
|
7
|
+
* @auto-scaling true
|
8
|
+
* @size 16:9 1280px 720px
|
9
|
+
* @size 4:3 960px 720px
|
10
|
+
*/div#\:\$p > svg > foreignObject > section{--base-size-4:calc(var(--marpit-root-font-size, 1rem) * 0.25);--base-size-8:calc(var(--marpit-root-font-size, 1rem) * 0.5);--base-size-16:calc(var(--marpit-root-font-size, 1rem) * 1);--base-size-24:calc(var(--marpit-root-font-size, 1rem) * 1.5);--base-size-40:calc(var(--marpit-root-font-size, 1rem) * 2.5);--base-text-weight-normal:400;--base-text-weight-medium:500;--base-text-weight-semibold:600;--fontStack-monospace:ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace;--fgColor-accent:Highlight;}div#\:\$p > svg > foreignObject > section [data-theme=light],div#\:\$p > svg > foreignObject > section{color-scheme:light;--focus-outlineColor:#0969da;--fgColor-default:#1f2328;--fgColor-muted:#59636e;--fgColor-accent:#0969da;--fgColor-success:#1a7f37;--fgColor-attention:#9a6700;--fgColor-danger:#d1242f;--fgColor-done:#8250df;--bgColor-default:#fff;--bgColor-muted:#f6f8fa;--bgColor-neutral-muted:#818b981f;--bgColor-attention-muted:#fff8c5;--borderColor-default:#d1d9e0;--borderColor-muted:#d1d9e0b3;--borderColor-neutral-muted:#d1d9e0b3;--borderColor-accent-emphasis:#0969da;--borderColor-success-emphasis:#1a7f37;--borderColor-attention-emphasis:#9a6700;--borderColor-danger-emphasis:#cf222e;--borderColor-done-emphasis:#8250df;--color-prettylights-syntax-comment:#59636e;--color-prettylights-syntax-constant:#0550ae;--color-prettylights-syntax-constant-other-reference-link:#0a3069;--color-prettylights-syntax-entity:#6639ba;--color-prettylights-syntax-storage-modifier-import:#1f2328;--color-prettylights-syntax-entity-tag:#0550ae;--color-prettylights-syntax-keyword:#cf222e;--color-prettylights-syntax-string:#0a3069;--color-prettylights-syntax-variable:#953800;--color-prettylights-syntax-brackethighlighter-unmatched:#82071e;--color-prettylights-syntax-brackethighlighter-angle:#59636e;--color-prettylights-syntax-invalid-illegal-text:#f6f8fa;--color-prettylights-syntax-invalid-illegal-bg:#82071e;--color-prettylights-syntax-carriage-return-text:#f6f8fa;--color-prettylights-syntax-carriage-return-bg:#cf222e;--color-prettylights-syntax-string-regexp:#116329;--color-prettylights-syntax-markup-list:#3b2300;--color-prettylights-syntax-markup-heading:#0550ae;--color-prettylights-syntax-markup-italic:#1f2328;--color-prettylights-syntax-markup-bold:#1f2328;--color-prettylights-syntax-markup-deleted-text:#82071e;--color-prettylights-syntax-markup-deleted-bg:#ffebe9;--color-prettylights-syntax-markup-inserted-text:#116329;--color-prettylights-syntax-markup-inserted-bg:#dafbe1;--color-prettylights-syntax-markup-changed-text:#953800;--color-prettylights-syntax-markup-changed-bg:#ffd8b5;--color-prettylights-syntax-markup-ignored-text:#d1d9e0;--color-prettylights-syntax-markup-ignored-bg:#0550ae;--color-prettylights-syntax-meta-diff-range:#8250df;--color-prettylights-syntax-sublimelinter-gutter-mark:#818b98;}div#\:\$p > svg > foreignObject > section [data-theme=dark],div#\:\$p > svg > foreignObject > section:where(.invert){color-scheme:dark;--focus-outlineColor:#1f6feb;--fgColor-default:#f0f6fc;--fgColor-muted:#9198a1;--fgColor-accent:#4493f8;--fgColor-success:#3fb950;--fgColor-attention:#d29922;--fgColor-danger:#f85149;--fgColor-done:#ab7df8;--bgColor-default:#0d1117;--bgColor-muted:#151b23;--bgColor-neutral-muted:#656c7633;--bgColor-attention-muted:#bb800926;--borderColor-default:#3d444d;--borderColor-muted:#3d444db3;--borderColor-neutral-muted:#3d444db3;--borderColor-accent-emphasis:#1f6feb;--borderColor-success-emphasis:#238636;--borderColor-attention-emphasis:#9e6a03;--borderColor-danger-emphasis:#da3633;--borderColor-done-emphasis:#8957e5;--color-prettylights-syntax-comment:#9198a1;--color-prettylights-syntax-constant:#79c0ff;--color-prettylights-syntax-constant-other-reference-link:#a5d6ff;--color-prettylights-syntax-entity:#d2a8ff;--color-prettylights-syntax-storage-modifier-import:#f0f6fc;--color-prettylights-syntax-entity-tag:#7ee787;--color-prettylights-syntax-keyword:#ff7b72;--color-prettylights-syntax-string:#a5d6ff;--color-prettylights-syntax-variable:#ffa657;--color-prettylights-syntax-brackethighlighter-unmatched:#f85149;--color-prettylights-syntax-brackethighlighter-angle:#9198a1;--color-prettylights-syntax-invalid-illegal-text:#f0f6fc;--color-prettylights-syntax-invalid-illegal-bg:#8e1519;--color-prettylights-syntax-carriage-return-text:#f0f6fc;--color-prettylights-syntax-carriage-return-bg:#b62324;--color-prettylights-syntax-string-regexp:#7ee787;--color-prettylights-syntax-markup-list:#f2cc60;--color-prettylights-syntax-markup-heading:#1f6feb;--color-prettylights-syntax-markup-italic:#f0f6fc;--color-prettylights-syntax-markup-bold:#f0f6fc;--color-prettylights-syntax-markup-deleted-text:#ffdcd7;--color-prettylights-syntax-markup-deleted-bg:#67060c;--color-prettylights-syntax-markup-inserted-text:#aff5b4;--color-prettylights-syntax-markup-inserted-bg:#033a16;--color-prettylights-syntax-markup-changed-text:#ffdfb6;--color-prettylights-syntax-markup-changed-bg:#5a1e02;--color-prettylights-syntax-markup-ignored-text:#f0f6fc;--color-prettylights-syntax-markup-ignored-bg:#1158c7;--color-prettylights-syntax-meta-diff-range:#d2a8ff;--color-prettylights-syntax-sublimelinter-gutter-mark:#3d444d;}div#\:\$p > svg > foreignObject > section{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;background-color:var(--bgColor-default);color:var(--fgColor-default);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;font-size:16px;line-height:1.5;margin:0;word-wrap:break-word}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size:16px;}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor .octicon-link:before,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor .octicon-link:before{background-color:currentColor;content:" ";display:inline-block;height:16px;-webkit-mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 0 0 1.06 1.06l1.25-1.25a2 2 0 1 1 2.83 2.83l-2.5 2.5a2 2 0 0 1-2.83 0 .75.75 0 0 0-1.06 1.06 3.5 3.5 0 0 0 4.95 0l2.5-2.5a3.5 3.5 0 0 0-4.95-4.95zm-4.69 9.64a2 2 0 0 1 0-2.83l2.5-2.5a2 2 0 0 1 2.83 0 .75.75 0 0 0 1.06-1.06 3.5 3.5 0 0 0-4.95 0l-2.5 2.5a3.5 3.5 0 0 0 4.95 4.95l1.25-1.25a.75.75 0 0 0-1.06-1.06l-1.25 1.25a2 2 0 0 1-2.83 0"/></svg>');mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M7.775 3.275a.75.75 0 0 0 1.06 1.06l1.25-1.25a2 2 0 1 1 2.83 2.83l-2.5 2.5a2 2 0 0 1-2.83 0 .75.75 0 0 0-1.06 1.06 3.5 3.5 0 0 0 4.95 0l2.5-2.5a3.5 3.5 0 0 0-4.95-4.95zm-4.69 9.64a2 2 0 0 1 0-2.83l2.5-2.5a2 2 0 0 1 2.83 0 .75.75 0 0 0 1.06-1.06 3.5 3.5 0 0 0-4.95 0l-2.5 2.5a3.5 3.5 0 0 0 4.95 4.95l1.25-1.25a.75.75 0 0 0-1.06-1.06l-1.25 1.25a2 2 0 0 1-2.83 0"/></svg>');width:16px}div#\:\$p > svg > foreignObject > section details,div#\:\$p > svg > foreignObject > section figcaption,div#\:\$p > svg > foreignObject > section figure{display:block}div#\:\$p > svg > foreignObject > section summary{display:list-item}div#\:\$p > svg > foreignObject > section [hidden]{display:none!important}div#\:\$p > svg > foreignObject > section a{background-color:transparent;color:var(--fgColor-accent);text-decoration:none}div#\:\$p > svg > foreignObject > section abbr[title]{border-bottom:none;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}div#\:\$p > svg > foreignObject > section b,div#\:\$p > svg > foreignObject > section strong{font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section dfn{font-style:italic}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){border-bottom:1px solid var(--borderColor-muted);font-size:2em;font-weight:var(--base-text-weight-semibold, 600);margin:.67em 0;padding-bottom:.3em}div#\:\$p > svg > foreignObject > section mark{background-color:var(--bgColor-attention-muted);color:var(--fgColor-default)}div#\:\$p > svg > foreignObject > section small{font-size:90%}div#\:\$p > svg > foreignObject > section sub,div#\:\$p > svg > foreignObject > section sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}div#\:\$p > svg > foreignObject > section sub{bottom:-.25em}div#\:\$p > svg > foreignObject > section sup{top:-.5em}div#\:\$p > svg > foreignObject > section img{border-style:none;box-sizing:content-box;max-width:100%}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section kbd,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section samp{font-family:monospace;font-size:1em}div#\:\$p > svg > foreignObject > section figure{margin:1em var(--base-size-40)}div#\:\$p > svg > foreignObject > section hr{background:transparent;background-color:var(--borderColor-default);border:0;box-sizing:content-box;height:.25em;margin:var(--base-size-24) 0;overflow:hidden;padding:0}div#\:\$p > svg > foreignObject > section input{font:inherit;font-family:inherit;font-size:inherit;line-height:inherit;margin:0;overflow:visible}div#\:\$p > svg > foreignObject > section [type=button],div#\:\$p > svg > foreignObject > section [type=reset],div#\:\$p > svg > foreignObject > section [type=submit]{-webkit-appearance:button;-moz-appearance:button;appearance:button}div#\:\$p > svg > foreignObject > section [type=checkbox],div#\:\$p > svg > foreignObject > section [type=radio]{box-sizing:border-box;padding:0}div#\:\$p > svg > foreignObject > section [type=number]::-webkit-inner-spin-button,div#\:\$p > svg > foreignObject > section [type=number]::-webkit-outer-spin-button{height:auto}div#\:\$p > svg > foreignObject > section [type=search]::-webkit-search-cancel-button,div#\:\$p > svg > foreignObject > section [type=search]::-webkit-search-decoration{-webkit-appearance:none;appearance:none}div#\:\$p > svg > foreignObject > section ::-webkit-input-placeholder{color:inherit;opacity:.54}div#\:\$p > svg > foreignObject > section ::-webkit-file-upload-button{-webkit-appearance:button;appearance:button;font:inherit}div#\:\$p > svg > foreignObject > section a:hover{text-decoration:underline}div#\:\$p > svg > foreignObject > section ::-moz-placeholder{color:var(--fgColor-muted);opacity:1}div#\:\$p > svg > foreignObject > section ::placeholder{color:var(--fgColor-muted);opacity:1}div#\:\$p > svg > foreignObject > section hr:after,div#\:\$p > svg > foreignObject > section hr:before{content:"";display:table}div#\:\$p > svg > foreignObject > section hr:after{clear:both}div#\:\$p > svg > foreignObject > section table{border-collapse:collapse;border-spacing:0;display:block;font-variant:tabular-nums;max-width:100%;overflow:auto;width:-moz-max-content;width:max-content}div#\:\$p > svg > foreignObject > section td,div#\:\$p > svg > foreignObject > section th{padding:0}div#\:\$p > svg > foreignObject > section details summary{cursor:pointer}div#\:\$p > svg > foreignObject > section [role=button]:focus,div#\:\$p > svg > foreignObject > section a:focus,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus,div#\:\$p > svg > foreignObject > section input[type=radio]:focus{box-shadow:none;outline:2px solid var(--focus-outlineColor);outline-offset:-2px}div#\:\$p > svg > foreignObject > section [role=button]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section a:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section input[type=radio]:focus:not(:focus-visible){outline:1px solid transparent}div#\:\$p > svg > foreignObject > section [role=button]:focus-visible,div#\:\$p > svg > foreignObject > section a:focus-visible,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus-visible,div#\:\$p > svg > foreignObject > section input[type=radio]:focus-visible{box-shadow:none;outline:2px solid var(--focus-outlineColor);outline-offset:-2px}div#\:\$p > svg > foreignObject > section a:not([class]):focus,div#\:\$p > svg > foreignObject > section a:not([class]):focus-visible,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus,div#\:\$p > svg > foreignObject > section input[type=checkbox]:focus-visible,div#\:\$p > svg > foreignObject > section input[type=radio]:focus,div#\:\$p > svg > foreignObject > section input[type=radio]:focus-visible{outline-offset:0}div#\:\$p > svg > foreignObject > section kbd{background-color:var(--bgColor-muted);border-bottom-color:var(--borderColor-neutral-muted);border:1px solid var(--borderColor-neutral-muted);border-radius:6px;box-shadow:inset 0 -1px 0 var(--borderColor-neutral-muted);color:var(--fgColor-default);display:inline-block;font:11px var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);line-height:10px;padding:var(--base-size-4);vertical-align:middle}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){font-weight:var(--base-text-weight-semibold, 600);line-height:1.25;margin-bottom:var(--base-size-16);margin-top:var(--base-size-24)}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){border-bottom:1px solid var(--borderColor-muted);font-size:1.5em;padding-bottom:.3em}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-size:1.25em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4){font-size:1em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-size:.875em}div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){color:var(--fgColor-muted);font-size:.85em;font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section p{margin-bottom:10px;margin-top:0}div#\:\$p > svg > foreignObject > section blockquote{border-left:.25em solid var(--borderColor-default);color:var(--fgColor-muted);margin:0;padding:0 1em}div#\:\$p > svg > foreignObject > section ol,div#\:\$p > svg > foreignObject > section ul{margin-bottom:0;margin-top:0;padding-left:2em}div#\:\$p > svg > foreignObject > section ol ol,div#\:\$p > svg > foreignObject > section ul ol{list-style-type:lower-roman}div#\:\$p > svg > foreignObject > section ol ol ol,div#\:\$p > svg > foreignObject > section ol ul ol,div#\:\$p > svg > foreignObject > section ul ol ol,div#\:\$p > svg > foreignObject > section ul ul ol{list-style-type:lower-alpha}div#\:\$p > svg > foreignObject > section dd{margin-left:0}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section samp,div#\:\$p > svg > foreignObject > section tt{font-family:var(--fontStack-monospace, ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace);font-size:12px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){margin-bottom:0;margin-top:0;word-wrap:normal}div#\:\$p > svg > foreignObject > section .octicon{display:inline-block;overflow:visible!important;vertical-align:text-bottom;fill:currentColor}div#\:\$p > svg > foreignObject > section input::-webkit-inner-spin-button,div#\:\$p > svg > foreignObject > section input::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none;margin:0}div#\:\$p > svg > foreignObject > section .mr-2{margin-right:var(--base-size-8, 8px)!important}div#\:\$p > svg > foreignObject > section:after,div#\:\$p > svg > foreignObject > section:before{display:table}div#\:\$p > svg > foreignObject > section:after{clear:both}div#\:\$p > svg > foreignObject > section>:first-child{margin-top:0!important}div#\:\$p > svg > foreignObject > section>:last-child{margin-bottom:0!important}div#\:\$p > svg > foreignObject > section a:not([href]){color:inherit;text-decoration:none}div#\:\$p > svg > foreignObject > section .absent{color:var(--fgColor-danger)}div#\:\$p > svg > foreignObject > section .anchor{float:left;line-height:1;margin-left:-20px;padding-right:var(--base-size-4)}div#\:\$p > svg > foreignObject > section .anchor:focus{outline:none}div#\:\$p > svg > foreignObject > section blockquote,div#\:\$p > svg > foreignObject > section details,div#\:\$p > svg > foreignObject > section dl,div#\:\$p > svg > foreignObject > section ol,div#\:\$p > svg > foreignObject > section p,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre),div#\:\$p > svg > foreignObject > section table,div#\:\$p > svg > foreignObject > section ul{margin-bottom:var(--base-size-16);margin-top:0}div#\:\$p > svg > foreignObject > section blockquote>:first-child{margin-top:0}div#\:\$p > svg > foreignObject > section blockquote>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) .octicon-link,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) .octicon-link{color:var(--fgColor-default);vertical-align:middle;visibility:hidden}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor{text-decoration:none}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5):hover .anchor .octicon-link,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6):hover .anchor .octicon-link{visibility:visible}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) code,div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) tt,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) code,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) tt,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) code,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) tt,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) code,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) tt,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) code,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) tt,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) code,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) tt{font-size:inherit;padding:0 .2em}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section summary :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section summary :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section summary :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section summary :is(h6, marp-h6){display:inline-block}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h3, marp-h3) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h4, marp-h4) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h5, marp-h5) .anchor,div#\:\$p > svg > foreignObject > section summary :is(h6, marp-h6) .anchor{margin-left:-40px}div#\:\$p > svg > foreignObject > section summary :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section summary :is(h2, marp-h2){border-bottom:0;padding-bottom:0}div#\:\$p > svg > foreignObject > section ol.no-list,div#\:\$p > svg > foreignObject > section ul.no-list{list-style-type:none;padding:0}div#\:\$p > svg > foreignObject > section ol[type="a s"]{list-style-type:lower-alpha}div#\:\$p > svg > foreignObject > section ol[type="A s"]{list-style-type:upper-alpha}div#\:\$p > svg > foreignObject > section ol[type="i s"]{list-style-type:lower-roman}div#\:\$p > svg > foreignObject > section ol[type="I s"]{list-style-type:upper-roman}div#\:\$p > svg > foreignObject > section div>ol:not([type]),div#\:\$p > svg > foreignObject > section ol[type="1"]{list-style-type:decimal}div#\:\$p > svg > foreignObject > section ol ol,div#\:\$p > svg > foreignObject > section ol ul,div#\:\$p > svg > foreignObject > section ul ol,div#\:\$p > svg > foreignObject > section ul ul{margin-bottom:0;margin-top:0}div#\:\$p > svg > foreignObject > section li>p{margin-top:var(--base-size-16)}div#\:\$p > svg > foreignObject > section li+li{margin-top:.25em}div#\:\$p > svg > foreignObject > section dl{padding:0}div#\:\$p > svg > foreignObject > section dl dt{font-size:1em;font-style:italic;font-weight:var(--base-text-weight-semibold, 600);margin-top:var(--base-size-16);padding:0}div#\:\$p > svg > foreignObject > section dl dd{margin-bottom:var(--base-size-16);padding:0 var(--base-size-16)}div#\:\$p > svg > foreignObject > section table th{font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section table td,div#\:\$p > svg > foreignObject > section table th{border:1px solid var(--borderColor-default);padding:6px 13px}div#\:\$p > svg > foreignObject > section table td>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section table tr{background-color:var(--bgColor-default);border-top:1px solid var(--borderColor-muted)}div#\:\$p > svg > foreignObject > section table tr:nth-child(2n){background-color:var(--bgColor-muted)}div#\:\$p > svg > foreignObject > section table img{background-color:transparent}div#\:\$p > svg > foreignObject > section img[align=right]{padding-left:20px}div#\:\$p > svg > foreignObject > section img[align=left]{padding-right:20px}div#\:\$p > svg > foreignObject > section .emoji{background-color:transparent;max-width:none;vertical-align:text-top}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame,div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame>:is(span, marp-span){display:block;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame>:is(span, marp-span){border:1px solid var(--borderColor-default);float:left;margin:13px 0 0;padding:7px;width:auto}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame :is(span, marp-span) img{display:block;float:left}div#\:\$p > svg > foreignObject > section :is(span, marp-span).frame :is(span, marp-span) :is(span, marp-span){clear:both;color:var(--fgColor-default);display:block;padding:5px 0 0}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center{clear:both;display:block;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center>:is(span, marp-span){display:block;margin:13px auto 0;overflow:hidden;text-align:center}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-center :is(span, marp-span) img{margin:0 auto;text-align:center}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right{clear:both;display:block;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right>:is(span, marp-span){display:block;margin:13px 0 0;overflow:hidden;text-align:right}div#\:\$p > svg > foreignObject > section :is(span, marp-span).align-right :is(span, marp-span) img{margin:0;text-align:right}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-left{display:block;float:left;margin-right:13px;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-left :is(span, marp-span){margin:13px 0 0}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-right{display:block;float:right;margin-left:13px;overflow:hidden}div#\:\$p > svg > foreignObject > section :is(span, marp-span).float-right>:is(span, marp-span){display:block;margin:13px auto 0;overflow:hidden;text-align:right}div#\:\$p > svg > foreignObject > section code,div#\:\$p > svg > foreignObject > section tt{background-color:var(--bgColor-neutral-muted);border-radius:6px;font-size:85%;margin:0;padding:.2em .4em;white-space:break-spaces}div#\:\$p > svg > foreignObject > section code br,div#\:\$p > svg > foreignObject > section tt br{display:none}div#\:\$p > svg > foreignObject > section del code{text-decoration:inherit}div#\:\$p > svg > foreignObject > section samp{font-size:85%}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) code{font-size:100%}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre)>code{background:transparent;border:0;margin:0;padding:0;white-space:pre;word-break:normal}div#\:\$p > svg > foreignObject > section .highlight{margin-bottom:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .highlight :is(pre, marp-pre){margin-bottom:0;word-break:normal}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){background-color:var(--bgColor-muted);border-radius:6px;color:var(--fgColor-default);font-size:85%;line-height:1.45;overflow:auto;padding:var(--base-size-16)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) code,div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) tt{display:inline;line-height:inherit;margin:0;max-width:auto;overflow:visible;padding:0;word-wrap:normal;background-color:transparent;border:0}div#\:\$p > svg > foreignObject > section .csv-data td,div#\:\$p > svg > foreignObject > section .csv-data th{font-size:12px;line-height:1;overflow:hidden;padding:5px;text-align:left;white-space:nowrap}div#\:\$p > svg > foreignObject > section .csv-data .blob-num{background:var(--bgColor-default);border:0;padding:10px var(--base-size-8) 9px;text-align:right}div#\:\$p > svg > foreignObject > section .csv-data tr{border-top:0}div#\:\$p > svg > foreignObject > section .csv-data th{background:var(--bgColor-muted);border-top:0;font-weight:var(--base-text-weight-semibold, 600)}div#\:\$p > svg > foreignObject > section [data-footnote-ref]:before{content:"["}div#\:\$p > svg > foreignObject > section [data-footnote-ref]:after{content:"]"}div#\:\$p > svg > foreignObject > section .footnotes{border-top:1px solid var(--borderColor-default);color:var(--fgColor-muted);font-size:12px}div#\:\$p > svg > foreignObject > section div#\:\$p > svg > foreignObject > section section.footnotes{--marpit-root-font-size:12px;}div#\:\$p > svg > foreignObject > section .footnotes ol,div#\:\$p > svg > foreignObject > section .footnotes ol ul{padding-left:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .footnotes ol ul{display:inline-block;margin-top:var(--base-size-16)}div#\:\$p > svg > foreignObject > section .footnotes li{position:relative}div#\:\$p > svg > foreignObject > section .footnotes li:target:before{border:2px solid var(--borderColor-accent-emphasis);border-radius:6px;bottom:calc(var(--base-size-8)*-1);content:"";left:calc(var(--base-size-24)*-1);pointer-events:none;position:absolute;right:calc(var(--base-size-8)*-1);top:calc(var(--base-size-8)*-1)}div#\:\$p > svg > foreignObject > section .footnotes li:target{color:var(--fgColor-default)}div#\:\$p > svg > foreignObject > section .footnotes .data-footnote-backref g-emoji{font-family:monospace}div#\:\$p > svg > foreignObject > section body:has(:modal){padding-right:var(--dialog-scrollgutter)!important}div#\:\$p > svg > foreignObject > section .pl-c{color:var(--color-prettylights-syntax-comment)}div#\:\$p > svg > foreignObject > section .pl-c1,div#\:\$p > svg > foreignObject > section .pl-s .pl-v{color:var(--color-prettylights-syntax-constant)}div#\:\$p > svg > foreignObject > section .pl-e,div#\:\$p > svg > foreignObject > section .pl-en{color:var(--color-prettylights-syntax-entity)}div#\:\$p > svg > foreignObject > section .pl-s .pl-s1,div#\:\$p > svg > foreignObject > section .pl-smi{color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section .pl-ent{color:var(--color-prettylights-syntax-entity-tag)}div#\:\$p > svg > foreignObject > section .pl-k{color:var(--color-prettylights-syntax-keyword)}div#\:\$p > svg > foreignObject > section .pl-pds,div#\:\$p > svg > foreignObject > section .pl-s,div#\:\$p > svg > foreignObject > section .pl-s .pl-pse .pl-s1,div#\:\$p > svg > foreignObject > section .pl-sr,div#\:\$p > svg > foreignObject > section .pl-sr .pl-cce,div#\:\$p > svg > foreignObject > section .pl-sr .pl-sra,div#\:\$p > svg > foreignObject > section .pl-sr .pl-sre{color:var(--color-prettylights-syntax-string)}div#\:\$p > svg > foreignObject > section .pl-smw,div#\:\$p > svg > foreignObject > section .pl-v{color:var(--color-prettylights-syntax-variable)}div#\:\$p > svg > foreignObject > section .pl-bu{color:var(--color-prettylights-syntax-brackethighlighter-unmatched)}div#\:\$p > svg > foreignObject > section .pl-ii{background-color:var(--color-prettylights-syntax-invalid-illegal-bg);color:var(--color-prettylights-syntax-invalid-illegal-text)}div#\:\$p > svg > foreignObject > section .pl-c2{background-color:var(--color-prettylights-syntax-carriage-return-bg);color:var(--color-prettylights-syntax-carriage-return-text)}div#\:\$p > svg > foreignObject > section .pl-sr .pl-cce{color:var(--color-prettylights-syntax-string-regexp);font-weight:700}div#\:\$p > svg > foreignObject > section .pl-ml{color:var(--color-prettylights-syntax-markup-list)}div#\:\$p > svg > foreignObject > section .pl-mh,div#\:\$p > svg > foreignObject > section .pl-mh .pl-en,div#\:\$p > svg > foreignObject > section .pl-ms{color:var(--color-prettylights-syntax-markup-heading);font-weight:700}div#\:\$p > svg > foreignObject > section .pl-mi{color:var(--color-prettylights-syntax-markup-italic);font-style:italic}div#\:\$p > svg > foreignObject > section .pl-mb{color:var(--color-prettylights-syntax-markup-bold);font-weight:700}div#\:\$p > svg > foreignObject > section .pl-md{background-color:var(--color-prettylights-syntax-markup-deleted-bg);color:var(--color-prettylights-syntax-markup-deleted-text)}div#\:\$p > svg > foreignObject > section .pl-mi1{background-color:var(--color-prettylights-syntax-markup-inserted-bg);color:var(--color-prettylights-syntax-markup-inserted-text)}div#\:\$p > svg > foreignObject > section .pl-mc{background-color:var(--color-prettylights-syntax-markup-changed-bg);color:var(--color-prettylights-syntax-markup-changed-text)}div#\:\$p > svg > foreignObject > section .pl-mi2{background-color:var(--color-prettylights-syntax-markup-ignored-bg);color:var(--color-prettylights-syntax-markup-ignored-text)}div#\:\$p > svg > foreignObject > section .pl-mdr{color:var(--color-prettylights-syntax-meta-diff-range);font-weight:700}div#\:\$p > svg > foreignObject > section .pl-ba{color:var(--color-prettylights-syntax-brackethighlighter-angle)}div#\:\$p > svg > foreignObject > section .pl-sg{color:var(--color-prettylights-syntax-sublimelinter-gutter-mark)}div#\:\$p > svg > foreignObject > section .pl-corl{color:var(--color-prettylights-syntax-constant-other-reference-link);text-decoration:underline}div#\:\$p > svg > foreignObject > section [role=button]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section [role=tabpanel][tabindex="0"]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section a:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section button:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section summary:focus:not(:focus-visible){box-shadow:none;outline:none}div#\:\$p > svg > foreignObject > section [tabindex="0"]:focus:not(:focus-visible),div#\:\$p > svg > foreignObject > section details-dialog:focus:not(:focus-visible){outline:none}div#\:\$p > svg > foreignObject > section g-emoji{display:inline-block;font-family:Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-size:1em;font-style:normal!important;font-weight:var(--base-text-weight-normal, 400);line-height:1;min-width:1ch;vertical-align:-.075em}div#\:\$p > svg > foreignObject > section g-emoji img{height:1em;width:1em}div#\:\$p > svg > foreignObject > section .task-list-item{list-style-type:none}div#\:\$p > svg > foreignObject > section .task-list-item label{font-weight:var(--base-text-weight-normal, 400)}div#\:\$p > svg > foreignObject > section .task-list-item.enabled label{cursor:pointer}div#\:\$p > svg > foreignObject > section .task-list-item+.task-list-item{margin-top:var(--base-size-4)}div#\:\$p > svg > foreignObject > section .task-list-item .handle{display:none}div#\:\$p > svg > foreignObject > section .task-list-item-checkbox{margin:0 .2em .25em -1.4em;vertical-align:middle}div#\:\$p > svg > foreignObject > section ul:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}div#\:\$p > svg > foreignObject > section ol:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}div#\:\$p > svg > foreignObject > section .contains-task-list:focus-within .task-list-item-convert-container,div#\:\$p > svg > foreignObject > section .contains-task-list:hover .task-list-item-convert-container{display:block;height:24px;overflow:visible;width:auto;clip:auto}div#\:\$p > svg > foreignObject > section ::-webkit-calendar-picker-indicator{filter:invert(50%)}div#\:\$p > svg > foreignObject > section .markdown-alert{border-left:.25em solid var(--borderColor-default);color:inherit;margin-bottom:var(--base-size-16);padding:var(--base-size-8) var(--base-size-16)}div#\:\$p > svg > foreignObject > section .markdown-alert>:first-child{margin-top:0}div#\:\$p > svg > foreignObject > section .markdown-alert>:last-child{margin-bottom:0}div#\:\$p > svg > foreignObject > section .markdown-alert .markdown-alert-title{align-items:center;display:flex;font-weight:var(--base-text-weight-medium, 500);line-height:1}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-note{border-left-color:var(--borderColor-accent-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-note .markdown-alert-title{color:var(--fgColor-accent)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-important{border-left-color:var(--borderColor-done-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-important .markdown-alert-title{color:var(--fgColor-done)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-warning{border-left-color:var(--borderColor-attention-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-warning .markdown-alert-title{color:var(--fgColor-attention)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-tip{border-left-color:var(--borderColor-success-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-tip .markdown-alert-title{color:var(--fgColor-success)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-caution{border-left-color:var(--borderColor-danger-emphasis)}div#\:\$p > svg > foreignObject > section .markdown-alert.markdown-alert-caution .markdown-alert-title{color:var(--fgColor-danger)}div#\:\$p > svg > foreignObject > section>:first-child>.heading-element:first-child{margin-top:0!important}div#\:\$p > svg > foreignObject > section .highlight :is(pre, marp-pre):has(+.zeroclipboard-container){min-height:52px}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1){color:var(--h1-color);font-size:1.6em}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){border-bottom:none}div#\:\$p > svg > foreignObject > section :is(h2, marp-h2){font-size:1.3em}div#\:\$p > svg > foreignObject > section :is(h3, marp-h3){font-size:1.1em}div#\:\$p > svg > foreignObject > section :is(h4, marp-h4){font-size:1.05em}div#\:\$p > svg > foreignObject > section :is(h5, marp-h5){font-size:1em}div#\:\$p > svg > foreignObject > section :is(h6, marp-h6){font-size:.9em}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1) strong,div#\:\$p > svg > foreignObject > section :is(h2, marp-h2) strong,div#\:\$p > svg > foreignObject > section :is(h3, marp-h3) strong,div#\:\$p > svg > foreignObject > section :is(h4, marp-h4) strong,div#\:\$p > svg > foreignObject > section :is(h5, marp-h5) strong,div#\:\$p > svg > foreignObject > section :is(h6, marp-h6) strong{color:var(--heading-strong-color);font-weight:inherit}div#\:\$p > svg > foreignObject > section :is(h1, marp-h1)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h2, marp-h2)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h3, marp-h3)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h4, marp-h4)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h5, marp-h5)::part(auto-scaling),div#\:\$p > svg > foreignObject > section :is(h6, marp-h6)::part(auto-scaling){max-height:563px}div#\:\$p > svg > foreignObject > section hr{height:0;padding-top:.25em}div#\:\$p > svg > foreignObject > section img{background-color:transparent}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre){border:1px solid var(--borderColor-default);line-height:1.15;overflow:visible}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre)::part(auto-scaling){max-height:529px}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs){color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-doctag),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-keyword),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta .hljs-keyword),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-template-tag),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-template-variable),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-type),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-variable.language_){color:var(--color-prettylights-syntax-keyword)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.class_),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.class_.inherited__),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-title.function_){color:var(--color-prettylights-syntax-entity)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-attr),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-attribute),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-literal),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-number),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-operator),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-attr),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-class),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-id),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-variable){color:var(--color-prettylights-syntax-constant)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-meta .hljs-string),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-regexp),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-string){color:var(--color-prettylights-syntax-string)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-built_in),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-symbol){color:var(--color-prettylights-syntax-variable)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-code),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-comment),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-formula){color:var(--color-prettylights-syntax-comment)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-name),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-quote),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-pseudo),div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-selector-tag){color:var(--color-prettylights-syntax-entity-tag)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-subst){color:var(--color-prettylights-syntax-storage-modifier-import)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-section){color:var(--color-prettylights-syntax-markup-heading);font-weight:700}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-bullet){color:var(--color-prettylights-syntax-markup-list)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-emphasis){color:var(--color-prettylights-syntax-markup-italic);font-style:italic}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-strong){color:var(--color-prettylights-syntax-markup-bold);font-weight:700}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-addition){background-color:var(--color-prettylights-syntax-markup-inserted-bg);color:var(--color-prettylights-syntax-markup-inserted-text)}div#\:\$p > svg > foreignObject > section :is(pre, marp-pre) :where(.hljs-deletion){background-color:var(--color-prettylights-syntax-markup-deleted-bg);color:var(--color-prettylights-syntax-markup-deleted-text)}div#\:\$p > svg > foreignObject > section footer,div#\:\$p > svg > foreignObject > section header{color:var(--header-footer-color);font-size:18px;left:30px;margin:0;position:absolute}div#\:\$p > svg > foreignObject > section header{top:21px}div#\:\$p > svg > foreignObject > section footer{bottom:21px}div#\:\$p > svg > foreignObject > section{--h1-color:#246;--header-footer-color:hsla(0,0%,40%,.75);--heading-strong-color:#48c;--paginate-color:#777;--base-size-4:4px;--base-size-8:8px;--base-size-16:16px;--base-size-24:24px;--base-size-40:40px;align-items:stretch;display:block;flex-flow:column nowrap;font-size:29px;height:720px;padding:78.5px;place-content:safe center center;width:1280px}div#\:\$p > svg > foreignObject > section{--marpit-root-font-size:29px;}div#\:\$p > svg > foreignObject > section:where(.invert){--h1-color:#cee7ff;--header-footer-color:hsla(0,0%,60%,.75);--heading-strong-color:#7bf;--paginate-color:#999;}div#\:\$p > svg > foreignObject > section>:last-child,div#\:\$p > svg > foreignObject > section[data-footer]>:nth-last-child(2){margin-bottom:0}div#\:\$p > svg > foreignObject > section>:first-child,div#\:\$p > svg > foreignObject > section>header:first-child+*{margin-top:0}div#\:\$p > svg > foreignObject > section:after{bottom:21px;color:var(--paginate-color);font-size:24px;padding:0;position:absolute;right:30px}div#\:\$p > svg > foreignObject > section:after{--marpit-root-font-size:24px;}div#\:\$p > svg > foreignObject > section[data-color] :is(h1, marp-h1),div#\:\$p > svg > foreignObject > section[data-color] :is(h2, marp-h2),div#\:\$p > svg > foreignObject > section[data-color] :is(h3, marp-h3),div#\:\$p > svg > foreignObject > section[data-color] :is(h4, marp-h4),div#\:\$p > svg > foreignObject > section[data-color] :is(h5, marp-h5),div#\:\$p > svg > foreignObject > section[data-color] :is(h6, marp-h6){color:currentcolor}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]{columns:initial!important;display:block!important;padding:0!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]::before, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"]::after, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"]::before, div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"]::after{display:none!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container]{all:initial;display:flex;flex-direction:row;height:100%;overflow:hidden;width:100%}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container][data-marpit-advanced-background-direction="vertical"]{flex-direction:column}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"][data-marpit-advanced-background-split] > div[data-marpit-advanced-background-container]{width:var(--marpit-advanced-background-split, 50%)}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"][data-marpit-advanced-background-split="right"] > div[data-marpit-advanced-background-container]{margin-left:calc(100% - var(--marpit-advanced-background-split, 50%))}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container] > figure{all:initial;background-position:center;background-repeat:no-repeat;background-size:cover;flex:auto;margin:0}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="background"] > div[data-marpit-advanced-background-container] > figure > figcaption{position:absolute;border:0;clip:rect(0, 0, 0, 0);height:1px;margin:-1px;overflow:hidden;padding:0;white-space:nowrap;width:1px}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="content"], div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="pseudo"]{background:transparent!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background="pseudo"], div#\:\$p > svg[data-marpit-svg] > foreignObject[data-marpit-advanced-background="pseudo"]{pointer-events:none!important}div#\:\$p > svg > foreignObject > section[data-marpit-advanced-background-split]{width:100%;height:100%}
|
11
|
+
</style></head><body><div class="bespoke-marp-osc"><button data-bespoke-marp-osc="prev" tabindex="-1" title="Previous slide">Previous slide</button><span data-bespoke-marp-osc="page"></span><button data-bespoke-marp-osc="next" tabindex="-1" title="Next slide">Next slide</button><button data-bespoke-marp-osc="fullscreen" tabindex="-1" title="Toggle fullscreen (f)">Toggle fullscreen</button><button data-bespoke-marp-osc="presenter" tabindex="-1" title="Open presenter view (p)">Open presenter view</button></div><div id=":$p"><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="1" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="1" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
12
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
13
|
+
|
14
|
+
<h1 id="%E8%B6%85%E5%85%A5%E9%96%80webassemblybr%E3%81%AE%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%92ruby%E3%81%A7%E6%9B%B8%E3%81%8F%E6%96%B9%E6%B3%95">超入門WebAssembly<br />(のランタイムをRubyで書く方法)</h1>
|
15
|
+
</section>
|
16
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="2" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
17
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
18
|
+
<h1 id="%E8%87%AA%E5%B7%B1%E7%B4%B9%E4%BB%8B">自己紹介</h1>
|
19
|
+
<ul>
|
20
|
+
<li>Uchio Kondo</li>
|
21
|
+
<li>@udzura</li>
|
22
|
+
</ul>
|
23
|
+
</section>
|
24
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="3" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="3" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
25
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
26
|
+
<h1 id="%E6%9C%80%E8%BF%91%E3%81%AE%E7%94%9F%E6%B4%BB">最近の生活</h1>
|
27
|
+
<ul>
|
28
|
+
<li>趣味: VM実装になりつつある...</li>
|
29
|
+
</ul>
|
30
|
+
</section>
|
31
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="4" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="4" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
32
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
33
|
+
<h1 id="mrubyedge">mruby/edge</h1>
|
34
|
+
<ul>
|
35
|
+
<li>Rustで書いたmrubyランタイム(mruby 3.x のバイトコードを実行可能)</li>
|
36
|
+
<li>基本的にmruby/cをベースにしている(一部必要な機能はmrubyから移植したい)</li>
|
37
|
+
</ul>
|
38
|
+
</section>
|
39
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="5" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="5" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
40
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
41
|
+
<h1 id="wardite">Wardite</h1>
|
42
|
+
<ul>
|
43
|
+
<li>Rubyで書いたWebAssemblyランタイム</li>
|
44
|
+
</ul>
|
45
|
+
</section>
|
46
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="6" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="6" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
47
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
48
|
+
<h1 id="%E4%BB%8A%E6%97%A5%E3%81%AF-wardite-%E3%81%AE%E8%A9%B1%E3%82%92%E3%81%97%E3%81%BE%E3%81%99">今日は Wardite の話をします</h1>
|
49
|
+
</section>
|
50
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="7" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="7" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
51
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
52
|
+
<h1 id="%E5%89%8D%E6%8F%90-webassembly-%E3%81%A8%E3%81%AF">前提: WebAssembly とは</h1>
|
53
|
+
</section>
|
54
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="8" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="8" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
55
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
56
|
+
<h1 id="webassembly-%E3%81%A8%E3%81%AF">WebAssembly とは</h1>
|
57
|
+
<ul>
|
58
|
+
<li>ブラウザで動くバイナリフォーマット</li>
|
59
|
+
<li>バイトコードをいろいろな言語(C, C++, Rust, ...)からコンパイルして、そのプログラムをブラウザの上で実行できる</li>
|
60
|
+
</ul>
|
61
|
+
</section>
|
62
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="9" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="9" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
63
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
64
|
+
<h1 id="webassembly-%E3%81%A8%E3%81%AF-1">WebAssembly とは</h1>
|
65
|
+
<ul>
|
66
|
+
<li><s>ブラウザで</s> いろいろなところで動くバイナリフォーマット</li>
|
67
|
+
</ul>
|
68
|
+
</section>
|
69
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="10" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="10" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
70
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
71
|
+
<h1 id="webassembly-%E3%81%AE%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88">WebAssembly のメリット</h1>
|
72
|
+
<ul>
|
73
|
+
<li>言語を選ばずにバイナリを作れる</li>
|
74
|
+
<li>そのバイナリは、ブラウザを中心にいろいろなところで動かせる
|
75
|
+
<ul>
|
76
|
+
<li>Write Once, Run Anywhere なのじゃよ...</li>
|
77
|
+
</ul>
|
78
|
+
</li>
|
79
|
+
<li>多くのランタイムで高速に動くことが期待できる
|
80
|
+
<ul>
|
81
|
+
<li>(安全性等もメリットですが今日は割愛)</li>
|
82
|
+
</ul>
|
83
|
+
</li>
|
84
|
+
</ul>
|
85
|
+
</section>
|
86
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="11" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="11" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
87
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
88
|
+
<h1 id="%E3%81%95%E3%81%A6wardite">さて、Wardite</h1>
|
89
|
+
</section>
|
90
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="12" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="12" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
91
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
92
|
+
<h1 id="wardite-%E3%81%AE%E7%89%B9%E5%BE%B4">Wardite の特徴</h1>
|
93
|
+
<ul>
|
94
|
+
<li>Pure Ruby 製
|
95
|
+
<ul>
|
96
|
+
<li>標準添付ライブラリ以外に動作上の依存ライブラリはなし</li>
|
97
|
+
</ul>
|
98
|
+
</li>
|
99
|
+
<li>Fully RBS annotated (rbs-inline)</li>
|
100
|
+
</ul>
|
101
|
+
</section>
|
102
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="13" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="13" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
103
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
104
|
+
<h1 id="%E3%81%AA%E3%81%9C-ruby-%E3%81%A7-webassembly-%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%AE%E3%81%8B">なぜ Ruby で WebAssembly ランタイムを書くのか</h1>
|
105
|
+
<ul>
|
106
|
+
<li>C拡張ベースの組み込みWebAssembly ランタイムなら実際結構ある
|
107
|
+
<ul>
|
108
|
+
<li>Wasmtime, Wasmedge, Wasmer, ...</li>
|
109
|
+
</ul>
|
110
|
+
</li>
|
111
|
+
<li>速度面でも強みはあるでしょう...</li>
|
112
|
+
</ul>
|
113
|
+
</section>
|
114
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="14" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="14" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
115
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
116
|
+
<h1 id="%E3%81%A7%E3%82%82">でも...</h1>
|
117
|
+
<ul>
|
118
|
+
<li>みなさん、このメッセージ好きですか?</li>
|
119
|
+
</ul>
|
120
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>Building native extensions. This could take a while...
|
121
|
+
</code></pre>
|
122
|
+
</section>
|
123
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="15" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="15" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
124
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
125
|
+
<h1 id="cf-wazero">cf. <a href="https://github.com/tetratelabs/wazero">wazero</a></h1>
|
126
|
+
<ul>
|
127
|
+
<li>Pure Go の WebAssembly ランタイム</li>
|
128
|
+
<li>cgo を避けたいGoのコミュニティで受け入れられている
|
129
|
+
<ul>
|
130
|
+
<li>wazero + tinygo でGoだけのプラグイン機構があったりする</li>
|
131
|
+
<li><a href="https://github.com/knqyf263/go-plugin">https://github.com/knqyf263/go-plugin</a></li>
|
132
|
+
</ul>
|
133
|
+
</li>
|
134
|
+
</ul>
|
135
|
+
</section>
|
136
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="16" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="16" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
137
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
138
|
+
<h1 id="pure-ruby%E3%81%A7%E3%81%82%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AE%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88">Pure Rubyであることのメリット</h1>
|
139
|
+
<ul>
|
140
|
+
<li>インストール・セットアップが簡単
|
141
|
+
<ul>
|
142
|
+
<li>Rubyが動けば動く、プラットフォームに依存しにくい</li>
|
143
|
+
</ul>
|
144
|
+
</li>
|
145
|
+
<li>さらに、Warditeを頑張って高速化することで色々貢献も出てきそう</li>
|
146
|
+
</ul>
|
147
|
+
<h2 id="%E3%81%A8%E3%81%AF%E3%81%84%E3%81%88">とはいえ</h2>
|
148
|
+
<ul>
|
149
|
+
<li>最初は「勉強目的」ではあった。思ったよりちゃんと動くので色んなユースケースを考えている</li>
|
150
|
+
</ul>
|
151
|
+
</section>
|
152
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="17" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="17" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
153
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
154
|
+
<h1 id="demo">demo</h1>
|
155
|
+
</section>
|
156
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="18" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="18" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
157
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
158
|
+
<h1 id="%E3%81%93%E3%81%86%E3%81%84%E3%81%86c%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99">こういうCのコードがあります</h1>
|
159
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-c"><span class="hljs-comment">/* fibonacci number in C */</span>
|
160
|
+
<span class="hljs-type">int</span> <span class="hljs-title function_">fib</span><span class="hljs-params">(<span class="hljs-type">int</span> n)</span> {
|
161
|
+
<span class="hljs-keyword">if</span> (n <= <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> n;
|
162
|
+
<span class="hljs-keyword">return</span> fib(n - <span class="hljs-number">1</span>) + fib(n - <span class="hljs-number">2</span>);
|
163
|
+
}
|
164
|
+
</code></pre>
|
165
|
+
</section>
|
166
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="19" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
167
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
168
|
+
<h1 id="%E3%81%93%E3%82%8C%E3%82%92webassembly%E3%81%AB%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%82%87%E3%81%86">これをWebAssemblyにコンパイルしてみましょう</h1>
|
169
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>$ clang --target=wasm32 \
|
170
|
+
--no-standard-libraries \
|
171
|
+
-Wl,--export-all -Wl,--no-entry \
|
172
|
+
-o fib.wasm \
|
173
|
+
fib.c
|
174
|
+
</code></pre>
|
175
|
+
</section>
|
176
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="20" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="20" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
177
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
178
|
+
<h1 id="%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%99">ブラウザで動かす</h1>
|
179
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-html"><span class="hljs-meta"><!DOCTYPE <span class="hljs-keyword">html</span>></span>
|
180
|
+
<span class="hljs-tag"><<span class="hljs-name">html</span>></span>
|
181
|
+
<span class="hljs-tag"><<span class="hljs-name">head</span>></span>
|
182
|
+
<span class="hljs-tag"><<span class="hljs-name">script</span>></span><span class="language-javascript">
|
183
|
+
<span class="hljs-title class_">WebAssembly</span>.<span class="hljs-title function_">instantiateStreaming</span>(<span class="hljs-title function_">fetch</span>(<span class="hljs-string">'./fib.wasm'</span>))
|
184
|
+
.<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">obj</span> =></span> {
|
185
|
+
<span class="hljs-title function_">alert</span>(<span class="hljs-string">`fib(20) = <span class="hljs-subst">${obj.instance.<span class="hljs-built_in">exports</span>.fib(<span class="hljs-number">20</span>)}</span>`</span>);
|
186
|
+
});
|
187
|
+
</span><span class="hljs-tag"></<span class="hljs-name">script</span>></span>
|
188
|
+
<span class="hljs-tag"></<span class="hljs-name">head</span>></span>
|
189
|
+
<span class="hljs-tag"><<span class="hljs-name">body</span>></span>
|
190
|
+
<span class="hljs-tag"></<span class="hljs-name">body</span>></span>
|
191
|
+
<span class="hljs-tag"></<span class="hljs-name">html</span>></span>
|
192
|
+
</code></pre>
|
193
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>$ ruby -run -e httpd . -p 8000
|
194
|
+
</code></pre>
|
195
|
+
</section>
|
196
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="21" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="21" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
197
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
198
|
+
<p><img src="./image.png" alt="" style="width:800px;" /></p>
|
199
|
+
</section>
|
200
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="22" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="22" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
201
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
202
|
+
<h1 id="%E6%89%8B%E5%85%83%E3%81%A7%E5%8B%95%E4%BD%9C">手元で動作</h1>
|
203
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>$ wasmtime --invoke fib fib.wasm 20
|
204
|
+
warning: using `--invoke` with a function that takes arguments
|
205
|
+
is experimental and may break in the future
|
206
|
+
warning: using `--invoke` with a function that returns values
|
207
|
+
is experimental and may break in the future
|
208
|
+
6765
|
209
|
+
</code></pre>
|
210
|
+
</section>
|
211
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="23" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="23" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
212
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
213
|
+
<h1 id="%E3%81%9D%E3%81%97%E3%81%A6-wardite%E3%81%A7%E3%82%82%E5%8B%95%E4%BD%9C">そして... Warditeでも動作</h1>
|
214
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>$ bundle exec wardite fib.wasm fib 20
|
215
|
+
return value: I32(6765)
|
216
|
+
</code></pre>
|
217
|
+
</section>
|
218
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="24" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="24" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
219
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
220
|
+
<h1 id="wardite-%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93">Wardite を支える技術</h1>
|
221
|
+
</section>
|
222
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="25" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="25" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
223
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
224
|
+
<h1 id="%E6%9C%80%E5%88%9D%E3%81%AE%E5%AE%9F%E8%A3%85">最初の実装</h1>
|
225
|
+
<ul>
|
226
|
+
<li>ゴリラさんの「<a href="https://zenn.dev/skanehira/books/writing-wasm-runtime-in-rust">RustでWasm Runtimeを実装する</a>」を参考に実装を開始した</li>
|
227
|
+
<li>元のコードがRustなので、強烈に型で守られたかったのと、RBS自体経験が浅いので勉強も兼ね、Full RBSを目指して移植していった</li>
|
228
|
+
</ul>
|
229
|
+
</section>
|
230
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="26" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="26" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
231
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
232
|
+
<h2 id="%E5%BD%93%E6%99%82%E3%81%AE%E3%83%A1%E3%83%A2%E3%82%92%E8%A6%8B%E3%81%AA%E3%81%8C%E3%82%89%E6%8C%AF%E3%82%8A%E8%BF%94%E3%82%8B%E3%81%A8">当時のメモを見ながら振り返ると</h2>
|
233
|
+
<ul>
|
234
|
+
<li>最初はとにかくデータ構造を把握しようとした
|
235
|
+
<ul>
|
236
|
+
<li><a href="https://zenn.dev/skanehira/books/writing-wasm-runtime-in-rust/viewer/04_wasm_binary_structure#wasm%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%81%AE%E5%85%A8%E4%BD%93%E5%83%8F">Wasmバイナリの全体像</a></li>
|
237
|
+
</ul>
|
238
|
+
</li>
|
239
|
+
<li>なぜかCの構造体で表現してるメモが...</li>
|
240
|
+
</ul>
|
241
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-c"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SectionHeader</span> {</span>
|
242
|
+
u8 code;
|
243
|
+
u32LEB128 size; <span class="hljs-comment">//先頭2バイトを除いたセクションデータのバイト数</span>
|
244
|
+
<span class="hljs-class"><span class="hljs-keyword">union</span> {</span>
|
245
|
+
u32LEB128 nr_types;
|
246
|
+
u32LEB128 nr_functions;
|
247
|
+
u32LEB128 nr_memories; <span class="hljs-comment">// num memoriesはメモリの個数だが、</span>
|
248
|
+
<span class="hljs-comment">// version 1の仕様ではメモリは1モジュールに1つしか定義できないので、</span>
|
249
|
+
<span class="hljs-comment">// 実質的にこの値は1で固定される。</span>
|
250
|
+
u32LEB128 nr_data_segments;
|
251
|
+
u32LEB128 nr_imports;
|
252
|
+
u32LEB128 nr_exports;
|
253
|
+
}
|
254
|
+
}
|
255
|
+
</code></pre>
|
256
|
+
</section>
|
257
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="27" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="27" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
258
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
259
|
+
<h2 id="section-size%E3%81%AFleb1281%E3%81%A7%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89%E3%81%95%E3%82%8C%E3%81%9Fu32">> section sizeはLEB128[1]でエンコードされたu32</h2>
|
260
|
+
<ul>
|
261
|
+
<li>LEB128っち何??????</li>
|
262
|
+
<li>DWARFの中とかで使われている可変長の数値表現らしい...</li>
|
263
|
+
</ul>
|
264
|
+
</section>
|
265
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="28" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="28" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
266
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
267
|
+
<h2 id="ruby%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3%81%84%E3%81%91%E3%81%AA%E3%81%84%E3%81%AE%E3%81%A7">Rubyで実装しないといけないので...</h2>
|
268
|
+
<ul>
|
269
|
+
<li>元の記事はnomのなんやライブラリを使っていたが、おれは自分で書いた</li>
|
270
|
+
</ul>
|
271
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-keyword">def</span> <span class="hljs-title function_">to_i_by_uleb128</span>(<span class="hljs-params">bytes</span>)
|
272
|
+
dest = <span class="hljs-number">0</span>
|
273
|
+
bytes.each_with_index <span class="hljs-keyword">do</span> |<span class="hljs-params">b, level</span>|
|
274
|
+
upper, lower = (b >> <span class="hljs-number">7</span>), (b & (<span class="hljs-number">1</span> << <span class="hljs-number">7</span>) - <span class="hljs-number">1</span>)
|
275
|
+
dest |= lower << (<span class="hljs-number">7</span> * level)
|
276
|
+
<span class="hljs-keyword">if</span> upper == <span class="hljs-number">0</span>
|
277
|
+
<span class="hljs-keyword">return</span> dest
|
278
|
+
<span class="hljs-keyword">end</span>
|
279
|
+
<span class="hljs-keyword">end</span>
|
280
|
+
<span class="hljs-keyword">raise</span> <span class="hljs-string">"unreachable"</span>
|
281
|
+
<span class="hljs-keyword">end</span>
|
282
|
+
|
283
|
+
to_i_by_uleb128 <span class="hljs-string">"\xB9\x64"</span>.unpack(<span class="hljs-string">"C*"</span>)
|
284
|
+
<span class="hljs-comment"># => 12857</span>
|
285
|
+
</code></pre>
|
286
|
+
</section>
|
287
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="29" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="29" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
288
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
289
|
+
<h2 id="%E3%81%93%E3%81%AE%E8%BE%BA%E3%82%8A%E3%81%AE%E6%83%85%E5%A0%B1%E3%82%92%E3%82%82%E3%81%A8%E3%81%AB%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%83%91%E3%83%BC%E3%82%B5%E3%82%92%E6%9B%B8%E3%81%8F">この辺りの情報をもとにバイナリパーサを書く</h2>
|
290
|
+
<ul>
|
291
|
+
<li>StringIO/File どちらも取る想定</li>
|
292
|
+
<li>バイト列を一つ一つ読み取る感じの実装になっている</li>
|
293
|
+
</ul>
|
294
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"> <span class="hljs-comment"># <span class="hljs-doctag">@rbs</span> return: Integer</span>
|
295
|
+
<span class="hljs-keyword">def</span> <span class="hljs-title function_">self</span>.preamble
|
296
|
+
asm = <span class="hljs-variable">@buf</span>.read <span class="hljs-number">4</span>
|
297
|
+
<span class="hljs-keyword">raise</span> <span class="hljs-title class_">LoadError</span>, <span class="hljs-string">"buffer too short"</span> <span class="hljs-keyword">if</span> !asm
|
298
|
+
<span class="hljs-keyword">raise</span> <span class="hljs-title class_">LoadError</span>, <span class="hljs-string">"invalid preamble"</span> asm != <span class="hljs-string">"\u0000asm"</span>
|
299
|
+
vstr = <span class="hljs-variable">@buf</span>.read(<span class="hljs-number">4</span>)
|
300
|
+
version = vstr.to_enum(<span class="hljs-symbol">:chars</span>)
|
301
|
+
.with_index
|
302
|
+
.inject(<span class="hljs-number">0</span>) {|<span class="hljs-params">dest, (c, i)</span>| dest |<span class="hljs-params"> (c.ord << i*8) }
|
303
|
+
<span class="hljs-keyword">raise</span> LoadError, "unsupported ver: #{version}" <span class="hljs-keyword">if</span> version != 1
|
304
|
+
|
305
|
+
version
|
306
|
+
<span class="hljs-keyword">end</span> # ...
|
307
|
+
</span></code></pre>
|
308
|
+
</section>
|
309
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="30" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="30" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
310
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
311
|
+
<h2 id="%E5%91%BD%E4%BB%A4%E3%82%92%E6%8A%8A%E6%8F%A1%E3%81%99%E3%82%8B">命令を把握する</h2>
|
312
|
+
<ul>
|
313
|
+
<li><a href="https://www.w3.org/TR/wasm-core-1/#a7-index-of-instructions">Wasm SpecのIndex of Instructions</a></li>
|
314
|
+
<li>メモには「思ったより多くなかった」って書いてあるが、いや多いでしょ(190個ぐらい)</li>
|
315
|
+
</ul>
|
316
|
+
</section>
|
317
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="31" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="31" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
318
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
319
|
+
<h2 id="webassembly-opcodes-table-%E3%81%8C%E4%BE%BF%E5%88%A9"><a href="https://pengowray.github.io/wasm-ops/">WebAssembly Opcodes Table</a> が便利</h2>
|
320
|
+
<p><img src="./image-1.png" alt="" style="width:1000px;" /></p>
|
321
|
+
</section>
|
322
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="32" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="32" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
323
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
324
|
+
<h2 id="%E9%A0%91%E5%BC%B5%E3%81%A3%E3%81%A6%E3%81%84%E3%81%9F%E9%81%8E%E5%8E%BB%E3%81%AE%E8%87%AA%E5%88%86">頑張っていた過去の自分</h2>
|
325
|
+
<ul>
|
326
|
+
<li>楽しそうですね</li>
|
327
|
+
</ul>
|
328
|
+
<p><img src="./image-2.png" alt="" style="width:550px;" /></p>
|
329
|
+
</section>
|
330
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="33" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="33" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
331
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
332
|
+
<h2 id="vm%E5%91%A8%E3%82%8A%E3%81%AE%E5%AE%9F%E8%A3%85">VM周りの実装</h2>
|
333
|
+
<ul>
|
334
|
+
<li><a href="https://webassembly.github.io/spec/core/exec/runtime.html#">Runtime Structure</a> も見ながら</li>
|
335
|
+
<li>Runtimeは以下のデータ構造を保持している
|
336
|
+
<ul>
|
337
|
+
<li>Store と呼ばれるglobal stateを表現した構造体</li>
|
338
|
+
<li>3つのスタック
|
339
|
+
<ul>
|
340
|
+
<li>Call Stack</li>
|
341
|
+
<li>Value Stack</li>
|
342
|
+
<li>Label Stack</li>
|
343
|
+
</ul>
|
344
|
+
</li>
|
345
|
+
</ul>
|
346
|
+
</li>
|
347
|
+
</ul>
|
348
|
+
</section>
|
349
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="34" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="34" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
350
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
351
|
+
<h2 id="ruby-%E3%81%A7%E6%9B%B8%E3%81%91%E3%81%B0%E3%81%93%E3%81%86%E3%81%84%E3%81%86%E6%84%9F%E3%81%98">Ruby で書けばこういう感じ</h2>
|
352
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Store</span>
|
353
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:funcs</span> <span class="hljs-comment">#: Array[WasmFunction|ExternalFunction]</span>
|
354
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:modules</span> <span class="hljs-comment">#: Hash[Symbol, wasmModule]</span>
|
355
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:memories</span> <span class="hljs-comment">#: Array[Memory]</span>
|
356
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:globals</span> <span class="hljs-comment">#: Array[Global]</span>
|
357
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:tables</span> <span class="hljs-comment">#: Array[Table]</span>
|
358
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:elements</span> <span class="hljs-comment">#: Array[[Symbol, Integer, Array[Integer]]]</span>
|
359
|
+
<span class="hljs-comment">#...</span>
|
360
|
+
</code></pre>
|
361
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Runtime</span>
|
362
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:store</span> <span class="hljs-comment">#: Store</span>
|
363
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:stack</span> <span class="hljs-comment">#: Array[wasmValue]</span>
|
364
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:call_stack</span> <span class="hljs-comment">#: Array[Frame]</span>
|
365
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:labels</span> <span class="hljs-comment">#: Array[Label]</span>
|
366
|
+
<span class="hljs-comment">#...</span>
|
367
|
+
</code></pre>
|
368
|
+
<ul>
|
369
|
+
<li>実際にはもっとごちゃついた関係になってる。整理したい...</li>
|
370
|
+
</ul>
|
371
|
+
</section>
|
372
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="35" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="35" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
373
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
374
|
+
<h2 id="%E5%91%BD%E4%BB%A4%E3%81%AF%E3%83%91%E3%83%BC%E3%82%B9%E3%81%97%E3%81%A6%E3%81%93%E3%81%86%E3%81%84%E3%81%86%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AB">命令はパースしてこういうクラスに</h2>
|
375
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Op</span>
|
376
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:namespace</span> <span class="hljs-comment">#: Symbol -- :i32/:i64/...</span>
|
377
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:code</span> <span class="hljs-comment">#: Symbol</span>
|
378
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:operand</span> <span class="hljs-comment">#: Array[operandItem]</span>
|
379
|
+
<span class="hljs-built_in">attr_accessor</span> <span class="hljs-symbol">:meta</span> <span class="hljs-comment">#: Hash[Symbol, Integer]</span>
|
380
|
+
<span class="hljs-keyword">end</span>
|
381
|
+
</code></pre>
|
382
|
+
<h2 id="vm%E3%81%AE%E5%91%BD%E4%BB%A4%E5%AE%9F%E8%A1%8C%E9%83%A8%E5%88%86">VMの命令実行部分</h2>
|
383
|
+
<ul>
|
384
|
+
<li>フレームに現在実行しているコード自体とその位置の情報がある</li>
|
385
|
+
<li>それを上からやっていく</li>
|
386
|
+
</ul>
|
387
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-comment"># <span class="hljs-doctag">@rbs</span> return: void</span>
|
388
|
+
<span class="hljs-keyword">def</span> <span class="hljs-title function_">execute!</span>
|
389
|
+
loop <span class="hljs-keyword">do</span>
|
390
|
+
cur_frame = <span class="hljs-variable language_">self</span>.call_stack.last <span class="hljs-comment">#: Frame</span>
|
391
|
+
<span class="hljs-keyword">if</span> !cur_frame
|
392
|
+
<span class="hljs-keyword">break</span>
|
393
|
+
<span class="hljs-keyword">end</span>
|
394
|
+
cur_frame.pc += <span class="hljs-number">1</span>
|
395
|
+
insn = cur_frame.body[cur_frame.pc]
|
396
|
+
<span class="hljs-keyword">if</span> !insn
|
397
|
+
<span class="hljs-keyword">break</span>
|
398
|
+
<span class="hljs-keyword">end</span>
|
399
|
+
eval_insn(cur_frame, insn)
|
400
|
+
<span class="hljs-keyword">end</span>
|
401
|
+
<span class="hljs-keyword">end</span>
|
402
|
+
</code></pre>
|
403
|
+
</section>
|
404
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="36" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="36" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
405
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
406
|
+
<h2 id="vm%E5%90%8D%E7%89%A9%E3%81%A7%E3%81%A3%E3%81%8B%E3%81%84case%E6%96%87">VM名物でっかいcase文</h2>
|
407
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-comment"># <span class="hljs-doctag">@rbs</span> frame: Frame</span>
|
408
|
+
<span class="hljs-comment"># <span class="hljs-doctag">@rbs</span> insn: Op</span>
|
409
|
+
<span class="hljs-comment"># <span class="hljs-doctag">@rbs</span> return: void</span>
|
410
|
+
<span class="hljs-keyword">def</span> <span class="hljs-title function_">eval_insn</span>(<span class="hljs-params">frame, insn</span>)
|
411
|
+
<span class="hljs-comment"># unmached namespace...</span>
|
412
|
+
<span class="hljs-keyword">case</span> insn.code
|
413
|
+
<span class="hljs-keyword">when</span> <span class="hljs-symbol">:unreachable</span>
|
414
|
+
<span class="hljs-keyword">raise</span> <span class="hljs-title class_">Unreachable</span>, <span class="hljs-string">"unreachable op"</span>
|
415
|
+
<span class="hljs-keyword">when</span> <span class="hljs-symbol">:nop</span>
|
416
|
+
<span class="hljs-keyword">return</span>
|
417
|
+
<span class="hljs-keyword">when</span> <span class="hljs-symbol">:br</span>
|
418
|
+
level = insn.operand[<span class="hljs-number">0</span>]
|
419
|
+
pc = do_branch(frame.labels, stack, level)
|
420
|
+
frame.pc = pc
|
421
|
+
<span class="hljs-comment">#...</span>
|
422
|
+
</code></pre>
|
423
|
+
</section>
|
424
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="37" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="37" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
425
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
426
|
+
<h2 id="%E3%81%A8%E3%81%93%E3%82%8D%E3%81%A7">ところで</h2>
|
427
|
+
<ul>
|
428
|
+
<li>i32/i64,f32/f64で共通の処理が多い</li>
|
429
|
+
<li>Generatorでまとめて作るようにした</li>
|
430
|
+
</ul>
|
431
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-keyword">when</span> <span class="hljs-symbol">:i32_add</span>
|
432
|
+
right, left = runtime.stack.pop, runtime.stack.pop
|
433
|
+
<span class="hljs-keyword">if</span> !right.is_a?(<span class="hljs-variable constant_">I32</span>) |<span class="hljs-params"></span>| !left.is_a?(<span class="hljs-variable constant_">I32</span>)
|
434
|
+
<span class="hljs-keyword">raise</span> <span class="hljs-title class_">EvalError</span>, <span class="hljs-string">"maybe empty or invalid stack"</span>
|
435
|
+
<span class="hljs-keyword">end</span>
|
436
|
+
runtime.stack.push(<span class="hljs-variable constant_">I32</span>(left.value + right.value))
|
437
|
+
|
438
|
+
<span class="hljs-comment"># ...</span>
|
439
|
+
<span class="hljs-keyword">when</span> <span class="hljs-symbol">:i64_add</span>
|
440
|
+
right, left = runtime.stack.pop, runtime.stack.pop
|
441
|
+
<span class="hljs-keyword">if</span> !right.is_a?(<span class="hljs-variable constant_">I64</span>) |<span class="hljs-params"></span>| !left.is_a?(<span class="hljs-variable constant_">I64</span>)
|
442
|
+
<span class="hljs-keyword">raise</span> <span class="hljs-title class_">EvalError</span>, <span class="hljs-string">"maybe empty or invalid stack"</span>
|
443
|
+
<span class="hljs-keyword">end</span>
|
444
|
+
runtime.stack.push(<span class="hljs-variable constant_">I64</span>(left.value + right.value))
|
445
|
+
</code></pre>
|
446
|
+
</section>
|
447
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="38" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="38" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
448
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
449
|
+
<h2 id="%E3%81%93%E3%81%86%E3%81%84%E3%81%86dsl%E3%81%A7%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%9F">こういうDSLで生成するようにした</h2>
|
450
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby">task <span class="hljs-symbol">:generate</span> <span class="hljs-keyword">do</span>
|
451
|
+
<span class="hljs-title class_">GenAlu</span>.execute(libdir + <span class="hljs-string">"/wardite/alu_i32.generated.rb"</span>, <span class="hljs-symbol">prefix:</span> <span class="hljs-string">"i32"</span>, <span class="hljs-symbol">defined_ops:</span> [
|
452
|
+
<span class="hljs-symbol">:load</span>,
|
453
|
+
<span class="hljs-symbol">:load8_s</span>,
|
454
|
+
<span class="hljs-symbol">:load8_u</span>,
|
455
|
+
<span class="hljs-symbol">:load16_s</span>,
|
456
|
+
<span class="hljs-symbol">:load16_u</span>,
|
457
|
+
<span class="hljs-symbol">:store</span>,
|
458
|
+
<span class="hljs-symbol">:store8</span>,
|
459
|
+
<span class="hljs-symbol">:store16</span>,
|
460
|
+
<span class="hljs-symbol">:const</span>,
|
461
|
+
<span class="hljs-symbol">:eqz</span>,
|
462
|
+
<span class="hljs-symbol">:eq</span>,
|
463
|
+
<span class="hljs-symbol">:ne</span>,
|
464
|
+
<span class="hljs-symbol">:lts</span>,
|
465
|
+
<span class="hljs-comment"># ...</span>
|
466
|
+
<span class="hljs-symbol">:rotr</span>,
|
467
|
+
])
|
468
|
+
</code></pre>
|
469
|
+
<ul>
|
470
|
+
<li>あとは <code>rake generate</code></li>
|
471
|
+
</ul>
|
472
|
+
</section>
|
473
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="39" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="39" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
474
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
475
|
+
<h2 id="%E3%81%AA%E3%81%9C%E3%82%B3%E3%83%BC%E3%83%89%E7%94%9F%E6%88%90">なぜコード生成?</h2>
|
476
|
+
<ul>
|
477
|
+
<li>メタプログラミングはやめとこかと思った
|
478
|
+
<ul>
|
479
|
+
<li>命令はすごい数そのパスを通るので、パフォーマンス面の心配</li>
|
480
|
+
<li>RBS/rbs-inline と相性が悪そうな予感(杞憂かもだが)</li>
|
481
|
+
</ul>
|
482
|
+
</li>
|
483
|
+
</ul>
|
484
|
+
</section>
|
485
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="40" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="40" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
486
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
487
|
+
<h2 id="%E9%96%A2%E6%95%B0%E3%82%92%E5%91%BC%E3%81%B6%E3%81%A8%E3%81%8D%E3%81%AE%E5%91%BD%E4%BB%A4%E3%81%AE%E8%A7%A3%E8%AA%AC">関数を呼ぶときの命令の解説</h2>
|
488
|
+
<ul>
|
489
|
+
<li>関数インスタンスを取り出してフレームをプッシュする</li>
|
490
|
+
</ul>
|
491
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-keyword">when</span> <span class="hljs-symbol">:call</span>
|
492
|
+
idx = insn.operand[<span class="hljs-number">0</span>]
|
493
|
+
fn = <span class="hljs-variable language_">self</span>.instance.store.funcs[idx]
|
494
|
+
<span class="hljs-keyword">case</span> fn
|
495
|
+
<span class="hljs-keyword">when</span> <span class="hljs-title class_">WasmFunction</span>
|
496
|
+
push_frame(fn)
|
497
|
+
<span class="hljs-comment"># ... call external</span>
|
498
|
+
<span class="hljs-keyword">else</span>
|
499
|
+
<span class="hljs-keyword">raise</span> <span class="hljs-title class_">GenericError</span>, <span class="hljs-string">"got a non-function pointer"</span>
|
500
|
+
<span class="hljs-keyword">end</span>
|
501
|
+
</code></pre>
|
502
|
+
</section>
|
503
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="41" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="41" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
504
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
505
|
+
<h2 id="%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%82%92%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E3%81%99%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89">フレームをプッシュするコード</h2>
|
506
|
+
<ul>
|
507
|
+
<li>初期変数(引数+コードで使う変数)をフレームに積む</li>
|
508
|
+
<li>pcを -1 に初期化</li>
|
509
|
+
<li>フレームをコールスタックに積む</li>
|
510
|
+
</ul>
|
511
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-keyword">def</span> <span class="hljs-title function_">push_frame</span>(<span class="hljs-params">wasm_function</span>)
|
512
|
+
local_start = stack.size - wasm_function.callsig.size
|
513
|
+
locals = stack[local_start..]
|
514
|
+
<span class="hljs-variable language_">self</span>.stack = drained_stack(local_start)
|
515
|
+
locals.concat(wasm_function.default_locals)
|
516
|
+
|
517
|
+
arity = wasm_function.retsig.size
|
518
|
+
frame = <span class="hljs-title class_">Frame</span>.new(-<span class="hljs-number">1</span>, stack.size, wasm_function.body, arity, locals)
|
519
|
+
<span class="hljs-variable language_">self</span>.call_stack.push(frame)
|
520
|
+
<span class="hljs-keyword">end</span>
|
521
|
+
</code></pre>
|
522
|
+
</section>
|
523
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="42" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="42" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
524
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
525
|
+
<h2 id="return%E3%81%99%E3%82%8B%E6%99%82">returnする時</h2>
|
526
|
+
<ul>
|
527
|
+
<li>stackを巻き戻します</li>
|
528
|
+
</ul>
|
529
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-keyword">def</span> <span class="hljs-title function_">stack_unwind</span>(<span class="hljs-params">sp, arity</span>)
|
530
|
+
<span class="hljs-keyword">if</span> arity > <span class="hljs-number">0</span>
|
531
|
+
<span class="hljs-keyword">if</span> arity > <span class="hljs-number">1</span>
|
532
|
+
<span class="hljs-keyword">raise</span> <span class="hljs-symbol">:</span><span class="hljs-symbol">:NotImplementedError</span>, <span class="hljs-string">"return artiy >= 2 not yet supported ;;"</span>
|
533
|
+
<span class="hljs-keyword">end</span>
|
534
|
+
value = stack.pop
|
535
|
+
<span class="hljs-variable language_">self</span>.stack = stack[<span class="hljs-number">0</span>...sp]
|
536
|
+
stack.push value
|
537
|
+
<span class="hljs-keyword">else</span>
|
538
|
+
<span class="hljs-variable language_">self</span>.stack = stack[<span class="hljs-number">0</span>...sp]
|
539
|
+
<span class="hljs-keyword">end</span>
|
540
|
+
<span class="hljs-keyword">end</span>
|
541
|
+
</code></pre>
|
542
|
+
</section>
|
543
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="43" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="43" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
544
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
545
|
+
<h2 id="wasi-p1-%E5%91%A8%E3%82%8A">WASI (p1) 周り</h2>
|
546
|
+
<ul>
|
547
|
+
<li>ただのimport moduleなのでまずその仕組みを作る</li>
|
548
|
+
<li>あとはこういう関数を地道に実装するだけやで...</li>
|
549
|
+
</ul>
|
550
|
+
<pre is="marp-pre" data-auto-scaling="downscale-only"><code class="language-ruby"><span class="hljs-keyword">class</span> <span class="hljs-title class_">WasiSnapshotPreview1</span>
|
551
|
+
<span class="hljs-comment"># <span class="hljs-doctag">@rbs</span> store: Store</span>
|
552
|
+
<span class="hljs-comment"># <span class="hljs-doctag">@rbs</span> args: Array[wasmValue]</span>
|
553
|
+
<span class="hljs-comment"># <span class="hljs-doctag">@rbs</span> return: Object</span>
|
554
|
+
<span class="hljs-keyword">def</span> <span class="hljs-title function_">random_get</span>(<span class="hljs-params">store, args</span>)
|
555
|
+
buf = args[<span class="hljs-number">0</span>].value.to_i
|
556
|
+
buflen = args[<span class="hljs-number">1</span>].value.to_i
|
557
|
+
randoms = <span class="hljs-title class_">SecureRandom</span>.random_bytes(buflen) <span class="hljs-comment">#: String</span>
|
558
|
+
memory = store.memories[<span class="hljs-number">0</span>]
|
559
|
+
memory.data[buf...(buf+buflen)] = randoms
|
560
|
+
<span class="hljs-number">0</span>
|
561
|
+
<span class="hljs-keyword">end</span>
|
562
|
+
<span class="hljs-keyword">end</span>
|
563
|
+
</code></pre>
|
564
|
+
<ul>
|
565
|
+
<li>ちなみに、hello worldだけなら <code>fd_write</code> のみでいける</li>
|
566
|
+
</ul>
|
567
|
+
</section>
|
568
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="44" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="44" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
569
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
570
|
+
<h1 id="%E3%81%A8%E3%81%84%E3%81%86%E6%84%9F%E3%81%98%E3%81%A7%E5%9C%B0%E9%81%93%E3%81%AB%E5%AE%9F%E8%A3%85%E4%B8%AD">という感じで地道に実装中</h1>
|
571
|
+
</section>
|
572
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="45" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="45" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
573
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
574
|
+
<h1 id="%E4%BB%96%E8%A9%B1%E3%81%97%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8">他、話していないこと</h1>
|
575
|
+
<ul>
|
576
|
+
<li>WASM specに対応したテスト実行の仕方
|
577
|
+
<ul>
|
578
|
+
<li><a href="https://udzura.hatenablog.jp/entry/2024/11/24/210124">ブログに少し書いた</a></li>
|
579
|
+
<li>超カバレッジ低い、i32系だけ。</li>
|
580
|
+
</ul>
|
581
|
+
</li>
|
582
|
+
<li>パフォーマンスチューニング
|
583
|
+
<ul>
|
584
|
+
<li><a href="https://udzura.hatenablog.jp/entry/2024/12/20/173728">ブログ書いた</a></li>
|
585
|
+
</ul>
|
586
|
+
</li>
|
587
|
+
</ul>
|
588
|
+
</section>
|
589
|
+
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="46" data-class="lead" data-paginate="true" data-background-color="#fff" data-background-image="url('https://example.com/background.png')" data-header="超入門WebAssembly(のランタイムをRubyで書く方法)" data-theme="default" lang="ja-JP" class="lead" data-marpit-pagination="46" style="--class:lead;--paginate:true;--background-color:#fff;--background-image:url('https://example.com/background.png');--header:超入門WebAssembly(のランタイムをRubyで書く方法);--theme:default;background-color:#fff;background-image:url('https://example.com/background.png');background-position:center;background-repeat:no-repeat;background-size:cover;" data-marpit-pagination-total="46">
|
590
|
+
<header>超入門WebAssembly(のランタイムをRubyで書く方法)</header>
|
591
|
+
<h1 id="%E4%BB%8A%E5%BE%8C%E3%81%AE%E5%B1%95%E6%9C%9B">今後の展望</h1>
|
592
|
+
<ul>
|
593
|
+
<li>WASI、specカバレッジ、パフォチューを地道に</li>
|
594
|
+
<li><code>ruby.wasm</code> を動かしたいぞん
|
595
|
+
<ul>
|
596
|
+
<li>ひとまずWASIサポート関数を増やすなど頑張りが必要</li>
|
597
|
+
<li>速度は... 我慢で対応(?)</li>
|
598
|
+
</ul>
|
599
|
+
</li>
|
600
|
+
<li>Component も読めるようにしたい
|
601
|
+
<ul>
|
602
|
+
<li>簡単なものならまあ...</li>
|
603
|
+
</ul>
|
604
|
+
</li>
|
605
|
+
<li>もちろん、松山でWarditeの話をしたいですね
|
606
|
+
<ul>
|
607
|
+
<li>mruby/edgeか、どちらかをね。</li>
|
608
|
+
</ul>
|
609
|
+
</li>
|
610
|
+
</ul>
|
611
|
+
</section>
|
612
|
+
<script>!function(){"use strict";const t={h1:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"1"},style:"display: block; font-size: 2em; margin-block-start: 0.67em; margin-block-end: 0.67em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h2:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"2"},style:"display: block; font-size: 1.5em; margin-block-start: 0.83em; margin-block-end: 0.83em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h3:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"3"},style:"display: block; font-size: 1.17em; margin-block-start: 1em; margin-block-end: 1em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h4:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"4"},style:"display: block; margin-block-start: 1.33em; margin-block-end: 1.33em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h5:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"5"},style:"display: block; font-size: 0.83em; margin-block-start: 1.67em; margin-block-end: 1.67em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h6:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"6"},style:"display: block; font-size: 0.67em; margin-block-start: 2.33em; margin-block-end: 2.33em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},span:{proto:()=>HTMLSpanElement},pre:{proto:()=>HTMLElement,style:"display: block; font-family: monospace; white-space: pre; margin: 1em 0; --marp-auto-scaling-white-space: pre;"}},e="data-marp-auto-scaling-wrapper",i="data-marp-auto-scaling-svg",n="data-marp-auto-scaling-container";class s extends HTMLElement{container;containerSize;containerObserver;svg;svgComputedStyle;svgPreserveAspectRatio="xMinYMid meet";wrapper;wrapperSize;wrapperObserver;constructor(){super();const t=t=>([e])=>{const{width:i,height:n}=e.contentRect;this[t]={width:i,height:n},this.updateSVGRect()};this.attachShadow({mode:"open"}),this.containerObserver=new ResizeObserver(t("containerSize")),this.wrapperObserver=new ResizeObserver(((...e)=>{t("wrapperSize")(...e),this.flushSvgDisplay()}))}static get observedAttributes(){return["data-downscale-only"]}connectedCallback(){this.shadowRoot.innerHTML=`\n<style>\n svg[${i}] { display: block; width: 100%; height: auto; vertical-align: top; }\n span[${n}] { display: table; white-space: var(--marp-auto-scaling-white-space, nowrap); width: max-content; }\n</style>\n<div ${e}>\n <svg part="svg" ${i}>\n <foreignObject><span ${n}><slot></slot></span></foreignObject>\n </svg>\n</div>\n `.split(/\n\s*/).join(""),this.wrapper=this.shadowRoot.querySelector(`div[${e}]`)??void 0;const t=this.svg;this.svg=this.wrapper?.querySelector(`svg[${i}]`)??void 0,this.svg!==t&&(this.svgComputedStyle=this.svg?window.getComputedStyle(this.svg):void 0),this.container=this.svg?.querySelector(`span[${n}]`)??void 0,this.observe()}disconnectedCallback(){this.svg=void 0,this.svgComputedStyle=void 0,this.wrapper=void 0,this.container=void 0,this.observe()}attributeChangedCallback(){this.observe()}flushSvgDisplay(){const{svg:t}=this;t&&(t.style.display="inline",requestAnimationFrame((()=>{t.style.display=""})))}observe(){this.containerObserver.disconnect(),this.wrapperObserver.disconnect(),this.wrapper&&this.wrapperObserver.observe(this.wrapper),this.container&&this.containerObserver.observe(this.container),this.svgComputedStyle&&this.observeSVGStyle(this.svgComputedStyle)}observeSVGStyle(t){const e=()=>{const i=(()=>{const e=t.getPropertyValue("--preserve-aspect-ratio");if(e)return e.trim();return`x${(({textAlign:t,direction:e})=>{if(t.endsWith("left"))return"Min";if(t.endsWith("right"))return"Max";if("start"===t||"end"===t){let i="rtl"===e;return"end"===t&&(i=!i),i?"Max":"Min"}return"Mid"})(t)}YMid meet`})();i!==this.svgPreserveAspectRatio&&(this.svgPreserveAspectRatio=i,this.updateSVGRect()),t===this.svgComputedStyle&&requestAnimationFrame(e)};e()}updateSVGRect(){let t=Math.ceil(this.containerSize?.width??0);const e=Math.ceil(this.containerSize?.height??0);void 0!==this.dataset.downscaleOnly&&(t=Math.max(t,this.wrapperSize?.width??0));const i=this.svg?.querySelector(":scope > foreignObject");if(i?.setAttribute("width",`${t}`),i?.setAttribute("height",`${e}`),this.svg&&(this.svg.setAttribute("viewBox",`0 0 ${t} ${e}`),this.svg.setAttribute("preserveAspectRatio",this.svgPreserveAspectRatio),this.svg.style.height=t<=0||e<=0?"0":""),this.container){const t=this.svgPreserveAspectRatio.toLowerCase();this.container.style.marginLeft=t.startsWith("xmid")||t.startsWith("xmax")?"auto":"0",this.container.style.marginRight=t.startsWith("xmi")?"auto":"0"}}}const r=(t,{attrs:e={},style:i})=>class extends t{constructor(...t){super(...t);for(const[t,i]of Object.entries(e))this.hasAttribute(t)||this.setAttribute(t,i);this._shadow()}static get observedAttributes(){return["data-auto-scaling"]}connectedCallback(){this._update()}attributeChangedCallback(){this._update()}_shadow(){if(!this.shadowRoot)try{this.attachShadow({mode:"open"})}catch(t){if(!(t instanceof Error&&"NotSupportedError"===t.name))throw t}return this.shadowRoot}_update(){const t=this._shadow();if(t){const e=i?`<style>:host { ${i} }</style>`:"";let n="<slot></slot>";const{autoScaling:s}=this.dataset;if(void 0!==s){n=`<marp-auto-scaling exportparts="svg:auto-scaling" ${"downscale-only"===s?"data-downscale-only":""}>${n}</marp-auto-scaling>`}t.innerHTML=e+n}}};let o;const a=Symbol();let l;const c="marpitSVGPolyfill:setZoomFactor,",d=Symbol(),h=Symbol();const g=()=>{const t="Apple Computer, Inc."===navigator.vendor,e=t?[u]:[],i={then:e=>(t?(async()=>{if(void 0===l){const t=document.createElement("canvas");t.width=10,t.height=10;const e=t.getContext("2d"),i=new Image(10,10),n=new Promise((t=>{i.addEventListener("load",(()=>t()))}));i.crossOrigin="anonymous",i.src="data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%2210%22%20viewBox%3D%220%200%201%201%22%3E%3CforeignObject%20width%3D%221%22%20height%3D%221%22%20requiredExtensions%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%3E%3Cdiv%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%20style%3D%22width%3A%201px%3B%20height%3A%201px%3B%20background%3A%20red%3B%20position%3A%20relative%22%3E%3C%2Fdiv%3E%3C%2FforeignObject%3E%3C%2Fsvg%3E",await n,e.drawImage(i,0,0),l=e.getImageData(5,5,1,1).data[3]<128}return l})().then((t=>{null==e||e(t?[u]:[])})):null==e||e([]),i)};return Object.assign(e,i)};let p,m;function u(t){const e="object"==typeof t&&t.target||document,i="object"==typeof t?t.zoom:t;window[h]||(Object.defineProperty(window,h,{configurable:!0,value:!0}),document.body.style.zoom=1.0001,document.body.offsetHeight,document.body.style.zoom=1,window.addEventListener("message",(({data:t,origin:e})=>{if(e===window.origin)try{if(t&&"string"==typeof t&&t.startsWith(c)){const[,e]=t.split(","),i=Number.parseFloat(e);Number.isNaN(i)||(m=i)}}catch(t){console.error(t)}})));let n=!1;Array.from(e.querySelectorAll("svg[data-marpit-svg]"),(t=>{var e,s,r,o;t.style.transform||(t.style.transform="translateZ(0)");const a=i||m||t.currentScale||1;p!==a&&(p=a,n=a);const l=t.getBoundingClientRect(),{length:c}=t.children;for(let i=0;i<c;i+=1){const n=t.children[i];if(n.getScreenCTM){const t=n.getScreenCTM();if(t){const i=null!==(s=null===(e=n.x)||void 0===e?void 0:e.baseVal.value)&&void 0!==s?s:0,c=null!==(o=null===(r=n.y)||void 0===r?void 0:r.baseVal.value)&&void 0!==o?o:0,d=n.children.length;for(let e=0;e<d;e+=1){const s=n.children[e];if("SECTION"===s.tagName){const{style:e}=s;e.transformOrigin||(e.transformOrigin=`${-i}px ${-c}px`),e.transform=`scale(${a}) matrix(${t.a}, ${t.b}, ${t.c}, ${t.d}, ${t.e-l.left}, ${t.f-l.top}) translateZ(0.0001px)`;break}}}}}})),!1!==n&&Array.from(e.querySelectorAll("iframe"),(({contentWindow:t})=>{null==t||t.postMessage(`${c}${n}`,"null"===window.origin?"*":window.origin)}))}function v({once:t=!1,target:e=document}={}){const i=function(t=document){if(t[d])return t[d];let e=!0;const i=()=>{e=!1,delete t[d]};Object.defineProperty(t,d,{configurable:!0,value:i});let n=[],s=!1;(async()=>{try{n=await g()}finally{s=!0}})();const r=()=>{for(const e of n)e({target:t});s&&0===n.length||e&&window.requestAnimationFrame(r)};return r(),i}(e);return t?(i(),()=>{}):i}p=1,m=void 0;const w=Symbol(),b=(e=document)=>{if("undefined"==typeof window)throw new Error("Marp Core's browser script is valid only in browser context.");if(((e=document)=>{const i=window[a];i||customElements.define("marp-auto-scaling",s);for(const n of Object.keys(t)){const s=`marp-${n}`,a=t[n].proto();(o??(o=!!document.createElement("div",{is:"marp-auto-scaling"}).outerHTML.startsWith("<div is"),o))&&a!==HTMLElement?i||customElements.define(s,r(a,{style:t[n].style}),{extends:n}):(i||customElements.define(s,r(HTMLElement,t[n])),e.querySelectorAll(`${n}[is="${s}"]`).forEach((t=>{t.outerHTML=t.outerHTML.replace(new RegExp(`^<${n}`,"i"),`<${s}`).replace(new RegExp(`</${n}>$`,"i"),`</${s}>`)})))}window[a]=!0})(e),e[w])return e[w];const i=v({target:e}),n=()=>{i(),delete e[w]},l=Object.assign(n,{cleanup:n,update:()=>b(e)});return Object.defineProperty(e,w,{configurable:!0,value:l}),l},y=document.currentScript;b(y?y.getRootNode():document)}();
|
613
|
+
</script></foreignObject></svg></div><div class="bespoke-marp-note" data-index="11" tabindex="0"><p>ちなみに標準添付ライブラリもstringioだけです。これも削っちゃおうかな?</p></div><div class="bespoke-marp-note" data-index="25" tabindex="0"><p>この発表本当にRubyのコードでないなw</p></div><div class="bespoke-marp-note" data-index="38" tabindex="0"><p>GoとRustを結構書いてきたので、別に生成すれば良くね?って自然な気持ちで思ったのが大きいかな...</p></div><script>/*!! License: https://unpkg.com/@marp-team/marp-cli@4.0.4/lib/bespoke.js.LICENSE.txt */
|
614
|
+
!function(){"use strict";function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t,n,r=(n||(n=1,t={from:function(e,t){var n,r=1===(e.parent||e).nodeType?e.parent||e:document.querySelector(e.parent||e),o=[].filter.call("string"==typeof e.slides?r.querySelectorAll(e.slides):e.slides||r.children,(function(e){return"SCRIPT"!==e.nodeName})),a={},i=function(e,t){return(t=t||{}).index=o.indexOf(e),t.slide=e,t},s=function(e,t){a[e]=(a[e]||[]).filter((function(e){return e!==t}))},c=function(e,t){return(a[e]||[]).reduce((function(e,n){return e&&!1!==n(t)}),!0)},l=function(e,t){o[e]&&(n&&c("deactivate",i(n,t)),n=o[e],c("activate",i(n,t)))},d=function(e,t){var r=o.indexOf(n)+e;c(e>0?"next":"prev",i(n,t))&&l(r,t)},u={off:s,on:function(e,t){return(a[e]||(a[e]=[])).push(t),s.bind(null,e,t)},fire:c,slide:function(e,t){if(!arguments.length)return o.indexOf(n);c("slide",i(o[e],t))&&l(e,t)},next:d.bind(null,1),prev:d.bind(null,-1),parent:r,slides:o,destroy:function(e){c("destroy",i(n,e)),a={}}};return(t||[]).forEach((function(e){e(u)})),n||l(0),u}}),t),o=e(r);const a=document.body,i=(...e)=>history.replaceState(...e),s="",c="presenter",l="next",d=["",c,l],u="bespoke-marp-",f=`data-${u}`,m=(e,{protocol:t,host:n,pathname:r,hash:o}=location)=>{const a=e.toString();return`${t}//${n}${r}${a?"?":""}${a}${o}`},g=()=>a.dataset.bespokeView,p=e=>new URLSearchParams(location.search).get(e),v=(e,t={})=>{const n={location,setter:i,...t},r=new URLSearchParams(n.location.search);for(const t of Object.keys(e)){const n=e[t];"string"==typeof n?r.set(t,n):r.delete(t)}try{n.setter({...window.history.state??{}},"",m(r,n.location))}catch(e){console.error(e)}},h=(()=>{const e="bespoke-marp";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch{return!1}})(),y=e=>{try{return localStorage.getItem(e)}catch{return null}},b=(e,t)=>{try{return localStorage.setItem(e,t),!0}catch{return!1}},w=e=>{try{return localStorage.removeItem(e),!0}catch{return!1}},x=(e,t)=>{const n="aria-hidden";t?e.setAttribute(n,"true"):e.removeAttribute(n)},k=e=>{e.parent.classList.add(`${u}parent`),e.slides.forEach((e=>e.classList.add(`${u}slide`))),e.on("activate",(t=>{const n=`${u}active`,r=t.slide,o=r.classList,a=!o.contains(n);if(e.slides.forEach((e=>{e.classList.remove(n),x(e,!0)})),o.add(n),x(r,!1),a){const e=`${n}-ready`;o.add(e),document.body.clientHeight,o.remove(e)}}))},$=e=>{let t=0,n=0;Object.defineProperty(e,"fragments",{enumerable:!0,value:e.slides.map((e=>[null,...e.querySelectorAll("[data-marpit-fragment]")]))});const r=r=>void 0!==e.fragments[t][n+r],o=(r,o)=>{t=r,n=o,e.fragments.forEach(((e,t)=>{e.forEach(((e,n)=>{if(null==e)return;const a=t<r||t===r&&n<=o;e.setAttribute(`${f}fragment`,(a?"":"in")+"active");const i=`${f}current-fragment`;t===r&&n===o?e.setAttribute(i,"current"):e.removeAttribute(i)}))})),e.fragmentIndex=o;const a={slide:e.slides[r],index:r,fragments:e.fragments[r],fragmentIndex:o};e.fire("fragment",a)};e.on("next",(({fragment:a=!0})=>{if(a){if(r(1))return o(t,n+1),!1;const a=t+1;e.fragments[a]&&o(a,0)}else{const r=e.fragments[t].length;if(n+1<r)return o(t,r-1),!1;const a=e.fragments[t+1];a&&o(t+1,a.length-1)}})),e.on("prev",(({fragment:a=!0})=>{if(r(-1)&&a)return o(t,n-1),!1;const i=t-1;e.fragments[i]&&o(i,e.fragments[i].length-1)})),e.on("slide",(({index:t,fragment:n})=>{let r=0;if(void 0!==n){const o=e.fragments[t];if(o){const{length:e}=o;r=-1===n?e-1:Math.min(Math.max(n,0),e-1)}}o(t,r)})),o(0,0)},E=document,L=()=>!(!E.fullscreenEnabled&&!E.webkitFullscreenEnabled),S=()=>!(!E.fullscreenElement&&!E.webkitFullscreenElement),P=e=>{e.fullscreen=()=>{L()&&(async()=>{S()?(E.exitFullscreen||E.webkitExitFullscreen)?.call(E):((e=E.body)=>{(e.requestFullscreen||e.webkitRequestFullscreen)?.call(e)})()})()},document.addEventListener("keydown",(t=>{"f"!==t.key&&"F11"!==t.key||t.altKey||t.ctrlKey||t.metaKey||!L()||(e.fullscreen(),t.preventDefault())}))},_=`${u}inactive`,T=(e=2e3)=>({parent:t,fire:n})=>{const r=t.classList,o=e=>n(`marp-${e?"":"in"}active`);let a;const i=()=>{a&&clearTimeout(a),a=setTimeout((()=>{r.add(_),o()}),e),r.contains(_)&&(r.remove(_),o(!0))};for(const e of["mousedown","mousemove","touchend"])document.addEventListener(e,i);setTimeout(i,0)},I=["AUDIO","BUTTON","INPUT","SELECT","TEXTAREA","VIDEO"],M=e=>{e.parent.addEventListener("keydown",(e=>{if(!e.target)return;const t=e.target;(I.includes(t.nodeName)||"true"===t.contentEditable)&&e.stopPropagation()}))},O=e=>{window.addEventListener("load",(()=>{for(const t of e.slides){const e=t.querySelector("marp-auto-scaling, [data-auto-scaling], [data-marp-fitting]");t.setAttribute(`${f}load`,e?"":"hideable")}}))},A=({interval:e=250}={})=>t=>{document.addEventListener("keydown",(e=>{if(" "===e.key&&e.shiftKey)t.prev();else if("ArrowLeft"===e.key||"ArrowUp"===e.key||"PageUp"===e.key)t.prev({fragment:!e.shiftKey});else if(" "!==e.key||e.shiftKey)if("ArrowRight"===e.key||"ArrowDown"===e.key||"PageDown"===e.key)t.next({fragment:!e.shiftKey});else if("End"===e.key)t.slide(t.slides.length-1,{fragment:-1});else{if("Home"!==e.key)return;t.slide(0)}else t.next();e.preventDefault()}));let n,r,o=0;t.parent.addEventListener("wheel",(a=>{let i=!1;const s=(e,t)=>{e&&(i=i||((e,t)=>((e,t)=>{const n="X"===t?"Width":"Height";return e[`client${n}`]<e[`scroll${n}`]})(e,t)&&((e,t)=>{const{overflow:n}=e,r=e[`overflow${t}`];return"auto"===n||"scroll"===n||"auto"===r||"scroll"===r})(getComputedStyle(e),t))(e,t)),e?.parentElement&&s(e.parentElement,t)};if(0!==a.deltaX&&s(a.target,"X"),0!==a.deltaY&&s(a.target,"Y"),i)return;a.preventDefault();const c=Math.sqrt(a.deltaX**2+a.deltaY**2);if(void 0!==a.wheelDelta){if(void 0===a.webkitForce&&Math.abs(a.wheelDelta)<40)return;if(a.deltaMode===a.DOM_DELTA_PIXEL&&c<4)return}else if(a.deltaMode===a.DOM_DELTA_PIXEL&&c<12)return;r&&clearTimeout(r),r=setTimeout((()=>{n=0}),e);const l=Date.now()-o<e,d=c<=n;if(n=c,l||d)return;let u;(a.deltaX>0||a.deltaY>0)&&(u="next"),(a.deltaX<0||a.deltaY<0)&&(u="prev"),u&&(t[u](),o=Date.now())}))},C=(e=`.${u}osc`)=>{const t=document.querySelector(e);if(!t)return()=>{};const n=(e,n)=>{t.querySelectorAll(`[${f}osc=${JSON.stringify(e)}]`).forEach(n)};return L()||n("fullscreen",(e=>e.style.display="none")),h||n("presenter",(e=>{e.disabled=!0,e.title="Presenter view is disabled due to restricted localStorage."})),e=>{t.addEventListener("click",(t=>{if(t.target instanceof HTMLElement){const{bespokeMarpOsc:n}=t.target.dataset;n&&t.target.blur();const r={fragment:!t.shiftKey};"next"===n?e.next(r):"prev"===n?e.prev(r):"fullscreen"===n?e?.fullscreen():"presenter"===n&&e.openPresenterView()}})),e.parent.appendChild(t),e.on("activate",(({index:t})=>{n("page",(n=>n.textContent=`Page ${t+1} of ${e.slides.length}`))})),e.on("fragment",(({index:t,fragments:r,fragmentIndex:o})=>{n("prev",(e=>e.disabled=0===t&&0===o)),n("next",(n=>n.disabled=t===e.slides.length-1&&o===r.length-1))})),e.on("marp-active",(()=>x(t,!1))),e.on("marp-inactive",(()=>x(t,!0))),L()&&(e=>{for(const t of["","webkit"])E.addEventListener(t+"fullscreenchange",e)})((()=>n("fullscreen",(e=>e.classList.toggle("exit",L()&&S())))))}},D=e=>{window.addEventListener("message",(t=>{if(t.origin!==window.origin)return;const[n,r]=t.data.split(":");if("navigate"===n){const[t,n]=r.split(",");let o=Number.parseInt(t,10),a=Number.parseInt(n,10)+1;a>=e.fragments[o].length&&(o+=1,a=0),e.slide(o,{fragment:a})}}))};var N,B,q,K,j,F,V,U={exports:{}},X=(N||(N=1,U.exports=(B=["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"],q=function(e){return String(e).replace(/[&<>"']/g,(function(e){return"&"+K[e]+";"}))},K={"&":"amp","<":"lt",">":"gt",'"':"quot","'":"apos"},j="dangerouslySetInnerHTML",F={className:"class",htmlFor:"for"},V={},function(e,t){var n=[],r="";t=t||{};for(var o=arguments.length;o-- >2;)n.push(arguments[o]);if("function"==typeof e)return t.children=n.reverse(),e(t);if(e){if(r+="<"+e,t)for(var a in t)!1!==t[a]&&null!=t[a]&&a!==j&&(r+=" "+(F[a]?F[a]:q(a))+'="'+q(t[a])+'"');r+=">"}if(-1===B.indexOf(e)){if(t[j])r+=t[j].__html;else for(;n.length;){var i=n.pop();if(i)if(i.pop)for(var s=i.length;s--;)n.push(i[s]);else r+=!0===V[i]?i:q(i)}r+=e?"</"+e+">":""}return V[r]=!0,r})),U.exports),H=e(X);const R=({children:e})=>H(null,null,...e),W=`${u}presenter-`,J={container:`${W}container`,dragbar:`${W}dragbar-container`,next:`${W}next`,nextContainer:`${W}next-container`,noteContainer:`${W}note-container`,noteWrapper:`${W}note-wrapper`,noteButtons:`${W}note-buttons`,infoContainer:`${W}info-container`,infoPage:`${W}info-page`,infoPageText:`${W}info-page-text`,infoPagePrev:`${W}info-page-prev`,infoPageNext:`${W}info-page-next`,noteButtonsBigger:`${W}note-bigger`,noteButtonsSmaller:`${W}note-smaller`,infoTime:`${W}info-time`,infoTimer:`${W}info-timer`},Y=e=>{const{title:t}=document;document.title="[Presenter view]"+(t?` - ${t}`:"");const n={},r=e=>(n[e]=n[e]||document.querySelector(`.${e}`),n[e]);document.body.appendChild((e=>{const t=document.createElement("div");return t.className=J.container,t.appendChild(e),t.insertAdjacentHTML("beforeend",H(R,null,H("div",{class:J.nextContainer},H("iframe",{class:J.next,src:"?view=next"})),H("div",{class:J.dragbar}),H("div",{class:J.noteContainer},H("div",{class:J.noteWrapper}),H("div",{class:J.noteButtons},H("button",{class:J.noteButtonsSmaller,tabindex:"-1",title:"Smaller notes font size"},"Smaller notes font size"),H("button",{class:J.noteButtonsBigger,tabindex:"-1",title:"Bigger notes font size"},"Bigger notes font size"))),H("div",{class:J.infoContainer},H("div",{class:J.infoPage},H("button",{class:J.infoPagePrev,tabindex:"-1",title:"Previous"},"Previous"),H("span",{class:J.infoPageText}),H("button",{class:J.infoPageNext,tabindex:"-1",title:"Next"},"Next")),H("time",{class:J.infoTime,title:"Current time"}),H("time",{class:J.infoTimer,title:"Timer"})))),t})(e.parent)),(e=>{let t=!1;r(J.dragbar).addEventListener("mousedown",(()=>{t=!0,r(J.dragbar).classList.add("active")})),window.addEventListener("mouseup",(()=>{t=!1,r(J.dragbar).classList.remove("active")})),window.addEventListener("mousemove",(e=>{if(!t)return;const n=e.clientX/document.documentElement.clientWidth*100;r(J.container).style.setProperty("--bespoke-marp-presenter-split-ratio",`${Math.max(0,Math.min(100,n))}%`)})),r(J.nextContainer).addEventListener("click",(()=>e.next()));const n=r(J.next),o=(a=n,(e,t)=>a.contentWindow?.postMessage(`navigate:${e},${t}`,"null"===window.origin?"*":window.origin));var a;n.addEventListener("load",(()=>{r(J.nextContainer).classList.add("active"),o(e.slide(),e.fragmentIndex),e.on("fragment",(({index:e,fragmentIndex:t})=>o(e,t)))}));const i=document.querySelectorAll(".bespoke-marp-note");i.forEach((e=>{e.addEventListener("keydown",(e=>e.stopPropagation())),r(J.noteWrapper).appendChild(e)})),e.on("activate",(()=>i.forEach((t=>t.classList.toggle("active",t.dataset.index==e.slide())))));let s=0;const c=e=>{s=Math.max(-5,s+e),r(J.noteContainer).style.setProperty("--bespoke-marp-note-font-scale",(1.2**s).toFixed(4))},l=()=>c(1),d=()=>c(-1),u=r(J.noteButtonsBigger),f=r(J.noteButtonsSmaller);u.addEventListener("click",(()=>{u.blur(),l()})),f.addEventListener("click",(()=>{f.blur(),d()})),document.addEventListener("keydown",(e=>{"+"===e.key&&l(),"-"===e.key&&d()}),!0),e.on("activate",(({index:t})=>{r(J.infoPageText).textContent=`${t+1} / ${e.slides.length}`}));const m=r(J.infoPagePrev),g=r(J.infoPageNext);m.addEventListener("click",(t=>{m.blur(),e.prev({fragment:!t.shiftKey})})),g.addEventListener("click",(t=>{g.blur(),e.next({fragment:!t.shiftKey})})),e.on("fragment",(({index:t,fragments:n,fragmentIndex:r})=>{m.disabled=0===t&&0===r,g.disabled=t===e.slides.length-1&&r===n.length-1}));let p=new Date;const v=()=>{const e=new Date,t=e=>`${Math.floor(e)}`.padStart(2,"0"),n=e.getTime()-p.getTime(),o=t(n/1e3%60),a=t(n/1e3/60%60),i=t(n/36e5%24);r(J.infoTime).textContent=e.toLocaleTimeString(),r(J.infoTimer).textContent=`${i}:${a}:${o}`};v(),setInterval(v,250),r(J.infoTimer).addEventListener("click",(()=>{p=new Date}))})(e)},z=e=>{if(!(e=>e.syncKey&&"string"==typeof e.syncKey)(e))throw new Error("The current instance of Bespoke.js is invalid for Marp bespoke presenter plugin.");Object.defineProperties(e,{openPresenterView:{enumerable:!0,value:G},presenterUrl:{enumerable:!0,get:Q}}),h&&document.addEventListener("keydown",(t=>{"p"!==t.key||t.altKey||t.ctrlKey||t.metaKey||(t.preventDefault(),e.openPresenterView())}))};function G(){const{max:e,floor:t}=Math,n=e(t(.85*window.innerWidth),640),r=e(t(.85*window.innerHeight),360);return window.open(this.presenterUrl,W+this.syncKey,`width=${n},height=${r},menubar=no,toolbar=no`)}function Q(){const e=new URLSearchParams(location.search);return e.set("view","presenter"),e.set("sync",this.syncKey),m(e)}const Z=e=>{const t=g();return t===l&&e.appendChild(document.createElement("span")),{[s]:z,[c]:Y,[l]:D}[t]},ee=e=>{e.on("activate",(t=>{document.querySelectorAll(".bespoke-progress-parent > .bespoke-progress-bar").forEach((n=>{n.style.flexBasis=100*t.index/(e.slides.length-1)+"%"}))}))},te=e=>{const t=Number.parseInt(e,10);return Number.isNaN(t)?null:t},ne=(e={})=>{const t={history:!0,...e};return e=>{let n=!0;const r=e=>{const t=n;try{return n=!0,e()}finally{n=t}},o=(t={fragment:!0})=>{let n=t.fragment?te(p("f")||""):null;((t,n)=>{const{min:r,max:o}=Math,{fragments:a,slides:i}=e,s=o(0,r(t,i.length-1)),c=o(0,r(n||0,a[s].length-1));s===e.slide()&&c===e.fragmentIndex||e.slide(s,{fragment:c})})((()=>{if(location.hash){const[t]=location.hash.slice(1).split(":~:");if(/^\d+$/.test(t))return(te(t)??1)-1;const r=document.getElementById(t)||document.querySelector(`a[name="${CSS.escape(t)}"]`);if(r){const{length:t}=e.slides;for(let o=0;o<t;o+=1)if(e.slides[o].contains(r)){const t=e.fragments?.[o],a=r.closest("[data-marpit-fragment]");if(t&&a){const e=t.indexOf(a);e>=0&&(n=e)}return o}}}return 0})(),n)};e.on("fragment",(({index:e,fragmentIndex:r})=>{n||v({f:0===r||r.toString()},{location:{...location,hash:`#${e+1}`},setter:(...e)=>t.history?history.pushState(...e):history.replaceState(...e)})})),setTimeout((()=>{o(),window.addEventListener("hashchange",(()=>r((()=>{o({fragment:!1}),v({f:void 0})})))),window.addEventListener("popstate",(()=>{n||r((()=>o()))})),n=!1}),0)}},re=(e={})=>{const t=e.key||window.history.state?.marpBespokeSyncKey||Math.random().toString(36).slice(2),n=`bespoke-marp-sync-${t}`;var r;r={marpBespokeSyncKey:t},v({},{setter:(e,...t)=>i({...e,...r},...t)});const o=()=>{const e=y(n);return e?JSON.parse(e):Object.create(null)},a=e=>{const t=o(),r={...t,...e(t)};return b(n,JSON.stringify(r)),r},s=()=>{window.removeEventListener("pageshow",s),a((e=>({reference:(e.reference||0)+1})))};return e=>{s(),Object.defineProperty(e,"syncKey",{value:t,enumerable:!0});let r=!0;setTimeout((()=>{e.on("fragment",(e=>{r&&a((()=>({index:e.index,fragmentIndex:e.fragmentIndex})))}))}),0),window.addEventListener("storage",(t=>{if(t.key===n&&t.oldValue&&t.newValue){const n=JSON.parse(t.oldValue),o=JSON.parse(t.newValue);if(n.index!==o.index||n.fragmentIndex!==o.fragmentIndex)try{r=!1,e.slide(o.index,{fragment:o.fragmentIndex,forSync:!0})}finally{r=!0}}}));const i=()=>{const{reference:e}=o();void 0===e||e<=1?w(n):a((()=>({reference:e-1})))};window.addEventListener("pagehide",(e=>{e.persisted&&window.addEventListener("pageshow",s),i()})),e.on("destroy",i)}},{PI:oe,abs:ae,sqrt:ie,atan2:se}=Math,ce={passive:!0},le=({slope:e=-.7,swipeThreshold:t=30}={})=>n=>{let r;const o=n.parent,a=e=>{const t=o.getBoundingClientRect();return{x:e.pageX-(t.left+t.right)/2,y:e.pageY-(t.top+t.bottom)/2}};o.addEventListener("touchstart",(({touches:e})=>{r=1===e.length?a(e[0]):void 0}),ce),o.addEventListener("touchmove",(e=>{if(r)if(1===e.touches.length){e.preventDefault();const t=a(e.touches[0]),n=t.x-r.x,o=t.y-r.y;r.delta=ie(ae(n)**2+ae(o)**2),r.radian=se(n,o)}else r=void 0})),o.addEventListener("touchend",(o=>{if(r){if(r.delta&&r.delta>=t&&r.radian){const t=(r.radian-e+oe)%(2*oe)-oe;n[t<0?"next":"prev"](),o.stopPropagation()}r=void 0}}),ce)},de=new Map;de.clear(),de.set("none",{backward:{both:void 0,incoming:void 0,outgoing:void 0},forward:{both:void 0,incoming:void 0,outgoing:void 0}});const ue={both:"",outgoing:"outgoing-",incoming:"incoming-"},fe={forward:"",backward:"-backward"},me=e=>`--marp-bespoke-transition-animation-${e}`,ge=e=>`--marp-transition-${e}`,pe=me("name"),ve=me("duration"),he=e=>new Promise((t=>{const n={},r=document.createElement("div"),o=e=>{r.remove(),t(e)};r.addEventListener("animationstart",(()=>o(n))),Object.assign(r.style,{animationName:e,animationDuration:"1s",animationFillMode:"both",animationPlayState:"paused",position:"absolute",pointerEvents:"none"}),document.body.appendChild(r);const a=getComputedStyle(r).getPropertyValue(ge("duration"));a&&(n.defaultDuration=a),((e,t)=>{requestAnimationFrame((()=>{e.style.animationPlayState="running",requestAnimationFrame((()=>t(void 0)))}))})(r,o)})),ye=async e=>de.has(e)?de.get(e):(e=>{const t={},n=[];for(const[r,o]of Object.entries(ue))for(const[a,i]of Object.entries(fe)){const s=`marp-${o}transition${i}-${e}`;n.push(he(s).then((e=>{t[a]=t[a]||{},t[a][r]=e?{...e,name:s}:void 0})))}return Promise.all(n).then((()=>t))})(e).then((t=>(de.set(e,t),t))),be=e=>Object.values(e).flatMap(Object.values).every((e=>!e)),we=(e,{type:t,backward:n})=>{const r=e[n?"backward":"forward"],o=(()=>{const e=r[t],n=e=>({[pe]:e.name});if(e)return n(e);if(r.both){const e=n(r.both);return"incoming"===t&&(e[me("direction")]="reverse"),e}})();return!o&&n?we(e,{type:t,backward:!1}):o||{[pe]:"__bespoke_marp_transition_no_animation__"}},xe=e=>{if(e)try{const t=JSON.parse(e);if((e=>{if("object"!=typeof e)return!1;const t=e;return"string"==typeof t.name&&(void 0===t.duration||"string"==typeof t.duration)})(t))return t}catch{}},ke="_tSId",$e="_tA",Ee="bespoke-marp-transition-warming-up",Le=window.matchMedia("(prefers-reduced-motion: reduce)"),Se="__bespoke_marp_transition_reduced_outgoing__",Pe="__bespoke_marp_transition_reduced_incoming__",_e={forward:{both:void 0,incoming:{name:Pe},outgoing:{name:Se}},backward:{both:void 0,incoming:{name:Pe},outgoing:{name:Se}}},Te=e=>{if(!document.startViewTransition)return;const t=t=>(void 0!==t&&(e._tD=t),e._tD);let n;t(!1),((...e)=>{const t=[...new Set(e).values()];return Promise.all(t.map((e=>ye(e)))).then()})(...Array.from(document.querySelectorAll("section[data-transition], section[data-transition-back]")).flatMap((e=>[e.dataset.transition,e.dataset.transitionBack].flatMap((e=>{const t=xe(e);return[t?.name,t?.builtinFallback?`__builtin__${t.name}`:void 0]})).filter((e=>!!e))))).then((()=>{document.querySelectorAll("style").forEach((e=>{e.innerHTML=e.innerHTML.replace(/--marp-transition-duration:[^;}]*[;}]/g,(e=>e.slice(0,-1)+"!important"+e.slice(-1)))}))}));const r=(n,{back:r,cond:o})=>a=>{const i=t();if(i)return!!a[$e]||!("object"!=typeof i||(i.skipTransition(),!a.forSync));if(!o(a))return!0;const s=e.slides[e.slide()],c=()=>a.back??r,l="data-transition"+(c()?"-back":""),d=s.querySelector(`section[${l}]`);if(!d)return!0;const u=xe(d.getAttribute(l)??void 0);return!u||((async(e,{builtinFallback:t=!0}={})=>{let n=await ye(e);if(be(n)){if(!t)return;return n=await ye(`__builtin__${e}`),be(n)?void 0:n}return n})(u.name,{builtinFallback:u.builtinFallback}).then((e=>{if(!e){t(!0);try{n(a)}finally{t(!1)}return}let r=e;Le.matches&&(console.warn("Use a constant animation to transition because preferring reduced motion by viewer has detected."),r=_e);const o=document.getElementById(ke);o&&o.remove();const i=document.createElement("style");i.id=ke,document.head.appendChild(i),((e,t)=>{const n=[`:root{${ge("direction")}:${t.backward?-1:1};}`,":root:has(.bespoke-marp-inactive){cursor:none;}"],r=t=>{const n=e[t].both?.defaultDuration||e[t].outgoing?.defaultDuration||e[t].incoming?.defaultDuration;return"forward"===t?n:n||r("forward")},o=t.duration||r(t.backward?"backward":"forward");void 0!==o&&n.push(`::view-transition-group(*){${ve}:${o};}`);const a=e=>Object.entries(e).map((([e,t])=>`${e}:${t};`)).join("");return n.push(`::view-transition-old(root){${a(we(e,{...t,type:"outgoing"}))}}`,`::view-transition-new(root){${a(we(e,{...t,type:"incoming"}))}}`),n})(r,{backward:c(),duration:u.duration}).forEach((e=>i.sheet?.insertRule(e)));const s=document.documentElement.classList;s.add(Ee);let l=!1;const d=()=>{l||(n(a),l=!0,s.remove(Ee))},f=()=>{t(!1),i.remove(),s.remove(Ee)};try{t(!0);const e=document.startViewTransition(d);t(e),e.finished.finally(f)}catch(e){console.error(e),d(),f()}})),!1)};e.on("prev",r((t=>e.prev({...t,[$e]:!0})),{back:!0,cond:e=>e.index>0&&!((e.fragment??1)&&n.fragmentIndex>0)})),e.on("next",r((t=>e.next({...t,[$e]:!0})),{cond:t=>t.index+1<e.slides.length&&!(n.fragmentIndex+1<n.fragments.length)})),setTimeout((()=>{e.on("slide",r((t=>e.slide(t.index,{...t,[$e]:!0})),{cond:t=>{const n=e.slide();return t.index!==n&&(t.back=t.index<n,!0)}}))}),0),e.on("fragment",(e=>{n=e}))};let Ie;const Me=()=>(void 0===Ie&&(Ie="wakeLock"in navigator&&navigator.wakeLock),Ie),Oe=async()=>{const e=Me();if(e)try{return await e.request("screen")}catch(e){console.warn(e)}return null},Ae=async()=>{if(!Me())return;let e;const t=()=>{e&&"visible"===document.visibilityState&&Oe()};for(const e of["visibilitychange","fullscreenchange"])document.addEventListener(e,t);return e=await Oe(),e};((e=document.getElementById(":$p"))=>{(()=>{const e=p("view");a.dataset.bespokeView=e===l||e===c?e:""})();const t=(e=>{const t=p(e);return v({[e]:void 0}),t})("sync")||void 0;o.from(e,((...e)=>{const t=d.findIndex((e=>g()===e));return e.map((([e,n])=>e[t]&&n)).filter((e=>e))})([[1,1,0],re({key:t})],[[1,1,1],Z(e)],[[1,1,0],M],[[1,1,1],k],[[1,0,0],T()],[[1,1,1],O],[[1,1,1],ne({history:!1})],[[1,1,0],A()],[[1,1,0],P],[[1,0,0],ee],[[1,1,0],le()],[[1,0,0],C()],[[1,0,0],Te],[[1,1,1],$],[[1,1,0],Ae]))})()}();</script></body></html>
|