detached d7ef3db

Merge branch 'feat/x9' into feat/xwayland-builtin

commit
d7ef3dbee481613ad1682c2eccf389978bc81392
author
brice · · 2026-10-22 16:26 UTC
committer
brice · · 2026-10-22 17:55 UTC
merge of
46fd2a1 + 1f67695 · diff against the first parent
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
20 files · +5357 -2967
M .mockery.yml +5 -0
@@ -87,6 +87,11 @@ packages:
87 dir: internal/adapters/wayland87 dir: internal/adapters/wayland
88 pkgname: wayland88 pkgname: wayland
89 filename: acquire_poller_mock_test.go89 filename: acquire_poller_mock_test.go
90+ xwmSelection:
91+ config:
92+ dir: internal/adapters/wayland
93+ pkgname: wayland
94+ filename: xwm_selection_mock_test.go
90 syncobjDevice:95 syncobjDevice:
91 config:96 config:
92 dir: internal/adapters/wayland97 dir: internal/adapters/wayland
M Makefile +1 -1
@@ -70,7 +70,7 @@ adapter-imports:
70 [ -z "$$bad" ] || { echo "$$bad"; echo 'adapter imports another adapter: use ports or a shared library (Makefile ADAPTER_LIBS)' >&2; exit 1; }70 [ -z "$$bad" ] || { echo "$$bad"; echo 'adapter imports another adapter: use ports or a shared library (Makefile ADAPTER_LIBS)' >&2; exit 1; }
71 # Fast, mandatory guards for tiled content publications and SHM copies.71 # Fast, mandatory guards for tiled content publications and SHM copies.
72 perf-check:72 perf-check:
73- CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations|TestPropertyUnchangedAllocations|TestDispatchAllocations|TestConfigureFlushAllocations|TestFocusAllocations|TestSpaceAllocations|TestUnmanagedGeometryAllocations|TestFocusInUnmanagedAllocations|TestUnmanagedPublishAllocations|TestUnmanagedHitAllocations|TestOverrideMovedUnchangedAllocations|TestFullscreenConfigureAllocations|TestKeyboardGrabSyncAllocations)$$' -count=173+ CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations|TestPropertyUnchangedAllocations|TestDispatchAllocations|TestConfigureFlushAllocations|TestFocusAllocations|TestSpaceAllocations|TestUnmanagedGeometryAllocations|TestFocusInUnmanagedAllocations|TestUnmanagedPublishAllocations|TestUnmanagedHitAllocations|TestOverrideMovedUnchangedAllocations|TestFullscreenConfigureAllocations|TestKeyboardGrabSyncAllocations|TestSelectionCopyAllocations|TestSelectionCopyAllocationsWaylandToX|TestSelectionINCRChunkAllocations)$$' -count=1
74 CGO_ENABLED=0 go test -tags xturbo_poison ./internal/adapters/wayland/xwm -count=174 CGO_ENABLED=0 go test -tags xturbo_poison ./internal/adapters/wayland/xwm -count=1
75 check: vet test arch fakes-check log-check perf-check75 check: vet test arch fakes-check log-check perf-check
76 76
M internal/adapters/wayland/clipboard.go +5 -0
@@ -37,6 +37,8 @@ type clipSource struct {
37 // used: the source was set, rejected or dragged; it cannot be set37 // used: the source was set, rejected or dragged; it cannot be set
38 // again and takes no more MIME types.38 // again and takes no more MIME types.
39 used bool39 used bool
40+ // x11: the offer is an X client's selection (xSource), not a Wayland one.
41+ x11 bool
40 // res is the wl_data_source (nil for the other protocols); actions are42 // res is the wl_data_source (nil for the other protocols); actions are
41 // its set_actions, for drag and drop only (dnd.go).43 // its set_actions, for drag and drop only (dnd.go).
42 res *wayland.DataSource44 res *wayland.DataSource
@@ -105,6 +107,7 @@ func (s *Server) setSelection(kind int, src *clipSource) {
105 if src != nil && src != s.selections[kind] && src.alive() {107 if src != nil && src != s.selections[kind] && src.alive() {
106 src.cancel()108 src.cancel()
107 }109 }
110+ s.exposeToX(kind, nil) // X clients must not read a protected selection
108 return111 return
109 }112 }
110 old := s.selections[kind]113 old := s.selections[kind]
@@ -116,6 +119,7 @@ func (s *Server) setSelection(kind int, src *clipSource) {
116 old.cancel()119 old.cancel()
117 }120 }
118 s.announceAll(kind)121 s.announceAll(kind)
122+ s.exposeToX(kind, src)
119 }123 }
120 124
121 // announceAll sends the selection of kind to the focused client and to125 // announceAll sends the selection of kind to the focused client and to
@@ -187,6 +191,7 @@ func (s *Server) sourceGone(src *clipSource) {
187 if s.selections[kind] == src {191 if s.selections[kind] == src {
188 s.selections[kind] = nil192 s.selections[kind] = nil
189 s.announceAll(kind)193 s.announceAll(kind)
194+ s.exposeToX(kind, nil)
190 }195 }
191 }196 }
192 }197 }
A internal/adapters/wayland/clipboard_xwm.go +93 -0
@@ -0,0 +1,93 @@
1+package wayland
2+
3+import (
4+ "slices"
5+
6+ "golang.org/x/sys/unix"
7+)
8+
9+// The text clipboard bridge between Wayland and the built-in XWM. An X
10+// client's selection becomes a clipSource like any other (xSource); a Wayland
11+// selection is exposed to X through exposeToX. The X protocol side lives in
12+// the xwm package; nothing of it reaches core or ports.
13+
14+// xwmSelection is the XWM as the clipboard sees it.
15+type xwmSelection interface {
16+ // WaylandSelection: a Wayland client owns kind with these MIME types;
17+ // nil mimes: none does (or it is protected).
18+ WaylandSelection(kind int, mimes []string)
19+ // SelectionReceive hands the XWM the write end of a reader's pipe (it
20+ // closes it) to fill with the X selection as mime.
21+ SelectionReceive(kind int, mime string, fd int)
22+}
23+
24+// xSource is the clipSource of an X-owned selection: no Wayland client, the
25+// data comes from the XWM. It is valid while it is the current X source.
26+func (s *Server) xSource(kind int, mimes []string) *clipSource {
27+ src := &clipSource{mimes: slices.Clone(mimes), used: true, x11: true}
28+ src.alive = func() bool { return s.xsel[kind] == src }
29+ src.cancel = func() {}
30+ src.send = func(mime string, fd int) {
31+ x := s.xwmSel
32+ if x == nil {
33+ return
34+ }
35+ // receive closes its fd after send: the XWM gets its own.
36+ dup, err := unix.FcntlInt(uintptr(fd), unix.F_DUPFD_CLOEXEC, 0)
37+ if err != nil {
38+ return
39+ }
40+ x.SelectionReceive(kind, mime, dup)
41+ }
42+ return src
43+}
44+
45+// setXSelection is the XWM's report: an X client owns kind (mimes), or none
46+// does. A Wayland owner that already replaced the X one is never clobbered.
47+func (s *Server) setXSelection(kind int, mimes []string) {
48+ if len(mimes) == 0 {
49+ cur := s.xsel[kind]
50+ s.xsel[kind] = nil
51+ if cur != nil && s.selections[kind] == cur {
52+ s.setSelection(kind, nil)
53+ }
54+ return
55+ }
56+ src := s.xSource(kind, mimes)
57+ s.xsel[kind] = src
58+ s.setSelection(kind, src)
59+}
60+
61+// exposeToX tells the XWM what Wayland offers. An X source is not exposed
62+// back (it is X's own); nil withdraws.
63+func (s *Server) exposeToX(kind int, src *clipSource) {
64+ if s.xwmSel == nil {
65+ return
66+ }
67+ if src == nil || src.x11 {
68+ s.xwmSel.WaylandSelection(kind, nil)
69+ return
70+ }
71+ s.xwmSel.WaylandSelection(kind, src.mimes)
72+}
73+
74+// xSelectionRead returns a non-blocking read end of the Wayland selection
75+// kind as mime, or -1.
76+func (s *Server) xSelectionRead(kind int, mime string) int {
77+ src := s.selections[kind]
78+ if src == nil || src.x11 || s.protected() || !src.alive() || !slices.Contains(src.mimes, mime) {
79+ return -1
80+ }
81+ var p [2]int
82+ if unix.Pipe2(p[:], unix.O_CLOEXEC) != nil {
83+ return -1
84+ }
85+ if unix.SetNonblock(p[0], true) != nil {
86+ unix.Close(p[0])
87+ unix.Close(p[1])
88+ return -1
89+ }
90+ src.send(mime, p[1])
91+ unix.Close(p[1])
92+ return p[0]
93+}
A internal/adapters/wayland/clipboard_xwm_test.go +147 -0
@@ -0,0 +1,147 @@
1+package wayland
2+
3+import (
4+ "testing"
5+ "time"
6+
7+ "github.com/bnema/go-wayland-bindings/server/wayland"
8+ "github.com/stretchr/testify/mock"
9+ "golang.org/x/sys/unix"
10+)
11+
12+func onDisplay(t *testing.T, s *Server, f func()) {
13+ t.Helper()
14+ if !s.display.Do(f) {
15+ t.Fatal("display stopped")
16+ }
17+}
18+
19+// receiveVia asks the offer for mime into a fresh pipe and returns its read end.
20+func receiveVia(t *testing.T, cc *clipClient, offer uint32, mime string) int {
21+ t.Helper()
22+ var fds [2]int
23+ if err := unix.Pipe2(fds[:], unix.O_CLOEXEC); err != nil {
24+ t.Fatal(err)
25+ }
26+ t.Cleanup(func() { unix.Close(fds[0]) })
27+ if err := wireRequest(cc.c, offer, uint16(wayland.DataOfferRequestReceive), []int{fds[1]}, mime); err != nil {
28+ t.Fatal(err)
29+ }
30+ _ = unix.Close(fds[1])
31+ if err := cc.c.Roundtrip(); err != nil {
32+ t.Fatal(err)
33+ }
34+ return fds[0]
35+}
36+
37+// An X selection reaches the focused client and not the others, is replaced
38+// when a Wayland client copies (and is then not read back from X), and is
39+// never read while the session is protected.
40+func TestXSelectionReachesWaylandClients(t *testing.T) {
41+ s, events, commands, dir := keyboardServer(t)
42+ state := installSecurity(t, s)
43+ xm := newMockxwmSelection(t)
44+ onDisplay(t, s, func() { s.xwmSel = xm })
45+ a := newClipClient(t, s, dir, events)
46+ b := newClipClient(t, s, dir, events)
47+ a.focus(t, commands)
48+
49+ // X owns CLIPBOARD: the focused client gets an offer, the other none.
50+ xm.EXPECT().WaylandSelection(selClipboard, []string(nil)).Maybe()
51+ onDisplay(t, s, func() { s.setXSelection(selClipboard, []string{"text/plain;charset=utf-8", "UTF8_STRING"}) })
52+ offer, ok := a.selection(t)
53+ if !ok || offer == 0 {
54+ t.Fatalf("focused client got no X offer: %d %v", offer, ok)
55+ }
56+ if id, ok := b.selection(t); ok {
57+ t.Fatalf("unfocused client got %d", id)
58+ }
59+
60+ // Reading reaches the XWM with a pipe it owns.
61+ got := make(chan string, 1)
62+ xm.EXPECT().SelectionReceive(selClipboard, "UTF8_STRING", mock.Anything).Run(func(_ int, mime string, fd int) {
63+ _, _ = unix.Write(fd, []byte("from x"))
64+ _ = unix.Close(fd)
65+ got <- mime
66+ }).Once()
67+ r := receiveVia(t, a, offer, "UTF8_STRING")
68+ select {
69+ case <-got:
70+ case <-time.After(2 * time.Second):
71+ t.Fatal("XWM never asked to receive")
72+ }
73+ buf := make([]byte, 16)
74+ n, err := unix.Read(r, buf)
75+ if err != nil || string(buf[:n]) != "from x" {
76+ t.Fatalf("pipe: %q %v", buf[:n], err)
77+ }
78+
79+ // Focus follows: b gets the X offer too (focus replay).
80+ if id := b.focus(t, commands); id == 0 {
81+ t.Fatal("no X offer on focus")
82+ }
83+
84+ // A Wayland copy replaces it and is exposed to X.
85+ xm.EXPECT().WaylandSelection(selClipboard, []string{"text/plain"}).Once()
86+ b.copy(t)
87+ if id, ok := b.selection(t); !ok || id == 0 {
88+ t.Fatal("copy gave no offer")
89+ }
90+ // X clearing afterwards never clobbers the Wayland owner.
91+ onDisplay(t, s, func() { s.setXSelection(selClipboard, nil) })
92+ if id, ok := b.selection(t); ok && id == 0 {
93+ t.Fatal("the Wayland selection was cleared by X")
94+ }
95+
96+ // Protection: the X offer is not readable, and X cannot read Wayland.
97+ onDisplay(t, s, func() { s.setXSelection(selClipboard, []string{"UTF8_STRING"}) })
98+ protect(t, s, state, 1, true)
99+ var fd int
100+ onDisplay(t, s, func() { fd = s.xSelectionRead(selClipboard, "text/plain") })
101+ if fd >= 0 {
102+ unix.Close(fd)
103+ t.Fatal("protected selection readable by X")
104+ }
105+ protect(t, s, state, 2, false)
106+}
107+
108+// A Wayland client's text selection is read for X through a pipe it fills.
109+func TestXSelectionReadFromWayland(t *testing.T) {
110+ s, events, commands, dir := keyboardServer(t)
111+ xm := newMockxwmSelection(t)
112+ onDisplay(t, s, func() { s.xwmSel = xm })
113+ a := newClipClient(t, s, dir, events)
114+ a.focus(t, commands)
115+ xm.EXPECT().WaylandSelection(selClipboard, []string(nil)).Maybe() // teardown destroys the source
116+ xm.EXPECT().WaylandSelection(selClipboard, []string{"text/plain"}).Once()
117+ src := a.copy(t)
118+ var fd int
119+ onDisplay(t, s, func() { fd = s.xSelectionRead(selClipboard, "text/plain") })
120+ if fd < 0 {
121+ t.Fatal("no read end")
122+ }
123+ defer unix.Close(fd)
124+ deadline := time.After(2 * time.Second)
125+ for len(src.sends) == 0 {
126+ if err := a.c.Roundtrip(); err != nil {
127+ t.Fatal(err)
128+ }
129+ select {
130+ case <-deadline:
131+ t.Fatal("source never asked to send")
132+ case <-time.After(5 * time.Millisecond):
133+ }
134+ }
135+ buf := make([]byte, 16)
136+ n, err := unix.Read(fd, buf)
137+ if err != nil || string(buf[:n]) != "pasted" {
138+ t.Fatalf("read %q %v", buf[:n], err)
139+ }
140+ onDisplay(t, s, func() {
141+ fd2 := s.xSelectionRead(selClipboard, "image/png")
142+ if fd2 >= 0 {
143+ unix.Close(fd2)
144+ t.Error("unoffered mime readable")
145+ }
146+ })
147+}
M internal/adapters/wayland/server.go +3 -0
@@ -313,6 +313,8 @@ type Server struct {
313 cursorReady chan struct{}313 cursorReady chan struct{}
314 // Clipboard and primary selection (clipboard.go).314 // Clipboard and primary selection (clipboard.go).
315 selections [2]*clipSource315 selections [2]*clipSource
316+ xsel [2]*clipSource // the current X-owned source per kind, if any
317+ xwmSel xwmSelection // the XWM's clipboard side; nil without one
316 // Drag and drop (dnd.go): the drag in progress, drops waiting for318 // Drag and drop (dnd.go): the drag in progress, drops waiting for
317 // their finish, and each client's data devices.319 // their finish, and each client's data devices.
318 dnd *dndState320 dnd *dndState
@@ -607,6 +609,7 @@ func (s *Server) Run(ctx context.Context) error {
607 if s.xwm != nil {609 if s.xwm != nil {
608 s.xwm.CloseConn()610 s.xwm.CloseConn()
609 s.xwm = nil611 s.xwm = nil
612+ s.xwmSel = nil
610 }613 }
611 s.forgetXwayland()614 s.forgetXwayland()
612 s.stopSecurityContexts()615 s.stopSecurityContexts()
M internal/adapters/wayland/x11window.go +24 -2
@@ -1,6 +1,8 @@
1 package wayland1 package wayland
2 2
3 import (3 import (
4+ "time"
5+
4 "github.com/bnema/go-wayland-bindings/server/wayland"6 "github.com/bnema/go-wayland-bindings/server/wayland"
5 "github.com/bnema/go-wayland-bindings/server/xwaylandshell"7 "github.com/bnema/go-wayland-bindings/server/xwaylandshell"
6 "github.com/bnema/neferwl/internal/adapters/wayland/xwm"8 "github.com/bnema/neferwl/internal/adapters/wayland/xwm"
@@ -97,10 +99,11 @@ func (xwaylandSurface) Destroy(*xwaylandshell.XwaylandSurfaceV1) {}
97 func (s *Server) installXWM(x *xwm.XWM) {99 func (s *Server) installXWM(x *xwm.XWM) {
98 s.teardownXWM()100 s.teardownXWM()
99 s.xwm = x101 s.xwm = x
102+ s.xwmSel = x
100 x.UseSpace(&s.xspace)103 x.UseSpace(&s.xspace)
101 if err := x.Attach(s.display, hostImpl{s}); err != nil {104 if err := x.Attach(s.display, hostImpl{s}); err != nil {
102 s.log.Warn().Err(err).Msg("X11 window management disabled")105 s.log.Warn().Err(err).Msg("X11 window management disabled")
103- s.xwm = nil106+ s.xwm, s.xwmSel = nil, nil
104 x.CloseConn()107 x.CloseConn()
105 return108 return
106 }109 }
@@ -110,13 +113,18 @@ func (s *Server) installXWM(x *xwm.XWM) {
110 x.SetSerial(surf.identity, surf.x11Serial)113 x.SetSerial(surf.identity, surf.x11Serial)
111 }114 }
112 }115 }
116+ for kind, src := range s.selections { // what Wayland offered before the XWM attached
117+ if src != nil && src.alive() {
118+ s.exposeToX(kind, src)
119+ }
120+ }
113 x.LayoutChanged(true)121 x.LayoutChanged(true)
114 }122 }
115 123
116 // teardownXWM closes the window manager, dropping its windows. Idempotent.124 // teardownXWM closes the window manager, dropping its windows. Idempotent.
117 func (s *Server) teardownXWM() {125 func (s *Server) teardownXWM() {
118 if x := s.xwm; x != nil {126 if x := s.xwm; x != nil {
119- s.xwm = nil127+ s.xwm, s.xwmSel = nil, nil
120 x.Close()128 x.Close()
121 }129 }
122 }130 }
@@ -373,6 +381,20 @@ func (h hostImpl) OverrideMoved(slot xwm.Slot, x, y, w, h2 int) {
373 }381 }
374 382
375 // OverrideGone ends an override window: unmapped, or destroyed.383 // OverrideGone ends an override window: unmapped, or destroyed.
384+func (h hostImpl) SelectionOwned(kind int, mimes []string) {
385+ h.s.log.Debug().Int("kind", kind).Int("mimes", len(mimes)).Msg("X selection owner changed")
386+ h.s.setXSelection(kind, mimes)
387+}
388+
389+func (h hostImpl) SelectionRead(kind int, mime string) int {
390+ return h.s.xSelectionRead(kind, mime)
391+}
392+
393+func (h hostImpl) After(d time.Duration, fn func()) func() {
394+ t := h.s.clock.AfterFunc(d, func() { h.s.display.Post(fn) })
395+ return func() { t.Stop() }
396+}
397+
376 func (h hostImpl) OverrideGone(slot xwm.Slot) {398 func (h hostImpl) OverrideGone(slot xwm.Slot) {
377 s := h.s399 s := h.s
378 win := s.x11Slots[slot]400 win := s.x11Slots[slot]
M internal/adapters/wayland/xwm/atoms.go +16 -0
@@ -46,6 +46,14 @@ const (
46 atomClipboard46 atomClipboard
47 atomPrimary47 atomPrimary
48 atomTargets48 atomTargets
49+ atomString
50+ atomText
51+ atomTextPlain
52+ atomTextPlainUTF8
53+ atomIncr
54+ atomTimestamp
55+ atomNeferwlData
56+ atomNeferwlTargets
49 atomCount57 atomCount
50 )58 )
51 59
@@ -93,4 +101,12 @@ var atomNames = [atomCount]string{
93 atomClipboard: "CLIPBOARD",101 atomClipboard: "CLIPBOARD",
94 atomPrimary: "PRIMARY",102 atomPrimary: "PRIMARY",
95 atomTargets: "TARGETS",103 atomTargets: "TARGETS",
104+ atomString: "STRING",
105+ atomText: "TEXT",
106+ atomTextPlain: "text/plain",
107+ atomTextPlainUTF8: "text/plain;charset=utf-8",
108+ atomIncr: "INCR",
109+ atomTimestamp: "TIMESTAMP",
110+ atomNeferwlData: "_NEFERWL_DATA",
111+ atomNeferwlTargets: "_NEFERWL_TARGETS",
96 }112 }
M internal/adapters/wayland/xwm/events.go +15 -2
@@ -21,6 +21,9 @@ const (
21 kindVersion21 kindVersion
22 kindTree22 kindTree
23 kindOverrideType23 kindOverrideType
24+ kindSelTargets
25+ kindSelData
26+ kindSelOut
24 )27 )
25 28
26 // onEvent dispatches an X event. Before Attach there is no host: only the29 // onEvent dispatches an X event. Before Attach there is no host: only the
@@ -59,6 +62,8 @@ func (x *XWM) onEvent(ev *xturbo.Event) {
59 x.onClientMessage(ev)62 x.onClientMessage(ev)
60 case xproto.KindFocusIn:63 case xproto.KindFocusIn:
61 x.onFocusIn(ev)64 x.onFocusIn(ev)
65+ default:
66+ x.onSelectionEvent(ev)
62 }67 }
63 }68 }
64 69
@@ -95,6 +100,12 @@ func (x *XWM) onReply(r *xturbo.Reply) {
95 case kindTree:100 case kindTree:
96 x.onTreeReply(r)101 x.onTreeReply(r)
97 return102 return
103+ case kindSelTargets:
104+ x.onTargetsReply(r)
105+ return
106+ case kindSelData:
107+ x.onSelDataReply(r)
108+ return
98 }109 }
99 s, rec := x.tab.live(r.Args[0])110 s, rec := x.tab.live(r.Args[0])
100 if rec == nil {111 if rec == nil {
@@ -126,6 +137,8 @@ func (x *XWM) onError(e *xturbo.XError) {
126 return137 return
127 }138 }
128 switch e.Kind {139 switch e.Kind {
140+ case kindSelTargets, kindSelData, kindSelOut:
141+ x.onSelError(e)
129 case kindRootMask:142 case kindRootMask:
130 if e.Code == xproto.BadAccess {143 if e.Code == xproto.BadAccess {
131 x.bootErr = ErrWMExists144 x.bootErr = ErrWMExists
@@ -165,7 +178,7 @@ func (x *XWM) onError(e *xturbo.XError) {
165 func (x *XWM) onCreateNotify(ev *xturbo.Event) {178 func (x *XWM) onCreateNotify(ev *xturbo.Event) {
166 e := xproto.CreateNotifyOf(ev)179 e := xproto.CreateNotifyOf(ev)
167 xid := uint32(e.Window())180 xid := uint32(e.Window())
168- if xid == x.wmWin || x.tab.lookup(xid) != 0 {181+ if xid == x.wmWin || xid == x.selWin || x.tab.lookup(xid) != 0 {
169 return182 return
170 }183 }
171 s := x.insert(xid)184 s := x.insert(xid)
@@ -213,7 +226,7 @@ func (x *XWM) onTreeReply(r *xturbo.Reply) {
213 children := q.Children()226 children := q.Children()
214 for i := 0; i < children.Len(); i++ {227 for i := 0; i < children.Len(); i++ {
215 xid := uint32(children.At(i))228 xid := uint32(children.At(i))
216- if xid == x.wmWin || x.tab.lookup(xid) != 0 {229+ if xid == x.wmWin || xid == x.selWin || x.tab.lookup(xid) != 0 {
217 continue230 continue
218 }231 }
219 s := x.insert(xid)232 s := x.insert(xid)
M internal/adapters/wayland/xwm/host.go +21 -1
@@ -1,6 +1,10 @@
1 package xwm1 package xwm
2 2
3-import "github.com/bnema/neferwl/internal/ports"3+import (
4+ "time"
5+
6+ "github.com/bnema/neferwl/internal/ports"
7+)
4 8
5 // Slot is the XWM's window slot: table index + 1, stable until the window is9 // Slot is the XWM's window slot: table index + 1, stable until the window is
6 // destroyed. 0 means none.10 // destroyed. 0 means none.
@@ -53,6 +57,22 @@ type host interface {
53 OverrideMoved(slot Slot, x, y, w, h int)57 OverrideMoved(slot Slot, x, y, w, h int)
54 // OverrideGone ends a mapped override window: unmapped or destroyed.58 // OverrideGone ends a mapped override window: unmapped or destroyed.
55 OverrideGone(slot Slot)59 OverrideGone(slot Slot)
60+
61+ // SelectionOwned: an X client owns kind (SelClipboard/SelPrimary) and
62+ // offers these MIME types, or none does any more (mimes nil). mimes is
63+ // scratch: the host copies it.
64+ SelectionOwned(kind int, mimes []string)
65+
66+ // SelectionRead asks for the data of the current Wayland selection kind
67+ // as mime: it returns a non-blocking read end the XWM closes, or -1 when
68+ // there is none, it is protected, or mime is not offered.
69+ SelectionRead(kind int, mime string) (fd int)
70+
71+ // After runs fn on the display goroutine once d has elapsed, unless the
72+ // returned cancel ran first. cancel is idempotent and display goroutine
73+ // only; fn may still run once after cancel when it was already queued,
74+ // so callers guard with their own generation.
75+ After(d time.Duration, fn func()) (cancel func())
56 }76 }
57 77
58 // fdSource is the display's event source for the X socket (*server.Source).78 // fdSource is the display's event source for the X socket (*server.Source).
M internal/adapters/wayland/xwm/host_mock_test.go +164 -0
@@ -5,6 +5,8 @@
5 package xwm5 package xwm
6 6
7 import (7 import (
8+ "time"
9+
8 "github.com/bnema/neferwl/internal/ports"10 "github.com/bnema/neferwl/internal/ports"
9 mock "github.com/stretchr/testify/mock"11 mock "github.com/stretchr/testify/mock"
10 )12 )
@@ -45,6 +47,65 @@ func (_m *mockhost) EXPECT() *mockhost_Expecter {
45 return &mockhost_Expecter{mock: &_m.Mock}47 return &mockhost_Expecter{mock: &_m.Mock}
46 }48 }
47 49
50+// After provides a mock function for the type mockhost
51+func (_mock *mockhost) After(d time.Duration, fn func()) func() {
52+ ret := _mock.Called(d, fn)
53+
54+ if len(ret) == 0 {
55+ panic("no return value specified for After")
56+ }
57+
58+ var r0 func()
59+ if returnFunc, ok := ret.Get(0).(func(time.Duration, func()) func()); ok {
60+ r0 = returnFunc(d, fn)
61+ } else {
62+ if ret.Get(0) != nil {
63+ r0 = ret.Get(0).(func())
64+ }
65+ }
66+ return r0
67+}
68+
69+// mockhost_After_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'After'
70+type mockhost_After_Call struct {
71+ *mock.Call
72+}
73+
74+// After is a helper method to define mock.On call
75+// - d time.Duration
76+// - fn func()
77+func (_e *mockhost_Expecter) After(d any, fn any) *mockhost_After_Call {
78+ return &mockhost_After_Call{Call: _e.mock.On("After", d, fn)}
79+}
80+
81+func (_c *mockhost_After_Call) Run(run func(d time.Duration, fn func())) *mockhost_After_Call {
82+ _c.Call.Run(func(args mock.Arguments) {
83+ var arg0 time.Duration
84+ if args[0] != nil {
85+ arg0 = args[0].(time.Duration)
86+ }
87+ var arg1 func()
88+ if args[1] != nil {
89+ arg1 = args[1].(func())
90+ }
91+ run(
92+ arg0,
93+ arg1,
94+ )
95+ })
96+ return _c
97+}
98+
99+func (_c *mockhost_After_Call) Return(cancel func()) *mockhost_After_Call {
100+ _c.Call.Return(cancel)
101+ return _c
102+}
103+
104+func (_c *mockhost_After_Call) RunAndReturn(run func(d time.Duration, fn func()) func()) *mockhost_After_Call {
105+ _c.Call.Return(run)
106+ return _c
107+}
108+
48 // AppID provides a mock function for the type mockhost109 // AppID provides a mock function for the type mockhost
49 func (_mock *mockhost) AppID(slot Slot, appID string) {110 func (_mock *mockhost) AppID(slot Slot, appID string) {
50 _mock.Called(slot, appID)111 _mock.Called(slot, appID)
@@ -564,6 +625,109 @@ func (_c *mockhost_Ready_Call) RunAndReturn(run func(slot Slot, info WindowInfo)
564 return _c625 return _c
565 }626 }
566 627
628+// SelectionOwned provides a mock function for the type mockhost
629+func (_mock *mockhost) SelectionOwned(kind int, mimes []string) {
630+ _mock.Called(kind, mimes)
631+ return
632+}
633+
634+// mockhost_SelectionOwned_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectionOwned'
635+type mockhost_SelectionOwned_Call struct {
636+ *mock.Call
637+}
638+
639+// SelectionOwned is a helper method to define mock.On call
640+// - kind int
641+// - mimes []string
642+func (_e *mockhost_Expecter) SelectionOwned(kind any, mimes any) *mockhost_SelectionOwned_Call {
643+ return &mockhost_SelectionOwned_Call{Call: _e.mock.On("SelectionOwned", kind, mimes)}
644+}
645+
646+func (_c *mockhost_SelectionOwned_Call) Run(run func(kind int, mimes []string)) *mockhost_SelectionOwned_Call {
647+ _c.Call.Run(func(args mock.Arguments) {
648+ var arg0 int
649+ if args[0] != nil {
650+ arg0 = args[0].(int)
651+ }
652+ var arg1 []string
653+ if args[1] != nil {
654+ arg1 = args[1].([]string)
655+ }
656+ run(
657+ arg0,
658+ arg1,
659+ )
660+ })
661+ return _c
662+}
663+
664+func (_c *mockhost_SelectionOwned_Call) Return() *mockhost_SelectionOwned_Call {
665+ _c.Call.Return()
666+ return _c
667+}
668+
669+func (_c *mockhost_SelectionOwned_Call) RunAndReturn(run func(kind int, mimes []string)) *mockhost_SelectionOwned_Call {
670+ _c.Run(run)
671+ return _c
672+}
673+
674+// SelectionRead provides a mock function for the type mockhost
675+func (_mock *mockhost) SelectionRead(kind int, mime string) int {
676+ ret := _mock.Called(kind, mime)
677+
678+ if len(ret) == 0 {
679+ panic("no return value specified for SelectionRead")
680+ }
681+
682+ var r0 int
683+ if returnFunc, ok := ret.Get(0).(func(int, string) int); ok {
684+ r0 = returnFunc(kind, mime)
685+ } else {
686+ r0 = ret.Get(0).(int)
687+ }
688+ return r0
689+}
690+
691+// mockhost_SelectionRead_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectionRead'
692+type mockhost_SelectionRead_Call struct {
693+ *mock.Call
694+}
695+
696+// SelectionRead is a helper method to define mock.On call
697+// - kind int
698+// - mime string
699+func (_e *mockhost_Expecter) SelectionRead(kind any, mime any) *mockhost_SelectionRead_Call {
700+ return &mockhost_SelectionRead_Call{Call: _e.mock.On("SelectionRead", kind, mime)}
701+}
702+
703+func (_c *mockhost_SelectionRead_Call) Run(run func(kind int, mime string)) *mockhost_SelectionRead_Call {
704+ _c.Call.Run(func(args mock.Arguments) {
705+ var arg0 int
706+ if args[0] != nil {
707+ arg0 = args[0].(int)
708+ }
709+ var arg1 string
710+ if args[1] != nil {
711+ arg1 = args[1].(string)
712+ }
713+ run(
714+ arg0,
715+ arg1,
716+ )
717+ })
718+ return _c
719+}
720+
721+func (_c *mockhost_SelectionRead_Call) Return(fd int) *mockhost_SelectionRead_Call {
722+ _c.Call.Return(fd)
723+ return _c
724+}
725+
726+func (_c *mockhost_SelectionRead_Call) RunAndReturn(run func(kind int, mime string) int) *mockhost_SelectionRead_Call {
727+ _c.Call.Return(run)
728+ return _c
729+}
730+
567 // Title provides a mock function for the type mockhost731 // Title provides a mock function for the type mockhost
568 func (_mock *mockhost) Title(slot Slot, title string) {732 func (_mock *mockhost) Title(slot Slot, title string) {
569 _mock.Called(slot, title)733 _mock.Called(slot, title)
M internal/adapters/wayland/xwm/props.go +7 -0
@@ -113,6 +113,13 @@ func (x *XWM) requestProp(s Slot, idx int) {
113 // being mapped or is mapped; unwatched atoms cost nothing.113 // being mapped or is mapped; unwatched atoms cost nothing.
114 func (x *XWM) onPropertyNotify(ev *xturbo.Event) {114 func (x *XWM) onPropertyNotify(ev *xturbo.Event) {
115 e := xproto.PropertyNotifyOf(ev)115 e := xproto.PropertyNotifyOf(ev)
116+ if uint32(e.Window()) == x.selWin && x.selWin != 0 {
117+ x.onSelProperty(ev)
118+ return
119+ }
120+ if x.onRequestorProperty(e) {
121+ return
122+ }
116 s := x.tab.lookup(uint32(e.Window()))123 s := x.tab.lookup(uint32(e.Window()))
117 if s == 0 {124 if s == 0 {
118 return125 return
A internal/adapters/wayland/xwm/selection.go +1032 -0
@@ -0,0 +1,1032 @@
1+package xwm
2+
3+import (
4+ "encoding/binary"
5+ "errors"
6+ "time"
7+
8+ "bnema.dev/xturbo"
9+ "bnema.dev/xturbo/xfixes"
10+ "bnema.dev/xturbo/xproto"
11+ "golang.org/x/sys/unix"
12+)
13+
14+// The selection bridge: text-only CLIPBOARD and PRIMARY between X clients and
15+// the Wayland clipboard. Display goroutine only; nothing here is locked.
16+
17+// Selection kinds, in the order clipboard.go uses.
18+const (
19+ SelClipboard = iota
20+ SelPrimary
21+ selKinds
22+)
23+
24+// textMimes are the MIME types the bridge offers, in the order of preference;
25+// mimeTarget gives the atom an X owner must advertise for each.
26+var (
27+ textMimes = [5]string{"text/plain;charset=utf-8", "text/plain", "UTF8_STRING", "STRING", "TEXT"}
28+ mimeTarget = [5]int{atomUTF8String, atomString, atomUTF8String, atomString, atomUTF8String}
29+)
30+
31+// selState is one selection.
32+type selState struct {
33+ atom uint32
34+ gen uint32 // bumped on every ownership change; stales TARGETS probes
35+ owner uint32 // X owner window other than selWin, 0 none
36+ ours bool // selWin owns the selection (Wayland -> X)
37+ // wl is what the Wayland side offers while ours: raw text availability.
38+ wlUTF8, wlPlain bool
39+ wlMime [len(textMimes)]string // offered text MIMEs, in textMimes order, "" absent
40+}
41+
42+const (
43+ chunk = 65536 // every transfer step moves at most this many bytes
44+ nXfer = 4 // concurrent transfers per direction, and pool buffers
45+ tickEvery = time.Second
46+ xIdleMax = 10 // ticks without X-side progress
47+ rIdleMax = 30 // ticks of a reader that does not drain its pipe
48+)
49+
50+// bufPool is the fixed set of transfer buffers.
51+type bufPool struct {
52+ bufs [nXfer][chunk]byte
53+ free [nXfer]int8
54+ n int
55+}
56+
57+func (p *bufPool) init() {
58+ for i := range p.free {
59+ p.free[i] = int8(i)
60+ }
61+ p.n = nXfer
62+}
63+
64+// get returns a free buffer index, -1 when the pool is exhausted.
65+func (p *bufPool) get() int {
66+ if p.n == 0 {
67+ return -1
68+ }
69+ p.n--
70+ return int(p.free[p.n])
71+}
72+
73+func (p *bufPool) put(i int) {
74+ p.free[p.n] = int8(i)
75+ p.n++
76+}
77+
78+// X -> Wayland transfer states.
79+const (
80+ inFree uint8 = iota
81+ inQueued // waiting for the conversion property to be free
82+ inConverting
83+ inWaitIncr // waiting for the next INCR chunk (PropertyNotify)
84+ inWriting // a buffer is pending on the Wayland reader's pipe
85+ inReading // a GetProperty is outstanding
86+)
87+
88+// xin is one X -> Wayland transfer.
89+type xin struct {
90+ x *XWM
91+ idx int
92+ state uint8
93+ kind int
94+ fd int
95+ target uint32
96+ order uint64
97+ gen uint32 // stales replies of an aborted transfer
98+ incr bool
99+ buf int
100+ off, n int
101+ words uint32 // long offset of the next piece of a long property
102+ more bool // the last piece left bytes in the property
103+ ready bool // the owner wrote the next INCR chunk while a buffer was pending
104+ idle int
105+ src fdSource
106+ onR func() // pipe hangup
107+ onW func() // pipe writable
108+}
109+
110+// selBridge is the XWM's selection state.
111+type selBridge struct {
112+ st [selKinds]selState
113+ mimes [len(textMimes)]string // scratch handed to SelectionOwned
114+ pool bufPool
115+ in [nXfer]xin
116+ out [nXfer]xout
117+ order uint64
118+ // active is the transfer that owns the conversion property, -1 none.
119+ active int
120+ timerOn bool
121+ cancel func()
122+ tickFn func()
123+}
124+
125+func (x *XWM) initSelection() {
126+ b := &x.sel
127+ b.pool.init()
128+ b.active = -1
129+ b.tickFn = x.selTick
130+ for i := range b.in {
131+ t := &b.in[i]
132+ t.x, t.idx, t.buf = x, i, -1
133+ t.onR = func() { t.x.inAbort(t.idx, true) }
134+ t.onW = func() { t.x.inWritable(t.idx) }
135+ }
136+ for i := range b.out {
137+ o := &b.out[i]
138+ o.x, o.idx, o.buf, o.fd = x, i, -1, -1
139+ o.onR = func() { o.x.outReadable(o.idx) }
140+ }
141+}
142+
143+// bootSelection creates the selection window and asks for ownership events.
144+// Without XFixes the bridge stays off.
145+func (x *XWM) bootSelection(root xproto.Window) {
146+ if !x.conn.Ext().Info(xturbo.ExtXFixes).Present {
147+ x.log.Warn().Msg("X server has no XFixes: clipboard bridge disabled")
148+ return
149+ }
150+ xid := x.selWin
151+ b := x.conn.Buf()
152+ var wv xproto.CreateWindowValues
153+ wv.SetEventMask(xproto.EventMaskPropertyChange)
154+ xproto.CreateWindow(b, 0, xproto.Window(xid), root, -1, -1, 1, 1, 0, xproto.WindowClassInputOnly, 0, &wv)
155+ x.sel.st[SelClipboard].atom = x.atoms[atomClipboard]
156+ x.sel.st[SelPrimary].atom = x.atoms[atomPrimary]
157+ const mask = xfixes.SelectionEventMaskSetSelectionOwner | xfixes.SelectionEventMaskSelectionWindowDestroy | xfixes.SelectionEventMaskSelectionClientClose
158+ for k := range x.sel.st {
159+ xfixes.SelectSelectionInput(b, root, xproto.Atom(x.sel.st[k].atom), mask)
160+ }
161+}
162+
163+// selKind maps a selection atom to its kind, -1 when it is neither.
164+func (x *XWM) selKind(atom uint32) int {
165+ for k := range x.sel.st {
166+ if x.sel.st[k].atom == atom && atom != 0 {
167+ return k
168+ }
169+ }
170+ return -1
171+}
172+
173+// onSelectionEvent handles the selection events; others are ignored.
174+func (x *XWM) onSelectionEvent(ev *xturbo.Event) {
175+ if x.selWin == 0 {
176+ return
177+ }
178+ switch ev.Kind {
179+ case xfixes.KindSelectionNotify:
180+ x.onXFixesSelection(ev)
181+ case xproto.KindSelectionNotify:
182+ x.onSelectionNotify(ev)
183+ case xproto.KindSelectionRequest:
184+ x.onSelectionRequest(ev)
185+ case xproto.KindSelectionClear:
186+ x.onSelectionClear(ev)
187+ }
188+}
189+
190+// onXFixesSelection: the owner of a selection changed.
191+func (x *XWM) onXFixesSelection(ev *xturbo.Event) {
192+ e := xfixes.SelectionNotifyOf(ev)
193+ k := x.selKind(uint32(e.Selection()))
194+ if k < 0 {
195+ return
196+ }
197+ st := &x.sel.st[k]
198+ owner := uint32(e.Owner())
199+ if owner == x.selWin { // our own SetSelectionOwner echoed back
200+ return
201+ }
202+ st.gen++
203+ st.owner = owner
204+ if owner == 0 {
205+ x.log.Debug().Int("kind", k).Msg("selection: no X owner")
206+ x.host.SelectionOwned(k, nil)
207+ return
208+ }
209+ x.log.Debug().Int("kind", k).Uint32("owner", owner).Msg("selection: X owner")
210+ xproto.ConvertSelection(x.conn.Buf(), xproto.Window(x.selWin), xproto.Atom(st.atom),
211+ xproto.Atom(x.atoms[atomTargets]), xproto.Atom(x.atoms[atomNeferwlTargets]), 0)
212+ x.wake()
213+}
214+
215+// onSelectionNotify: a ConvertSelection we issued was answered.
216+func (x *XWM) onSelectionNotify(ev *xturbo.Event) {
217+ e := xproto.SelectionNotifyOf(ev)
218+ if uint32(e.Requestor()) != x.selWin {
219+ return
220+ }
221+ k := x.selKind(uint32(e.Selection()))
222+ if k < 0 {
223+ return
224+ }
225+ if uint32(e.Target()) != x.atoms[atomTargets] {
226+ x.onDataNotify(e)
227+ return
228+ }
229+ {
230+ if e.Property() == 0 {
231+ if x.sel.st[k].owner != 0 {
232+ x.host.SelectionOwned(k, nil)
233+ }
234+ return
235+ }
236+ seq := xproto.GetProperty(x.conn.Buf(), true, xproto.Window(x.selWin), xproto.Atom(x.atoms[atomNeferwlTargets]), 0, 0, 256)
237+ x.expect(seq, kindSelTargets, uint32(k), x.sel.st[k].gen)
238+ x.wake()
239+ return
240+ }
241+}
242+
243+// onTargetsReply turns the owner's TARGETS list into the MIME types offered
244+// to Wayland: the text subset, empty for images, files and the like.
245+func (x *XWM) onTargetsReply(r *xturbo.Reply) {
246+ k := int(r.Args[0])
247+ if k < 0 || k >= selKinds || r.Args[1] != x.sel.st[k].gen {
248+ return
249+ }
250+ g, ok := xproto.ParseGetPropertyReply(r.Raw)
251+ if !ok {
252+ return
253+ }
254+ var have [atomCount]bool
255+ if g.Format() == 32 {
256+ v := g.Value()
257+ for i := 0; i+4 <= len(v); i += 4 {
258+ a := binary.LittleEndian.Uint32(v[i:])
259+ for _, t := range [...]int{atomUTF8String, atomString, atomText} {
260+ if a == x.atoms[t] {
261+ have[t] = true
262+ }
263+ }
264+ }
265+ }
266+ n := 0
267+ for i, m := range textMimes {
268+ if have[mimeTarget[i]] {
269+ x.sel.mimes[n] = m
270+ n++
271+ }
272+ }
273+ if n == 0 {
274+ x.host.SelectionOwned(k, nil)
275+ return
276+ }
277+ x.host.SelectionOwned(k, x.sel.mimes[:n])
278+}
279+
280+// ---- X -> Wayland ----
281+
282+// SelectionReceive: a Wayland reader wants the X selection kind as mime. The
283+// XWM takes fd (a write end it now owns) and closes it when done.
284+func (x *XWM) SelectionReceive(kind int, mime string, fd int) {
285+ target := uint32(0)
286+ for i, m := range textMimes {
287+ if m == mime {
288+ target = x.atoms[mimeTarget[i]]
289+ break
290+ }
291+ }
292+ if x.selWin == 0 || x.closed || kind < 0 || kind >= selKinds || target == 0 || x.sel.st[kind].owner == 0 {
293+ _ = unix.Close(fd)
294+ return
295+ }
296+ if unix.SetNonblock(fd, true) != nil {
297+ _ = unix.Close(fd)
298+ return
299+ }
300+ for i := range x.sel.in {
301+ t := &x.sel.in[i]
302+ if t.state != inFree {
303+ continue
304+ }
305+ x.sel.order++
306+ t.state, t.kind, t.fd, t.target, t.order = inQueued, kind, fd, target, x.sel.order
307+ t.incr, t.buf, t.off, t.n, t.words, t.more, t.ready, t.idle, t.src = false, -1, 0, 0, 0, false, false, 0, nil
308+ x.selEnsureTimer()
309+ x.inStartNext()
310+ return
311+ }
312+ x.log.Warn().Msg("selection: too many transfers, paste refused")
313+ _ = unix.Close(fd)
314+}
315+
316+// inStartNext starts the oldest queued transfer when none is converting.
317+func (x *XWM) inStartNext() {
318+ b := &x.sel
319+ if b.active >= 0 {
320+ return
321+ }
322+ best := -1
323+ for i := range b.in {
324+ if b.in[i].state == inQueued && (best < 0 || b.in[i].order < b.in[best].order) {
325+ best = i
326+ }
327+ }
328+ if best < 0 {
329+ return
330+ }
331+ t := &b.in[best]
332+ t.state, t.idle = inConverting, 0
333+ b.active = best
334+ xproto.ConvertSelection(x.conn.Buf(), xproto.Window(x.selWin), xproto.Atom(b.st[t.kind].atom),
335+ xproto.Atom(t.target), xproto.Atom(x.atoms[atomNeferwlData]), 0)
336+ x.wake()
337+}
338+
339+// inFinish ends transfer i and starts the next one.
340+func (x *XWM) inFinish(i int) {
341+ b := &x.sel
342+ t := &b.in[i]
343+ if t.src != nil {
344+ t.src.Remove()
345+ t.src = nil
346+ }
347+ if t.fd >= 0 {
348+ _ = unix.Close(t.fd)
349+ }
350+ if t.buf >= 0 {
351+ b.pool.put(t.buf)
352+ t.buf = -1
353+ }
354+ t.gen++
355+ t.state, t.fd = inFree, -1
356+ if b.active == i {
357+ b.active = -1
358+ }
359+ x.inStartNext()
360+}
361+
362+// inAbort drops transfer i, deleting the conversion property when X may still
363+// be writing it.
364+func (x *XWM) inAbort(i int, del bool) {
365+ t := &x.sel.in[i]
366+ if t.state == inFree {
367+ return
368+ }
369+ if del && x.sel.active == i && !x.closed {
370+ xproto.DeleteProperty(x.conn.Buf(), xproto.Window(x.selWin), xproto.Atom(x.atoms[atomNeferwlData]))
371+ x.wake()
372+ }
373+ x.inFinish(i)
374+}
375+
376+// onDataNotify: the owner answered our data ConvertSelection.
377+func (x *XWM) onDataNotify(e xproto.SelectionNotifyEvent) {
378+ i := x.sel.active
379+ if i < 0 {
380+ return
381+ }
382+ t := &x.sel.in[i]
383+ if t.state != inConverting || uint32(e.Target()) != t.target {
384+ return
385+ }
386+ if e.Property() == 0 {
387+ x.inFinish(i)
388+ return
389+ }
390+ t.words = 0
391+ x.inRequest(i)
392+}
393+
394+// inRequest asks for the next piece of the property; delete makes INCR and
395+// whole-value reads advance.
396+func (x *XWM) inRequest(i int) {
397+ t := &x.sel.in[i]
398+ t.state = inReading
399+ seq := xproto.GetProperty(x.conn.Buf(), true, xproto.Window(x.selWin), xproto.Atom(x.atoms[atomNeferwlData]),
400+ 0, t.words, chunk/4)
401+ if seq != 0 {
402+ if err := x.conn.Expect(seq, kindSelData, uint32(i), t.gen, 0, 0); err != nil {
403+ x.stats.RingFull++
404+ }
405+ }
406+ x.wake()
407+}
408+
409+// onSelDataReply handles one piece of the converted property.
410+func (x *XWM) onSelDataReply(r *xturbo.Reply) {
411+ i := int(r.Args[0])
412+ if i < 0 || i >= nXfer {
413+ return
414+ }
415+ t := &x.sel.in[i]
416+ if t.state != inReading || t.gen != r.Args[1] {
417+ return
418+ }
419+ g, ok := xproto.ParseGetPropertyReply(r.Raw)
420+ if !ok || g.Format() == 0 {
421+ x.inAbort(i, false)
422+ return
423+ }
424+ t.idle = 0
425+ if uint32(g.Type()) == x.atoms[atomIncr] {
426+ t.incr, t.state, t.words, t.more = true, inWaitIncr, 0, false
427+ return
428+ }
429+ v := g.Value()
430+ if g.Format() != 8 || len(v) > chunk {
431+ x.inAbort(i, true)
432+ return
433+ }
434+ t.more = g.BytesAfter() > 0
435+ if len(v) == 0 {
436+ if t.more { // cannot happen: bytes remain only after a non-empty read
437+ x.inAbort(i, true)
438+ return
439+ }
440+ x.inNext(i)
441+ return
442+ }
443+ b := x.sel.pool.get()
444+ if b < 0 {
445+ x.log.Warn().Msg("selection: no free buffer, paste aborted")
446+ x.inAbort(i, true)
447+ return
448+ }
449+ t.buf = b
450+ t.n = copy(x.sel.pool.bufs[b][:], v)
451+ t.off = 0
452+ t.words += uint32(t.n) / 4
453+ t.state = inWriting
454+ x.inDrain(i)
455+}
456+
457+// inDrain writes the pending buffer to the reader's pipe.
458+func (x *XWM) inDrain(i int) {
459+ t := &x.sel.in[i]
460+ buf := &x.sel.pool.bufs[t.buf]
461+ for t.off < t.n {
462+ n, err := unix.Write(t.fd, buf[t.off:t.n])
463+ switch {
464+ case err == nil:
465+ t.off += n
466+ t.idle = 0
467+ case errors.Is(err, unix.EINTR):
468+ case errors.Is(err, unix.EAGAIN):
469+ x.inWatch(i, true)
470+ return
471+ default: // EPIPE: the reader went away
472+ x.inAbort(i, true)
473+ return
474+ }
475+ }
476+ x.sel.pool.put(t.buf)
477+ t.buf = -1
478+ if t.src != nil {
479+ x.inWatch(i, false)
480+ }
481+ x.inNext(i)
482+}
483+
484+// inWatch arms or disarms writable interest on the reader's pipe.
485+func (x *XWM) inWatch(i int, on bool) {
486+ t := &x.sel.in[i]
487+ if t.src == nil {
488+ if !on || x.addFD == nil {
489+ if on {
490+ x.inAbort(i, true)
491+ }
492+ return
493+ }
494+ src, err := x.addFD(t.fd, t.onR, t.onW)
495+ if err != nil {
496+ x.inAbort(i, true)
497+ return
498+ }
499+ t.src = src
500+ }
501+ if err := t.src.SetWritable(on); err != nil {
502+ x.inAbort(i, true)
503+ }
504+}
505+
506+// inWritable: the pipe has room again.
507+func (x *XWM) inWritable(i int) {
508+ t := &x.sel.in[i]
509+ if t.state == inWriting && t.buf >= 0 {
510+ x.inDrain(i)
511+ }
512+}
513+
514+// inNext decides what follows a drained (or empty) piece.
515+func (x *XWM) inNext(i int) {
516+ t := &x.sel.in[i]
517+ switch {
518+ case t.more: // the rest of this property
519+ x.inRequest(i)
520+ case t.incr && t.n > 0:
521+ t.state, t.n, t.words = inWaitIncr, 0, 0
522+ if t.ready {
523+ t.ready = false
524+ x.inRequest(i)
525+ }
526+ default: // single value done, or the empty INCR terminator
527+ x.inFinish(i)
528+ }
529+}
530+
531+// onSelProperty: PropertyNotify on the selection window.
532+func (x *XWM) onSelProperty(ev *xturbo.Event) {
533+ e := xproto.PropertyNotifyOf(ev)
534+ if e.State() != xproto.PropertyNewValue || uint32(e.Atom()) != x.atoms[atomNeferwlData] {
535+ return
536+ }
537+ // (a Deleted state on a requestor is handled by onRequestorProperty)
538+ i := x.sel.active
539+ if i < 0 || !x.sel.in[i].incr {
540+ return
541+ }
542+ t := &x.sel.in[i]
543+ switch t.state {
544+ case inWaitIncr:
545+ t.idle = 0
546+ t.n = 0
547+ x.inRequest(i)
548+ case inWriting, inReading:
549+ t.ready = true // no request while a buffer is pending: backpressure
550+ }
551+}
552+
553+// onSelError: a selection request failed; the awaited reply never comes.
554+func (x *XWM) onSelError(e *xturbo.XError) {
555+ if e.Kind == kindSelOut {
556+ if i := int(e.Args[0]); i >= 0 && i < nXfer && x.sel.out[i].gen == e.Args[1] && x.sel.out[i].state != outFree {
557+ x.outAbort(i)
558+ }
559+ return
560+ }
561+ if e.Kind == kindSelData {
562+ if i := int(e.Args[0]); i >= 0 && i < nXfer && x.sel.in[i].gen == e.Args[1] && x.sel.in[i].state == inReading {
563+ x.inAbort(i, false)
564+ }
565+ }
566+}
567+
568+// ---- timeouts ----
569+
570+func (x *XWM) selEnsureTimer() {
571+ b := &x.sel
572+ if b.timerOn || x.after == nil {
573+ return
574+ }
575+ b.timerOn = true
576+ b.cancel = x.after(tickEvery, b.tickFn)
577+}
578+
579+// selTick ages every transfer by one second and aborts the stalled ones.
580+func (x *XWM) selTick() {
581+ b := &x.sel
582+ b.timerOn, b.cancel = false, nil
583+ if x.closed {
584+ return
585+ }
586+ live := false
587+ for i := range b.in {
588+ t := &b.in[i]
589+ if t.state == inFree {
590+ continue
591+ }
592+ t.idle++
593+ limit := xIdleMax
594+ if t.state == inWriting {
595+ limit = rIdleMax
596+ }
597+ if t.state != inQueued && t.idle >= limit {
598+ x.log.Warn().Int("kind", t.kind).Msg("selection: transfer timed out")
599+ x.inAbort(i, true)
600+ continue
601+ }
602+ live = true
603+ }
604+ for i := range b.out {
605+ o := &b.out[i]
606+ if o.state == outFree {
607+ continue
608+ }
609+ o.idle++
610+ limit := rIdleMax
611+ if o.incr && o.n > 0 && !o.credit {
612+ limit = xIdleMax // the requestor does not delete the property
613+ }
614+ if o.idle >= limit {
615+ x.log.Warn().Int("kind", o.kind).Msg("selection: transfer timed out")
616+ x.outAbort(i)
617+ continue
618+ }
619+ live = true
620+ }
621+ if live {
622+ x.selEnsureTimer()
623+ }
624+}
625+
626+// selClose aborts every transfer.
627+func (x *XWM) selClose() {
628+ for i := range x.sel.out {
629+ if x.sel.out[i].state != outFree {
630+ x.outAbort(i)
631+ }
632+ }
633+ for i := range x.sel.in {
634+ if x.sel.in[i].state != inFree {
635+ x.inAbort(i, false)
636+ }
637+ }
638+ if x.sel.cancel != nil {
639+ x.sel.cancel()
640+ x.sel.cancel = nil
641+ }
642+}
643+
644+// ---- Wayland -> X ----
645+
646+// Wayland -> X transfer states.
647+const (
648+ outFree uint8 = iota
649+ outActive
650+)
651+
652+// xout is one Wayland -> X transfer.
653+type xout struct {
654+ x *XWM
655+ idx int
656+ state uint8
657+ kind int
658+ requestor uint32
659+ property uint32
660+ target uint32
661+ time uint32
662+ fd int
663+ buf int
664+ n int
665+ eof bool
666+ incr bool // INCR announced
667+ credit bool // the requestor deleted the property: the next chunk may go
668+ notified bool // the requestor got its SelectionNotify
669+ idle int
670+ gen uint32
671+ src fdSource
672+ onR func()
673+}
674+
675+// WaylandSelection: a Wayland client owns kind with these MIME types, or none
676+// does (mimes nil). The XWM takes X ownership when text is offered.
677+func (x *XWM) WaylandSelection(kind int, mimes []string) {
678+ if x.selWin == 0 || x.closed || kind < 0 || kind >= selKinds || x.host == nil {
679+ return
680+ }
681+ st := &x.sel.st[kind]
682+ st.wlUTF8, st.wlPlain = false, false
683+ st.wlMime = [len(textMimes)]string{}
684+ for _, m := range mimes {
685+ for i, tm := range textMimes {
686+ if m != tm {
687+ continue
688+ }
689+ st.wlMime[i] = m
690+ if mimeTarget[i] == atomUTF8String {
691+ st.wlUTF8 = true
692+ } else {
693+ st.wlPlain = true
694+ }
695+ }
696+ }
697+ for i := range x.sel.out { // the data being served is stale
698+ if x.sel.out[i].state != outFree && x.sel.out[i].kind == kind {
699+ x.outAbort(i)
700+ }
701+ }
702+ b := x.conn.Buf()
703+ if !st.wlUTF8 && !st.wlPlain {
704+ if st.ours {
705+ st.ours = false
706+ xproto.SetSelectionOwner(b, 0, xproto.Atom(st.atom), 0)
707+ x.wake()
708+ }
709+ return
710+ }
711+ st.ours = true
712+ st.gen++
713+ st.owner = 0
714+ xproto.SetSelectionOwner(b, xproto.Window(x.selWin), xproto.Atom(st.atom), 0)
715+ x.log.Debug().Int("kind", kind).Msg("selection: Wayland owner")
716+ x.wake()
717+}
718+
719+// onSelectionClear: someone else took a selection from selWin.
720+func (x *XWM) onSelectionClear(ev *xturbo.Event) {
721+ e := xproto.SelectionClearOf(ev)
722+ k := x.selKind(uint32(e.Selection()))
723+ if k < 0 || uint32(e.Owner()) != x.selWin {
724+ return
725+ }
726+ x.sel.st[k].ours = false
727+ for i := range x.sel.out {
728+ if x.sel.out[i].state != outFree && x.sel.out[i].kind == k {
729+ x.outAbort(i)
730+ }
731+ }
732+}
733+
734+// notify sends a SelectionNotify to the requestor; property 0 refuses.
735+func (x *XWM) notify(requestor, selection, target, property, time uint32) {
736+ d := xproto.SelectionNotifyEventData{
737+ Time: xproto.Timestamp(time), Requestor: xproto.Window(requestor),
738+ Selection: xproto.Atom(selection), Target: xproto.Atom(target), Property: xproto.Atom(property),
739+ }
740+ var ev [32]byte
741+ d.Put(&ev)
742+ xproto.SendEvent(x.conn.Buf(), false, xproto.Window(requestor), 0, &ev)
743+ x.wake()
744+}
745+
746+// onSelectionRequest: an X client asks selWin for the Wayland selection.
747+func (x *XWM) onSelectionRequest(ev *xturbo.Event) {
748+ e := xproto.SelectionRequestOf(ev)
749+ if uint32(e.Owner()) != x.selWin {
750+ return
751+ }
752+ sel, req, target, prop, time := uint32(e.Selection()), uint32(e.Requestor()), uint32(e.Target()), uint32(e.Property()), uint32(e.Time())
753+ k := x.selKind(sel)
754+ if k < 0 || !x.sel.st[k].ours {
755+ x.notify(req, sel, target, 0, time)
756+ return
757+ }
758+ if prop == 0 { // obsolete client
759+ prop = target
760+ }
761+ st := &x.sel.st[k]
762+ switch target {
763+ case x.atoms[atomTargets]:
764+ var list [5]uint32
765+ n := 0
766+ list[n], n = x.atoms[atomTargets], n+1
767+ if st.wlUTF8 {
768+ list[n], n = x.atoms[atomUTF8String], n+1
769+ list[n], n = x.atoms[atomText], n+1
770+ }
771+ list[n], n = x.atoms[atomString], n+1
772+ xproto.ChangeProperty(x.conn.Buf(), xproto.PropModeReplace, xproto.Window(req), xproto.Atom(prop),
773+ xproto.AtomAtom, 32, uint32(n), x.encode32(list[:n]))
774+ x.notify(req, sel, target, prop, time)
775+ return
776+ case x.atoms[atomUTF8String], x.atoms[atomText], x.atoms[atomString]:
777+ default:
778+ x.notify(req, sel, target, 0, time)
779+ return
780+ }
781+ // Choose the Wayland MIME: UTF-8 targets prefer the UTF-8 types; STRING
782+ // prefers plain text and falls back to the UTF-8 bytes unchanged.
783+ mime := ""
784+ order := [...]int{0, 2, 4, 1, 3} // utf8 types, then plain
785+ if target == x.atoms[atomString] {
786+ order = [...]int{1, 3, 0, 2, 4}
787+ }
788+ for _, i := range order {
789+ if st.wlMime[i] != "" && (target == x.atoms[atomString] || mimeTarget[i] == atomUTF8String) {
790+ mime = st.wlMime[i]
791+ break
792+ }
793+ }
794+ if mime == "" {
795+ x.notify(req, sel, target, 0, time)
796+ return
797+ }
798+ for i := range x.sel.out { // one transfer per (requestor, property)
799+ o := &x.sel.out[i]
800+ if o.state != outFree && o.requestor == req && o.property == prop {
801+ x.notify(req, sel, target, 0, time)
802+ return
803+ }
804+ }
805+ slot := -1
806+ for i := range x.sel.out {
807+ if x.sel.out[i].state == outFree {
808+ slot = i
809+ break
810+ }
811+ }
812+ if slot < 0 || x.sel.pool.n == 0 {
813+ x.log.Warn().Msg("selection: too many transfers, request refused")
814+ x.notify(req, sel, target, 0, time)
815+ return
816+ }
817+ fd := x.host.SelectionRead(k, mime)
818+ if fd < 0 {
819+ x.notify(req, sel, target, 0, time)
820+ return
821+ }
822+ x.startOut(slot, k, req, prop, target, time, fd)
823+}
824+
825+// startOut begins serving the data on fd (a non-blocking read end it now
826+// owns) to requestor.
827+func (x *XWM) startOut(slot, k int, req, prop, target, time uint32, fd int) {
828+ o := &x.sel.out[slot]
829+ o.state, o.kind, o.requestor, o.property, o.target, o.time = outActive, k, req, prop, target, time
830+ o.fd, o.buf, o.n, o.eof, o.incr, o.credit, o.notified, o.idle, o.src = fd, x.sel.pool.get(), 0, false, false, false, false, 0, nil
831+ x.selEnsureTimer()
832+ x.outRead(slot) // data may already be waiting
833+}
834+
835+// encode32 packs vals into the shared scratch.
836+func (x *XWM) encode32(vals []uint32) []byte {
837+ n := 4 * len(vals)
838+ if cap(x.scratch) < n {
839+ x.scratch = make([]byte, 0, n)
840+ }
841+ p := x.scratch[:n]
842+ for i, v := range vals {
843+ binary.LittleEndian.PutUint32(p[4*i:], v)
844+ }
845+ return p
846+}
847+
848+// outWatch registers the pipe's read end with the display.
849+func (x *XWM) outWatch(i int) {
850+ o := &x.sel.out[i]
851+ if o.src != nil {
852+ return
853+ }
854+ if x.addFD == nil {
855+ x.outAbort(i)
856+ return
857+ }
858+ src, err := x.addFD(o.fd, o.onR, nil)
859+ if err != nil {
860+ x.outAbort(i)
861+ return
862+ }
863+ o.src = src
864+}
865+
866+// outUnwatch drops read interest: the buffer is full and nothing may be read
867+// until the requestor consumed the previous chunk.
868+func (x *XWM) outUnwatch(i int) {
869+ o := &x.sel.out[i]
870+ if o.src != nil {
871+ o.src.Remove()
872+ o.src = nil
873+ }
874+}
875+
876+// outReadable is the pipe's read callback.
877+func (x *XWM) outReadable(i int) {
878+ if x.sel.out[i].state == outFree {
879+ return
880+ }
881+ x.outRead(i)
882+}
883+
884+// outRead fills the buffer from the pipe and advances the transfer.
885+func (x *XWM) outRead(i int) {
886+ o := &x.sel.out[i]
887+ buf := &x.sel.pool.bufs[o.buf]
888+ for o.n < chunk && !o.eof {
889+ n, err := unix.Read(o.fd, buf[o.n:])
890+ switch {
891+ case err == nil && n == 0:
892+ o.eof = true
893+ case err == nil:
894+ o.n += n
895+ o.idle = 0
896+ case errors.Is(err, unix.EINTR):
897+ continue
898+ case errors.Is(err, unix.EAGAIN):
899+ x.outPump(i)
900+ return
901+ default:
902+ x.outAbort(i)
903+ return
904+ }
905+ }
906+ x.outPump(i)
907+}
908+
909+// outPump sends what the state allows.
910+func (x *XWM) outPump(i int) {
911+ o := &x.sel.out[i]
912+ if o.state == outFree {
913+ return
914+ }
915+ full := o.n == chunk
916+ if !o.incr {
917+ switch {
918+ case o.eof: // whole value
919+ x.outSetProp(i, o.n)
920+ x.notify(o.requestor, x.sel.st[o.kind].atom, o.target, o.property, o.time)
921+ x.outFinish(i)
922+ case full: // does not fit one request: INCR
923+ o.incr, o.notified = true, true
924+ var v xproto.ChangeWindowAttributesValues
925+ v.SetEventMask(xproto.EventMaskPropertyChange)
926+ xproto.ChangeWindowAttributes(x.conn.Buf(), xproto.Window(o.requestor), &v)
927+ xproto.ChangeProperty(x.conn.Buf(), xproto.PropModeReplace, xproto.Window(o.requestor), xproto.Atom(o.property),
928+ xproto.Atom(x.atoms[atomIncr]), 32, 1, x.encode32([]uint32{0}))
929+ x.notify(o.requestor, x.sel.st[o.kind].atom, o.target, o.property, o.time)
930+ x.outUnwatch(i)
931+ default:
932+ x.outWatch(i)
933+ }
934+ return
935+ }
936+ if o.credit && (full || o.eof) {
937+ o.credit = false
938+ o.idle = 0
939+ x.outSetProp(i, o.n)
940+ if o.n == 0 { // the empty chunk ends the transfer
941+ x.outFinish(i)
942+ return
943+ }
944+ o.n = 0
945+ }
946+ if o.n < chunk && !o.eof {
947+ x.outWatch(i)
948+ } else {
949+ x.outUnwatch(i)
950+ }
951+}
952+
953+// outSetProp writes the first n buffered bytes as the property value.
954+func (x *XWM) outSetProp(i, n int) {
955+ o := &x.sel.out[i]
956+ seq := xproto.ChangeProperty(x.conn.Buf(), xproto.PropModeReplace, xproto.Window(o.requestor), xproto.Atom(o.property),
957+ xproto.Atom(o.target), 8, uint32(n), x.sel.pool.bufs[o.buf][:n])
958+ if seq != 0 {
959+ if err := x.conn.Expect(seq, kindSelOut, uint32(i), o.gen, 0, 0); err != nil {
960+ x.stats.RingFull++
961+ }
962+ }
963+ x.wake()
964+}
965+
966+// outFinish ends a completed transfer.
967+func (x *XWM) outFinish(i int) {
968+ o := &x.sel.out[i]
969+ if o.incr && !x.closed {
970+ var v xproto.ChangeWindowAttributesValues
971+ v.SetEventMask(0)
972+ xproto.ChangeWindowAttributes(x.conn.Buf(), xproto.Window(o.requestor), &v)
973+ x.wake()
974+ }
975+ x.outRelease(i)
976+}
977+
978+// outRelease frees the transfer's resources.
979+func (x *XWM) outRelease(i int) {
980+ o := &x.sel.out[i]
981+ x.outUnwatch(i)
982+ if o.fd >= 0 {
983+ _ = unix.Close(o.fd)
984+ }
985+ if o.buf >= 0 {
986+ x.sel.pool.put(o.buf)
987+ }
988+ o.fd, o.buf = -1, -1
989+ o.gen++
990+ o.state = outFree
991+}
992+
993+// outAbort ends a transfer early: the requestor is refused (before its
994+// notification) or released (INCR: mask dropped, property deleted).
995+func (x *XWM) outAbort(i int) {
996+ o := &x.sel.out[i]
997+ if o.state == outFree {
998+ return
999+ }
1000+ if !x.closed {
1001+ switch {
1002+ case !o.notified:
1003+ x.notify(o.requestor, x.sel.st[o.kind].atom, o.target, 0, o.time)
1004+ case o.incr:
1005+ var v xproto.ChangeWindowAttributesValues
1006+ v.SetEventMask(0)
1007+ xproto.ChangeWindowAttributes(x.conn.Buf(), xproto.Window(o.requestor), &v)
1008+ xproto.DeleteProperty(x.conn.Buf(), xproto.Window(o.requestor), xproto.Atom(o.property))
1009+ x.wake()
1010+ }
1011+ }
1012+ x.outRelease(i)
1013+}
1014+
1015+// onRequestorProperty: PropertyNotify on a window we serve by INCR.
1016+func (x *XWM) onRequestorProperty(e xproto.PropertyNotifyEvent) bool {
1017+ if e.State() != xproto.PropertyDelete {
1018+ return false
1019+ }
1020+ hit := false
1021+ for i := range x.sel.out {
1022+ o := &x.sel.out[i]
1023+ if o.state == outFree || !o.incr || o.requestor != uint32(e.Window()) || o.property != uint32(e.Atom()) {
1024+ continue
1025+ }
1026+ hit = true
1027+ o.credit = true
1028+ o.idle = 0
1029+ x.outPump(i)
1030+ }
1031+ return hit
1032+}
A internal/adapters/wayland/xwm/selection_test.go +685 -0
@@ -0,0 +1,685 @@
1+package xwm
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "io"
7+ "os"
8+ "testing"
9+ "time"
10+
11+ "bnema.dev/xturbo"
12+ "bnema.dev/xturbo/xproto"
13+ "github.com/stretchr/testify/mock"
14+ "github.com/stretchr/testify/require"
15+ "golang.org/x/sys/unix"
16+)
17+
18+const peerXFixesFirstEvent = 87
19+
20+// xfixesSelection sends an XFixesSelectionNotify.
21+func (p *xpeer) xfixesSelection(owner, selection uint32) {
22+ p.event(peerXFixesFirstEvent, func(b *[32]byte) {
23+ binary.LittleEndian.PutUint32(b[4:], peerRoot)
24+ binary.LittleEndian.PutUint32(b[8:], owner)
25+ binary.LittleEndian.PutUint32(b[12:], selection)
26+ })
27+}
28+
29+// selectionNotify sends a core SelectionNotify to the requestor.
30+func (p *xpeer) selectionNotify(requestor, selection, target, property uint32) {
31+ p.event(31, func(b *[32]byte) {
32+ binary.LittleEndian.PutUint32(b[8:], requestor)
33+ binary.LittleEndian.PutUint32(b[12:], selection)
34+ binary.LittleEndian.PutUint32(b[16:], target)
35+ binary.LittleEndian.PutUint32(b[20:], property)
36+ })
37+}
38+
39+// pumpReq dispatches X events until a request matching match was sent after
40+// the first skip requests.
41+func pumpReq(t *testing.T, x *XWM, p *xpeer, skip int, match func(xpeerReq) bool) (xpeerReq, int) {
42+ t.Helper()
43+ var found xpeerReq
44+ next := skip
45+ readUntil(t, x, func() bool {
46+ x.flush()
47+ reqs := p.requests()
48+ for i := skip; i < len(reqs); i++ {
49+ if match(reqs[i]) {
50+ found, next = reqs[i], i+1
51+ return true
52+ }
53+ }
54+ return false
55+ })
56+ return found, next
57+}
58+
59+func TestSelectionBoot(t *testing.T) {
60+ x, p := bootPeer(t, nil)
61+ require.NotZero(t, x.selWin)
62+ reqs := p.requests()
63+ var created, selected int
64+ for _, r := range reqs {
65+ switch {
66+ case r.major == opCreateWindow && r.u32(4) == x.selWin:
67+ created++
68+ require.EqualValues(t, 2, binary.LittleEndian.Uint16(r.raw[22:]), "InputOnly")
69+ case r.major == 138 && r.minor == 2: // SelectSelectionInput
70+ selected++
71+ require.EqualValues(t, peerRoot, r.u32(4))
72+ require.Contains(t, []uint32{p.atom("CLIPBOARD"), p.atom("PRIMARY")}, r.u32(8))
73+ require.EqualValues(t, 7, r.u32(12))
74+ }
75+ }
76+ require.Equal(t, 1, created)
77+ require.Equal(t, 2, selected)
78+}
79+
80+func TestSelectionXOwnsAnnounces(t *testing.T) {
81+ x, p, h, _, _ := attached(t)
82+ const owner = 0x500010
83+ clip, prim := p.atom("CLIPBOARD"), p.atom("PRIMARY")
84+ tgt := p.atom("TARGETS")
85+
86+ // Owner with text targets: TARGETS probe, then the intersection.
87+ p.xfixesSelection(owner, clip)
88+ req, n := pumpReq(t, x, p, 0, func(r xpeerReq) bool { return r.major == 24 }) // ConvertSelection
89+ require.Equal(t, x.selWin, req.u32(4))
90+ require.Equal(t, clip, req.u32(8))
91+ require.Equal(t, tgt, req.u32(12))
92+ prop := req.u32(16)
93+ require.Equal(t, p.atom("_NEFERWL_TARGETS"), prop)
94+ p.setProp(x.selWin, prop, 4, 32, le32(tgt, p.atom("UTF8_STRING"), p.atom("image/png"), p.atom("TEXT")))
95+ got := make(chan []string, 8)
96+ h.EXPECT().SelectionOwned(SelClipboard, []string{"text/plain;charset=utf-8", "UTF8_STRING", "TEXT"}).Run(func(int, []string) { got <- nil }).Once()
97+ p.selectionNotify(x.selWin, clip, tgt, prop)
98+ readUntil(t, x, func() bool { return len(got) == 1 })
99+ pumpReq(t, x, p, n, func(r xpeerReq) bool { return r.major == opGetProperty && r.u32(8) == prop })
100+
101+ // Only image/png: nothing offered.
102+ p.xfixesSelection(owner, prim)
103+ pumpReq(t, x, p, n, func(r xpeerReq) bool { return r.major == 24 && r.u32(8) == prim })
104+ p.setProp(x.selWin, prop, 4, 32, le32(tgt, p.atom("image/png")))
105+ h.EXPECT().SelectionOwned(SelPrimary, []string(nil)).Run(func(int, []string) { got <- nil }).Once()
106+ p.selectionNotify(x.selWin, prim, tgt, prop)
107+ readUntil(t, x, func() bool { return len(got) == 2 })
108+
109+ // Owner None.
110+ h.EXPECT().SelectionOwned(SelClipboard, []string(nil)).Run(func(int, []string) { got <- nil }).Once()
111+ p.xfixesSelection(0, clip)
112+ readUntil(t, x, func() bool { return len(got) == 3 })
113+
114+ // Our own window: ignored (the mock fails on any host call).
115+ before := len(p.requests())
116+ p.xfixesSelection(x.selWin, clip)
117+ ev := x.Stats().Events
118+ readUntil(t, x, func() bool { return x.Stats().Events > ev })
119+ x.flush()
120+ require.Equal(t, before, len(p.requests()))
121+}
122+
123+// ---- X -> Wayland ----
124+
125+type selRig struct {
126+ x *XWM
127+ p *xpeer
128+ h *mockhost
129+ clip uint32
130+ utf8 uint32
131+ data uint32
132+ skip int
133+ timer func()
134+}
135+
136+// ownedRig attaches an XWM whose CLIPBOARD is owned by an X client offering text.
137+func ownedRig(t *testing.T) *selRig {
138+ t.Helper()
139+ x, p, h, _, _ := attached(t)
140+ r := &selRig{x: x, p: p, h: h, clip: p.atom("CLIPBOARD"), utf8: p.atom("UTF8_STRING"), data: p.atom("_NEFERWL_DATA")}
141+ h.EXPECT().After(mock.Anything, mock.Anything).Run(func(_ time.Duration, fn func()) { r.timer = fn }).Return(func() {}).Maybe()
142+ got := 0
143+ h.EXPECT().SelectionOwned(SelClipboard, mock.Anything).Run(func(int, []string) { got++ }).Once()
144+ p.xfixesSelection(0x500010, r.clip)
145+ _, n := pumpReq(t, x, p, 0, func(q xpeerReq) bool { return q.major == 24 })
146+ tgt := p.atom("TARGETS")
147+ p.setProp(x.selWin, p.atom("_NEFERWL_TARGETS"), 4, 32, le32(tgt, r.utf8))
148+ p.selectionNotify(x.selWin, r.clip, tgt, p.atom("_NEFERWL_TARGETS"))
149+ readUntil(t, x, func() bool { return got == 1 })
150+ r.skip = len(p.requests())
151+ _ = n
152+ return r
153+}
154+
155+// receive starts a paste and returns the read end of its pipe.
156+func (r *selRig) receive(t *testing.T, size int) *os.File {
157+ t.Helper()
158+ fds := make([]int, 2)
159+ require.NoError(t, unix.Pipe2(fds, unix.O_CLOEXEC))
160+ if size > 0 {
161+ _, err := unix.FcntlInt(uintptr(fds[0]), unix.F_SETPIPE_SZ, size)
162+ require.NoError(t, err)
163+ }
164+ r.x.SelectionReceive(SelClipboard, "text/plain;charset=utf-8", fds[1])
165+ r.x.flush()
166+ f := os.NewFile(uintptr(fds[0]), "pipe-r")
167+ t.Cleanup(func() { f.Close() })
168+ return f
169+}
170+
171+func (r *selRig) waitGet(t *testing.T) {
172+ t.Helper()
173+ _, n := pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == opGetProperty && q.u32(8) == r.data })
174+ r.skip = n
175+}
176+
177+func pattern(n int) []byte {
178+ b := make([]byte, n)
179+ for i := range b {
180+ b[i] = byte(i*7 + i/251)
181+ }
182+ return b
183+}
184+
185+func TestSelectionXToWaylandSmall(t *testing.T) {
186+ r := ownedRig(t)
187+ f := r.receive(t, 0)
188+ req, n := pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == 24 })
189+ require.Equal(t, r.x.selWin, req.u32(4))
190+ require.Equal(t, r.clip, req.u32(8))
191+ require.Equal(t, r.utf8, req.u32(12))
192+ require.Equal(t, r.data, req.u32(16))
193+ r.skip = n
194+ r.p.setProp(r.x.selWin, r.data, r.utf8, 8, []byte("hello clipboard"))
195+ r.p.selectionNotify(r.x.selWin, r.clip, r.utf8, r.data)
196+ r.waitGet(t)
197+ buf := make([]byte, 64)
198+ var got []byte
199+ readUntil(t, r.x, func() bool {
200+ m, _ := unix.Read(int(f.Fd()), buf[:0:0])
201+ _ = m
202+ return r.x.sel.in[0].state == inFree
203+ })
204+ m, err := f.Read(buf)
205+ require.NoError(t, err)
206+ got = buf[:m]
207+ require.Equal(t, "hello clipboard", string(got))
208+ _, ok := r.p.prop(r.x.selWin, "_NEFERWL_DATA")
209+ require.False(t, ok, "property deleted by the read")
210+ _, err = f.Read(buf)
211+ require.ErrorIs(t, err, io.EOF, "write end closed")
212+}
213+
214+func TestSelectionXToWaylandRefused(t *testing.T) {
215+ r := ownedRig(t)
216+ f := r.receive(t, 0)
217+ _, n := pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == 24 })
218+ r.skip = n
219+ r.p.selectionNotify(r.x.selWin, r.clip, r.utf8, 0)
220+ readUntil(t, r.x, func() bool { return r.x.sel.in[0].state == inFree })
221+ _, err := f.Read(make([]byte, 8))
222+ require.ErrorIs(t, err, io.EOF)
223+}
224+
225+func TestSelectionXToWaylandINCR(t *testing.T) {
226+ r := ownedRig(t)
227+ const total = 1 << 20
228+ want := pattern(total)
229+ f := r.receive(t, 1<<20)
230+ _, n := pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == 24 })
231+ r.skip = n
232+ r.p.setProp(r.x.selWin, r.data, r.p.atom("INCR"), 32, le32(total))
233+ r.p.selectionNotify(r.x.selWin, r.clip, r.utf8, r.data)
234+ r.waitGet(t) // reads and deletes the INCR marker
235+ gets := 1
236+ for off := 0; off <= total; off += chunk {
237+ end := min(off+chunk, total)
238+ r.p.setProp(r.x.selWin, r.data, r.utf8, 8, want[off:end])
239+ r.p.propertyNotify(r.x.selWin, r.data, false)
240+ r.waitGet(t)
241+ gets++
242+ }
243+ readUntil(t, r.x, func() bool { return r.x.sel.in[0].state == inFree })
244+ got, err := io.ReadAll(f)
245+ require.NoError(t, err)
246+ require.True(t, bytes.Equal(want, got), "byte-exact, got %d", len(got))
247+ require.Equal(t, 1+total/chunk+1, gets, "marker, 16 chunks, empty terminator")
248+}
249+
250+// A reader that does not drain: no further GetProperty until the pipe has room.
251+func TestSelectionXToWaylandBackpressure(t *testing.T) {
252+ r := ownedRig(t)
253+ src := newMockfdSource(t)
254+ var onW func()
255+ r.x.addFD = func(_ int, _, w func()) (fdSource, error) { onW = w; return src, nil }
256+ src.EXPECT().SetWritable(true).Return(nil).Once()
257+ src.EXPECT().SetWritable(false).Return(nil).Once()
258+ src.EXPECT().Remove().Return().Once()
259+ f := r.receive(t, 0) // default 64 KiB pipe
260+ _, n := pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == 24 })
261+ r.skip = n
262+ r.p.setProp(r.x.selWin, r.data, r.p.atom("INCR"), 32, le32(3*chunk))
263+ r.p.selectionNotify(r.x.selWin, r.clip, r.utf8, r.data)
264+ r.waitGet(t)
265+ want := pattern(3 * chunk)
266+ chunkN := func(k int) {
267+ r.p.setProp(r.x.selWin, r.data, r.utf8, 8, want[k*chunk:(k+1)*chunk])
268+ r.p.propertyNotify(r.x.selWin, r.data, false)
269+ }
270+ chunkN(0) // fills the pipe exactly
271+ r.waitGet(t)
272+ readUntil(t, r.x, func() bool { return r.x.sel.in[0].state == inWaitIncr })
273+ chunkN(1) // nobody reads: EAGAIN, the buffer stays pending
274+ r.waitGet(t)
275+ readUntil(t, r.x, func() bool { return r.x.sel.in[0].state == inWriting })
276+ require.NotNil(t, onW)
277+
278+ gets := getProps(r.p, 0, r.x.selWin)
279+ chunkN(2) // announced while a buffer is pending
280+ ev := r.x.Stats().Events
281+ readUntil(t, r.x, func() bool { return r.x.Stats().Events > ev })
282+ r.x.flush()
283+ require.Equal(t, gets, getProps(r.p, 0, r.x.selWin), "no GetProperty while a buffer is pending")
284+
285+ got := make([]byte, 0, 3*chunk)
286+ buf := make([]byte, chunk)
287+ m, err := f.Read(buf) // the reader wakes: room again
288+ require.NoError(t, err)
289+ got = append(got, buf[:m]...)
290+ onW()
291+ require.Equal(t, inReading, r.x.sel.in[0].state, "the pending announcement is served once drained")
292+ r.waitGet(t)
293+ _ = got
294+ r.x.selClose()
295+}
296+
297+func TestSelectionTimeouts(t *testing.T) {
298+ r := ownedRig(t)
299+ f := r.receive(t, 0)
300+ _, n := pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == 24 })
301+ r.skip = n
302+ require.NotNil(t, r.timer)
303+ // X stays silent after ConvertSelection: nine ticks keep it alive, the tenth aborts.
304+ for i := 0; i < xIdleMax-1; i++ {
305+ fn := r.timer
306+ fn()
307+ require.Equal(t, inConverting, r.x.sel.in[0].state, i)
308+ }
309+ r.timer()
310+ require.Equal(t, inFree, r.x.sel.in[0].state)
311+ _, err := f.Read(make([]byte, 8))
312+ require.ErrorIs(t, err, io.EOF, "fd closed")
313+ pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == opDeleteProperty && q.u32(8) == r.data })
314+ require.Equal(t, nXfer, r.x.sel.pool.n)
315+}
316+
317+func TestSelectionPoolExhausted(t *testing.T) {
318+ r := ownedRig(t)
319+ var files []*os.File
320+ for i := 0; i < nXfer; i++ {
321+ files = append(files, r.receive(t, 0))
322+ }
323+ fifth := r.receive(t, 0)
324+ _, err := fifth.Read(make([]byte, 8))
325+ require.ErrorIs(t, err, io.EOF, "the fifth paste is refused with its pipe closed")
326+ for i := range r.x.sel.in {
327+ require.NotEqual(t, inFree, r.x.sel.in[i].state, i)
328+ }
329+ _ = files
330+ r.x.selClose()
331+ for i := range r.x.sel.in {
332+ require.Equal(t, inFree, r.x.sel.in[i].state, i)
333+ }
334+}
335+
336+// allocRig is a rig whose peer sinks requests and whose timer seam is inert.
337+func allocRig(t *testing.T) *selRig {
338+ r := ownedRig(t)
339+ sinkPeer(t, r.x, r.p)
340+ r.x.after = func(time.Duration, func()) func() { return func() {} }
341+ r.x.sel.timerOn = true // no timer re-arming in the measured loop
342+ return r
343+}
344+
345+func dataReply(r *selRig, typ uint32, payload []byte) *xturbo.Reply {
346+ raw := make([]byte, 32+(len(payload)+3)&^3)
347+ raw[0], raw[1] = 1, 8
348+ binary.LittleEndian.PutUint32(raw[8:], typ)
349+ binary.LittleEndian.PutUint32(raw[16:], uint32(len(payload)))
350+ copy(raw[32:], payload)
351+ return &xturbo.Reply{Kind: kindSelData, Raw: raw}
352+}
353+
354+func TestSelectionCopyAllocations(t *testing.T) {
355+ r := allocRig(t)
356+ x := r.x
357+ fds := make([]int, 2)
358+ require.NoError(t, unix.Pipe2(fds, unix.O_CLOEXEC))
359+ t.Cleanup(func() { unix.Close(fds[0]); unix.Close(fds[1]) })
360+ payload := pattern(4096)
361+ rep := dataReply(r, r.utf8, payload)
362+ var note xturbo.Event
363+ note.Kind = xproto.KindSelectionNotify
364+ binary.LittleEndian.PutUint32(note.Raw[8:], x.selWin)
365+ binary.LittleEndian.PutUint32(note.Raw[12:], r.clip)
366+ binary.LittleEndian.PutUint32(note.Raw[16:], r.utf8)
367+ binary.LittleEndian.PutUint32(note.Raw[20:], r.data)
368+ sink := make([]byte, 8192)
369+ mime := textMimes[0]
370+ round := func() {
371+ fd, err := unix.FcntlInt(uintptr(fds[1]), unix.F_DUPFD_CLOEXEC, 0)
372+ if err != nil {
373+ t.Fatal("dup")
374+ }
375+ x.SelectionReceive(SelClipboard, mime, fd)
376+ x.onSelectionNotify(&note)
377+ rep.Args = [4]uint32{0, x.sel.in[0].gen}
378+ x.onSelDataReply(rep)
379+ if m, err := unix.Read(fds[0], sink); err != nil || m != 4096 {
380+ t.Fatal("read")
381+ }
382+ x.posted = false
383+ x.flush()
384+ }
385+ round()
386+ require.Zero(t, testing.AllocsPerRun(100, round))
387+}
388+
389+func TestSelectionINCRChunkAllocations(t *testing.T) {
390+ r := allocRig(t)
391+ x := r.x
392+ fds := make([]int, 2)
393+ require.NoError(t, unix.Pipe2(fds, unix.O_CLOEXEC))
394+ t.Cleanup(func() { unix.Close(fds[0]); unix.Close(fds[1]) })
395+ x.SelectionReceive(SelClipboard, textMimes[0], fds[1])
396+ var note xturbo.Event
397+ note.Kind = xproto.KindSelectionNotify
398+ binary.LittleEndian.PutUint32(note.Raw[8:], x.selWin)
399+ binary.LittleEndian.PutUint32(note.Raw[12:], r.clip)
400+ binary.LittleEndian.PutUint32(note.Raw[16:], r.utf8)
401+ binary.LittleEndian.PutUint32(note.Raw[20:], r.data)
402+ x.onSelectionNotify(&note)
403+ x.onSelDataReply(dataReply(r, r.p.atom("INCR"), le32(1<<20)))
404+ require.Equal(t, inWaitIncr, x.sel.in[0].state)
405+ rep := dataReply(r, r.utf8, pattern(chunk))
406+ var pn xturbo.Event
407+ pn.Kind = xproto.KindPropertyNotify
408+ binary.LittleEndian.PutUint32(pn.Raw[4:], x.selWin)
409+ binary.LittleEndian.PutUint32(pn.Raw[8:], r.data)
410+ sink := make([]byte, chunk)
411+ step := func() {
412+ x.onSelProperty(&pn)
413+ rep.Args = [4]uint32{0, x.sel.in[0].gen}
414+ x.onSelDataReply(rep)
415+ if m, err := unix.Read(fds[0], sink); err != nil || m != chunk {
416+ t.Fatal("read")
417+ }
418+ x.posted = false
419+ x.flush()
420+ }
421+ step()
422+ require.Zero(t, testing.AllocsPerRun(100, step))
423+ require.Equal(t, inWaitIncr, x.sel.in[0].state)
424+}
425+
426+// ---- Wayland -> X ----
427+
428+const reqWin = 0x500020
429+
430+func (p *xpeer) selectionRequest(owner, requestor, selection, target, property uint32) {
431+ p.event(30, func(b *[32]byte) {
432+ binary.LittleEndian.PutUint32(b[8:], owner)
433+ binary.LittleEndian.PutUint32(b[12:], requestor)
434+ binary.LittleEndian.PutUint32(b[16:], selection)
435+ binary.LittleEndian.PutUint32(b[20:], target)
436+ binary.LittleEndian.PutUint32(b[24:], property)
437+ })
438+}
439+
440+func (p *xpeer) selectionClear(owner, selection uint32) {
441+ p.event(29, func(b *[32]byte) {
442+ binary.LittleEndian.PutUint32(b[8:], owner)
443+ binary.LittleEndian.PutUint32(b[12:], selection)
444+ })
445+}
446+
447+// sentNotify returns the property of the SelectionNotify SendEvent after skip.
448+func sentNotify(t *testing.T, r *selRig) (property uint32) {
449+ t.Helper()
450+ req, n := pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == opSendEvent && q.raw[12] == 31 })
451+ r.skip = n
452+ require.EqualValues(t, reqWin, req.u32(4))
453+ require.Equal(t, r.clip, binary.LittleEndian.Uint32(req.raw[12+12:]))
454+ return binary.LittleEndian.Uint32(req.raw[12+20:])
455+}
456+
457+// ownedByWayland attaches an XWM and gives CLIPBOARD to a Wayland client offering mimes.
458+func ownedByWayland(t *testing.T, mimes ...string) *selRig {
459+ t.Helper()
460+ x, p, h, _, _ := attached(t)
461+ r := &selRig{x: x, p: p, h: h, clip: p.atom("CLIPBOARD"), utf8: p.atom("UTF8_STRING"), data: p.atom("_NEFERWL_DATA")}
462+ h.EXPECT().After(mock.Anything, mock.Anything).Run(func(_ time.Duration, fn func()) { r.timer = fn }).Return(func() {}).Maybe()
463+ x.WaylandSelection(SelClipboard, mimes)
464+ x.flush()
465+ req, n := pumpReq(t, x, p, 0, func(q xpeerReq) bool { return q.major == opSetSelectionOwner && q.u32(8) == r.clip })
466+ require.Equal(t, x.selWin, req.u32(4))
467+ r.skip = n
468+ return r
469+}
470+
471+// serve queues a SelectionRequest; SelectionRead hands out the read end of a
472+// pipe whose write end is returned.
473+func (r *selRig) serve(t *testing.T, target uint32) (w *os.File) {
474+ t.Helper()
475+ fds := make([]int, 2)
476+ require.NoError(t, unix.Pipe2(fds, unix.O_CLOEXEC|unix.O_NONBLOCK))
477+ r.h.EXPECT().SelectionRead(SelClipboard, mock.Anything).Return(fds[0]).Once()
478+ r.p.selectionRequest(r.x.selWin, reqWin, r.clip, target, r.data)
479+ w = os.NewFile(uintptr(fds[1]), "pipe-w")
480+ t.Cleanup(func() { w.Close() })
481+ return w
482+}
483+
484+func TestSelectionWaylandToXTargets(t *testing.T) {
485+ r := ownedByWayland(t, "text/plain")
486+ r.p.selectionRequest(r.x.selWin, reqWin, r.clip, r.p.atom("TARGETS"), r.data)
487+ require.Equal(t, r.data, sentNotify(t, r))
488+ v, ok := r.p.prop(reqWin, "_NEFERWL_DATA")
489+ require.True(t, ok)
490+ require.Equal(t, []uint32{r.p.atom("TARGETS"), r.p.atom("STRING")}, atomsOf(v), "no UTF8 target for text/plain only")
491+ r.p.selectionRequest(r.x.selWin, reqWin, r.clip, r.p.atom("image/png"), r.data)
492+ require.Zero(t, sentNotify(t, r), "unknown target refused")
493+ // UTF8_STRING is not offered by a text/plain-only source, but STRING reads it.
494+ r.p.selectionRequest(r.x.selWin, reqWin, r.clip, r.utf8, r.data)
495+ require.Zero(t, sentNotify(t, r), "no UTF-8 text offered")
496+}
497+
498+func TestSelectionWaylandToXSmall(t *testing.T) {
499+ r := ownedByWayland(t, "text/plain;charset=utf-8")
500+ w := r.serve(t, r.utf8)
501+ data := pattern(4096)
502+ _, err := w.Write(data)
503+ require.NoError(t, err)
504+ require.NoError(t, w.Close())
505+ require.Equal(t, r.data, sentNotify(t, r))
506+ v, ok := r.p.prop(reqWin, "_NEFERWL_DATA")
507+ require.True(t, ok)
508+ require.Equal(t, r.utf8, v.typ)
509+ require.True(t, bytes.Equal(data, v.data))
510+ require.Equal(t, nXfer, r.x.sel.pool.n)
511+}
512+
513+func TestSelectionWaylandToXINCR(t *testing.T) {
514+ r := ownedByWayland(t, "text/plain;charset=utf-8")
515+ src := newMockfdSource(t)
516+ var onR func()
517+ removes := 0
518+ r.x.addFD = func(_ int, rd, _ func()) (fdSource, error) { onR = rd; return src, nil }
519+ src.EXPECT().Remove().Run(func() { removes++ }).Return().Maybe()
520+ const total = 1<<20 + 123
521+ data := pattern(total)
522+ w := r.serve(t, r.utf8)
523+ require.NoError(t, unix.SetNonblock(int(w.Fd()), false))
524+ go func() { _, _ = w.Write(data); w.Close() }()
525+
526+ // The first fill is a whole chunk: INCR is announced.
527+ var got []byte
528+ deadline := time.Now().Add(5 * time.Second)
529+ for !r.x.sel.out[0].incr {
530+ require.True(t, time.Now().Before(deadline), "INCR never announced")
531+ r.x.onReadable()
532+ if onR != nil && r.x.sel.out[0].state == outActive {
533+ onR()
534+ }
535+ time.Sleep(time.Millisecond)
536+ }
537+ require.Equal(t, r.data, sentNotify(t, r))
538+ v, _ := r.p.prop(reqWin, "_NEFERWL_DATA")
539+ require.Equal(t, r.p.atom("INCR"), v.typ)
540+ mask, _ := pumpReq(t, r.x, r.p, 0, func(q xpeerReq) bool {
541+ return q.major == opChangeWindowAttributes && q.u32(4) == reqWin && q.u32(12) == uint32(xproto.EventMaskPropertyChange)
542+ })
543+ require.NotZero(t, mask.raw)
544+
545+ chunks := 0
546+ for {
547+ // The requestor deletes the property: the next chunk goes out.
548+ r.p.propertyNotify(reqWin, r.data, true)
549+ before := len(r.p.requests())
550+ if onR != nil {
551+ time.Sleep(time.Millisecond)
552+ }
553+ var cp xpeerProp
554+ readUntil(t, r.x, func() bool {
555+ if onR != nil && r.x.sel.out[0].state != outFree && r.x.sel.out[0].n < chunk && !r.x.sel.out[0].eof {
556+ onR()
557+ }
558+ r.x.flush()
559+ for _, q := range r.p.requests()[before:] {
560+ if q.major == opChangeProperty && q.u32(4) == reqWin {
561+ return true
562+ }
563+ }
564+ return false
565+ })
566+ cp, _ = r.p.prop(reqWin, "_NEFERWL_DATA")
567+ chunks++
568+ if len(cp.data) == 0 {
569+ break
570+ }
571+ require.Equal(t, r.utf8, cp.typ)
572+ got = append(got, cp.data...)
573+ }
574+ require.True(t, bytes.Equal(data, got), "byte-exact: %d of %d", len(got), total)
575+ require.Equal(t, total/chunk+2, chunks, "16 full chunks, the tail, then the empty terminator")
576+ readUntil(t, r.x, func() bool { return r.x.sel.out[0].state == outFree })
577+ // The mask is removed at the end.
578+ reqs := r.p.requests()
579+ last := reqs[len(reqs)-1]
580+ for i := len(reqs) - 1; i >= 0; i-- {
581+ if reqs[i].major == opChangeWindowAttributes && reqs[i].u32(4) == reqWin {
582+ last = reqs[i]
583+ break
584+ }
585+ }
586+ require.Zero(t, last.u32(12), "event mask dropped")
587+ require.Equal(t, nXfer, r.x.sel.pool.n)
588+}
589+
590+func TestSelectionWaylandToXTimeoutAndClear(t *testing.T) {
591+ r := ownedByWayland(t, "text/plain;charset=utf-8")
592+ src := newMockfdSource(t)
593+ src.EXPECT().Remove().Return().Maybe()
594+ r.x.addFD = func(_ int, _, _ func()) (fdSource, error) { return src, nil }
595+ w := r.serve(t, r.utf8)
596+ _, err := w.Write(pattern(chunk)) // a full chunk: INCR
597+ require.NoError(t, err)
598+ readUntil(t, r.x, func() bool { return r.x.sel.out[0].incr })
599+ require.Equal(t, r.data, sentNotify(t, r))
600+ require.NotNil(t, r.timer)
601+ for i := 0; i < xIdleMax; i++ {
602+ require.Equal(t, outActive, r.x.sel.out[0].state, i)
603+ r.timer()
604+ }
605+ require.Equal(t, outFree, r.x.sel.out[0].state, "no Deleted for 10 s aborts")
606+ pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == opDeleteProperty && q.u32(4) == reqWin })
607+
608+ // SelectionClear aborts a running transfer and refuses further requests.
609+ w2 := r.serve(t, r.utf8)
610+ _, err = w2.Write(pattern(chunk))
611+ require.NoError(t, err)
612+ readUntil(t, r.x, func() bool { return r.x.sel.out[0].state == outActive })
613+ r.p.selectionClear(r.x.selWin, r.clip)
614+ readUntil(t, r.x, func() bool { return r.x.sel.out[0].state == outFree })
615+ r.p.selectionRequest(r.x.selWin, reqWin, r.clip, r.utf8, r.data)
616+ require.Equal(t, r.data, sentNotify(t, r), "INCR announcement of the aborted transfer")
617+ require.Zero(t, sentNotify(t, r), "request after the clear is refused")
618+}
619+
620+// Replacing the Wayland selection mid-transfer aborts it; nil releases X ownership.
621+func TestSelectionClearAndRace(t *testing.T) {
622+ r := ownedByWayland(t, "text/plain;charset=utf-8")
623+ src := newMockfdSource(t)
624+ src.EXPECT().Remove().Return().Maybe()
625+ r.x.addFD = func(_ int, _, _ func()) (fdSource, error) { return src, nil }
626+ w := r.serve(t, r.utf8)
627+ _, err := w.Write(pattern(chunk))
628+ require.NoError(t, err)
629+ readUntil(t, r.x, func() bool { return r.x.sel.out[0].incr })
630+ r.x.WaylandSelection(SelClipboard, []string{"text/plain"})
631+ require.Equal(t, outFree, r.x.sel.out[0].state)
632+ r.x.WaylandSelection(SelClipboard, nil) // protected or cleared
633+ r.x.flush()
634+ req, _ := pumpReq(t, r.x, r.p, r.skip, func(q xpeerReq) bool { return q.major == opSetSelectionOwner && q.u32(4) == 0 })
635+ require.Equal(t, r.clip, req.u32(8), "ownership released")
636+ require.False(t, r.x.sel.st[SelClipboard].ours)
637+}
638+
639+func TestSelectionCopyAllocationsWaylandToX(t *testing.T) {
640+ r := ownedByWayland(t, "text/plain;charset=utf-8")
641+ x := r.x
642+ sinkPeer(t, x, r.p)
643+ x.after = func(time.Duration, func()) func() { return func() {} }
644+ x.sel.timerOn = true
645+ data := pattern(4096)
646+ var ev xturbo.Event
647+ ev.Kind = xproto.KindSelectionRequest
648+ binary.LittleEndian.PutUint32(ev.Raw[8:], x.selWin)
649+ binary.LittleEndian.PutUint32(ev.Raw[12:], reqWin)
650+ binary.LittleEndian.PutUint32(ev.Raw[16:], r.clip)
651+ binary.LittleEndian.PutUint32(ev.Raw[20:], r.utf8)
652+ binary.LittleEndian.PutUint32(ev.Raw[24:], r.data)
653+ fds := make([]int, 2)
654+ round := func() {
655+ if unix.Pipe2(fds, unix.O_CLOEXEC|unix.O_NONBLOCK) != nil {
656+ t.Fatal("pipe")
657+ }
658+ if _, err := unix.Write(fds[1], data); err != nil {
659+ t.Fatal("write")
660+ }
661+ unix.Close(fds[1])
662+ x.host.(*mockhost).ExpectedCalls = nil
663+ x.onSelectionRequest(&ev)
664+ x.posted = false
665+ x.flush()
666+ }
667+ _ = round
668+ // The host mock's matching is not allocation free, so the host call is replaced.
669+ x.sel.st[SelClipboard].wlMime = [len(textMimes)]string{"text/plain;charset=utf-8"}
670+ allocs := testing.AllocsPerRun(100, func() {
671+ if unix.Pipe2(fds, unix.O_CLOEXEC|unix.O_NONBLOCK) != nil {
672+ t.Fatal("pipe")
673+ }
674+ if _, err := unix.Write(fds[1], data); err != nil {
675+ t.Fatal("write")
676+ }
677+ unix.Close(fds[1])
678+ x.startOut(0, SelClipboard, reqWin, r.data, r.utf8, 0, fds[0])
679+ x.posted = false
680+ x.flush()
681+ })
682+ // Pipe2 itself does not allocate; the measured path is read + ChangeProperty + SendEvent.
683+ require.Zero(t, allocs)
684+ require.Equal(t, outFree, x.sel.out[0].state)
685+}
M internal/adapters/wayland/xwm/testdata/streams/property_unchanged.hex +949 -949
@@ -1,950 +1,950 @@
1-1c00660001005000f303000000000000000000000000000000000000000000001+1c00710001005000f30300000000000000000000000000000000000000000000
2-0108670003000000ef03000000000000090000000000000000000000000000002+0108720003000000ef0300000000000009000000000000000000000000000000
3-6e6574207469746c650000001c00670001005000f303000000000000000000003+6e6574207469746c650000001c00720001005000f30300000000000000000000
4-0000000000000000000000000108680003000000ef03000000000000090000004+0000000000000000000000000108730003000000ef0300000000000009000000
5-0000000000000000000000006e6574207469746c650000001c006800010050005+0000000000000000000000006e6574207469746c650000001c00730001005000
6-f3030000000000000000000000000000000000000000000001086900030000006+f303000000000000000000000000000000000000000000000108740003000000
7-ef03000000000000090000000000000000000000000000006e6574207469746c7+ef03000000000000090000000000000000000000000000006e6574207469746c
8-650000001c00690001005000f3030000000000000000000000000000000000008+650000001c00740001005000f303000000000000000000000000000000000000
9-0000000001086a0003000000ef030000000000000900000000000000000000009+000000000108750003000000ef03000000000000090000000000000000000000
10-000000006e6574207469746c650000001c006a0001005000f30300000000000010+000000006e6574207469746c650000001c00750001005000f303000000000000
11-0000000000000000000000000000000001086b0003000000ef0300000000000011+000000000000000000000000000000000108760003000000ef03000000000000
12-090000000000000000000000000000006e6574207469746c650000001c006b0012+090000000000000000000000000000006e6574207469746c650000001c007600
13-01005000f3030000000000000000000000000000000000000000000001086c0013+01005000f3030000000000000000000000000000000000000000000001087700
14-03000000ef03000000000000090000000000000000000000000000006e65742014+03000000ef03000000000000090000000000000000000000000000006e657420
15-7469746c650000001c006c0001005000f303000000000000000000000000000015+7469746c650000001c00770001005000f3030000000000000000000000000000
16-000000000000000001086d0003000000ef03000000000000090000000000000016+00000000000000000108780003000000ef030000000000000900000000000000
17-00000000000000006e6574207469746c650000001c006d0001005000f303000017+00000000000000006e6574207469746c650000001c00780001005000f3030000
18-000000000000000000000000000000000000000001086e0003000000ef03000018+00000000000000000000000000000000000000000108790003000000ef030000
19-00000000090000000000000000000000000000006e6574207469746c6500000019+00000000090000000000000000000000000000006e6574207469746c65000000
20-1c006e0001005000f3030000000000000000000000000000000000000000000020+1c00790001005000f30300000000000000000000000000000000000000000000
21-01086f0003000000ef030000000000000900000000000000000000000000000021+01087a0003000000ef0300000000000009000000000000000000000000000000
22-6e6574207469746c650000001c006f0001005000f3030000000000000000000022+6e6574207469746c650000001c007a0001005000f30300000000000000000000
23-0000000000000000000000000108700003000000ef030000000000000900000023+00000000000000000000000001087b0003000000ef0300000000000009000000
24-0000000000000000000000006e6574207469746c650000001c0070000100500024+0000000000000000000000006e6574207469746c650000001c007b0001005000
25-f30300000000000000000000000000000000000000000000010871000300000025+f3030000000000000000000000000000000000000000000001087c0003000000
26-ef03000000000000090000000000000000000000000000006e6574207469746c26+ef03000000000000090000000000000000000000000000006e6574207469746c
27-650000001c00710001005000f30300000000000000000000000000000000000027+650000001c007c0001005000f303000000000000000000000000000000000000
28-000000000108720003000000ef0300000000000009000000000000000000000028+0000000001087d0003000000ef03000000000000090000000000000000000000
29-000000006e6574207469746c650000001c00720001005000f30300000000000029+000000006e6574207469746c650000001c007d0001005000f303000000000000
30-000000000000000000000000000000000108730003000000ef0300000000000030+0000000000000000000000000000000001087e0003000000ef03000000000000
31-090000000000000000000000000000006e6574207469746c650000001c00730031+090000000000000000000000000000006e6574207469746c650000001c007e00
32-01005000f303000000000000000000000000000000000000000000000108740032+01005000f3030000000000000000000000000000000000000000000001087f00
33-03000000ef03000000000000090000000000000000000000000000006e65742033+03000000ef03000000000000090000000000000000000000000000006e657420
34-7469746c650000001c00740001005000f303000000000000000000000000000034+7469746c650000001c007f0001005000f3030000000000000000000000000000
35-00000000000000000108750003000000ef03000000000000090000000000000035+00000000000000000108800003000000ef030000000000000900000000000000
36-00000000000000006e6574207469746c650000001c00750001005000f303000036+00000000000000006e6574207469746c650000001c00800001005000f3030000
37-00000000000000000000000000000000000000000108760003000000ef03000037+00000000000000000000000000000000000000000108810003000000ef030000
38-00000000090000000000000000000000000000006e6574207469746c6500000038+00000000090000000000000000000000000000006e6574207469746c65000000
39-1c00760001005000f3030000000000000000000000000000000000000000000039+1c00810001005000f30300000000000000000000000000000000000000000000
40-0108770003000000ef030000000000000900000000000000000000000000000040+0108820003000000ef0300000000000009000000000000000000000000000000
41-6e6574207469746c650000001c00770001005000f3030000000000000000000041+6e6574207469746c650000001c00820001005000f30300000000000000000000
42-0000000000000000000000000108780003000000ef030000000000000900000042+0000000000000000000000000108830003000000ef0300000000000009000000
43-0000000000000000000000006e6574207469746c650000001c0078000100500043+0000000000000000000000006e6574207469746c650000001c00830001005000
44-f30300000000000000000000000000000000000000000000010879000300000044+f303000000000000000000000000000000000000000000000108840003000000
45-ef03000000000000090000000000000000000000000000006e6574207469746c45+ef03000000000000090000000000000000000000000000006e6574207469746c
46-650000001c00790001005000f30300000000000000000000000000000000000046+650000001c00840001005000f303000000000000000000000000000000000000
47-0000000001087a0003000000ef0300000000000009000000000000000000000047+000000000108850003000000ef03000000000000090000000000000000000000
48-000000006e6574207469746c650000001c007a0001005000f30300000000000048+000000006e6574207469746c650000001c00850001005000f303000000000000
49-0000000000000000000000000000000001087b0003000000ef0300000000000049+000000000000000000000000000000000108860003000000ef03000000000000
50-090000000000000000000000000000006e6574207469746c650000001c007b0050+090000000000000000000000000000006e6574207469746c650000001c008600
51-01005000f3030000000000000000000000000000000000000000000001087c0051+01005000f3030000000000000000000000000000000000000000000001088700
52-03000000ef03000000000000090000000000000000000000000000006e65742052+03000000ef03000000000000090000000000000000000000000000006e657420
53-7469746c650000001c007c0001005000f303000000000000000000000000000053+7469746c650000001c00870001005000f3030000000000000000000000000000
54-000000000000000001087d0003000000ef03000000000000090000000000000054+00000000000000000108880003000000ef030000000000000900000000000000
55-00000000000000006e6574207469746c650000001c007d0001005000f303000055+00000000000000006e6574207469746c650000001c00880001005000f3030000
56-000000000000000000000000000000000000000001087e0003000000ef03000056+00000000000000000000000000000000000000000108890003000000ef030000
57-00000000090000000000000000000000000000006e6574207469746c6500000057+00000000090000000000000000000000000000006e6574207469746c65000000
58-1c007e0001005000f3030000000000000000000000000000000000000000000058+1c00890001005000f30300000000000000000000000000000000000000000000
59-01087f0003000000ef030000000000000900000000000000000000000000000059+01088a0003000000ef0300000000000009000000000000000000000000000000
60-6e6574207469746c650000001c007f0001005000f3030000000000000000000060+6e6574207469746c650000001c008a0001005000f30300000000000000000000
61-0000000000000000000000000108800003000000ef030000000000000900000061+00000000000000000000000001088b0003000000ef0300000000000009000000
62-0000000000000000000000006e6574207469746c650000001c0080000100500062+0000000000000000000000006e6574207469746c650000001c008b0001005000
63-f30300000000000000000000000000000000000000000000010881000300000063+f3030000000000000000000000000000000000000000000001088c0003000000
64-ef03000000000000090000000000000000000000000000006e6574207469746c64+ef03000000000000090000000000000000000000000000006e6574207469746c
65-650000001c00810001005000f30300000000000000000000000000000000000065+650000001c008c0001005000f303000000000000000000000000000000000000
66-000000000108820003000000ef0300000000000009000000000000000000000066+0000000001088d0003000000ef03000000000000090000000000000000000000
67-000000006e6574207469746c650000001c00820001005000f30300000000000067+000000006e6574207469746c650000001c008d0001005000f303000000000000
68-000000000000000000000000000000000108830003000000ef0300000000000068+0000000000000000000000000000000001088e0003000000ef03000000000000
69-090000000000000000000000000000006e6574207469746c650000001c00830069+090000000000000000000000000000006e6574207469746c650000001c008e00
70-01005000f303000000000000000000000000000000000000000000000108840070+01005000f3030000000000000000000000000000000000000000000001088f00
71-03000000ef03000000000000090000000000000000000000000000006e65742071+03000000ef03000000000000090000000000000000000000000000006e657420
72-7469746c650000001c00840001005000f303000000000000000000000000000072+7469746c650000001c008f0001005000f3030000000000000000000000000000
73-00000000000000000108850003000000ef03000000000000090000000000000073+00000000000000000108900003000000ef030000000000000900000000000000
74-00000000000000006e6574207469746c650000001c00850001005000f303000074+00000000000000006e6574207469746c650000001c00900001005000f3030000
75-00000000000000000000000000000000000000000108860003000000ef03000075+00000000000000000000000000000000000000000108910003000000ef030000
76-00000000090000000000000000000000000000006e6574207469746c6500000076+00000000090000000000000000000000000000006e6574207469746c65000000
77-1c00860001005000f3030000000000000000000000000000000000000000000077+1c00910001005000f30300000000000000000000000000000000000000000000
78-0108870003000000ef030000000000000900000000000000000000000000000078+0108920003000000ef0300000000000009000000000000000000000000000000
79-6e6574207469746c650000001c00870001005000f3030000000000000000000079+6e6574207469746c650000001c00920001005000f30300000000000000000000
80-0000000000000000000000000108880003000000ef030000000000000900000080+0000000000000000000000000108930003000000ef0300000000000009000000
81-0000000000000000000000006e6574207469746c650000001c0088000100500081+0000000000000000000000006e6574207469746c650000001c00930001005000
82-f30300000000000000000000000000000000000000000000010889000300000082+f303000000000000000000000000000000000000000000000108940003000000
83-ef03000000000000090000000000000000000000000000006e6574207469746c83+ef03000000000000090000000000000000000000000000006e6574207469746c
84-650000001c00890001005000f30300000000000000000000000000000000000084+650000001c00940001005000f303000000000000000000000000000000000000
85-0000000001088a0003000000ef0300000000000009000000000000000000000085+000000000108950003000000ef03000000000000090000000000000000000000
86-000000006e6574207469746c650000001c008a0001005000f30300000000000086+000000006e6574207469746c650000001c00950001005000f303000000000000
87-0000000000000000000000000000000001088b0003000000ef0300000000000087+000000000000000000000000000000000108960003000000ef03000000000000
88-090000000000000000000000000000006e6574207469746c650000001c008b0088+090000000000000000000000000000006e6574207469746c650000001c009600
89-01005000f3030000000000000000000000000000000000000000000001088c0089+01005000f3030000000000000000000000000000000000000000000001089700
90-03000000ef03000000000000090000000000000000000000000000006e65742090+03000000ef03000000000000090000000000000000000000000000006e657420
91-7469746c650000001c008c0001005000f303000000000000000000000000000091+7469746c650000001c00970001005000f3030000000000000000000000000000
92-000000000000000001088d0003000000ef03000000000000090000000000000092+00000000000000000108980003000000ef030000000000000900000000000000
93-00000000000000006e6574207469746c650000001c008d0001005000f303000093+00000000000000006e6574207469746c650000001c00980001005000f3030000
94-000000000000000000000000000000000000000001088e0003000000ef03000094+00000000000000000000000000000000000000000108990003000000ef030000
95-00000000090000000000000000000000000000006e6574207469746c6500000095+00000000090000000000000000000000000000006e6574207469746c65000000
96-1c008e0001005000f3030000000000000000000000000000000000000000000096+1c00990001005000f30300000000000000000000000000000000000000000000
97-01088f0003000000ef030000000000000900000000000000000000000000000097+01089a0003000000ef0300000000000009000000000000000000000000000000
98-6e6574207469746c650000001c008f0001005000f3030000000000000000000098+6e6574207469746c650000001c009a0001005000f30300000000000000000000
99-0000000000000000000000000108900003000000ef030000000000000900000099+00000000000000000000000001089b0003000000ef0300000000000009000000
100-0000000000000000000000006e6574207469746c650000001c00900001005000100+0000000000000000000000006e6574207469746c650000001c009b0001005000
101-f303000000000000000000000000000000000000000000000108910003000000101+f3030000000000000000000000000000000000000000000001089c0003000000
102-ef03000000000000090000000000000000000000000000006e6574207469746c102+ef03000000000000090000000000000000000000000000006e6574207469746c
103-650000001c00910001005000f303000000000000000000000000000000000000103+650000001c009c0001005000f303000000000000000000000000000000000000
104-000000000108920003000000ef03000000000000090000000000000000000000104+0000000001089d0003000000ef03000000000000090000000000000000000000
105-000000006e6574207469746c650000001c00920001005000f303000000000000105+000000006e6574207469746c650000001c009d0001005000f303000000000000
106-000000000000000000000000000000000108930003000000ef03000000000000106+0000000000000000000000000000000001089e0003000000ef03000000000000
107-090000000000000000000000000000006e6574207469746c650000001c009300107+090000000000000000000000000000006e6574207469746c650000001c009e00
108-01005000f3030000000000000000000000000000000000000000000001089400108+01005000f3030000000000000000000000000000000000000000000001089f00
109-03000000ef03000000000000090000000000000000000000000000006e657420109+03000000ef03000000000000090000000000000000000000000000006e657420
110-7469746c650000001c00940001005000f3030000000000000000000000000000110+7469746c650000001c009f0001005000f3030000000000000000000000000000
111-00000000000000000108950003000000ef030000000000000900000000000000111+00000000000000000108a00003000000ef030000000000000900000000000000
112-00000000000000006e6574207469746c650000001c00950001005000f3030000112+00000000000000006e6574207469746c650000001c00a00001005000f3030000
113-00000000000000000000000000000000000000000108960003000000ef030000113+00000000000000000000000000000000000000000108a10003000000ef030000
114-00000000090000000000000000000000000000006e6574207469746c65000000114+00000000090000000000000000000000000000006e6574207469746c65000000
115-1c00960001005000f30300000000000000000000000000000000000000000000115+1c00a10001005000f30300000000000000000000000000000000000000000000
116-0108970003000000ef0300000000000009000000000000000000000000000000116+0108a20003000000ef0300000000000009000000000000000000000000000000
117-6e6574207469746c650000001c00970001005000f30300000000000000000000117+6e6574207469746c650000001c00a20001005000f30300000000000000000000
118-0000000000000000000000000108980003000000ef0300000000000009000000118+0000000000000000000000000108a30003000000ef0300000000000009000000
119-0000000000000000000000006e6574207469746c650000001c00980001005000119+0000000000000000000000006e6574207469746c650000001c00a30001005000
120-f303000000000000000000000000000000000000000000000108990003000000120+f303000000000000000000000000000000000000000000000108a40003000000
121-ef03000000000000090000000000000000000000000000006e6574207469746c121+ef03000000000000090000000000000000000000000000006e6574207469746c
122-650000001c00990001005000f303000000000000000000000000000000000000122+650000001c00a40001005000f303000000000000000000000000000000000000
123-0000000001089a0003000000ef03000000000000090000000000000000000000123+000000000108a50003000000ef03000000000000090000000000000000000000
124-000000006e6574207469746c650000001c009a0001005000f303000000000000124+000000006e6574207469746c650000001c00a50001005000f303000000000000
125-0000000000000000000000000000000001089b0003000000ef03000000000000125+000000000000000000000000000000000108a60003000000ef03000000000000
126-090000000000000000000000000000006e6574207469746c650000001c009b00126+090000000000000000000000000000006e6574207469746c650000001c00a600
127-01005000f3030000000000000000000000000000000000000000000001089c00127+01005000f303000000000000000000000000000000000000000000000108a700
128-03000000ef03000000000000090000000000000000000000000000006e657420128+03000000ef03000000000000090000000000000000000000000000006e657420
129-7469746c650000001c009c0001005000f3030000000000000000000000000000129+7469746c650000001c00a70001005000f3030000000000000000000000000000
130-000000000000000001089d0003000000ef030000000000000900000000000000130+00000000000000000108a80003000000ef030000000000000900000000000000
131-00000000000000006e6574207469746c650000001c009d0001005000f3030000131+00000000000000006e6574207469746c650000001c00a80001005000f3030000
132-000000000000000000000000000000000000000001089e0003000000ef030000132+00000000000000000000000000000000000000000108a90003000000ef030000
133-00000000090000000000000000000000000000006e6574207469746c65000000133+00000000090000000000000000000000000000006e6574207469746c65000000
134-1c009e0001005000f30300000000000000000000000000000000000000000000134+1c00a90001005000f30300000000000000000000000000000000000000000000
135-01089f0003000000ef0300000000000009000000000000000000000000000000135+0108aa0003000000ef0300000000000009000000000000000000000000000000
136-6e6574207469746c650000001c009f0001005000f30300000000000000000000136+6e6574207469746c650000001c00aa0001005000f30300000000000000000000
137-0000000000000000000000000108a00003000000ef0300000000000009000000137+0000000000000000000000000108ab0003000000ef0300000000000009000000
138-0000000000000000000000006e6574207469746c650000001c00a00001005000138+0000000000000000000000006e6574207469746c650000001c00ab0001005000
139-f303000000000000000000000000000000000000000000000108a10003000000139+f303000000000000000000000000000000000000000000000108ac0003000000
140-ef03000000000000090000000000000000000000000000006e6574207469746c140+ef03000000000000090000000000000000000000000000006e6574207469746c
141-650000001c00a10001005000f303000000000000000000000000000000000000141+650000001c00ac0001005000f303000000000000000000000000000000000000
142-000000000108a20003000000ef03000000000000090000000000000000000000142+000000000108ad0003000000ef03000000000000090000000000000000000000
143-000000006e6574207469746c650000001c00a20001005000f303000000000000143+000000006e6574207469746c650000001c00ad0001005000f303000000000000
144-000000000000000000000000000000000108a30003000000ef03000000000000144+000000000000000000000000000000000108ae0003000000ef03000000000000
145-090000000000000000000000000000006e6574207469746c650000001c00a300145+090000000000000000000000000000006e6574207469746c650000001c00ae00
146-01005000f303000000000000000000000000000000000000000000000108a400146+01005000f303000000000000000000000000000000000000000000000108af00
147-03000000ef03000000000000090000000000000000000000000000006e657420147+03000000ef03000000000000090000000000000000000000000000006e657420
148-7469746c650000001c00a40001005000f3030000000000000000000000000000148+7469746c650000001c00af0001005000f3030000000000000000000000000000
149-00000000000000000108a50003000000ef030000000000000900000000000000149+00000000000000000108b00003000000ef030000000000000900000000000000
150-00000000000000006e6574207469746c650000001c00a50001005000f3030000150+00000000000000006e6574207469746c650000001c00b00001005000f3030000
151-00000000000000000000000000000000000000000108a60003000000ef030000151+00000000000000000000000000000000000000000108b10003000000ef030000
152-00000000090000000000000000000000000000006e6574207469746c65000000152+00000000090000000000000000000000000000006e6574207469746c65000000
153-1c00a60001005000f30300000000000000000000000000000000000000000000153+1c00b10001005000f30300000000000000000000000000000000000000000000
154-0108a70003000000ef0300000000000009000000000000000000000000000000154+0108b20003000000ef0300000000000009000000000000000000000000000000
155-6e6574207469746c650000001c00a70001005000f30300000000000000000000155+6e6574207469746c650000001c00b20001005000f30300000000000000000000
156-0000000000000000000000000108a80003000000ef0300000000000009000000156+0000000000000000000000000108b30003000000ef0300000000000009000000
157-0000000000000000000000006e6574207469746c650000001c00a80001005000157+0000000000000000000000006e6574207469746c650000001c00b30001005000
158-f303000000000000000000000000000000000000000000000108a90003000000158+f303000000000000000000000000000000000000000000000108b40003000000
159-ef03000000000000090000000000000000000000000000006e6574207469746c159+ef03000000000000090000000000000000000000000000006e6574207469746c
160-650000001c00a90001005000f303000000000000000000000000000000000000160+650000001c00b40001005000f303000000000000000000000000000000000000
161-000000000108aa0003000000ef03000000000000090000000000000000000000161+000000000108b50003000000ef03000000000000090000000000000000000000
162-000000006e6574207469746c650000001c00aa0001005000f303000000000000162+000000006e6574207469746c650000001c00b50001005000f303000000000000
163-000000000000000000000000000000000108ab0003000000ef03000000000000163+000000000000000000000000000000000108b60003000000ef03000000000000
164-090000000000000000000000000000006e6574207469746c650000001c00ab00164+090000000000000000000000000000006e6574207469746c650000001c00b600
165-01005000f303000000000000000000000000000000000000000000000108ac00165+01005000f303000000000000000000000000000000000000000000000108b700
166-03000000ef03000000000000090000000000000000000000000000006e657420166+03000000ef03000000000000090000000000000000000000000000006e657420
167-7469746c650000001c00ac0001005000f3030000000000000000000000000000167+7469746c650000001c00b70001005000f3030000000000000000000000000000
168-00000000000000000108ad0003000000ef030000000000000900000000000000168+00000000000000000108b80003000000ef030000000000000900000000000000
169-00000000000000006e6574207469746c650000001c00ad0001005000f3030000169+00000000000000006e6574207469746c650000001c00b80001005000f3030000
170-00000000000000000000000000000000000000000108ae0003000000ef030000170+00000000000000000000000000000000000000000108b90003000000ef030000
171-00000000090000000000000000000000000000006e6574207469746c65000000171+00000000090000000000000000000000000000006e6574207469746c65000000
172-1c00ae0001005000f30300000000000000000000000000000000000000000000172+1c00b90001005000f30300000000000000000000000000000000000000000000
173-0108af0003000000ef0300000000000009000000000000000000000000000000173+0108ba0003000000ef0300000000000009000000000000000000000000000000
174-6e6574207469746c650000001c00af0001005000f30300000000000000000000174+6e6574207469746c650000001c00ba0001005000f30300000000000000000000
175-0000000000000000000000000108b00003000000ef0300000000000009000000175+0000000000000000000000000108bb0003000000ef0300000000000009000000
176-0000000000000000000000006e6574207469746c650000001c00b00001005000176+0000000000000000000000006e6574207469746c650000001c00bb0001005000
177-f303000000000000000000000000000000000000000000000108b10003000000177+f303000000000000000000000000000000000000000000000108bc0003000000
178-ef03000000000000090000000000000000000000000000006e6574207469746c178+ef03000000000000090000000000000000000000000000006e6574207469746c
179-650000001c00b10001005000f303000000000000000000000000000000000000179+650000001c00bc0001005000f303000000000000000000000000000000000000
180-000000000108b20003000000ef03000000000000090000000000000000000000180+000000000108bd0003000000ef03000000000000090000000000000000000000
181-000000006e6574207469746c650000001c00b20001005000f303000000000000181+000000006e6574207469746c650000001c00bd0001005000f303000000000000
182-000000000000000000000000000000000108b30003000000ef03000000000000182+000000000000000000000000000000000108be0003000000ef03000000000000
183-090000000000000000000000000000006e6574207469746c650000001c00b300183+090000000000000000000000000000006e6574207469746c650000001c00be00
184-01005000f303000000000000000000000000000000000000000000000108b400184+01005000f303000000000000000000000000000000000000000000000108bf00
185-03000000ef03000000000000090000000000000000000000000000006e657420185+03000000ef03000000000000090000000000000000000000000000006e657420
186-7469746c650000001c00b40001005000f3030000000000000000000000000000186+7469746c650000001c00bf0001005000f3030000000000000000000000000000
187-00000000000000000108b50003000000ef030000000000000900000000000000187+00000000000000000108c00003000000ef030000000000000900000000000000
188-00000000000000006e6574207469746c650000001c00b50001005000f3030000188+00000000000000006e6574207469746c650000001c00c00001005000f3030000
189-00000000000000000000000000000000000000000108b60003000000ef030000189+00000000000000000000000000000000000000000108c10003000000ef030000
190-00000000090000000000000000000000000000006e6574207469746c65000000190+00000000090000000000000000000000000000006e6574207469746c65000000
191-1c00b60001005000f30300000000000000000000000000000000000000000000191+1c00c10001005000f30300000000000000000000000000000000000000000000
192-0108b70003000000ef0300000000000009000000000000000000000000000000192+0108c20003000000ef0300000000000009000000000000000000000000000000
193-6e6574207469746c650000001c00b70001005000f30300000000000000000000193+6e6574207469746c650000001c00c20001005000f30300000000000000000000
194-0000000000000000000000000108b80003000000ef0300000000000009000000194+0000000000000000000000000108c30003000000ef0300000000000009000000
195-0000000000000000000000006e6574207469746c650000001c00b80001005000195+0000000000000000000000006e6574207469746c650000001c00c30001005000
196-f303000000000000000000000000000000000000000000000108b90003000000196+f303000000000000000000000000000000000000000000000108c40003000000
197-ef03000000000000090000000000000000000000000000006e6574207469746c197+ef03000000000000090000000000000000000000000000006e6574207469746c
198-650000001c00b90001005000f303000000000000000000000000000000000000198+650000001c00c40001005000f303000000000000000000000000000000000000
199-000000000108ba0003000000ef03000000000000090000000000000000000000199+000000000108c50003000000ef03000000000000090000000000000000000000
200-000000006e6574207469746c650000001c00ba0001005000f303000000000000200+000000006e6574207469746c650000001c00c50001005000f303000000000000
201-000000000000000000000000000000000108bb0003000000ef03000000000000201+000000000000000000000000000000000108c60003000000ef03000000000000
202-090000000000000000000000000000006e6574207469746c650000001c00bb00202+090000000000000000000000000000006e6574207469746c650000001c00c600
203-01005000f303000000000000000000000000000000000000000000000108bc00203+01005000f303000000000000000000000000000000000000000000000108c700
204-03000000ef03000000000000090000000000000000000000000000006e657420204+03000000ef03000000000000090000000000000000000000000000006e657420
205-7469746c650000001c00bc0001005000f3030000000000000000000000000000205+7469746c650000001c00c70001005000f3030000000000000000000000000000
206-00000000000000000108bd0003000000ef030000000000000900000000000000206+00000000000000000108c80003000000ef030000000000000900000000000000
207-00000000000000006e6574207469746c650000001c00bd0001005000f3030000207+00000000000000006e6574207469746c650000001c00c80001005000f3030000
208-00000000000000000000000000000000000000000108be0003000000ef030000208+00000000000000000000000000000000000000000108c90003000000ef030000
209-00000000090000000000000000000000000000006e6574207469746c65000000209+00000000090000000000000000000000000000006e6574207469746c65000000
210-1c00be0001005000f30300000000000000000000000000000000000000000000210+1c00c90001005000f30300000000000000000000000000000000000000000000
211-0108bf0003000000ef0300000000000009000000000000000000000000000000211+0108ca0003000000ef0300000000000009000000000000000000000000000000
212-6e6574207469746c650000001c00bf0001005000f30300000000000000000000212+6e6574207469746c650000001c00ca0001005000f30300000000000000000000
213-0000000000000000000000000108c00003000000ef0300000000000009000000213+0000000000000000000000000108cb0003000000ef0300000000000009000000
214-0000000000000000000000006e6574207469746c650000001c00c00001005000214+0000000000000000000000006e6574207469746c650000001c00cb0001005000
215-f303000000000000000000000000000000000000000000000108c10003000000215+f303000000000000000000000000000000000000000000000108cc0003000000
216-ef03000000000000090000000000000000000000000000006e6574207469746c216+ef03000000000000090000000000000000000000000000006e6574207469746c
217-650000001c00c10001005000f303000000000000000000000000000000000000217+650000001c00cc0001005000f303000000000000000000000000000000000000
218-000000000108c20003000000ef03000000000000090000000000000000000000218+000000000108cd0003000000ef03000000000000090000000000000000000000
219-000000006e6574207469746c650000001c00c20001005000f303000000000000219+000000006e6574207469746c650000001c00cd0001005000f303000000000000
220-000000000000000000000000000000000108c30003000000ef03000000000000220+000000000000000000000000000000000108ce0003000000ef03000000000000
221-090000000000000000000000000000006e6574207469746c650000001c00c300221+090000000000000000000000000000006e6574207469746c650000001c00ce00
222-01005000f303000000000000000000000000000000000000000000000108c400222+01005000f303000000000000000000000000000000000000000000000108cf00
223-03000000ef03000000000000090000000000000000000000000000006e657420223+03000000ef03000000000000090000000000000000000000000000006e657420
224-7469746c650000001c00c40001005000f3030000000000000000000000000000224+7469746c650000001c00cf0001005000f3030000000000000000000000000000
225-00000000000000000108c50003000000ef030000000000000900000000000000225+00000000000000000108d00003000000ef030000000000000900000000000000
226-00000000000000006e6574207469746c650000001c00c50001005000f3030000226+00000000000000006e6574207469746c650000001c00d00001005000f3030000
227-00000000000000000000000000000000000000000108c60003000000ef030000227+00000000000000000000000000000000000000000108d10003000000ef030000
228-00000000090000000000000000000000000000006e6574207469746c65000000228+00000000090000000000000000000000000000006e6574207469746c65000000
229-1c00c60001005000f30300000000000000000000000000000000000000000000229+1c00d10001005000f30300000000000000000000000000000000000000000000
230-0108c70003000000ef0300000000000009000000000000000000000000000000230+0108d20003000000ef0300000000000009000000000000000000000000000000
231-6e6574207469746c650000001c00c70001005000f30300000000000000000000231+6e6574207469746c650000001c00d20001005000f30300000000000000000000
232-0000000000000000000000000108c80003000000ef0300000000000009000000232+0000000000000000000000000108d30003000000ef0300000000000009000000
233-0000000000000000000000006e6574207469746c650000001c00c80001005000233+0000000000000000000000006e6574207469746c650000001c00d30001005000
234-f303000000000000000000000000000000000000000000000108c90003000000234+f303000000000000000000000000000000000000000000000108d40003000000
235-ef03000000000000090000000000000000000000000000006e6574207469746c235+ef03000000000000090000000000000000000000000000006e6574207469746c
236-650000001c00c90001005000f303000000000000000000000000000000000000236+650000001c00d40001005000f303000000000000000000000000000000000000
237-000000000108ca0003000000ef03000000000000090000000000000000000000237+000000000108d50003000000ef03000000000000090000000000000000000000
238-000000006e6574207469746c650000001c00ca0001005000f303000000000000238+000000006e6574207469746c650000001c00d50001005000f303000000000000
239-000000000000000000000000000000000108cb0003000000ef03000000000000239+000000000000000000000000000000000108d60003000000ef03000000000000
240-090000000000000000000000000000006e6574207469746c650000001c00cb00240+090000000000000000000000000000006e6574207469746c650000001c00d600
241-01005000f303000000000000000000000000000000000000000000000108cc00241+01005000f303000000000000000000000000000000000000000000000108d700
242-03000000ef03000000000000090000000000000000000000000000006e657420242+03000000ef03000000000000090000000000000000000000000000006e657420
243-7469746c650000001c00cc0001005000f3030000000000000000000000000000243+7469746c650000001c00d70001005000f3030000000000000000000000000000
244-00000000000000000108cd0003000000ef030000000000000900000000000000244+00000000000000000108d80003000000ef030000000000000900000000000000
245-00000000000000006e6574207469746c650000001c00cd0001005000f3030000245+00000000000000006e6574207469746c650000001c00d80001005000f3030000
246-00000000000000000000000000000000000000000108ce0003000000ef030000246+00000000000000000000000000000000000000000108d90003000000ef030000
247-00000000090000000000000000000000000000006e6574207469746c65000000247+00000000090000000000000000000000000000006e6574207469746c65000000
248-1c00ce0001005000f30300000000000000000000000000000000000000000000248+1c00d90001005000f30300000000000000000000000000000000000000000000
249-0108cf0003000000ef0300000000000009000000000000000000000000000000249+0108da0003000000ef0300000000000009000000000000000000000000000000
250-6e6574207469746c650000001c00cf0001005000f30300000000000000000000250+6e6574207469746c650000001c00da0001005000f30300000000000000000000
251-0000000000000000000000000108d00003000000ef0300000000000009000000251+0000000000000000000000000108db0003000000ef0300000000000009000000
252-0000000000000000000000006e6574207469746c650000001c00d00001005000252+0000000000000000000000006e6574207469746c650000001c00db0001005000
253-f303000000000000000000000000000000000000000000000108d10003000000253+f303000000000000000000000000000000000000000000000108dc0003000000
254-ef03000000000000090000000000000000000000000000006e6574207469746c254+ef03000000000000090000000000000000000000000000006e6574207469746c
255-650000001c00d10001005000f303000000000000000000000000000000000000255+650000001c00dc0001005000f303000000000000000000000000000000000000
256-000000000108d20003000000ef03000000000000090000000000000000000000256+000000000108dd0003000000ef03000000000000090000000000000000000000
257-000000006e6574207469746c650000001c00d20001005000f303000000000000257+000000006e6574207469746c650000001c00dd0001005000f303000000000000
258-000000000000000000000000000000000108d30003000000ef03000000000000258+000000000000000000000000000000000108de0003000000ef03000000000000
259-090000000000000000000000000000006e6574207469746c650000001c00d300259+090000000000000000000000000000006e6574207469746c650000001c00de00
260-01005000f303000000000000000000000000000000000000000000000108d400260+01005000f303000000000000000000000000000000000000000000000108df00
261-03000000ef03000000000000090000000000000000000000000000006e657420261+03000000ef03000000000000090000000000000000000000000000006e657420
262-7469746c650000001c00d40001005000f3030000000000000000000000000000262+7469746c650000001c00df0001005000f3030000000000000000000000000000
263-00000000000000000108d50003000000ef030000000000000900000000000000263+00000000000000000108e00003000000ef030000000000000900000000000000
264-00000000000000006e6574207469746c650000001c00d50001005000f3030000264+00000000000000006e6574207469746c650000001c00e00001005000f3030000
265-00000000000000000000000000000000000000000108d60003000000ef030000265+00000000000000000000000000000000000000000108e10003000000ef030000
266-00000000090000000000000000000000000000006e6574207469746c65000000266+00000000090000000000000000000000000000006e6574207469746c65000000
267-1c00d60001005000f30300000000000000000000000000000000000000000000267+1c00e10001005000f30300000000000000000000000000000000000000000000
268-0108d70003000000ef0300000000000009000000000000000000000000000000268+0108e20003000000ef0300000000000009000000000000000000000000000000
269-6e6574207469746c650000001c00d70001005000f30300000000000000000000269+6e6574207469746c650000001c00e20001005000f30300000000000000000000
270-0000000000000000000000000108d80003000000ef0300000000000009000000270+0000000000000000000000000108e30003000000ef0300000000000009000000
271-0000000000000000000000006e6574207469746c650000001c00d80001005000271+0000000000000000000000006e6574207469746c650000001c00e30001005000
272-f303000000000000000000000000000000000000000000000108d90003000000272+f303000000000000000000000000000000000000000000000108e40003000000
273-ef03000000000000090000000000000000000000000000006e6574207469746c273+ef03000000000000090000000000000000000000000000006e6574207469746c
274-650000001c00d90001005000f303000000000000000000000000000000000000274+650000001c00e40001005000f303000000000000000000000000000000000000
275-000000000108da0003000000ef03000000000000090000000000000000000000275+000000000108e50003000000ef03000000000000090000000000000000000000
276-000000006e6574207469746c650000001c00da0001005000f303000000000000276+000000006e6574207469746c650000001c00e50001005000f303000000000000
277-000000000000000000000000000000000108db0003000000ef03000000000000277+000000000000000000000000000000000108e60003000000ef03000000000000
278-090000000000000000000000000000006e6574207469746c650000001c00db00278+090000000000000000000000000000006e6574207469746c650000001c00e600
279-01005000f303000000000000000000000000000000000000000000000108dc00279+01005000f303000000000000000000000000000000000000000000000108e700
280-03000000ef03000000000000090000000000000000000000000000006e657420280+03000000ef03000000000000090000000000000000000000000000006e657420
281-7469746c650000001c00dc0001005000f3030000000000000000000000000000281+7469746c650000001c00e70001005000f3030000000000000000000000000000
282-00000000000000000108dd0003000000ef030000000000000900000000000000282+00000000000000000108e80003000000ef030000000000000900000000000000
283-00000000000000006e6574207469746c650000001c00dd0001005000f3030000283+00000000000000006e6574207469746c650000001c00e80001005000f3030000
284-00000000000000000000000000000000000000000108de0003000000ef030000284+00000000000000000000000000000000000000000108e90003000000ef030000
285-00000000090000000000000000000000000000006e6574207469746c65000000285+00000000090000000000000000000000000000006e6574207469746c65000000
286-1c00de0001005000f30300000000000000000000000000000000000000000000286+1c00e90001005000f30300000000000000000000000000000000000000000000
287-0108df0003000000ef0300000000000009000000000000000000000000000000287+0108ea0003000000ef0300000000000009000000000000000000000000000000
288-6e6574207469746c650000001c00df0001005000f30300000000000000000000288+6e6574207469746c650000001c00ea0001005000f30300000000000000000000
289-0000000000000000000000000108e00003000000ef0300000000000009000000289+0000000000000000000000000108eb0003000000ef0300000000000009000000
290-0000000000000000000000006e6574207469746c650000001c00e00001005000290+0000000000000000000000006e6574207469746c650000001c00eb0001005000
291-f303000000000000000000000000000000000000000000000108e10003000000291+f303000000000000000000000000000000000000000000000108ec0003000000
292-ef03000000000000090000000000000000000000000000006e6574207469746c292+ef03000000000000090000000000000000000000000000006e6574207469746c
293-650000001c00e10001005000f303000000000000000000000000000000000000293+650000001c00ec0001005000f303000000000000000000000000000000000000
294-000000000108e20003000000ef03000000000000090000000000000000000000294+000000000108ed0003000000ef03000000000000090000000000000000000000
295-000000006e6574207469746c650000001c00e20001005000f303000000000000295+000000006e6574207469746c650000001c00ed0001005000f303000000000000
296-000000000000000000000000000000000108e30003000000ef03000000000000296+000000000000000000000000000000000108ee0003000000ef03000000000000
297-090000000000000000000000000000006e6574207469746c650000001c00e300297+090000000000000000000000000000006e6574207469746c650000001c00ee00
298-01005000f303000000000000000000000000000000000000000000000108e400298+01005000f303000000000000000000000000000000000000000000000108ef00
299-03000000ef03000000000000090000000000000000000000000000006e657420299+03000000ef03000000000000090000000000000000000000000000006e657420
300-7469746c650000001c00e40001005000f3030000000000000000000000000000300+7469746c650000001c00ef0001005000f3030000000000000000000000000000
301-00000000000000000108e50003000000ef030000000000000900000000000000301+00000000000000000108f00003000000ef030000000000000900000000000000
302-00000000000000006e6574207469746c650000001c00e50001005000f3030000302+00000000000000006e6574207469746c650000001c00f00001005000f3030000
303-00000000000000000000000000000000000000000108e60003000000ef030000303+00000000000000000000000000000000000000000108f10003000000ef030000
304-00000000090000000000000000000000000000006e6574207469746c65000000304+00000000090000000000000000000000000000006e6574207469746c65000000
305-1c00e60001005000f30300000000000000000000000000000000000000000000305+1c00f10001005000f30300000000000000000000000000000000000000000000
306-0108e70003000000ef0300000000000009000000000000000000000000000000306+0108f20003000000ef0300000000000009000000000000000000000000000000
307-6e6574207469746c650000001c00e70001005000f30300000000000000000000307+6e6574207469746c650000001c00f20001005000f30300000000000000000000
308-0000000000000000000000000108e80003000000ef0300000000000009000000308+0000000000000000000000000108f30003000000ef0300000000000009000000
309-0000000000000000000000006e6574207469746c650000001c00e80001005000309+0000000000000000000000006e6574207469746c650000001c00f30001005000
310-f303000000000000000000000000000000000000000000000108e90003000000310+f303000000000000000000000000000000000000000000000108f40003000000
311-ef03000000000000090000000000000000000000000000006e6574207469746c311+ef03000000000000090000000000000000000000000000006e6574207469746c
312-650000001c00e90001005000f303000000000000000000000000000000000000312+650000001c00f40001005000f303000000000000000000000000000000000000
313-000000000108ea0003000000ef03000000000000090000000000000000000000313+000000000108f50003000000ef03000000000000090000000000000000000000
314-000000006e6574207469746c650000001c00ea0001005000f303000000000000314+000000006e6574207469746c650000001c00f50001005000f303000000000000
315-000000000000000000000000000000000108eb0003000000ef03000000000000315+000000000000000000000000000000000108f60003000000ef03000000000000
316-090000000000000000000000000000006e6574207469746c650000001c00eb00316+090000000000000000000000000000006e6574207469746c650000001c00f600
317-01005000f303000000000000000000000000000000000000000000000108ec00317+01005000f303000000000000000000000000000000000000000000000108f700
318-03000000ef03000000000000090000000000000000000000000000006e657420318+03000000ef03000000000000090000000000000000000000000000006e657420
319-7469746c650000001c00ec0001005000f3030000000000000000000000000000319+7469746c650000001c00f70001005000f3030000000000000000000000000000
320-00000000000000000108ed0003000000ef030000000000000900000000000000320+00000000000000000108f80003000000ef030000000000000900000000000000
321-00000000000000006e6574207469746c650000001c00ed0001005000f3030000321+00000000000000006e6574207469746c650000001c00f80001005000f3030000
322-00000000000000000000000000000000000000000108ee0003000000ef030000322+00000000000000000000000000000000000000000108f90003000000ef030000
323-00000000090000000000000000000000000000006e6574207469746c65000000323+00000000090000000000000000000000000000006e6574207469746c65000000
324-1c00ee0001005000f30300000000000000000000000000000000000000000000324+1c00f90001005000f30300000000000000000000000000000000000000000000
325-0108ef0003000000ef0300000000000009000000000000000000000000000000325+0108fa0003000000ef0300000000000009000000000000000000000000000000
326-6e6574207469746c650000001c00ef0001005000f30300000000000000000000326+6e6574207469746c650000001c00fa0001005000f30300000000000000000000
327-0000000000000000000000000108f00003000000ef0300000000000009000000327+0000000000000000000000000108fb0003000000ef0300000000000009000000
328-0000000000000000000000006e6574207469746c650000001c00f00001005000328+0000000000000000000000006e6574207469746c650000001c00fb0001005000
329-f303000000000000000000000000000000000000000000000108f10003000000329+f303000000000000000000000000000000000000000000000108fc0003000000
330-ef03000000000000090000000000000000000000000000006e6574207469746c330+ef03000000000000090000000000000000000000000000006e6574207469746c
331-650000001c00f10001005000f303000000000000000000000000000000000000331+650000001c00fc0001005000f303000000000000000000000000000000000000
332-000000000108f20003000000ef03000000000000090000000000000000000000332+000000000108fd0003000000ef03000000000000090000000000000000000000
333-000000006e6574207469746c650000001c00f20001005000f303000000000000333+000000006e6574207469746c650000001c00fd0001005000f303000000000000
334-000000000000000000000000000000000108f30003000000ef03000000000000334+000000000000000000000000000000000108fe0003000000ef03000000000000
335-090000000000000000000000000000006e6574207469746c650000001c00f300335+090000000000000000000000000000006e6574207469746c650000001c00fe00
336-01005000f303000000000000000000000000000000000000000000000108f400336+01005000f303000000000000000000000000000000000000000000000108ff00
337-03000000ef03000000000000090000000000000000000000000000006e657420337+03000000ef03000000000000090000000000000000000000000000006e657420
338-7469746c650000001c00f40001005000f3030000000000000000000000000000338+7469746c650000001c00ff0001005000f3030000000000000000000000000000
339-00000000000000000108f50003000000ef030000000000000900000000000000339+00000000000000000108000103000000ef030000000000000900000000000000
340-00000000000000006e6574207469746c650000001c00f50001005000f3030000340+00000000000000006e6574207469746c650000001c00000101005000f3030000
341-00000000000000000000000000000000000000000108f60003000000ef030000341+00000000000000000000000000000000000000000108010103000000ef030000
342-00000000090000000000000000000000000000006e6574207469746c65000000342+00000000090000000000000000000000000000006e6574207469746c65000000
343-1c00f60001005000f30300000000000000000000000000000000000000000000343+1c00010101005000f30300000000000000000000000000000000000000000000
344-0108f70003000000ef0300000000000009000000000000000000000000000000344+0108020103000000ef0300000000000009000000000000000000000000000000
345-6e6574207469746c650000001c00f70001005000f30300000000000000000000345+6e6574207469746c650000001c00020101005000f30300000000000000000000
346-0000000000000000000000000108f80003000000ef0300000000000009000000346+0000000000000000000000000108030103000000ef0300000000000009000000
347-0000000000000000000000006e6574207469746c650000001c00f80001005000347+0000000000000000000000006e6574207469746c650000001c00030101005000
348-f303000000000000000000000000000000000000000000000108f90003000000348+f303000000000000000000000000000000000000000000000108040103000000
349-ef03000000000000090000000000000000000000000000006e6574207469746c349+ef03000000000000090000000000000000000000000000006e6574207469746c
350-650000001c00f90001005000f303000000000000000000000000000000000000350+650000001c00040101005000f303000000000000000000000000000000000000
351-000000000108fa0003000000ef03000000000000090000000000000000000000351+000000000108050103000000ef03000000000000090000000000000000000000
352-000000006e6574207469746c650000001c00fa0001005000f303000000000000352+000000006e6574207469746c650000001c00050101005000f303000000000000
353-000000000000000000000000000000000108fb0003000000ef03000000000000353+000000000000000000000000000000000108060103000000ef03000000000000
354-090000000000000000000000000000006e6574207469746c650000001c00fb00354+090000000000000000000000000000006e6574207469746c650000001c000601
355-01005000f303000000000000000000000000000000000000000000000108fc00355+01005000f3030000000000000000000000000000000000000000000001080701
356-03000000ef03000000000000090000000000000000000000000000006e657420356+03000000ef03000000000000090000000000000000000000000000006e657420
357-7469746c650000001c00fc0001005000f3030000000000000000000000000000357+7469746c650000001c00070101005000f3030000000000000000000000000000
358-00000000000000000108fd0003000000ef030000000000000900000000000000358+00000000000000000108080103000000ef030000000000000900000000000000
359-00000000000000006e6574207469746c650000001c00fd0001005000f3030000359+00000000000000006e6574207469746c650000001c00080101005000f3030000
360-00000000000000000000000000000000000000000108fe0003000000ef030000360+00000000000000000000000000000000000000000108090103000000ef030000
361-00000000090000000000000000000000000000006e6574207469746c65000000361+00000000090000000000000000000000000000006e6574207469746c65000000
362-1c00fe0001005000f30300000000000000000000000000000000000000000000362+1c00090101005000f30300000000000000000000000000000000000000000000
363-0108ff0003000000ef0300000000000009000000000000000000000000000000363+01080a0103000000ef0300000000000009000000000000000000000000000000
364-6e6574207469746c650000001c00ff0001005000f30300000000000000000000364+6e6574207469746c650000001c000a0101005000f30300000000000000000000
365-0000000000000000000000000108000103000000ef0300000000000009000000365+00000000000000000000000001080b0103000000ef0300000000000009000000
366-0000000000000000000000006e6574207469746c650000001c00000101005000366+0000000000000000000000006e6574207469746c650000001c000b0101005000
367-f303000000000000000000000000000000000000000000000108010103000000367+f3030000000000000000000000000000000000000000000001080c0103000000
368-ef03000000000000090000000000000000000000000000006e6574207469746c368+ef03000000000000090000000000000000000000000000006e6574207469746c
369-650000001c00010101005000f303000000000000000000000000000000000000369+650000001c000c0101005000f303000000000000000000000000000000000000
370-000000000108020103000000ef03000000000000090000000000000000000000370+0000000001080d0103000000ef03000000000000090000000000000000000000
371-000000006e6574207469746c650000001c00020101005000f303000000000000371+000000006e6574207469746c650000001c000d0101005000f303000000000000
372-000000000000000000000000000000000108030103000000ef03000000000000372+0000000000000000000000000000000001080e0103000000ef03000000000000
373-090000000000000000000000000000006e6574207469746c650000001c000301373+090000000000000000000000000000006e6574207469746c650000001c000e01
374-01005000f3030000000000000000000000000000000000000000000001080401374+01005000f3030000000000000000000000000000000000000000000001080f01
375-03000000ef03000000000000090000000000000000000000000000006e657420375+03000000ef03000000000000090000000000000000000000000000006e657420
376-7469746c650000001c00040101005000f3030000000000000000000000000000376+7469746c650000001c000f0101005000f3030000000000000000000000000000
377-00000000000000000108050103000000ef030000000000000900000000000000377+00000000000000000108100103000000ef030000000000000900000000000000
378-00000000000000006e6574207469746c650000001c00050101005000f3030000378+00000000000000006e6574207469746c650000001c00100101005000f3030000
379-00000000000000000000000000000000000000000108060103000000ef030000379+00000000000000000000000000000000000000000108110103000000ef030000
380-00000000090000000000000000000000000000006e6574207469746c65000000380+00000000090000000000000000000000000000006e6574207469746c65000000
381-1c00060101005000f30300000000000000000000000000000000000000000000381+1c00110101005000f30300000000000000000000000000000000000000000000
382-0108070103000000ef0300000000000009000000000000000000000000000000382+0108120103000000ef0300000000000009000000000000000000000000000000
383-6e6574207469746c650000001c00070101005000f30300000000000000000000383+6e6574207469746c650000001c00120101005000f30300000000000000000000
384-0000000000000000000000000108080103000000ef0300000000000009000000384+0000000000000000000000000108130103000000ef0300000000000009000000
385-0000000000000000000000006e6574207469746c650000001c00080101005000385+0000000000000000000000006e6574207469746c650000001c00130101005000
386-f303000000000000000000000000000000000000000000000108090103000000386+f303000000000000000000000000000000000000000000000108140103000000
387-ef03000000000000090000000000000000000000000000006e6574207469746c387+ef03000000000000090000000000000000000000000000006e6574207469746c
388-650000001c00090101005000f303000000000000000000000000000000000000388+650000001c00140101005000f303000000000000000000000000000000000000
389-0000000001080a0103000000ef03000000000000090000000000000000000000389+000000000108150103000000ef03000000000000090000000000000000000000
390-000000006e6574207469746c650000001c000a0101005000f303000000000000390+000000006e6574207469746c650000001c00150101005000f303000000000000
391-0000000000000000000000000000000001080b0103000000ef03000000000000391+000000000000000000000000000000000108160103000000ef03000000000000
392-090000000000000000000000000000006e6574207469746c650000001c000b01392+090000000000000000000000000000006e6574207469746c650000001c001601
393-01005000f3030000000000000000000000000000000000000000000001080c01393+01005000f3030000000000000000000000000000000000000000000001081701
394-03000000ef03000000000000090000000000000000000000000000006e657420394+03000000ef03000000000000090000000000000000000000000000006e657420
395-7469746c650000001c000c0101005000f3030000000000000000000000000000395+7469746c650000001c00170101005000f3030000000000000000000000000000
396-000000000000000001080d0103000000ef030000000000000900000000000000396+00000000000000000108180103000000ef030000000000000900000000000000
397-00000000000000006e6574207469746c650000001c000d0101005000f3030000397+00000000000000006e6574207469746c650000001c00180101005000f3030000
398-000000000000000000000000000000000000000001080e0103000000ef030000398+00000000000000000000000000000000000000000108190103000000ef030000
399-00000000090000000000000000000000000000006e6574207469746c65000000399+00000000090000000000000000000000000000006e6574207469746c65000000
400-1c000e0101005000f30300000000000000000000000000000000000000000000400+1c00190101005000f30300000000000000000000000000000000000000000000
401-01080f0103000000ef0300000000000009000000000000000000000000000000401+01081a0103000000ef0300000000000009000000000000000000000000000000
402-6e6574207469746c650000001c000f0101005000f30300000000000000000000402+6e6574207469746c650000001c001a0101005000f30300000000000000000000
403-0000000000000000000000000108100103000000ef0300000000000009000000403+00000000000000000000000001081b0103000000ef0300000000000009000000
404-0000000000000000000000006e6574207469746c650000001c00100101005000404+0000000000000000000000006e6574207469746c650000001c001b0101005000
405-f303000000000000000000000000000000000000000000000108110103000000405+f3030000000000000000000000000000000000000000000001081c0103000000
406-ef03000000000000090000000000000000000000000000006e6574207469746c406+ef03000000000000090000000000000000000000000000006e6574207469746c
407-650000001c00110101005000f303000000000000000000000000000000000000407+650000001c001c0101005000f303000000000000000000000000000000000000
408-000000000108120103000000ef03000000000000090000000000000000000000408+0000000001081d0103000000ef03000000000000090000000000000000000000
409-000000006e6574207469746c650000001c00120101005000f303000000000000409+000000006e6574207469746c650000001c001d0101005000f303000000000000
410-000000000000000000000000000000000108130103000000ef03000000000000410+0000000000000000000000000000000001081e0103000000ef03000000000000
411-090000000000000000000000000000006e6574207469746c650000001c001301411+090000000000000000000000000000006e6574207469746c650000001c001e01
412-01005000f3030000000000000000000000000000000000000000000001081401412+01005000f3030000000000000000000000000000000000000000000001081f01
413-03000000ef03000000000000090000000000000000000000000000006e657420413+03000000ef03000000000000090000000000000000000000000000006e657420
414-7469746c650000001c00140101005000f3030000000000000000000000000000414+7469746c650000001c001f0101005000f3030000000000000000000000000000
415-00000000000000000108150103000000ef030000000000000900000000000000415+00000000000000000108200103000000ef030000000000000900000000000000
416-00000000000000006e6574207469746c650000001c00150101005000f3030000416+00000000000000006e6574207469746c650000001c00200101005000f3030000
417-00000000000000000000000000000000000000000108160103000000ef030000417+00000000000000000000000000000000000000000108210103000000ef030000
418-00000000090000000000000000000000000000006e6574207469746c65000000418+00000000090000000000000000000000000000006e6574207469746c65000000
419-1c00160101005000f30300000000000000000000000000000000000000000000419+1c00210101005000f30300000000000000000000000000000000000000000000
420-0108170103000000ef0300000000000009000000000000000000000000000000420+0108220103000000ef0300000000000009000000000000000000000000000000
421-6e6574207469746c650000001c00170101005000f30300000000000000000000421+6e6574207469746c650000001c00220101005000f30300000000000000000000
422-0000000000000000000000000108180103000000ef0300000000000009000000422+0000000000000000000000000108230103000000ef0300000000000009000000
423-0000000000000000000000006e6574207469746c650000001c00180101005000423+0000000000000000000000006e6574207469746c650000001c00230101005000
424-f303000000000000000000000000000000000000000000000108190103000000424+f303000000000000000000000000000000000000000000000108240103000000
425-ef03000000000000090000000000000000000000000000006e6574207469746c425+ef03000000000000090000000000000000000000000000006e6574207469746c
426-650000001c00190101005000f303000000000000000000000000000000000000426+650000001c00240101005000f303000000000000000000000000000000000000
427-0000000001081a0103000000ef03000000000000090000000000000000000000427+000000000108250103000000ef03000000000000090000000000000000000000
428-000000006e6574207469746c650000001c001a0101005000f303000000000000428+000000006e6574207469746c650000001c00250101005000f303000000000000
429-0000000000000000000000000000000001081b0103000000ef03000000000000429+000000000000000000000000000000000108260103000000ef03000000000000
430-090000000000000000000000000000006e6574207469746c650000001c001b01430+090000000000000000000000000000006e6574207469746c650000001c002601
431-01005000f3030000000000000000000000000000000000000000000001081c01431+01005000f3030000000000000000000000000000000000000000000001082701
432-03000000ef03000000000000090000000000000000000000000000006e657420432+03000000ef03000000000000090000000000000000000000000000006e657420
433-7469746c650000001c001c0101005000f3030000000000000000000000000000433+7469746c650000001c00270101005000f3030000000000000000000000000000
434-000000000000000001081d0103000000ef030000000000000900000000000000434+00000000000000000108280103000000ef030000000000000900000000000000
435-00000000000000006e6574207469746c650000001c001d0101005000f3030000435+00000000000000006e6574207469746c650000001c00280101005000f3030000
436-000000000000000000000000000000000000000001081e0103000000ef030000436+00000000000000000000000000000000000000000108290103000000ef030000
437-00000000090000000000000000000000000000006e6574207469746c65000000437+00000000090000000000000000000000000000006e6574207469746c65000000
438-1c001e0101005000f30300000000000000000000000000000000000000000000438+1c00290101005000f30300000000000000000000000000000000000000000000
439-01081f0103000000ef0300000000000009000000000000000000000000000000439+01082a0103000000ef0300000000000009000000000000000000000000000000
440-6e6574207469746c650000001c001f0101005000f30300000000000000000000440+6e6574207469746c650000001c002a0101005000f30300000000000000000000
441-0000000000000000000000000108200103000000ef0300000000000009000000441+00000000000000000000000001082b0103000000ef0300000000000009000000
442-0000000000000000000000006e6574207469746c650000001c00200101005000442+0000000000000000000000006e6574207469746c650000001c002b0101005000
443-f303000000000000000000000000000000000000000000000108210103000000443+f3030000000000000000000000000000000000000000000001082c0103000000
444-ef03000000000000090000000000000000000000000000006e6574207469746c444+ef03000000000000090000000000000000000000000000006e6574207469746c
445-650000001c00210101005000f303000000000000000000000000000000000000445+650000001c002c0101005000f303000000000000000000000000000000000000
446-000000000108220103000000ef03000000000000090000000000000000000000446+0000000001082d0103000000ef03000000000000090000000000000000000000
447-000000006e6574207469746c650000001c00220101005000f303000000000000447+000000006e6574207469746c650000001c002d0101005000f303000000000000
448-000000000000000000000000000000000108230103000000ef03000000000000448+0000000000000000000000000000000001082e0103000000ef03000000000000
449-090000000000000000000000000000006e6574207469746c650000001c002301449+090000000000000000000000000000006e6574207469746c650000001c002e01
450-01005000f3030000000000000000000000000000000000000000000001082401450+01005000f3030000000000000000000000000000000000000000000001082f01
451-03000000ef03000000000000090000000000000000000000000000006e657420451+03000000ef03000000000000090000000000000000000000000000006e657420
452-7469746c650000001c00240101005000f3030000000000000000000000000000452+7469746c650000001c002f0101005000f3030000000000000000000000000000
453-00000000000000000108250103000000ef030000000000000900000000000000453+00000000000000000108300103000000ef030000000000000900000000000000
454-00000000000000006e6574207469746c650000001c00250101005000f3030000454+00000000000000006e6574207469746c650000001c00300101005000f3030000
455-00000000000000000000000000000000000000000108260103000000ef030000455+00000000000000000000000000000000000000000108310103000000ef030000
456-00000000090000000000000000000000000000006e6574207469746c65000000456+00000000090000000000000000000000000000006e6574207469746c65000000
457-1c00260101005000f30300000000000000000000000000000000000000000000457+1c00310101005000f30300000000000000000000000000000000000000000000
458-0108270103000000ef0300000000000009000000000000000000000000000000458+0108320103000000ef0300000000000009000000000000000000000000000000
459-6e6574207469746c650000001c00270101005000f30300000000000000000000459+6e6574207469746c650000001c00320101005000f30300000000000000000000
460-0000000000000000000000000108280103000000ef0300000000000009000000460+0000000000000000000000000108330103000000ef0300000000000009000000
461-0000000000000000000000006e6574207469746c650000001c00280101005000461+0000000000000000000000006e6574207469746c650000001c00330101005000
462-f303000000000000000000000000000000000000000000000108290103000000462+f303000000000000000000000000000000000000000000000108340103000000
463-ef03000000000000090000000000000000000000000000006e6574207469746c463+ef03000000000000090000000000000000000000000000006e6574207469746c
464-650000001c00290101005000f303000000000000000000000000000000000000464+650000001c00340101005000f303000000000000000000000000000000000000
465-0000000001082a0103000000ef03000000000000090000000000000000000000465+000000000108350103000000ef03000000000000090000000000000000000000
466-000000006e6574207469746c650000001c002a0101005000f303000000000000466+000000006e6574207469746c650000001c00350101005000f303000000000000
467-0000000000000000000000000000000001082b0103000000ef03000000000000467+000000000000000000000000000000000108360103000000ef03000000000000
468-090000000000000000000000000000006e6574207469746c650000001c002b01468+090000000000000000000000000000006e6574207469746c650000001c003601
469-01005000f3030000000000000000000000000000000000000000000001082c01469+01005000f3030000000000000000000000000000000000000000000001083701
470-03000000ef03000000000000090000000000000000000000000000006e657420470+03000000ef03000000000000090000000000000000000000000000006e657420
471-7469746c650000001c002c0101005000f3030000000000000000000000000000471+7469746c650000001c00370101005000f3030000000000000000000000000000
472-000000000000000001082d0103000000ef030000000000000900000000000000472+00000000000000000108380103000000ef030000000000000900000000000000
473-00000000000000006e6574207469746c650000001c002d0101005000f3030000473+00000000000000006e6574207469746c650000001c00380101005000f3030000
474-000000000000000000000000000000000000000001082e0103000000ef030000474+00000000000000000000000000000000000000000108390103000000ef030000
475-00000000090000000000000000000000000000006e6574207469746c65000000475+00000000090000000000000000000000000000006e6574207469746c65000000
476-1c002e0101005000f30300000000000000000000000000000000000000000000476+1c00390101005000f30300000000000000000000000000000000000000000000
477-01082f0103000000ef0300000000000009000000000000000000000000000000477+01083a0103000000ef0300000000000009000000000000000000000000000000
478-6e6574207469746c650000001c002f0101005000f30300000000000000000000478+6e6574207469746c650000001c003a0101005000f30300000000000000000000
479-0000000000000000000000000108300103000000ef0300000000000009000000479+00000000000000000000000001083b0103000000ef0300000000000009000000
480-0000000000000000000000006e6574207469746c650000001c00300101005000480+0000000000000000000000006e6574207469746c650000001c003b0101005000
481-f303000000000000000000000000000000000000000000000108310103000000481+f3030000000000000000000000000000000000000000000001083c0103000000
482-ef03000000000000090000000000000000000000000000006e6574207469746c482+ef03000000000000090000000000000000000000000000006e6574207469746c
483-650000001c00310101005000f303000000000000000000000000000000000000483+650000001c003c0101005000f303000000000000000000000000000000000000
484-000000000108320103000000ef03000000000000090000000000000000000000484+0000000001083d0103000000ef03000000000000090000000000000000000000
485-000000006e6574207469746c650000001c00320101005000f303000000000000485+000000006e6574207469746c650000001c003d0101005000f303000000000000
486-000000000000000000000000000000000108330103000000ef03000000000000486+0000000000000000000000000000000001083e0103000000ef03000000000000
487-090000000000000000000000000000006e6574207469746c650000001c003301487+090000000000000000000000000000006e6574207469746c650000001c003e01
488-01005000f3030000000000000000000000000000000000000000000001083401488+01005000f3030000000000000000000000000000000000000000000001083f01
489-03000000ef03000000000000090000000000000000000000000000006e657420489+03000000ef03000000000000090000000000000000000000000000006e657420
490-7469746c650000001c00340101005000f3030000000000000000000000000000490+7469746c650000001c003f0101005000f3030000000000000000000000000000
491-00000000000000000108350103000000ef030000000000000900000000000000491+00000000000000000108400103000000ef030000000000000900000000000000
492-00000000000000006e6574207469746c650000001c00350101005000f3030000492+00000000000000006e6574207469746c650000001c00400101005000f3030000
493-00000000000000000000000000000000000000000108360103000000ef030000493+00000000000000000000000000000000000000000108410103000000ef030000
494-00000000090000000000000000000000000000006e6574207469746c65000000494+00000000090000000000000000000000000000006e6574207469746c65000000
495-1c00360101005000f30300000000000000000000000000000000000000000000495+1c00410101005000f30300000000000000000000000000000000000000000000
496-0108370103000000ef0300000000000009000000000000000000000000000000496+0108420103000000ef0300000000000009000000000000000000000000000000
497-6e6574207469746c650000001c00370101005000f30300000000000000000000497+6e6574207469746c650000001c00420101005000f30300000000000000000000
498-0000000000000000000000000108380103000000ef0300000000000009000000498+0000000000000000000000000108430103000000ef0300000000000009000000
499-0000000000000000000000006e6574207469746c650000001c00380101005000499+0000000000000000000000006e6574207469746c650000001c00430101005000
500-f303000000000000000000000000000000000000000000000108390103000000500+f303000000000000000000000000000000000000000000000108440103000000
501-ef03000000000000090000000000000000000000000000006e6574207469746c501+ef03000000000000090000000000000000000000000000006e6574207469746c
502-650000001c00390101005000f303000000000000000000000000000000000000502+650000001c00440101005000f303000000000000000000000000000000000000
503-0000000001083a0103000000ef03000000000000090000000000000000000000503+000000000108450103000000ef03000000000000090000000000000000000000
504-000000006e6574207469746c650000001c003a0101005000f303000000000000504+000000006e6574207469746c650000001c00450101005000f303000000000000
505-0000000000000000000000000000000001083b0103000000ef03000000000000505+000000000000000000000000000000000108460103000000ef03000000000000
506-090000000000000000000000000000006e6574207469746c650000001c003b01506+090000000000000000000000000000006e6574207469746c650000001c004601
507-01005000f3030000000000000000000000000000000000000000000001083c01507+01005000f3030000000000000000000000000000000000000000000001084701
508-03000000ef03000000000000090000000000000000000000000000006e657420508+03000000ef03000000000000090000000000000000000000000000006e657420
509-7469746c650000001c003c0101005000f3030000000000000000000000000000509+7469746c650000001c00470101005000f3030000000000000000000000000000
510-000000000000000001083d0103000000ef030000000000000900000000000000510+00000000000000000108480103000000ef030000000000000900000000000000
511-00000000000000006e6574207469746c650000001c003d0101005000f3030000511+00000000000000006e6574207469746c650000001c00480101005000f3030000
512-000000000000000000000000000000000000000001083e0103000000ef030000512+00000000000000000000000000000000000000000108490103000000ef030000
513-00000000090000000000000000000000000000006e6574207469746c65000000513+00000000090000000000000000000000000000006e6574207469746c65000000
514-1c003e0101005000f30300000000000000000000000000000000000000000000514+1c00490101005000f30300000000000000000000000000000000000000000000
515-01083f0103000000ef0300000000000009000000000000000000000000000000515+01084a0103000000ef0300000000000009000000000000000000000000000000
516-6e6574207469746c650000001c003f0101005000f30300000000000000000000516+6e6574207469746c650000001c004a0101005000f30300000000000000000000
517-0000000000000000000000000108400103000000ef0300000000000009000000517+00000000000000000000000001084b0103000000ef0300000000000009000000
518-0000000000000000000000006e6574207469746c650000001c00400101005000518+0000000000000000000000006e6574207469746c650000001c004b0101005000
519-f303000000000000000000000000000000000000000000000108410103000000519+f3030000000000000000000000000000000000000000000001084c0103000000
520-ef03000000000000090000000000000000000000000000006e6574207469746c520+ef03000000000000090000000000000000000000000000006e6574207469746c
521-650000001c00410101005000f303000000000000000000000000000000000000521+650000001c004c0101005000f303000000000000000000000000000000000000
522-000000000108420103000000ef03000000000000090000000000000000000000522+0000000001084d0103000000ef03000000000000090000000000000000000000
523-000000006e6574207469746c650000001c00420101005000f303000000000000523+000000006e6574207469746c650000001c004d0101005000f303000000000000
524-000000000000000000000000000000000108430103000000ef03000000000000524+0000000000000000000000000000000001084e0103000000ef03000000000000
525-090000000000000000000000000000006e6574207469746c650000001c004301525+090000000000000000000000000000006e6574207469746c650000001c004e01
526-01005000f3030000000000000000000000000000000000000000000001084401526+01005000f3030000000000000000000000000000000000000000000001084f01
527-03000000ef03000000000000090000000000000000000000000000006e657420527+03000000ef03000000000000090000000000000000000000000000006e657420
528-7469746c650000001c00440101005000f3030000000000000000000000000000528+7469746c650000001c004f0101005000f3030000000000000000000000000000
529-00000000000000000108450103000000ef030000000000000900000000000000529+00000000000000000108500103000000ef030000000000000900000000000000
530-00000000000000006e6574207469746c650000001c00450101005000f3030000530+00000000000000006e6574207469746c650000001c00500101005000f3030000
531-00000000000000000000000000000000000000000108460103000000ef030000531+00000000000000000000000000000000000000000108510103000000ef030000
532-00000000090000000000000000000000000000006e6574207469746c65000000532+00000000090000000000000000000000000000006e6574207469746c65000000
533-1c00460101005000f30300000000000000000000000000000000000000000000533+1c00510101005000f30300000000000000000000000000000000000000000000
534-0108470103000000ef0300000000000009000000000000000000000000000000534+0108520103000000ef0300000000000009000000000000000000000000000000
535-6e6574207469746c650000001c00470101005000f30300000000000000000000535+6e6574207469746c650000001c00520101005000f30300000000000000000000
536-0000000000000000000000000108480103000000ef0300000000000009000000536+0000000000000000000000000108530103000000ef0300000000000009000000
537-0000000000000000000000006e6574207469746c650000001c00480101005000537+0000000000000000000000006e6574207469746c650000001c00530101005000
538-f303000000000000000000000000000000000000000000000108490103000000538+f303000000000000000000000000000000000000000000000108540103000000
539-ef03000000000000090000000000000000000000000000006e6574207469746c539+ef03000000000000090000000000000000000000000000006e6574207469746c
540-650000001c00490101005000f303000000000000000000000000000000000000540+650000001c00540101005000f303000000000000000000000000000000000000
541-0000000001084a0103000000ef03000000000000090000000000000000000000541+000000000108550103000000ef03000000000000090000000000000000000000
542-000000006e6574207469746c650000001c004a0101005000f303000000000000542+000000006e6574207469746c650000001c00550101005000f303000000000000
543-0000000000000000000000000000000001084b0103000000ef03000000000000543+000000000000000000000000000000000108560103000000ef03000000000000
544-090000000000000000000000000000006e6574207469746c650000001c004b01544+090000000000000000000000000000006e6574207469746c650000001c005601
545-01005000f3030000000000000000000000000000000000000000000001084c01545+01005000f3030000000000000000000000000000000000000000000001085701
546-03000000ef03000000000000090000000000000000000000000000006e657420546+03000000ef03000000000000090000000000000000000000000000006e657420
547-7469746c650000001c004c0101005000f3030000000000000000000000000000547+7469746c650000001c00570101005000f3030000000000000000000000000000
548-000000000000000001084d0103000000ef030000000000000900000000000000548+00000000000000000108580103000000ef030000000000000900000000000000
549-00000000000000006e6574207469746c650000001c004d0101005000f3030000549+00000000000000006e6574207469746c650000001c00580101005000f3030000
550-000000000000000000000000000000000000000001084e0103000000ef030000550+00000000000000000000000000000000000000000108590103000000ef030000
551-00000000090000000000000000000000000000006e6574207469746c65000000551+00000000090000000000000000000000000000006e6574207469746c65000000
552-1c004e0101005000f30300000000000000000000000000000000000000000000552+1c00590101005000f30300000000000000000000000000000000000000000000
553-01084f0103000000ef0300000000000009000000000000000000000000000000553+01085a0103000000ef0300000000000009000000000000000000000000000000
554-6e6574207469746c650000001c004f0101005000f30300000000000000000000554+6e6574207469746c650000001c005a0101005000f30300000000000000000000
555-0000000000000000000000000108500103000000ef0300000000000009000000555+00000000000000000000000001085b0103000000ef0300000000000009000000
556-0000000000000000000000006e6574207469746c650000001c00500101005000556+0000000000000000000000006e6574207469746c650000001c005b0101005000
557-f303000000000000000000000000000000000000000000000108510103000000557+f3030000000000000000000000000000000000000000000001085c0103000000
558-ef03000000000000090000000000000000000000000000006e6574207469746c558+ef03000000000000090000000000000000000000000000006e6574207469746c
559-650000001c00510101005000f303000000000000000000000000000000000000559+650000001c005c0101005000f303000000000000000000000000000000000000
560-000000000108520103000000ef03000000000000090000000000000000000000560+0000000001085d0103000000ef03000000000000090000000000000000000000
561-000000006e6574207469746c650000001c00520101005000f303000000000000561+000000006e6574207469746c650000001c005d0101005000f303000000000000
562-000000000000000000000000000000000108530103000000ef03000000000000562+0000000000000000000000000000000001085e0103000000ef03000000000000
563-090000000000000000000000000000006e6574207469746c650000001c005301563+090000000000000000000000000000006e6574207469746c650000001c005e01
564-01005000f3030000000000000000000000000000000000000000000001085401564+01005000f3030000000000000000000000000000000000000000000001085f01
565-03000000ef03000000000000090000000000000000000000000000006e657420565+03000000ef03000000000000090000000000000000000000000000006e657420
566-7469746c650000001c00540101005000f3030000000000000000000000000000566+7469746c650000001c005f0101005000f3030000000000000000000000000000
567-00000000000000000108550103000000ef030000000000000900000000000000567+00000000000000000108600103000000ef030000000000000900000000000000
568-00000000000000006e6574207469746c650000001c00550101005000f3030000568+00000000000000006e6574207469746c650000001c00600101005000f3030000
569-00000000000000000000000000000000000000000108560103000000ef030000569+00000000000000000000000000000000000000000108610103000000ef030000
570-00000000090000000000000000000000000000006e6574207469746c65000000570+00000000090000000000000000000000000000006e6574207469746c65000000
571-1c00560101005000f30300000000000000000000000000000000000000000000571+1c00610101005000f30300000000000000000000000000000000000000000000
572-0108570103000000ef0300000000000009000000000000000000000000000000572+0108620103000000ef0300000000000009000000000000000000000000000000
573-6e6574207469746c650000001c00570101005000f30300000000000000000000573+6e6574207469746c650000001c00620101005000f30300000000000000000000
574-0000000000000000000000000108580103000000ef0300000000000009000000574+0000000000000000000000000108630103000000ef0300000000000009000000
575-0000000000000000000000006e6574207469746c650000001c00580101005000575+0000000000000000000000006e6574207469746c650000001c00630101005000
576-f303000000000000000000000000000000000000000000000108590103000000576+f303000000000000000000000000000000000000000000000108640103000000
577-ef03000000000000090000000000000000000000000000006e6574207469746c577+ef03000000000000090000000000000000000000000000006e6574207469746c
578-650000001c00590101005000f303000000000000000000000000000000000000578+650000001c00640101005000f303000000000000000000000000000000000000
579-0000000001085a0103000000ef03000000000000090000000000000000000000579+000000000108650103000000ef03000000000000090000000000000000000000
580-000000006e6574207469746c650000001c005a0101005000f303000000000000580+000000006e6574207469746c650000001c00650101005000f303000000000000
581-0000000000000000000000000000000001085b0103000000ef03000000000000581+000000000000000000000000000000000108660103000000ef03000000000000
582-090000000000000000000000000000006e6574207469746c650000001c005b01582+090000000000000000000000000000006e6574207469746c650000001c006601
583-01005000f3030000000000000000000000000000000000000000000001085c01583+01005000f3030000000000000000000000000000000000000000000001086701
584-03000000ef03000000000000090000000000000000000000000000006e657420584+03000000ef03000000000000090000000000000000000000000000006e657420
585-7469746c650000001c005c0101005000f3030000000000000000000000000000585+7469746c650000001c00670101005000f3030000000000000000000000000000
586-000000000000000001085d0103000000ef030000000000000900000000000000586+00000000000000000108680103000000ef030000000000000900000000000000
587-00000000000000006e6574207469746c650000001c005d0101005000f3030000587+00000000000000006e6574207469746c650000001c00680101005000f3030000
588-000000000000000000000000000000000000000001085e0103000000ef030000588+00000000000000000000000000000000000000000108690103000000ef030000
589-00000000090000000000000000000000000000006e6574207469746c65000000589+00000000090000000000000000000000000000006e6574207469746c65000000
590-1c005e0101005000f30300000000000000000000000000000000000000000000590+1c00690101005000f30300000000000000000000000000000000000000000000
591-01085f0103000000ef0300000000000009000000000000000000000000000000591+01086a0103000000ef0300000000000009000000000000000000000000000000
592-6e6574207469746c650000001c005f0101005000f30300000000000000000000592+6e6574207469746c650000001c006a0101005000f30300000000000000000000
593-0000000000000000000000000108600103000000ef0300000000000009000000593+00000000000000000000000001086b0103000000ef0300000000000009000000
594-0000000000000000000000006e6574207469746c650000001c00600101005000594+0000000000000000000000006e6574207469746c650000001c006b0101005000
595-f303000000000000000000000000000000000000000000000108610103000000595+f3030000000000000000000000000000000000000000000001086c0103000000
596-ef03000000000000090000000000000000000000000000006e6574207469746c596+ef03000000000000090000000000000000000000000000006e6574207469746c
597-650000001c00610101005000f303000000000000000000000000000000000000597+650000001c006c0101005000f303000000000000000000000000000000000000
598-000000000108620103000000ef03000000000000090000000000000000000000598+0000000001086d0103000000ef03000000000000090000000000000000000000
599-000000006e6574207469746c650000001c00620101005000f303000000000000599+000000006e6574207469746c650000001c006d0101005000f303000000000000
600-000000000000000000000000000000000108630103000000ef03000000000000600+0000000000000000000000000000000001086e0103000000ef03000000000000
601-090000000000000000000000000000006e6574207469746c650000001c006301601+090000000000000000000000000000006e6574207469746c650000001c006e01
602-01005000f3030000000000000000000000000000000000000000000001086401602+01005000f3030000000000000000000000000000000000000000000001086f01
603-03000000ef03000000000000090000000000000000000000000000006e657420603+03000000ef03000000000000090000000000000000000000000000006e657420
604-7469746c650000001c00640101005000f3030000000000000000000000000000604+7469746c650000001c006f0101005000f3030000000000000000000000000000
605-00000000000000000108650103000000ef030000000000000900000000000000605+00000000000000000108700103000000ef030000000000000900000000000000
606-00000000000000006e6574207469746c650000001c00650101005000f3030000606+00000000000000006e6574207469746c650000001c00700101005000f3030000
607-00000000000000000000000000000000000000000108660103000000ef030000607+00000000000000000000000000000000000000000108710103000000ef030000
608-00000000090000000000000000000000000000006e6574207469746c65000000608+00000000090000000000000000000000000000006e6574207469746c65000000
609-1c00660101005000f30300000000000000000000000000000000000000000000609+1c00710101005000f30300000000000000000000000000000000000000000000
610-0108670103000000ef0300000000000009000000000000000000000000000000610+0108720103000000ef0300000000000009000000000000000000000000000000
611-6e6574207469746c650000001c00670101005000f30300000000000000000000611+6e6574207469746c650000001c00720101005000f30300000000000000000000
612-0000000000000000000000000108680103000000ef0300000000000009000000612+0000000000000000000000000108730103000000ef0300000000000009000000
613-0000000000000000000000006e6574207469746c650000001c00680101005000613+0000000000000000000000006e6574207469746c650000001c00730101005000
614-f303000000000000000000000000000000000000000000000108690103000000614+f303000000000000000000000000000000000000000000000108740103000000
615-ef03000000000000090000000000000000000000000000006e6574207469746c615+ef03000000000000090000000000000000000000000000006e6574207469746c
616-650000001c00690101005000f303000000000000000000000000000000000000616+650000001c00740101005000f303000000000000000000000000000000000000
617-0000000001086a0103000000ef03000000000000090000000000000000000000617+000000000108750103000000ef03000000000000090000000000000000000000
618-000000006e6574207469746c650000001c006a0101005000f303000000000000618+000000006e6574207469746c650000001c00750101005000f303000000000000
619-0000000000000000000000000000000001086b0103000000ef03000000000000619+000000000000000000000000000000000108760103000000ef03000000000000
620-090000000000000000000000000000006e6574207469746c650000001c006b01620+090000000000000000000000000000006e6574207469746c650000001c007601
621-01005000f3030000000000000000000000000000000000000000000001086c01621+01005000f3030000000000000000000000000000000000000000000001087701
622-03000000ef03000000000000090000000000000000000000000000006e657420622+03000000ef03000000000000090000000000000000000000000000006e657420
623-7469746c650000001c006c0101005000f3030000000000000000000000000000623+7469746c650000001c00770101005000f3030000000000000000000000000000
624-000000000000000001086d0103000000ef030000000000000900000000000000624+00000000000000000108780103000000ef030000000000000900000000000000
625-00000000000000006e6574207469746c650000001c006d0101005000f3030000625+00000000000000006e6574207469746c650000001c00780101005000f3030000
626-000000000000000000000000000000000000000001086e0103000000ef030000626+00000000000000000000000000000000000000000108790103000000ef030000
627-00000000090000000000000000000000000000006e6574207469746c65000000627+00000000090000000000000000000000000000006e6574207469746c65000000
628-1c006e0101005000f30300000000000000000000000000000000000000000000628+1c00790101005000f30300000000000000000000000000000000000000000000
629-01086f0103000000ef0300000000000009000000000000000000000000000000629+01087a0103000000ef0300000000000009000000000000000000000000000000
630-6e6574207469746c650000001c006f0101005000f30300000000000000000000630+6e6574207469746c650000001c007a0101005000f30300000000000000000000
631-0000000000000000000000000108700103000000ef0300000000000009000000631+00000000000000000000000001087b0103000000ef0300000000000009000000
632-0000000000000000000000006e6574207469746c650000001c00700101005000632+0000000000000000000000006e6574207469746c650000001c007b0101005000
633-f303000000000000000000000000000000000000000000000108710103000000633+f3030000000000000000000000000000000000000000000001087c0103000000
634-ef03000000000000090000000000000000000000000000006e6574207469746c634+ef03000000000000090000000000000000000000000000006e6574207469746c
635-650000001c00710101005000f303000000000000000000000000000000000000635+650000001c007c0101005000f303000000000000000000000000000000000000
636-000000000108720103000000ef03000000000000090000000000000000000000636+0000000001087d0103000000ef03000000000000090000000000000000000000
637-000000006e6574207469746c650000001c00720101005000f303000000000000637+000000006e6574207469746c650000001c007d0101005000f303000000000000
638-000000000000000000000000000000000108730103000000ef03000000000000638+0000000000000000000000000000000001087e0103000000ef03000000000000
639-090000000000000000000000000000006e6574207469746c650000001c007301639+090000000000000000000000000000006e6574207469746c650000001c007e01
640-01005000f3030000000000000000000000000000000000000000000001087401640+01005000f3030000000000000000000000000000000000000000000001087f01
641-03000000ef03000000000000090000000000000000000000000000006e657420641+03000000ef03000000000000090000000000000000000000000000006e657420
642-7469746c650000001c00740101005000f3030000000000000000000000000000642+7469746c650000001c007f0101005000f3030000000000000000000000000000
643-00000000000000000108750103000000ef030000000000000900000000000000643+00000000000000000108800103000000ef030000000000000900000000000000
644-00000000000000006e6574207469746c650000001c00750101005000f3030000644+00000000000000006e6574207469746c650000001c00800101005000f3030000
645-00000000000000000000000000000000000000000108760103000000ef030000645+00000000000000000000000000000000000000000108810103000000ef030000
646-00000000090000000000000000000000000000006e6574207469746c65000000646+00000000090000000000000000000000000000006e6574207469746c65000000
647-1c00760101005000f30300000000000000000000000000000000000000000000647+1c00810101005000f30300000000000000000000000000000000000000000000
648-0108770103000000ef0300000000000009000000000000000000000000000000648+0108820103000000ef0300000000000009000000000000000000000000000000
649-6e6574207469746c650000001c00770101005000f30300000000000000000000649+6e6574207469746c650000001c00820101005000f30300000000000000000000
650-0000000000000000000000000108780103000000ef0300000000000009000000650+0000000000000000000000000108830103000000ef0300000000000009000000
651-0000000000000000000000006e6574207469746c650000001c00780101005000651+0000000000000000000000006e6574207469746c650000001c00830101005000
652-f303000000000000000000000000000000000000000000000108790103000000652+f303000000000000000000000000000000000000000000000108840103000000
653-ef03000000000000090000000000000000000000000000006e6574207469746c653+ef03000000000000090000000000000000000000000000006e6574207469746c
654-650000001c00790101005000f303000000000000000000000000000000000000654+650000001c00840101005000f303000000000000000000000000000000000000
655-0000000001087a0103000000ef03000000000000090000000000000000000000655+000000000108850103000000ef03000000000000090000000000000000000000
656-000000006e6574207469746c650000001c007a0101005000f303000000000000656+000000006e6574207469746c650000001c00850101005000f303000000000000
657-0000000000000000000000000000000001087b0103000000ef03000000000000657+000000000000000000000000000000000108860103000000ef03000000000000
658-090000000000000000000000000000006e6574207469746c650000001c007b01658+090000000000000000000000000000006e6574207469746c650000001c008601
659-01005000f3030000000000000000000000000000000000000000000001087c01659+01005000f3030000000000000000000000000000000000000000000001088701
660-03000000ef03000000000000090000000000000000000000000000006e657420660+03000000ef03000000000000090000000000000000000000000000006e657420
661-7469746c650000001c007c0101005000f3030000000000000000000000000000661+7469746c650000001c00870101005000f3030000000000000000000000000000
662-000000000000000001087d0103000000ef030000000000000900000000000000662+00000000000000000108880103000000ef030000000000000900000000000000
663-00000000000000006e6574207469746c650000001c007d0101005000f3030000663+00000000000000006e6574207469746c650000001c00880101005000f3030000
664-000000000000000000000000000000000000000001087e0103000000ef030000664+00000000000000000000000000000000000000000108890103000000ef030000
665-00000000090000000000000000000000000000006e6574207469746c65000000665+00000000090000000000000000000000000000006e6574207469746c65000000
666-1c007e0101005000f30300000000000000000000000000000000000000000000666+1c00890101005000f30300000000000000000000000000000000000000000000
667-01087f0103000000ef0300000000000009000000000000000000000000000000667+01088a0103000000ef0300000000000009000000000000000000000000000000
668-6e6574207469746c650000001c007f0101005000f30300000000000000000000668+6e6574207469746c650000001c008a0101005000f30300000000000000000000
669-0000000000000000000000000108800103000000ef0300000000000009000000669+00000000000000000000000001088b0103000000ef0300000000000009000000
670-0000000000000000000000006e6574207469746c650000001c00800101005000670+0000000000000000000000006e6574207469746c650000001c008b0101005000
671-f303000000000000000000000000000000000000000000000108810103000000671+f3030000000000000000000000000000000000000000000001088c0103000000
672-ef03000000000000090000000000000000000000000000006e6574207469746c672+ef03000000000000090000000000000000000000000000006e6574207469746c
673-650000001c00810101005000f303000000000000000000000000000000000000673+650000001c008c0101005000f303000000000000000000000000000000000000
674-000000000108820103000000ef03000000000000090000000000000000000000674+0000000001088d0103000000ef03000000000000090000000000000000000000
675-000000006e6574207469746c650000001c00820101005000f303000000000000675+000000006e6574207469746c650000001c008d0101005000f303000000000000
676-000000000000000000000000000000000108830103000000ef03000000000000676+0000000000000000000000000000000001088e0103000000ef03000000000000
677-090000000000000000000000000000006e6574207469746c650000001c008301677+090000000000000000000000000000006e6574207469746c650000001c008e01
678-01005000f3030000000000000000000000000000000000000000000001088401678+01005000f3030000000000000000000000000000000000000000000001088f01
679-03000000ef03000000000000090000000000000000000000000000006e657420679+03000000ef03000000000000090000000000000000000000000000006e657420
680-7469746c650000001c00840101005000f3030000000000000000000000000000680+7469746c650000001c008f0101005000f3030000000000000000000000000000
681-00000000000000000108850103000000ef030000000000000900000000000000681+00000000000000000108900103000000ef030000000000000900000000000000
682-00000000000000006e6574207469746c650000001c00850101005000f3030000682+00000000000000006e6574207469746c650000001c00900101005000f3030000
683-00000000000000000000000000000000000000000108860103000000ef030000683+00000000000000000000000000000000000000000108910103000000ef030000
684-00000000090000000000000000000000000000006e6574207469746c65000000684+00000000090000000000000000000000000000006e6574207469746c65000000
685-1c00860101005000f30300000000000000000000000000000000000000000000685+1c00910101005000f30300000000000000000000000000000000000000000000
686-0108870103000000ef0300000000000009000000000000000000000000000000686+0108920103000000ef0300000000000009000000000000000000000000000000
687-6e6574207469746c650000001c00870101005000f30300000000000000000000687+6e6574207469746c650000001c00920101005000f30300000000000000000000
688-0000000000000000000000000108880103000000ef0300000000000009000000688+0000000000000000000000000108930103000000ef0300000000000009000000
689-0000000000000000000000006e6574207469746c650000001c00880101005000689+0000000000000000000000006e6574207469746c650000001c00930101005000
690-f303000000000000000000000000000000000000000000000108890103000000690+f303000000000000000000000000000000000000000000000108940103000000
691-ef03000000000000090000000000000000000000000000006e6574207469746c691+ef03000000000000090000000000000000000000000000006e6574207469746c
692-650000001c00890101005000f303000000000000000000000000000000000000692+650000001c00940101005000f303000000000000000000000000000000000000
693-0000000001088a0103000000ef03000000000000090000000000000000000000693+000000000108950103000000ef03000000000000090000000000000000000000
694-000000006e6574207469746c650000001c008a0101005000f303000000000000694+000000006e6574207469746c650000001c00950101005000f303000000000000
695-0000000000000000000000000000000001088b0103000000ef03000000000000695+000000000000000000000000000000000108960103000000ef03000000000000
696-090000000000000000000000000000006e6574207469746c650000001c008b01696+090000000000000000000000000000006e6574207469746c650000001c009601
697-01005000f3030000000000000000000000000000000000000000000001088c01697+01005000f3030000000000000000000000000000000000000000000001089701
698-03000000ef03000000000000090000000000000000000000000000006e657420698+03000000ef03000000000000090000000000000000000000000000006e657420
699-7469746c650000001c008c0101005000f3030000000000000000000000000000699+7469746c650000001c00970101005000f3030000000000000000000000000000
700-000000000000000001088d0103000000ef030000000000000900000000000000700+00000000000000000108980103000000ef030000000000000900000000000000
701-00000000000000006e6574207469746c650000001c008d0101005000f3030000701+00000000000000006e6574207469746c650000001c00980101005000f3030000
702-000000000000000000000000000000000000000001088e0103000000ef030000702+00000000000000000000000000000000000000000108990103000000ef030000
703-00000000090000000000000000000000000000006e6574207469746c65000000703+00000000090000000000000000000000000000006e6574207469746c65000000
704-1c008e0101005000f30300000000000000000000000000000000000000000000704+1c00990101005000f30300000000000000000000000000000000000000000000
705-01088f0103000000ef0300000000000009000000000000000000000000000000705+01089a0103000000ef0300000000000009000000000000000000000000000000
706-6e6574207469746c650000001c008f0101005000f30300000000000000000000706+6e6574207469746c650000001c009a0101005000f30300000000000000000000
707-0000000000000000000000000108900103000000ef0300000000000009000000707+00000000000000000000000001089b0103000000ef0300000000000009000000
708-0000000000000000000000006e6574207469746c650000001c00900101005000708+0000000000000000000000006e6574207469746c650000001c009b0101005000
709-f303000000000000000000000000000000000000000000000108910103000000709+f3030000000000000000000000000000000000000000000001089c0103000000
710-ef03000000000000090000000000000000000000000000006e6574207469746c710+ef03000000000000090000000000000000000000000000006e6574207469746c
711-650000001c00910101005000f303000000000000000000000000000000000000711+650000001c009c0101005000f303000000000000000000000000000000000000
712-000000000108920103000000ef03000000000000090000000000000000000000712+0000000001089d0103000000ef03000000000000090000000000000000000000
713-000000006e6574207469746c650000001c00920101005000f303000000000000713+000000006e6574207469746c650000001c009d0101005000f303000000000000
714-000000000000000000000000000000000108930103000000ef03000000000000714+0000000000000000000000000000000001089e0103000000ef03000000000000
715-090000000000000000000000000000006e6574207469746c650000001c009301715+090000000000000000000000000000006e6574207469746c650000001c009e01
716-01005000f3030000000000000000000000000000000000000000000001089401716+01005000f3030000000000000000000000000000000000000000000001089f01
717-03000000ef03000000000000090000000000000000000000000000006e657420717+03000000ef03000000000000090000000000000000000000000000006e657420
718-7469746c650000001c00940101005000f3030000000000000000000000000000718+7469746c650000001c009f0101005000f3030000000000000000000000000000
719-00000000000000000108950103000000ef030000000000000900000000000000719+00000000000000000108a00103000000ef030000000000000900000000000000
720-00000000000000006e6574207469746c650000001c00950101005000f3030000720+00000000000000006e6574207469746c650000001c00a00101005000f3030000
721-00000000000000000000000000000000000000000108960103000000ef030000721+00000000000000000000000000000000000000000108a10103000000ef030000
722-00000000090000000000000000000000000000006e6574207469746c65000000722+00000000090000000000000000000000000000006e6574207469746c65000000
723-1c00960101005000f30300000000000000000000000000000000000000000000723+1c00a10101005000f30300000000000000000000000000000000000000000000
724-0108970103000000ef0300000000000009000000000000000000000000000000724+0108a20103000000ef0300000000000009000000000000000000000000000000
725-6e6574207469746c650000001c00970101005000f30300000000000000000000725+6e6574207469746c650000001c00a20101005000f30300000000000000000000
726-0000000000000000000000000108980103000000ef0300000000000009000000726+0000000000000000000000000108a30103000000ef0300000000000009000000
727-0000000000000000000000006e6574207469746c650000001c00980101005000727+0000000000000000000000006e6574207469746c650000001c00a30101005000
728-f303000000000000000000000000000000000000000000000108990103000000728+f303000000000000000000000000000000000000000000000108a40103000000
729-ef03000000000000090000000000000000000000000000006e6574207469746c729+ef03000000000000090000000000000000000000000000006e6574207469746c
730-650000001c00990101005000f303000000000000000000000000000000000000730+650000001c00a40101005000f303000000000000000000000000000000000000
731-0000000001089a0103000000ef03000000000000090000000000000000000000731+000000000108a50103000000ef03000000000000090000000000000000000000
732-000000006e6574207469746c650000001c009a0101005000f303000000000000732+000000006e6574207469746c650000001c00a50101005000f303000000000000
733-0000000000000000000000000000000001089b0103000000ef03000000000000733+000000000000000000000000000000000108a60103000000ef03000000000000
734-090000000000000000000000000000006e6574207469746c650000001c009b01734+090000000000000000000000000000006e6574207469746c650000001c00a601
735-01005000f3030000000000000000000000000000000000000000000001089c01735+01005000f303000000000000000000000000000000000000000000000108a701
736-03000000ef03000000000000090000000000000000000000000000006e657420736+03000000ef03000000000000090000000000000000000000000000006e657420
737-7469746c650000001c009c0101005000f3030000000000000000000000000000737+7469746c650000001c00a70101005000f3030000000000000000000000000000
738-000000000000000001089d0103000000ef030000000000000900000000000000738+00000000000000000108a80103000000ef030000000000000900000000000000
739-00000000000000006e6574207469746c650000001c009d0101005000f3030000739+00000000000000006e6574207469746c650000001c00a80101005000f3030000
740-000000000000000000000000000000000000000001089e0103000000ef030000740+00000000000000000000000000000000000000000108a90103000000ef030000
741-00000000090000000000000000000000000000006e6574207469746c65000000741+00000000090000000000000000000000000000006e6574207469746c65000000
742-1c009e0101005000f30300000000000000000000000000000000000000000000742+1c00a90101005000f30300000000000000000000000000000000000000000000
743-01089f0103000000ef0300000000000009000000000000000000000000000000743+0108aa0103000000ef0300000000000009000000000000000000000000000000
744-6e6574207469746c650000001c009f0101005000f30300000000000000000000744+6e6574207469746c650000001c00aa0101005000f30300000000000000000000
745-0000000000000000000000000108a00103000000ef0300000000000009000000745+0000000000000000000000000108ab0103000000ef0300000000000009000000
746-0000000000000000000000006e6574207469746c650000001c00a00101005000746+0000000000000000000000006e6574207469746c650000001c00ab0101005000
747-f303000000000000000000000000000000000000000000000108a10103000000747+f303000000000000000000000000000000000000000000000108ac0103000000
748-ef03000000000000090000000000000000000000000000006e6574207469746c748+ef03000000000000090000000000000000000000000000006e6574207469746c
749-650000001c00a10101005000f303000000000000000000000000000000000000749+650000001c00ac0101005000f303000000000000000000000000000000000000
750-000000000108a20103000000ef03000000000000090000000000000000000000750+000000000108ad0103000000ef03000000000000090000000000000000000000
751-000000006e6574207469746c650000001c00a20101005000f303000000000000751+000000006e6574207469746c650000001c00ad0101005000f303000000000000
752-000000000000000000000000000000000108a30103000000ef03000000000000752+000000000000000000000000000000000108ae0103000000ef03000000000000
753-090000000000000000000000000000006e6574207469746c650000001c00a301753+090000000000000000000000000000006e6574207469746c650000001c00ae01
754-01005000f303000000000000000000000000000000000000000000000108a401754+01005000f303000000000000000000000000000000000000000000000108af01
755-03000000ef03000000000000090000000000000000000000000000006e657420755+03000000ef03000000000000090000000000000000000000000000006e657420
756-7469746c650000001c00a40101005000f3030000000000000000000000000000756+7469746c650000001c00af0101005000f3030000000000000000000000000000
757-00000000000000000108a50103000000ef030000000000000900000000000000757+00000000000000000108b00103000000ef030000000000000900000000000000
758-00000000000000006e6574207469746c650000001c00a50101005000f3030000758+00000000000000006e6574207469746c650000001c00b00101005000f3030000
759-00000000000000000000000000000000000000000108a60103000000ef030000759+00000000000000000000000000000000000000000108b10103000000ef030000
760-00000000090000000000000000000000000000006e6574207469746c65000000760+00000000090000000000000000000000000000006e6574207469746c65000000
761-1c00a60101005000f30300000000000000000000000000000000000000000000761+1c00b10101005000f30300000000000000000000000000000000000000000000
762-0108a70103000000ef0300000000000009000000000000000000000000000000762+0108b20103000000ef0300000000000009000000000000000000000000000000
763-6e6574207469746c650000001c00a70101005000f30300000000000000000000763+6e6574207469746c650000001c00b20101005000f30300000000000000000000
764-0000000000000000000000000108a80103000000ef0300000000000009000000764+0000000000000000000000000108b30103000000ef0300000000000009000000
765-0000000000000000000000006e6574207469746c650000001c00a80101005000765+0000000000000000000000006e6574207469746c650000001c00b30101005000
766-f303000000000000000000000000000000000000000000000108a90103000000766+f303000000000000000000000000000000000000000000000108b40103000000
767-ef03000000000000090000000000000000000000000000006e6574207469746c767+ef03000000000000090000000000000000000000000000006e6574207469746c
768-650000001c00a90101005000f303000000000000000000000000000000000000768+650000001c00b40101005000f303000000000000000000000000000000000000
769-000000000108aa0103000000ef03000000000000090000000000000000000000769+000000000108b50103000000ef03000000000000090000000000000000000000
770-000000006e6574207469746c650000001c00aa0101005000f303000000000000770+000000006e6574207469746c650000001c00b50101005000f303000000000000
771-000000000000000000000000000000000108ab0103000000ef03000000000000771+000000000000000000000000000000000108b60103000000ef03000000000000
772-090000000000000000000000000000006e6574207469746c650000001c00ab01772+090000000000000000000000000000006e6574207469746c650000001c00b601
773-01005000f303000000000000000000000000000000000000000000000108ac01773+01005000f303000000000000000000000000000000000000000000000108b701
774-03000000ef03000000000000090000000000000000000000000000006e657420774+03000000ef03000000000000090000000000000000000000000000006e657420
775-7469746c650000001c00ac0101005000f3030000000000000000000000000000775+7469746c650000001c00b70101005000f3030000000000000000000000000000
776-00000000000000000108ad0103000000ef030000000000000900000000000000776+00000000000000000108b80103000000ef030000000000000900000000000000
777-00000000000000006e6574207469746c650000001c00ad0101005000f3030000777+00000000000000006e6574207469746c650000001c00b80101005000f3030000
778-00000000000000000000000000000000000000000108ae0103000000ef030000778+00000000000000000000000000000000000000000108b90103000000ef030000
779-00000000090000000000000000000000000000006e6574207469746c65000000779+00000000090000000000000000000000000000006e6574207469746c65000000
780-1c00ae0101005000f30300000000000000000000000000000000000000000000780+1c00b90101005000f30300000000000000000000000000000000000000000000
781-0108af0103000000ef0300000000000009000000000000000000000000000000781+0108ba0103000000ef0300000000000009000000000000000000000000000000
782-6e6574207469746c650000001c00af0101005000f30300000000000000000000782+6e6574207469746c650000001c00ba0101005000f30300000000000000000000
783-0000000000000000000000000108b00103000000ef0300000000000009000000783+0000000000000000000000000108bb0103000000ef0300000000000009000000
784-0000000000000000000000006e6574207469746c650000001c00b00101005000784+0000000000000000000000006e6574207469746c650000001c00bb0101005000
785-f303000000000000000000000000000000000000000000000108b10103000000785+f303000000000000000000000000000000000000000000000108bc0103000000
786-ef03000000000000090000000000000000000000000000006e6574207469746c786+ef03000000000000090000000000000000000000000000006e6574207469746c
787-650000001c00b10101005000f303000000000000000000000000000000000000787+650000001c00bc0101005000f303000000000000000000000000000000000000
788-000000000108b20103000000ef03000000000000090000000000000000000000788+000000000108bd0103000000ef03000000000000090000000000000000000000
789-000000006e6574207469746c650000001c00b20101005000f303000000000000789+000000006e6574207469746c650000001c00bd0101005000f303000000000000
790-000000000000000000000000000000000108b30103000000ef03000000000000790+000000000000000000000000000000000108be0103000000ef03000000000000
791-090000000000000000000000000000006e6574207469746c650000001c00b301791+090000000000000000000000000000006e6574207469746c650000001c00be01
792-01005000f303000000000000000000000000000000000000000000000108b401792+01005000f303000000000000000000000000000000000000000000000108bf01
793-03000000ef03000000000000090000000000000000000000000000006e657420793+03000000ef03000000000000090000000000000000000000000000006e657420
794-7469746c650000001c00b40101005000f3030000000000000000000000000000794+7469746c650000001c00bf0101005000f3030000000000000000000000000000
795-00000000000000000108b50103000000ef030000000000000900000000000000795+00000000000000000108c00103000000ef030000000000000900000000000000
796-00000000000000006e6574207469746c650000001c00b50101005000f3030000796+00000000000000006e6574207469746c650000001c00c00101005000f3030000
797-00000000000000000000000000000000000000000108b60103000000ef030000797+00000000000000000000000000000000000000000108c10103000000ef030000
798-00000000090000000000000000000000000000006e6574207469746c65000000798+00000000090000000000000000000000000000006e6574207469746c65000000
799-1c00b60101005000f30300000000000000000000000000000000000000000000799+1c00c10101005000f30300000000000000000000000000000000000000000000
800-0108b70103000000ef0300000000000009000000000000000000000000000000800+0108c20103000000ef0300000000000009000000000000000000000000000000
801-6e6574207469746c650000001c00b70101005000f30300000000000000000000801+6e6574207469746c650000001c00c20101005000f30300000000000000000000
802-0000000000000000000000000108b80103000000ef0300000000000009000000802+0000000000000000000000000108c30103000000ef0300000000000009000000
803-0000000000000000000000006e6574207469746c650000001c00b80101005000803+0000000000000000000000006e6574207469746c650000001c00c30101005000
804-f303000000000000000000000000000000000000000000000108b90103000000804+f303000000000000000000000000000000000000000000000108c40103000000
805-ef03000000000000090000000000000000000000000000006e6574207469746c805+ef03000000000000090000000000000000000000000000006e6574207469746c
806-650000001c00b90101005000f303000000000000000000000000000000000000806+650000001c00c40101005000f303000000000000000000000000000000000000
807-000000000108ba0103000000ef03000000000000090000000000000000000000807+000000000108c50103000000ef03000000000000090000000000000000000000
808-000000006e6574207469746c650000001c00ba0101005000f303000000000000808+000000006e6574207469746c650000001c00c50101005000f303000000000000
809-000000000000000000000000000000000108bb0103000000ef03000000000000809+000000000000000000000000000000000108c60103000000ef03000000000000
810-090000000000000000000000000000006e6574207469746c650000001c00bb01810+090000000000000000000000000000006e6574207469746c650000001c00c601
811-01005000f303000000000000000000000000000000000000000000000108bc01811+01005000f303000000000000000000000000000000000000000000000108c701
812-03000000ef03000000000000090000000000000000000000000000006e657420812+03000000ef03000000000000090000000000000000000000000000006e657420
813-7469746c650000001c00bc0101005000f3030000000000000000000000000000813+7469746c650000001c00c70101005000f3030000000000000000000000000000
814-00000000000000000108bd0103000000ef030000000000000900000000000000814+00000000000000000108c80103000000ef030000000000000900000000000000
815-00000000000000006e6574207469746c650000001c00bd0101005000f3030000815+00000000000000006e6574207469746c650000001c00c80101005000f3030000
816-00000000000000000000000000000000000000000108be0103000000ef030000816+00000000000000000000000000000000000000000108c90103000000ef030000
817-00000000090000000000000000000000000000006e6574207469746c65000000817+00000000090000000000000000000000000000006e6574207469746c65000000
818-1c00be0101005000f30300000000000000000000000000000000000000000000818+1c00c90101005000f30300000000000000000000000000000000000000000000
819-0108bf0103000000ef0300000000000009000000000000000000000000000000819+0108ca0103000000ef0300000000000009000000000000000000000000000000
820-6e6574207469746c650000001c00bf0101005000f30300000000000000000000820+6e6574207469746c650000001c00ca0101005000f30300000000000000000000
821-0000000000000000000000000108c00103000000ef0300000000000009000000821+0000000000000000000000000108cb0103000000ef0300000000000009000000
822-0000000000000000000000006e6574207469746c650000001c00c00101005000822+0000000000000000000000006e6574207469746c650000001c00cb0101005000
823-f303000000000000000000000000000000000000000000000108c10103000000823+f303000000000000000000000000000000000000000000000108cc0103000000
824-ef03000000000000090000000000000000000000000000006e6574207469746c824+ef03000000000000090000000000000000000000000000006e6574207469746c
825-650000001c00c10101005000f303000000000000000000000000000000000000825+650000001c00cc0101005000f303000000000000000000000000000000000000
826-000000000108c20103000000ef03000000000000090000000000000000000000826+000000000108cd0103000000ef03000000000000090000000000000000000000
827-000000006e6574207469746c650000001c00c20101005000f303000000000000827+000000006e6574207469746c650000001c00cd0101005000f303000000000000
828-000000000000000000000000000000000108c30103000000ef03000000000000828+000000000000000000000000000000000108ce0103000000ef03000000000000
829-090000000000000000000000000000006e6574207469746c650000001c00c301829+090000000000000000000000000000006e6574207469746c650000001c00ce01
830-01005000f303000000000000000000000000000000000000000000000108c401830+01005000f303000000000000000000000000000000000000000000000108cf01
831-03000000ef03000000000000090000000000000000000000000000006e657420831+03000000ef03000000000000090000000000000000000000000000006e657420
832-7469746c650000001c00c40101005000f3030000000000000000000000000000832+7469746c650000001c00cf0101005000f3030000000000000000000000000000
833-00000000000000000108c50103000000ef030000000000000900000000000000833+00000000000000000108d00103000000ef030000000000000900000000000000
834-00000000000000006e6574207469746c650000001c00c50101005000f3030000834+00000000000000006e6574207469746c650000001c00d00101005000f3030000
835-00000000000000000000000000000000000000000108c60103000000ef030000835+00000000000000000000000000000000000000000108d10103000000ef030000
836-00000000090000000000000000000000000000006e6574207469746c65000000836+00000000090000000000000000000000000000006e6574207469746c65000000
837-1c00c60101005000f30300000000000000000000000000000000000000000000837+1c00d10101005000f30300000000000000000000000000000000000000000000
838-0108c70103000000ef0300000000000009000000000000000000000000000000838+0108d20103000000ef0300000000000009000000000000000000000000000000
839-6e6574207469746c650000001c00c70101005000f30300000000000000000000839+6e6574207469746c650000001c00d20101005000f30300000000000000000000
840-0000000000000000000000000108c80103000000ef0300000000000009000000840+0000000000000000000000000108d30103000000ef0300000000000009000000
841-0000000000000000000000006e6574207469746c650000001c00c80101005000841+0000000000000000000000006e6574207469746c650000001c00d30101005000
842-f303000000000000000000000000000000000000000000000108c90103000000842+f303000000000000000000000000000000000000000000000108d40103000000
843-ef03000000000000090000000000000000000000000000006e6574207469746c843+ef03000000000000090000000000000000000000000000006e6574207469746c
844-650000001c00c90101005000f303000000000000000000000000000000000000844+650000001c00d40101005000f303000000000000000000000000000000000000
845-000000000108ca0103000000ef03000000000000090000000000000000000000845+000000000108d50103000000ef03000000000000090000000000000000000000
846-000000006e6574207469746c650000001c00ca0101005000f303000000000000846+000000006e6574207469746c650000001c00d50101005000f303000000000000
847-000000000000000000000000000000000108cb0103000000ef03000000000000847+000000000000000000000000000000000108d60103000000ef03000000000000
848-090000000000000000000000000000006e6574207469746c650000001c00cb01848+090000000000000000000000000000006e6574207469746c650000001c00d601
849-01005000f303000000000000000000000000000000000000000000000108cc01849+01005000f303000000000000000000000000000000000000000000000108d701
850-03000000ef03000000000000090000000000000000000000000000006e657420850+03000000ef03000000000000090000000000000000000000000000006e657420
851-7469746c650000001c00cc0101005000f3030000000000000000000000000000851+7469746c650000001c00d70101005000f3030000000000000000000000000000
852-00000000000000000108cd0103000000ef030000000000000900000000000000852+00000000000000000108d80103000000ef030000000000000900000000000000
853-00000000000000006e6574207469746c650000001c00cd0101005000f3030000853+00000000000000006e6574207469746c650000001c00d80101005000f3030000
854-00000000000000000000000000000000000000000108ce0103000000ef030000854+00000000000000000000000000000000000000000108d90103000000ef030000
855-00000000090000000000000000000000000000006e6574207469746c65000000855+00000000090000000000000000000000000000006e6574207469746c65000000
856-1c00ce0101005000f30300000000000000000000000000000000000000000000856+1c00d90101005000f30300000000000000000000000000000000000000000000
857-0108cf0103000000ef0300000000000009000000000000000000000000000000857+0108da0103000000ef0300000000000009000000000000000000000000000000
858-6e6574207469746c650000001c00cf0101005000f30300000000000000000000858+6e6574207469746c650000001c00da0101005000f30300000000000000000000
859-0000000000000000000000000108d00103000000ef0300000000000009000000859+0000000000000000000000000108db0103000000ef0300000000000009000000
860-0000000000000000000000006e6574207469746c650000001c00d00101005000860+0000000000000000000000006e6574207469746c650000001c00db0101005000
861-f303000000000000000000000000000000000000000000000108d10103000000861+f303000000000000000000000000000000000000000000000108dc0103000000
862-ef03000000000000090000000000000000000000000000006e6574207469746c862+ef03000000000000090000000000000000000000000000006e6574207469746c
863-650000001c00d10101005000f303000000000000000000000000000000000000863+650000001c00dc0101005000f303000000000000000000000000000000000000
864-000000000108d20103000000ef03000000000000090000000000000000000000864+000000000108dd0103000000ef03000000000000090000000000000000000000
865-000000006e6574207469746c650000001c00d20101005000f303000000000000865+000000006e6574207469746c650000001c00dd0101005000f303000000000000
866-000000000000000000000000000000000108d30103000000ef03000000000000866+000000000000000000000000000000000108de0103000000ef03000000000000
867-090000000000000000000000000000006e6574207469746c650000001c00d301867+090000000000000000000000000000006e6574207469746c650000001c00de01
868-01005000f303000000000000000000000000000000000000000000000108d401868+01005000f303000000000000000000000000000000000000000000000108df01
869-03000000ef03000000000000090000000000000000000000000000006e657420869+03000000ef03000000000000090000000000000000000000000000006e657420
870-7469746c650000001c00d40101005000f3030000000000000000000000000000870+7469746c650000001c00df0101005000f3030000000000000000000000000000
871-00000000000000000108d50103000000ef030000000000000900000000000000871+00000000000000000108e00103000000ef030000000000000900000000000000
872-00000000000000006e6574207469746c650000001c00d50101005000f3030000872+00000000000000006e6574207469746c650000001c00e00101005000f3030000
873-00000000000000000000000000000000000000000108d60103000000ef030000873+00000000000000000000000000000000000000000108e10103000000ef030000
874-00000000090000000000000000000000000000006e6574207469746c65000000874+00000000090000000000000000000000000000006e6574207469746c65000000
875-1c00d60101005000f30300000000000000000000000000000000000000000000875+1c00e10101005000f30300000000000000000000000000000000000000000000
876-0108d70103000000ef0300000000000009000000000000000000000000000000876+0108e20103000000ef0300000000000009000000000000000000000000000000
877-6e6574207469746c650000001c00d70101005000f30300000000000000000000877+6e6574207469746c650000001c00e20101005000f30300000000000000000000
878-0000000000000000000000000108d80103000000ef0300000000000009000000878+0000000000000000000000000108e30103000000ef0300000000000009000000
879-0000000000000000000000006e6574207469746c650000001c00d80101005000879+0000000000000000000000006e6574207469746c650000001c00e30101005000
880-f303000000000000000000000000000000000000000000000108d90103000000880+f303000000000000000000000000000000000000000000000108e40103000000
881-ef03000000000000090000000000000000000000000000006e6574207469746c881+ef03000000000000090000000000000000000000000000006e6574207469746c
882-650000001c00d90101005000f303000000000000000000000000000000000000882+650000001c00e40101005000f303000000000000000000000000000000000000
883-000000000108da0103000000ef03000000000000090000000000000000000000883+000000000108e50103000000ef03000000000000090000000000000000000000
884-000000006e6574207469746c650000001c00da0101005000f303000000000000884+000000006e6574207469746c650000001c00e50101005000f303000000000000
885-000000000000000000000000000000000108db0103000000ef03000000000000885+000000000000000000000000000000000108e60103000000ef03000000000000
886-090000000000000000000000000000006e6574207469746c650000001c00db01886+090000000000000000000000000000006e6574207469746c650000001c00e601
887-01005000f303000000000000000000000000000000000000000000000108dc01887+01005000f303000000000000000000000000000000000000000000000108e701
888-03000000ef03000000000000090000000000000000000000000000006e657420888+03000000ef03000000000000090000000000000000000000000000006e657420
889-7469746c650000001c00dc0101005000f3030000000000000000000000000000889+7469746c650000001c00e70101005000f3030000000000000000000000000000
890-00000000000000000108dd0103000000ef030000000000000900000000000000890+00000000000000000108e80103000000ef030000000000000900000000000000
891-00000000000000006e6574207469746c650000001c00dd0101005000f3030000891+00000000000000006e6574207469746c650000001c00e80101005000f3030000
892-00000000000000000000000000000000000000000108de0103000000ef030000892+00000000000000000000000000000000000000000108e90103000000ef030000
893-00000000090000000000000000000000000000006e6574207469746c65000000893+00000000090000000000000000000000000000006e6574207469746c65000000
894-1c00de0101005000f30300000000000000000000000000000000000000000000894+1c00e90101005000f30300000000000000000000000000000000000000000000
895-0108df0103000000ef0300000000000009000000000000000000000000000000895+0108ea0103000000ef0300000000000009000000000000000000000000000000
896-6e6574207469746c650000001c00df0101005000f30300000000000000000000896+6e6574207469746c650000001c00ea0101005000f30300000000000000000000
897-0000000000000000000000000108e00103000000ef0300000000000009000000897+0000000000000000000000000108eb0103000000ef0300000000000009000000
898-0000000000000000000000006e6574207469746c650000001c00e00101005000898+0000000000000000000000006e6574207469746c650000001c00eb0101005000
899-f303000000000000000000000000000000000000000000000108e10103000000899+f303000000000000000000000000000000000000000000000108ec0103000000
900-ef03000000000000090000000000000000000000000000006e6574207469746c900+ef03000000000000090000000000000000000000000000006e6574207469746c
901-650000001c00e10101005000f303000000000000000000000000000000000000901+650000001c00ec0101005000f303000000000000000000000000000000000000
902-000000000108e20103000000ef03000000000000090000000000000000000000902+000000000108ed0103000000ef03000000000000090000000000000000000000
903-000000006e6574207469746c650000001c00e20101005000f303000000000000903+000000006e6574207469746c650000001c00ed0101005000f303000000000000
904-000000000000000000000000000000000108e30103000000ef03000000000000904+000000000000000000000000000000000108ee0103000000ef03000000000000
905-090000000000000000000000000000006e6574207469746c650000001c00e301905+090000000000000000000000000000006e6574207469746c650000001c00ee01
906-01005000f303000000000000000000000000000000000000000000000108e401906+01005000f303000000000000000000000000000000000000000000000108ef01
907-03000000ef03000000000000090000000000000000000000000000006e657420907+03000000ef03000000000000090000000000000000000000000000006e657420
908-7469746c650000001c00e40101005000f3030000000000000000000000000000908+7469746c650000001c00ef0101005000f3030000000000000000000000000000
909-00000000000000000108e50103000000ef030000000000000900000000000000909+00000000000000000108f00103000000ef030000000000000900000000000000
910-00000000000000006e6574207469746c650000001c00e50101005000f3030000910+00000000000000006e6574207469746c650000001c00f00101005000f3030000
911-00000000000000000000000000000000000000000108e60103000000ef030000911+00000000000000000000000000000000000000000108f10103000000ef030000
912-00000000090000000000000000000000000000006e6574207469746c65000000912+00000000090000000000000000000000000000006e6574207469746c65000000
913-1c00e60101005000f30300000000000000000000000000000000000000000000913+1c00f10101005000f30300000000000000000000000000000000000000000000
914-0108e70103000000ef0300000000000009000000000000000000000000000000914+0108f20103000000ef0300000000000009000000000000000000000000000000
915-6e6574207469746c650000001c00e70101005000f30300000000000000000000915+6e6574207469746c650000001c00f20101005000f30300000000000000000000
916-0000000000000000000000000108e80103000000ef0300000000000009000000916+0000000000000000000000000108f30103000000ef0300000000000009000000
917-0000000000000000000000006e6574207469746c650000001c00e80101005000917+0000000000000000000000006e6574207469746c650000001c00f30101005000
918-f303000000000000000000000000000000000000000000000108e90103000000918+f303000000000000000000000000000000000000000000000108f40103000000
919-ef03000000000000090000000000000000000000000000006e6574207469746c919+ef03000000000000090000000000000000000000000000006e6574207469746c
920-650000001c00e90101005000f303000000000000000000000000000000000000920+650000001c00f40101005000f303000000000000000000000000000000000000
921-000000000108ea0103000000ef03000000000000090000000000000000000000921+000000000108f50103000000ef03000000000000090000000000000000000000
922-000000006e6574207469746c650000001c00ea0101005000f303000000000000922+000000006e6574207469746c650000001c00f50101005000f303000000000000
923-000000000000000000000000000000000108eb0103000000ef03000000000000923+000000000000000000000000000000000108f60103000000ef03000000000000
924-090000000000000000000000000000006e6574207469746c650000001c00eb01924+090000000000000000000000000000006e6574207469746c650000001c00f601
925-01005000f303000000000000000000000000000000000000000000000108ec01925+01005000f303000000000000000000000000000000000000000000000108f701
926-03000000ef03000000000000090000000000000000000000000000006e657420926+03000000ef03000000000000090000000000000000000000000000006e657420
927-7469746c650000001c00ec0101005000f3030000000000000000000000000000927+7469746c650000001c00f70101005000f3030000000000000000000000000000
928-00000000000000000108ed0103000000ef030000000000000900000000000000928+00000000000000000108f80103000000ef030000000000000900000000000000
929-00000000000000006e6574207469746c650000001c00ed0101005000f3030000929+00000000000000006e6574207469746c650000001c00f80101005000f3030000
930-00000000000000000000000000000000000000000108ee0103000000ef030000930+00000000000000000000000000000000000000000108f90103000000ef030000
931-00000000090000000000000000000000000000006e6574207469746c65000000931+00000000090000000000000000000000000000006e6574207469746c65000000
932-1c00ee0101005000f30300000000000000000000000000000000000000000000932+1c00f90101005000f30300000000000000000000000000000000000000000000
933-0108ef0103000000ef0300000000000009000000000000000000000000000000933+0108fa0103000000ef0300000000000009000000000000000000000000000000
934-6e6574207469746c650000001c00ef0101005000f30300000000000000000000934+6e6574207469746c650000001c00fa0101005000f30300000000000000000000
935-0000000000000000000000000108f00103000000ef0300000000000009000000935+0000000000000000000000000108fb0103000000ef0300000000000009000000
936-0000000000000000000000006e6574207469746c650000001c00f00101005000936+0000000000000000000000006e6574207469746c650000001c00fb0101005000
937-f303000000000000000000000000000000000000000000000108f10103000000937+f303000000000000000000000000000000000000000000000108fc0103000000
938-ef03000000000000090000000000000000000000000000006e6574207469746c938+ef03000000000000090000000000000000000000000000006e6574207469746c
939-650000001c00f10101005000f303000000000000000000000000000000000000939+650000001c00fc0101005000f303000000000000000000000000000000000000
940-000000000108f20103000000ef03000000000000090000000000000000000000940+000000000108fd0103000000ef03000000000000090000000000000000000000
941-000000006e6574207469746c650000001c00f20101005000f303000000000000941+000000006e6574207469746c650000001c00fd0101005000f303000000000000
942-000000000000000000000000000000000108f30103000000ef03000000000000942+000000000000000000000000000000000108fe0103000000ef03000000000000
943-090000000000000000000000000000006e6574207469746c650000001c00f301943+090000000000000000000000000000006e6574207469746c650000001c00fe01
944-01005000f303000000000000000000000000000000000000000000000108f401944+01005000f303000000000000000000000000000000000000000000000108ff01
945-03000000ef03000000000000090000000000000000000000000000006e657420945+03000000ef03000000000000090000000000000000000000000000006e657420
946-7469746c650000001c00f40101005000f3030000000000000000000000000000946+7469746c650000001c00ff0101005000f3030000000000000000000000000000
947-00000000000000000108f50103000000ef030000000000000900000000000000947+00000000000000000108000203000000ef030000000000000900000000000000
948-00000000000000006e6574207469746c650000001c00f50101005000f3030000948+00000000000000006e6574207469746c650000001c00000201005000f3030000
949-00000000000000000000000000000000000000000108f60103000000ef030000949+00000000000000000000000000000000000000000108010203000000ef030000
950 00000000090000000000000000000000000000006e6574207469746c65000000950 00000000090000000000000000000000000000006e6574207469746c65000000
M internal/adapters/wayland/xwm/testdata/streams/steady.hex +2000 -2000 large diff (4000 lines changed): collapsed
M internal/adapters/wayland/xwm/xpeer_test.go +16 -3
@@ -365,12 +365,25 @@ func (p *xpeer) answer(r xpeerReq, body []byte) {
365 delete(p.props[binary.LittleEndian.Uint32(body)], binary.LittleEndian.Uint32(body[4:]))365 delete(p.props[binary.LittleEndian.Uint32(body)], binary.LittleEndian.Uint32(body[4:]))
366 case r.major == opGetProperty:366 case r.major == opGetProperty:
367 win, prop := binary.LittleEndian.Uint32(body), binary.LittleEndian.Uint32(body[4:])367 win, prop := binary.LittleEndian.Uint32(body), binary.LittleEndian.Uint32(body[4:])
368+ off, length := int(binary.LittleEndian.Uint32(body[12:]))*4, int(binary.LittleEndian.Uint32(body[16:]))*4
368 v, ok := p.props[win][prop]369 v, ok := p.props[win][prop]
369- b := make([]byte, 24+(len(v.data)+3)&^3)370+ data, after := v.data, 0
371+ if off > len(data) {
372+ off = len(data)
373+ }
374+ data = data[off:]
375+ if len(data) > length {
376+ data, after = data[:length], len(data)-length
377+ }
378+ b := make([]byte, 24+(len(data)+3)&^3)
370 if ok && v.format != 0 {379 if ok && v.format != 0 {
371 binary.LittleEndian.PutUint32(b[0:], v.typ)380 binary.LittleEndian.PutUint32(b[0:], v.typ)
372- binary.LittleEndian.PutUint32(b[8:], uint32(len(v.data)/(int(v.format)/8)))381+ binary.LittleEndian.PutUint32(b[4:], uint32(after))
373- copy(b[24:], v.data)382+ binary.LittleEndian.PutUint32(b[8:], uint32(len(data)/(int(v.format)/8)))
383+ copy(b[24:], data)
384+ if r.raw[1] != 0 && after == 0 { // delete
385+ delete(p.props[win], prop)
386+ }
374 }387 }
375 p.reply(v.format, b)388 p.reply(v.format, b)
376 case r.major == opChangeWindowAttributes:389 case r.major == opChangeWindowAttributes:
M internal/adapters/wayland/xwm/xwm.go +30 -8
@@ -14,6 +14,7 @@ import (
14 "fmt"14 "fmt"
15 "io"15 "io"
16 "os"16 "os"
17+ "time"
17 18
18 "bnema.dev/xturbo"19 "bnema.dev/xturbo"
19 "bnema.dev/xturbo/composite"20 "bnema.dev/xturbo/composite"
@@ -49,18 +50,22 @@ const unpairedCap = 64
49 50
50 // XWM manages the windows of one Xwayland. Display goroutine only, after Boot.51 // XWM manages the windows of one Xwayland. Display goroutine only, after Boot.
51 type XWM struct {52 type XWM struct {
52- conn *xturbo.Conn53+ conn *xturbo.Conn
53- log zerowrap.Logger54+ log zerowrap.Logger
54- root uint3255+ root uint32
55- wmWin uint3256+ wmWin uint32
56- atoms [atomCount]uint3257+ selWin uint32 // selection bridge window (selection.go)
57- tab *table58+ sel selBridge
58- h xturbo.Handler59+ atoms [atomCount]uint32
59- stats Stats60+ tab *table
61+ h xturbo.Handler
62+ stats Stats
60 63
61 // attachment64 // attachment
62 host host65 host host
63 src fdSource66 src fdSource
67+ addFD func(fd int, onReadable, onWritable func()) (fdSource, error) // display fd source seam
68+ after func(d time.Duration, fn func()) (cancel func())
64 post func(func())69 post func(func())
65 flushFn func()70 flushFn func()
66 71
@@ -90,6 +95,7 @@ func newXWM(conn *xturbo.Conn, log zerowrap.Logger) *XWM {
90 x := &XWM{conn: conn, log: log, root: conn.Root(), tab: newTable(initialSlots), space: new(Space)}95 x := &XWM{conn: conn, log: log, root: conn.Root(), tab: newTable(initialSlots), space: new(Space)}
91 x.h = xturbo.Handler{OnEvent: x.onEvent, OnReply: x.onReply, OnError: x.onError}96 x.h = xturbo.Handler{OnEvent: x.onEvent, OnReply: x.onReply, OnError: x.onError}
92 x.fit()97 x.fit()
98+ x.initSelection()
93 return x99 return x
94 }100 }
95 101
@@ -227,6 +233,11 @@ func (x *XWM) boot() error {
227 return fmt.Errorf("xwm: allocate window id: %w", err)233 return fmt.Errorf("xwm: allocate window id: %w", err)
228 }234 }
229 x.wmWin = xid235 x.wmWin = xid
236+ if ext.Info(xturbo.ExtXFixes).Present {
237+ if x.selWin, err = conn.NewXID(); err != nil {
238+ return fmt.Errorf("xwm: allocate window id: %w", err)
239+ }
240+ }
230 241
231 b := conn.Buf()242 b := conn.Buf()
232 x.expect(composite.QueryVersion(b, 0, 4), kindVersion, versionComposite, 0)243 x.expect(composite.QueryVersion(b, 0, 4), kindVersion, versionComposite, 0)
@@ -267,6 +278,8 @@ func (x *XWM) boot() error {
267 xproto.SetSelectionOwner(b, xproto.Window(x.wmWin), xproto.Atom(x.atoms[atomWMS0]), 0)278 xproto.SetSelectionOwner(b, xproto.Window(x.wmWin), xproto.Atom(x.atoms[atomWMS0]), 0)
268 xproto.SetSelectionOwner(b, xproto.Window(x.wmWin), xproto.Atom(x.atoms[atomNetWMCMS0]), 0)279 xproto.SetSelectionOwner(b, xproto.Window(x.wmWin), xproto.Atom(x.atoms[atomNetWMCMS0]), 0)
269 280
281+ x.bootSelection(root)
282+
270 supported := [...]int{283 supported := [...]int{
271 atomNetWMState, atomNetActiveWindow, atomNetWMStateFocused,284 atomNetWMState, atomNetActiveWindow, atomNetWMStateFocused,
272 atomNetWMStateModal, atomNetWMStateFullscreen, atomNetClientList,285 atomNetWMStateModal, atomNetWMStateFullscreen, atomNetClientList,
@@ -303,6 +316,13 @@ func (x *XWM) boot() error {
303 // Attach registers the X socket with the display and hands the windows found316 // Attach registers the X socket with the display and hands the windows found
304 // at boot to h. Display goroutine only.317 // at boot to h. Display goroutine only.
305 func (x *XWM) Attach(d *server.Display, h host) error {318 func (x *XWM) Attach(d *server.Display, h host) error {
319+ x.addFD = func(fd int, r, w func()) (fdSource, error) {
320+ s, err := d.AddFDRW(fd, r, w)
321+ if err != nil {
322+ return nil, err
323+ }
324+ return s, nil
325+ }
306 src, err := d.AddFDRW(x.conn.Fd(), x.onReadable, x.onWritable)326 src, err := d.AddFDRW(x.conn.Fd(), x.onReadable, x.onWritable)
307 if err != nil {327 if err != nil {
308 return fmt.Errorf("xwm: watch X socket: %w", err)328 return fmt.Errorf("xwm: watch X socket: %w", err)
@@ -314,6 +334,7 @@ func (x *XWM) Attach(d *server.Display, h host) error {
314 // attach is Attach over its seams: the event source and the display's Post.334 // attach is Attach over its seams: the event source and the display's Post.
315 func (x *XWM) attach(src fdSource, h host, post func(func())) {335 func (x *XWM) attach(src fdSource, h host, post func(func())) {
316 x.src, x.host, x.post = src, h, post336 x.src, x.host, x.post = src, h, post
337+ x.after = h.After
317 x.flushFn = func() {338 x.flushFn = func() {
318 x.posted = false339 x.posted = false
319 x.flush()340 x.flush()
@@ -343,6 +364,7 @@ func (x *XWM) Close() {
343 return364 return
344 }365 }
345 x.closed = true366 x.closed = true
367+ x.selClose()
346 s := x.stats368 s := x.stats
347 x.log.Info().Uint64("events", s.Events).Uint64("replies", s.Replies).Uint64("errors", s.Errors).369 x.log.Info().Uint64("events", s.Events).Uint64("replies", s.Replies).Uint64("errors", s.Errors).
348 Uint64("unattributed", s.Unattributed).Uint64("stale", s.Stale).Uint64("ring_full", s.RingFull).370 Uint64("unattributed", s.Unattributed).Uint64("stale", s.Stale).Uint64("ring_full", s.RingFull).
M internal/adapters/wayland/xwm/xwm_test.go +1 -1
@@ -74,7 +74,7 @@ func TestBootRequests(t *testing.T) {
74 redirect = i74 redirect = i
75 require.EqualValues(t, peerRoot, r.u32(4))75 require.EqualValues(t, peerRoot, r.u32(4))
76 require.EqualValues(t, 1, r.raw[8], "manual")76 require.EqualValues(t, 1, r.raw[8], "manual")
77- case r.major == opCreateWindow:77+ case r.major == opCreateWindow && r.u32(4) == wm:
78 create = i78 create = i
79 require.Equal(t, wm, r.u32(4))79 require.Equal(t, wm, r.u32(4))
80 case r.major == opSetSelectionOwner && r.u32(8) == p.atom("WM_S0"):80 case r.major == opSetSelectionOwner && r.u32(8) == p.atom("WM_S0"):
A internal/adapters/wayland/xwm_selection_mock_test.go +143 -0
@@ -0,0 +1,143 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package wayland
6+
7+import (
8+ mock "github.com/stretchr/testify/mock"
9+)
10+
11+// newMockxwmSelection creates a new instance of mockxwmSelection. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
12+// The first argument is typically a *testing.T value.
13+func newMockxwmSelection(t interface {
14+ mock.TestingT
15+ Cleanup(func())
16+}) *mockxwmSelection {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
21+ mock := &mockxwmSelection{}
22+ mock.Mock.Test(t)
23+
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
30+
31+ return mock
32+}
33+
34+// mockxwmSelection is an autogenerated mock type for the xwmSelection type
35+type mockxwmSelection struct {
36+ mock.Mock
37+}
38+
39+type mockxwmSelection_Expecter struct {
40+ mock *mock.Mock
41+}
42+
43+func (_m *mockxwmSelection) EXPECT() *mockxwmSelection_Expecter {
44+ return &mockxwmSelection_Expecter{mock: &_m.Mock}
45+}
46+
47+// SelectionReceive provides a mock function for the type mockxwmSelection
48+func (_mock *mockxwmSelection) SelectionReceive(kind int, mime string, fd int) {
49+ _mock.Called(kind, mime, fd)
50+ return
51+}
52+
53+// mockxwmSelection_SelectionReceive_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SelectionReceive'
54+type mockxwmSelection_SelectionReceive_Call struct {
55+ *mock.Call
56+}
57+
58+// SelectionReceive is a helper method to define mock.On call
59+// - kind int
60+// - mime string
61+// - fd int
62+func (_e *mockxwmSelection_Expecter) SelectionReceive(kind any, mime any, fd any) *mockxwmSelection_SelectionReceive_Call {
63+ return &mockxwmSelection_SelectionReceive_Call{Call: _e.mock.On("SelectionReceive", kind, mime, fd)}
64+}
65+
66+func (_c *mockxwmSelection_SelectionReceive_Call) Run(run func(kind int, mime string, fd int)) *mockxwmSelection_SelectionReceive_Call {
67+ _c.Call.Run(func(args mock.Arguments) {
68+ var arg0 int
69+ if args[0] != nil {
70+ arg0 = args[0].(int)
71+ }
72+ var arg1 string
73+ if args[1] != nil {
74+ arg1 = args[1].(string)
75+ }
76+ var arg2 int
77+ if args[2] != nil {
78+ arg2 = args[2].(int)
79+ }
80+ run(
81+ arg0,
82+ arg1,
83+ arg2,
84+ )
85+ })
86+ return _c
87+}
88+
89+func (_c *mockxwmSelection_SelectionReceive_Call) Return() *mockxwmSelection_SelectionReceive_Call {
90+ _c.Call.Return()
91+ return _c
92+}
93+
94+func (_c *mockxwmSelection_SelectionReceive_Call) RunAndReturn(run func(kind int, mime string, fd int)) *mockxwmSelection_SelectionReceive_Call {
95+ _c.Run(run)
96+ return _c
97+}
98+
99+// WaylandSelection provides a mock function for the type mockxwmSelection
100+func (_mock *mockxwmSelection) WaylandSelection(kind int, mimes []string) {
101+ _mock.Called(kind, mimes)
102+ return
103+}
104+
105+// mockxwmSelection_WaylandSelection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WaylandSelection'
106+type mockxwmSelection_WaylandSelection_Call struct {
107+ *mock.Call
108+}
109+
110+// WaylandSelection is a helper method to define mock.On call
111+// - kind int
112+// - mimes []string
113+func (_e *mockxwmSelection_Expecter) WaylandSelection(kind any, mimes any) *mockxwmSelection_WaylandSelection_Call {
114+ return &mockxwmSelection_WaylandSelection_Call{Call: _e.mock.On("WaylandSelection", kind, mimes)}
115+}
116+
117+func (_c *mockxwmSelection_WaylandSelection_Call) Run(run func(kind int, mimes []string)) *mockxwmSelection_WaylandSelection_Call {
118+ _c.Call.Run(func(args mock.Arguments) {
119+ var arg0 int
120+ if args[0] != nil {
121+ arg0 = args[0].(int)
122+ }
123+ var arg1 []string
124+ if args[1] != nil {
125+ arg1 = args[1].([]string)
126+ }
127+ run(
128+ arg0,
129+ arg1,
130+ )
131+ })
132+ return _c
133+}
134+
135+func (_c *mockxwmSelection_WaylandSelection_Call) Return() *mockxwmSelection_WaylandSelection_Call {
136+ _c.Call.Return()
137+ return _c
138+}
139+
140+func (_c *mockxwmSelection_WaylandSelection_Call) RunAndReturn(run func(kind int, mimes []string)) *mockxwmSelection_WaylandSelection_Call {
141+ _c.Run(run)
142+ return _c
143+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 25

Tags 10

↑↓ moveenter openesc close