react-native-a11y-order 0.11.0-rc → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/android/src/main/java/com/a11yorder/core/A11yManagedFocusView.java +29 -0
- package/android/src/main/java/com/a11yorder/core/A11yViewOrder.java +1 -1
- package/android/src/main/java/com/a11yorder/modules/A11yAnnounceModule.java +20 -7
- package/android/src/main/java/com/a11yorder/views/A11yIndexView/A11yIndexViewManager.java +0 -6
- package/android/src/oldarch/A11yAnnounceModuleSpec.java +8 -1
- package/android/src/oldarch/A11yIndexViewManagerSpec.java +0 -1
- package/ios/helpers/RNAOSpeechAttributes.h +35 -0
- package/ios/helpers/RNAOSpeechAttributes.mm +64 -0
- package/ios/modules/RNAOA11yAnnounceModule.h +13 -9
- package/ios/modules/RNAOA11yAnnounceModule.mm +220 -14
- package/ios/services/RNAOA11yAnnounceService/RNAOA11yAnnounceService.h +11 -1
- package/ios/services/RNAOA11yAnnounceService/RNAOA11yAnnounceService.mm +55 -51
- package/ios/views/RNAOA11yIndexView/RNAOA11yIndexView.mm +0 -4
- package/ios/views/RNAOA11yIndexView/RNAOA11yIndexViewManager.mm +5 -5
- package/ios/views/RNAOA11yPaneTitleView/RNAOA11yPaneTitleView.mm +12 -2
- package/ios/views/base/{RNAOA11yAutoFocusView.h → RNAOA11yManagedFocusView.h} +5 -7
- package/ios/views/base/{RNAOA11yAutoFocusView.mm → RNAOA11yManagedFocusView.mm} +2 -19
- package/ios/views/base/RNAOA11yViewOrder.h +3 -3
- package/lib/commonjs/components/A11yCard/A11yCard.ios.js +8 -1
- package/lib/commonjs/components/A11yCard/A11yCard.ios.js.map +1 -1
- package/lib/commonjs/components/A11yIndex/A11yIndex.js +3 -2
- package/lib/commonjs/components/A11yIndex/A11yIndex.js.map +1 -1
- package/lib/commonjs/index.js +22 -4
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +4 -4
- package/lib/commonjs/modules/A11yAnnounceModule.android.js +37 -3
- package/lib/commonjs/modules/A11yAnnounceModule.android.js.map +1 -1
- package/lib/commonjs/modules/A11yAnnounceModule.js +66 -8
- package/lib/commonjs/modules/A11yAnnounceModule.js.map +1 -1
- package/lib/commonjs/nativeSpecs/A11yIndexNativeComponent.ts +0 -1
- package/lib/commonjs/nativeSpecs/NativeA11yAnnounceModule.js +2 -0
- package/lib/commonjs/nativeSpecs/NativeA11yAnnounceModule.js.map +1 -1
- package/lib/module/components/A11yCard/A11yCard.ios.js +8 -1
- package/lib/module/components/A11yCard/A11yCard.ios.js.map +1 -1
- package/lib/module/components/A11yIndex/A11yIndex.js +3 -2
- package/lib/module/components/A11yIndex/A11yIndex.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +1 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/modules/A11yAnnounceModule.android.js +32 -2
- package/lib/module/modules/A11yAnnounceModule.android.js.map +1 -1
- package/lib/module/modules/A11yAnnounceModule.js +62 -7
- package/lib/module/modules/A11yAnnounceModule.js.map +1 -1
- package/lib/module/nativeSpecs/A11yIndexNativeComponent.ts +0 -1
- package/lib/module/nativeSpecs/NativeA11yAnnounceModule.js +4 -0
- package/lib/module/nativeSpecs/NativeA11yAnnounceModule.js.map +1 -1
- package/lib/typescript/src/components/A11yCard/A11yCard.ios.d.ts.map +1 -1
- package/lib/typescript/src/components/A11yIndex/A11yIndex.d.ts +3 -126
- package/lib/typescript/src/components/A11yIndex/A11yIndex.d.ts.map +1 -1
- package/lib/typescript/src/components/A11yIndex/A11yIndex.types.d.ts +0 -4
- package/lib/typescript/src/components/A11yIndex/A11yIndex.types.d.ts.map +1 -1
- package/lib/typescript/src/components/A11yIndex/A11yIndex.web.d.ts +1 -125
- package/lib/typescript/src/components/A11yIndex/A11yIndex.web.d.ts.map +1 -1
- package/lib/typescript/src/components/A11yOrder/A11yOrder.d.ts +1 -124
- package/lib/typescript/src/components/A11yOrder/A11yOrder.d.ts.map +1 -1
- package/lib/typescript/src/components/A11yView/A11yView.d.ts +2 -126
- package/lib/typescript/src/components/A11yView/A11yView.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +7 -377
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.web.d.ts +11 -162
- package/lib/typescript/src/index.web.d.ts.map +1 -1
- package/lib/typescript/src/modules/A11yAnnounceModule.android.d.ts +25 -2
- package/lib/typescript/src/modules/A11yAnnounceModule.android.d.ts.map +1 -1
- package/lib/typescript/src/modules/A11yAnnounceModule.d.ts +112 -4
- package/lib/typescript/src/modules/A11yAnnounceModule.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpecs/A11yCardNativeComponent.d.ts +1 -3
- package/lib/typescript/src/nativeSpecs/A11yCardNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpecs/A11yIndexNativeComponent.d.ts +1 -4
- package/lib/typescript/src/nativeSpecs/A11yIndexNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpecs/A11yLockNativeComponent.d.ts +1 -3
- package/lib/typescript/src/nativeSpecs/A11yLockNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpecs/A11yOrderNativeComponent.d.ts +1 -3
- package/lib/typescript/src/nativeSpecs/A11yOrderNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpecs/A11yPaneTitleNativeComponent.d.ts +1 -3
- package/lib/typescript/src/nativeSpecs/A11yPaneTitleNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpecs/NativeA11yAnnounceModule.d.ts +22 -2
- package/lib/typescript/src/nativeSpecs/NativeA11yAnnounceModule.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/A11yCard/A11yCard.ios.tsx +8 -1
- package/src/components/A11yIndex/A11yIndex.tsx +5 -4
- package/src/components/A11yIndex/A11yIndex.types.ts +0 -5
- package/src/index.ts +12 -1
- package/src/index.web.ts +1 -1
- package/src/modules/A11yAnnounceModule.android.ts +18 -2
- package/src/modules/A11yAnnounceModule.ts +153 -9
- package/src/nativeSpecs/A11yIndexNativeComponent.ts +0 -1
- package/src/nativeSpecs/NativeA11yAnnounceModule.ts +31 -1
- package/android/src/main/java/com/a11yorder/core/A11yAutoFocusView.java +0 -61
|
@@ -1,5 +1,21 @@
|
|
|
1
|
+
// Android stub — bypasses the native bridge, uses the built-in API directly.
|
|
1
2
|
import { AccessibilityInfo } from 'react-native';
|
|
2
3
|
|
|
3
|
-
export const
|
|
4
|
-
announce:
|
|
4
|
+
export const ScreenReader = {
|
|
5
|
+
announce: (message: string) => {
|
|
6
|
+
AccessibilityInfo.announceForAccessibility(message);
|
|
7
|
+
return Promise.resolve({ id: '', status: 'fired' as const });
|
|
8
|
+
},
|
|
9
|
+
cancel: () => Promise.resolve({ id: '', status: 'cancelled' as const }),
|
|
10
|
+
cancelAll: () => Promise.resolve({ id: '', status: 'cancelled' as const }),
|
|
5
11
|
};
|
|
12
|
+
|
|
13
|
+
export const announce = (message: string) => {
|
|
14
|
+
AccessibilityInfo.announceForAccessibility(message);
|
|
15
|
+
return Promise.resolve({ id: '', status: 'fired' as const });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const cancel = () =>
|
|
19
|
+
Promise.resolve({ id: '', status: 'cancelled' as const });
|
|
20
|
+
export const cancelAll = () =>
|
|
21
|
+
Promise.resolve({ id: '', status: 'cancelled' as const });
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { NativeModules, Platform } from 'react-native';
|
|
2
|
+
import NativeA11yAnnounceModule from '../nativeSpecs/NativeA11yAnnounceModule';
|
|
2
3
|
|
|
3
4
|
const LINKING_ERROR =
|
|
4
|
-
`The package 'react-native-
|
|
5
|
+
`The package 'react-native-a11y-order' doesn't seem to be linked. Make sure: \n\n${Platform.select(
|
|
5
6
|
{ ios: "- You have run 'pod install'\n", default: '' }
|
|
6
7
|
)}- You rebuilt the app after installing the package\n` +
|
|
7
8
|
`- You are not using Expo Go\n`;
|
|
8
9
|
|
|
9
10
|
// @ts-expect-error
|
|
10
11
|
const isTurboModuleEnabled = global.__turboModuleProxy != null;
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
const A11yAnnounceNative = isTurboModuleEnabled
|
|
14
|
+
? NativeA11yAnnounceModule
|
|
13
15
|
: NativeModules.A11yAnnounceModule;
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
const A11yAnnounceProxy: typeof NativeA11yAnnounceModule =
|
|
18
|
+
A11yAnnounceNative ??
|
|
17
19
|
new Proxy(
|
|
18
20
|
{},
|
|
19
21
|
{
|
|
@@ -23,10 +25,152 @@ export const A11yAnnounce =
|
|
|
23
25
|
}
|
|
24
26
|
);
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
export type AnnouncePriority = 'low' | 'default' | 'high';
|
|
31
|
+
|
|
32
|
+
export type AnnounceStatus = 'spoken' | 'fired' | 'cancelled';
|
|
33
|
+
|
|
34
|
+
export type AnnounceOptions = {
|
|
35
|
+
/**
|
|
36
|
+
* Controls urgency. iOS 17+: maps to `UIAccessibilityPriority`.
|
|
37
|
+
*
|
|
38
|
+
* - `'low'` — spoken only when the screen reader is fully idle
|
|
39
|
+
* - `'default'` — standard queued announcement (default)
|
|
40
|
+
* - `'high'` — may preempt lower-priority pending items
|
|
41
|
+
*/
|
|
42
|
+
priority?: AnnouncePriority;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* When `true`, waits for current speech before speaking.
|
|
46
|
+
* When `false`, may interrupt current speech.
|
|
47
|
+
* Default: `true`
|
|
48
|
+
*/
|
|
49
|
+
queue?: boolean;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Navigation-aware mode. When `true`, the announcement waits for:
|
|
53
|
+
* - Active navigation transitions to finish (1 s lock after screen change)
|
|
54
|
+
* - The screen reader to have a focused element
|
|
55
|
+
* - A 300 ms debounce to prevent overlap with focus changes
|
|
56
|
+
*
|
|
57
|
+
* Promise resolves when the service **actually fires** the announcement
|
|
58
|
+
* (not just when it's enqueued), so `await` is meaningful.
|
|
59
|
+
* Default: `false`
|
|
60
|
+
*/
|
|
61
|
+
calm?: boolean;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Explicit delay in milliseconds before the announcement is posted.
|
|
65
|
+
* In `calm` mode the service manages its own timing; this is ignored.
|
|
66
|
+
* Default: `0`
|
|
67
|
+
*/
|
|
68
|
+
delayMs?: number;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* iOS-only speech characteristics. No-op on Android.
|
|
72
|
+
* Only relevant in direct mode (`calm: false`).
|
|
73
|
+
*/
|
|
74
|
+
speech?: {
|
|
75
|
+
/**
|
|
76
|
+
* BCP-47 language tag (e.g. `'fr-FR'`). Defaults to the system language.
|
|
77
|
+
* @platform ios
|
|
78
|
+
*/
|
|
79
|
+
language?: string;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Voice pitch multiplier, range `0.0`–`2.0`. Default: `1.0`.
|
|
83
|
+
* @platform ios
|
|
84
|
+
*/
|
|
85
|
+
pitch?: number;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Spell each character individually.
|
|
89
|
+
* Useful for codes, CAPTCHAs, or abbreviations.
|
|
90
|
+
* @platform ios
|
|
91
|
+
*/
|
|
92
|
+
spellOut?: boolean;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Read punctuation marks aloud (e.g. "comma", "period").
|
|
96
|
+
* @platform ios
|
|
97
|
+
*/
|
|
98
|
+
punctuation?: boolean;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* IPA pronunciation hint applied to the entire string.
|
|
102
|
+
* @platform ios
|
|
103
|
+
*/
|
|
104
|
+
ipaNotation?: string;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export type AnnouncementResult = {
|
|
109
|
+
/** UUID assigned at enqueue time. */
|
|
110
|
+
id: string;
|
|
111
|
+
/**
|
|
112
|
+
* - `'spoken'` — VoiceOver confirmed full speech (iOS direct mode only).
|
|
113
|
+
* - `'fired'` — posted to the screen reader; completion not confirmed.
|
|
114
|
+
* Always the case on Android. iOS calm mode resolves here
|
|
115
|
+
* once the service actually fires the announcement.
|
|
116
|
+
* - `'cancelled'` — explicitly cancelled via `cancel()` or `cancelAll()`.
|
|
117
|
+
*/
|
|
118
|
+
status: AnnounceStatus;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// ─── Core API ─────────────────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Posts a screen reader announcement.
|
|
125
|
+
*
|
|
126
|
+
* **calm mode** (`calm: true`): navigation-aware — waits for transitions to
|
|
127
|
+
* settle and for VoiceOver/TalkBack to have a focused element. Promise
|
|
128
|
+
* resolves when the announcement is **actually fired** (not just enqueued).
|
|
129
|
+
*
|
|
130
|
+
* **direct mode** (`calm: false`, default): posts immediately with speech
|
|
131
|
+
* attributes. On iOS, Promise resolves when VoiceOver confirms speech finished
|
|
132
|
+
* (`status: 'spoken'`) or was interrupted (`status: 'fired'`).
|
|
133
|
+
* On Android, always resolves immediately with `status: 'fired'`.
|
|
134
|
+
*/
|
|
135
|
+
export function announce(
|
|
136
|
+
message: string,
|
|
137
|
+
options?: AnnounceOptions
|
|
138
|
+
): Promise<AnnouncementResult> {
|
|
139
|
+
const { speech, ...rest } = options ?? {};
|
|
140
|
+
return A11yAnnounceProxy!.announce(message, {
|
|
141
|
+
...rest,
|
|
142
|
+
...speech,
|
|
143
|
+
}) as Promise<AnnouncementResult>;
|
|
28
144
|
}
|
|
29
145
|
|
|
30
|
-
|
|
31
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Cancels the announcement with the given `id`.
|
|
148
|
+
* In calm mode, removes it from the service queue if not yet fired.
|
|
149
|
+
* In direct mode, interrupts the active announcement if it matches.
|
|
150
|
+
*/
|
|
151
|
+
export function cancel(id: string): Promise<AnnouncementResult> {
|
|
152
|
+
return A11yAnnounceProxy!.cancel(id) as Promise<AnnouncementResult>;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Cancels all pending and active announcements.
|
|
157
|
+
* Calm-mode promises resolve with `status: 'cancelled'`.
|
|
158
|
+
*/
|
|
159
|
+
export function cancelAll(): Promise<AnnouncementResult> {
|
|
160
|
+
return A11yAnnounceProxy!.cancelAll() as Promise<AnnouncementResult>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ─── Namespace export (backward-compatible) ───────────────────────────────────
|
|
164
|
+
|
|
165
|
+
export const ScreenReader = {
|
|
166
|
+
/**
|
|
167
|
+
* Posts a navigation-aware announcement (calm mode).
|
|
168
|
+
* Waits for transitions to finish before speaking.
|
|
169
|
+
* Promise resolves when the announcement is actually fired.
|
|
170
|
+
*/
|
|
171
|
+
announce: (message: string, options?: AnnounceOptions) =>
|
|
172
|
+
announce(message, { calm: true, ...options }),
|
|
173
|
+
|
|
174
|
+
cancel,
|
|
175
|
+
cancelAll,
|
|
32
176
|
};
|
|
@@ -24,7 +24,6 @@ export interface A11yIndexNativeComponentProps extends ViewProps {
|
|
|
24
24
|
orderFocusType?: Int32;
|
|
25
25
|
shouldGroupAccessibilityChildren?: Int32;
|
|
26
26
|
|
|
27
|
-
autoFocus?: boolean;
|
|
28
27
|
descendantFocusChangedEnabled?: boolean;
|
|
29
28
|
|
|
30
29
|
onScreenReaderFocused?: DirectEventHandler<{}>;
|
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
import type { TurboModule } from 'react-native';
|
|
2
2
|
import { TurboModuleRegistry } from 'react-native';
|
|
3
3
|
|
|
4
|
+
// Speech options are kept flat here (bridge contract).
|
|
5
|
+
// The JS API groups them under `speech: {}` and flattens before calling native.
|
|
6
|
+
type AnnounceOptions = Readonly<{
|
|
7
|
+
priority?: string;
|
|
8
|
+
queue?: boolean;
|
|
9
|
+
calm?: boolean;
|
|
10
|
+
delayMs?: number;
|
|
11
|
+
language?: string;
|
|
12
|
+
pitch?: number;
|
|
13
|
+
spellOut?: boolean;
|
|
14
|
+
punctuation?: boolean;
|
|
15
|
+
ipaNotation?: string;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
18
|
+
type AnnouncementResult = Readonly<{
|
|
19
|
+
id: string;
|
|
20
|
+
// 'spoken' — VoiceOver confirmed full speech (iOS direct only)
|
|
21
|
+
// 'fired' — posted to screen reader; no completion confirmation
|
|
22
|
+
// 'cancelled' — explicitly cancelled via cancel() / cancelAll()
|
|
23
|
+
status: string;
|
|
24
|
+
}>;
|
|
25
|
+
|
|
4
26
|
export interface Spec extends TurboModule {
|
|
5
|
-
|
|
27
|
+
/** Enqueues a screen reader announcement. Resolves with AnnouncementResult. */
|
|
28
|
+
announce(
|
|
29
|
+
message: string,
|
|
30
|
+
options?: AnnounceOptions
|
|
31
|
+
): Promise<AnnouncementResult>;
|
|
32
|
+
/** Cancels a specific announcement by its id. Resolves with the cancelled item's result. */
|
|
33
|
+
cancel(id: string): Promise<AnnouncementResult>;
|
|
34
|
+
/** Drains the queue and interrupts current speech. */
|
|
35
|
+
cancelAll(): Promise<AnnouncementResult>;
|
|
6
36
|
}
|
|
7
37
|
|
|
8
38
|
export default TurboModuleRegistry.get<Spec>('A11yAnnounceModule');
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
package com.a11yorder.core;
|
|
2
|
-
|
|
3
|
-
import android.content.Context;
|
|
4
|
-
import android.view.View;
|
|
5
|
-
import android.view.accessibility.AccessibilityEvent;
|
|
6
|
-
|
|
7
|
-
import com.a11yorder.services.focus.A11yFocusDelegate;
|
|
8
|
-
import com.a11yorder.services.focus.A11yFocusProtocol;
|
|
9
|
-
import com.facebook.react.bridge.ReactContext;
|
|
10
|
-
|
|
11
|
-
public class A11yAutoFocusView extends A11yScreenReaderView implements A11yFocusProtocol {
|
|
12
|
-
private final A11yFocusDelegate a11yFocusDelegate;
|
|
13
|
-
private Boolean autoFocus = false;
|
|
14
|
-
private Boolean autoFocusOnce = false;
|
|
15
|
-
private Boolean hasBeenFocused = false;
|
|
16
|
-
|
|
17
|
-
public A11yAutoFocusView(Context context) {
|
|
18
|
-
super(context);
|
|
19
|
-
this.a11yFocusDelegate = new A11yFocusDelegate((ReactContext) context, this);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
@Override
|
|
23
|
-
public boolean isViewFocused() {
|
|
24
|
-
View focusTarget = this.isFocusable() ? this : this.getSubChild();
|
|
25
|
-
if (focusTarget == null) return false;
|
|
26
|
-
return focusTarget.isAccessibilityFocused();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public void setAutoFocus(Boolean value) {
|
|
30
|
-
this.autoFocus = value;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public void focus() {
|
|
34
|
-
a11yFocusDelegate.requestFocus();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@Override
|
|
38
|
-
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
|
|
39
|
-
int eventType = event.getEventType();
|
|
40
|
-
|
|
41
|
-
if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED && autoFocus && !hasBeenFocused) {
|
|
42
|
-
hasBeenFocused = true;
|
|
43
|
-
a11yFocusDelegate.onFocused();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return super.onRequestSendAccessibilityEvent(child, event);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@Override
|
|
50
|
-
protected void onAttachedToWindow() {
|
|
51
|
-
super.onAttachedToWindow();
|
|
52
|
-
if (autoFocus && !autoFocusOnce) {
|
|
53
|
-
autoFocusOnce = true;
|
|
54
|
-
|
|
55
|
-
if (!isViewFocused()) {
|
|
56
|
-
hasBeenFocused = false;
|
|
57
|
-
a11yFocusDelegate.requestFocus();
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|