@khanacademy/wonder-blocks-timing 2.1.0 → 2.1.2
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/CHANGELOG.md +26 -6
- package/dist/components/action-scheduler-provider.d.ts +26 -0
- package/dist/components/action-scheduler-provider.js.flow +35 -0
- package/dist/components/with-action-scheduler.d.ts +14 -0
- package/dist/components/with-action-scheduler.js.flow +26 -0
- package/dist/es/index.js +165 -380
- package/dist/hooks/internal/use-updating-ref.d.ts +13 -0
- package/dist/hooks/internal/use-updating-ref.js.flow +22 -0
- package/dist/hooks/use-interval.d.ts +8 -0
- package/dist/hooks/use-interval.js.flow +18 -0
- package/dist/hooks/use-scheduled-interval.d.ts +2 -0
- package/dist/hooks/use-scheduled-interval.js.flow +13 -0
- package/dist/hooks/use-scheduled-timeout.d.ts +2 -0
- package/dist/hooks/use-scheduled-timeout.js.flow +13 -0
- package/dist/hooks/use-timeout.d.ts +8 -0
- package/dist/hooks/use-timeout.js.flow +18 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +335 -778
- package/dist/index.js.flow +31 -2
- package/dist/util/action-scheduler.d.ts +21 -0
- package/dist/util/action-scheduler.js.flow +39 -0
- package/dist/util/animation-frame.d.ts +62 -0
- package/dist/util/animation-frame.js.flow +71 -0
- package/dist/util/interval.d.ts +60 -0
- package/dist/util/interval.js.flow +70 -0
- package/dist/util/policies.d.ts +8 -0
- package/dist/util/policies.js.flow +17 -0
- package/dist/util/timeout.d.ts +62 -0
- package/dist/util/timeout.js.flow +72 -0
- package/dist/util/types.d.ts +228 -0
- package/dist/util/types.js.flow +235 -0
- package/dist/util/types.typestest.d.ts +1 -0
- package/dist/util/types.typestest.js.flow +6 -0
- package/package.json +3 -3
- package/src/__docs__/_overview_.stories.mdx +17 -0
- package/src/components/__tests__/{action-scheduler-provider.test.js → action-scheduler-provider.test.tsx} +7 -10
- package/src/components/__tests__/{with-action-scheduler.test.js → with-action-scheduler.test.tsx} +11 -12
- package/src/components/{action-scheduler-provider.js → action-scheduler-provider.ts} +6 -7
- package/src/components/{with-action-scheduler.js → with-action-scheduler.tsx} +11 -19
- package/src/hooks/__tests__/{use-interval.test.js → use-interval.test.ts} +6 -7
- package/src/hooks/__tests__/{use-scheduled-interval.test.js → use-scheduled-interval.test.ts} +15 -8
- package/src/hooks/__tests__/{use-scheduled-timeout.test.js → use-scheduled-timeout.test.ts} +22 -13
- package/src/hooks/__tests__/{use-timeout.test.js → use-timeout.test.ts} +6 -7
- package/src/hooks/internal/{use-updating-ref.js → use-updating-ref.ts} +5 -2
- package/src/hooks/{use-interval.js → use-interval.ts} +2 -3
- package/src/hooks/{use-scheduled-interval.js → use-scheduled-interval.ts} +6 -6
- package/src/hooks/{use-scheduled-timeout.js → use-scheduled-timeout.ts} +6 -6
- package/src/hooks/{use-timeout.js → use-timeout.ts} +2 -3
- package/src/{index.js → index.ts} +7 -8
- package/src/util/__tests__/{action-scheduler.test.js → action-scheduler.test.ts} +14 -24
- package/src/util/__tests__/{animation-frame.test.js → animation-frame.test.ts} +10 -9
- package/src/util/__tests__/{interval.test.js → interval.test.ts} +3 -4
- package/src/util/__tests__/{timeout.test.js → timeout.test.ts} +3 -4
- package/src/util/{action-scheduler.js → action-scheduler.ts} +17 -10
- package/src/util/{animation-frame.js → animation-frame.ts} +6 -6
- package/src/util/{interval.js → interval.ts} +7 -6
- package/src/util/{policies.js → policies.ts} +2 -3
- package/src/util/{timeout.js → timeout.ts} +7 -6
- package/src/util/{types.js → types.ts} +21 -28
- package/src/util/{types.flowtest.js → types.typestest.tsx} +22 -20
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/docs.md +0 -406
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +0 -353
- package/src/__tests__/generated-snapshot.test.js +0 -155
- package/src/components/with-action-scheduler.md +0 -18
- package/src/hooks/use-interval.stories.mdx +0 -80
- package/src/hooks/use-scheduled-interval.stories.mdx +0 -147
- package/src/hooks/use-scheduled-timeout.stories.mdx +0 -148
- package/src/hooks/use-timeout.stories.mdx +0 -80
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import {Meta, Story, Source, Canvas} from "@storybook/addon-docs";
|
|
2
|
-
|
|
3
|
-
import {Body, HeadingSmall} from "@khanacademy/wonder-blocks-typography";
|
|
4
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
-
|
|
7
|
-
import {ClearPolicy, SchedulePolicy} from "../util/policies.js";
|
|
8
|
-
import {useScheduledInterval} from "./use-scheduled-interval.js";
|
|
9
|
-
|
|
10
|
-
<Meta
|
|
11
|
-
title="Timing/useScheduledInterval"
|
|
12
|
-
parameters={{
|
|
13
|
-
chromatic: {
|
|
14
|
-
disableSnapshot: true,
|
|
15
|
-
},
|
|
16
|
-
}}
|
|
17
|
-
/>
|
|
18
|
-
|
|
19
|
-
# `useScheduledInterval`
|
|
20
|
-
|
|
21
|
-
`useScheduledInterval` is a hook that provides a convenient API for setting and clearing
|
|
22
|
-
an interval. It is defined as follows:
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
function useScheduledInterval(
|
|
26
|
-
action: () => mixed,
|
|
27
|
-
timeoutMs: number,
|
|
28
|
-
options?: {|
|
|
29
|
-
schedulePolicy?: "schedule-immediately" | "schedule-on-demand",
|
|
30
|
-
clearPolicy?: "resolve-on-clear" | "cancel-on-clear",
|
|
31
|
-
|},
|
|
32
|
-
): ITimeout;
|
|
33
|
-
|
|
34
|
-
interface ITimeout {
|
|
35
|
-
get isSet(): boolean;
|
|
36
|
-
set(): void;
|
|
37
|
-
clear(policy?: ClearPolicy): void;
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
By default the interval will be set immediately up creation. The `options` parameter can
|
|
42
|
-
be used to control when when the interval is schedule and whether or not `action` should be
|
|
43
|
-
called when the interval is cleared.
|
|
44
|
-
|
|
45
|
-
Notes:
|
|
46
|
-
|
|
47
|
-
- Because `clear` takes a param, it's import that you don't pass it directly to an event handler,
|
|
48
|
-
e.g. `<Button onClick={clear} />` will not work as expected.
|
|
49
|
-
- Calling `set` after the interval has been cleared will restart the interval.
|
|
50
|
-
- Updating the second paramter, `timeoutMs`, will also restart the interval.
|
|
51
|
-
- When the component using this hooks is unmounted, the interval will automatically be cleared.
|
|
52
|
-
- Calling `set` after the interval is already set does nothing.
|
|
53
|
-
|
|
54
|
-
export const Immediately = () => {
|
|
55
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
56
|
-
const callback = React.useCallback(() => {
|
|
57
|
-
setCallCount((callCount) => callCount + 1);
|
|
58
|
-
}, []);
|
|
59
|
-
const interval = useScheduledInterval(callback, 1000);
|
|
60
|
-
return (
|
|
61
|
-
<View>
|
|
62
|
-
<View>isSet = {interval.isSet.toString()}</View>
|
|
63
|
-
<View>callCount = {callCount}</View>
|
|
64
|
-
<View style={{flexDirection: "row"}}>
|
|
65
|
-
<Button onClick={() => interval.set()}>Set interval</Button>
|
|
66
|
-
<Button onClick={() => interval.clear()}>Clear interval</Button>
|
|
67
|
-
</View>
|
|
68
|
-
</View>
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
<Canvas>
|
|
73
|
-
<Story name="Immediately">
|
|
74
|
-
<Immediately />
|
|
75
|
-
</Story>
|
|
76
|
-
</Canvas>
|
|
77
|
-
|
|
78
|
-
```jsx
|
|
79
|
-
const Immediately = () => {
|
|
80
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
81
|
-
const callback = React.useCallback(() => {
|
|
82
|
-
setCallCount((callCount) => callCount + 1);
|
|
83
|
-
}, []);
|
|
84
|
-
const interval = useScheduledInterval(callback, 1000);
|
|
85
|
-
return (
|
|
86
|
-
<View>
|
|
87
|
-
<View>isSet = {interval.isSet.toString()}</View>
|
|
88
|
-
<View>callCount = {callCount}</View>
|
|
89
|
-
<View style={{flexDirection: "row"}}>
|
|
90
|
-
<Button onClick={() => interval.set()}>Set interval</Button>
|
|
91
|
-
<Button onClick={() => interval.clear()}>Clear interval</Button>
|
|
92
|
-
</View>
|
|
93
|
-
</View>
|
|
94
|
-
);
|
|
95
|
-
};
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
export const OnDemandAndResolveOnClear = () => {
|
|
99
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
100
|
-
const callback = React.useCallback(() => {
|
|
101
|
-
console.log("action called");
|
|
102
|
-
setCallCount((callCount) => callCount + 1);
|
|
103
|
-
}, []);
|
|
104
|
-
const interval = useScheduledInterval(callback, 1000, {
|
|
105
|
-
clearPolicy: ClearPolicy.Resolve,
|
|
106
|
-
schedulePolicy: SchedulePolicy.OnDemand,
|
|
107
|
-
});
|
|
108
|
-
return (
|
|
109
|
-
<View>
|
|
110
|
-
<View>isSet = {interval.isSet.toString()}</View>
|
|
111
|
-
<View>callCount = {callCount}</View>
|
|
112
|
-
<View style={{flexDirection: "row"}}>
|
|
113
|
-
<Button onClick={() => interval.set()}>Set interval</Button>
|
|
114
|
-
<Button onClick={() => interval.clear()}>Clear interval</Button>
|
|
115
|
-
</View>
|
|
116
|
-
</View>
|
|
117
|
-
);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
<Canvas>
|
|
121
|
-
<Story name="OnDemandAndResolveOnClear">
|
|
122
|
-
<OnDemandAndResolveOnClear />
|
|
123
|
-
</Story>
|
|
124
|
-
</Canvas>
|
|
125
|
-
|
|
126
|
-
```jsx
|
|
127
|
-
const OnDemandAndResolveOnClear = () => {
|
|
128
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
129
|
-
const callback = React.useCallback(() => {
|
|
130
|
-
setCallCount((callCount) => callCount + 1);
|
|
131
|
-
}, []);
|
|
132
|
-
const interval = useScheduledInterval(callback, 1000, {
|
|
133
|
-
clearPolicy: ClearPolicy.Resolve,
|
|
134
|
-
schedulePolicy: SchedulePolicy.OnDemand,
|
|
135
|
-
});
|
|
136
|
-
return (
|
|
137
|
-
<View>
|
|
138
|
-
<View>isSet = {interval.isSet.toString()}</View>
|
|
139
|
-
<View>callCount = {callCount}</View>
|
|
140
|
-
<View style={{flexDirection: "row"}}>
|
|
141
|
-
<Button onClick={() => interval.set()}>Set interval</Button>
|
|
142
|
-
<Button onClick={() => interval.clear()}>Clear interval</Button>
|
|
143
|
-
</View>
|
|
144
|
-
</View>
|
|
145
|
-
);
|
|
146
|
-
};
|
|
147
|
-
```
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import {Meta, Story, Source, Canvas} from "@storybook/addon-docs";
|
|
2
|
-
|
|
3
|
-
import {Body, HeadingSmall} from "@khanacademy/wonder-blocks-typography";
|
|
4
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
-
|
|
7
|
-
import {ClearPolicy, SchedulePolicy} from "../util/policies.js";
|
|
8
|
-
import {useScheduledTimeout} from "./use-scheduled-timeout.js";
|
|
9
|
-
|
|
10
|
-
<Meta
|
|
11
|
-
title="Timing/useScheduledTimeout"
|
|
12
|
-
parameters={{
|
|
13
|
-
chromatic: {
|
|
14
|
-
disableSnapshot: true,
|
|
15
|
-
},
|
|
16
|
-
}}
|
|
17
|
-
/>
|
|
18
|
-
|
|
19
|
-
# `useScheduledTimeout`
|
|
20
|
-
|
|
21
|
-
`useScheduledTimeout` is a hook that provides a convenient API for setting and clearing
|
|
22
|
-
a timeout. It is defined as follows:
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
function useScheduledTimeout(
|
|
26
|
-
action: () => mixed,
|
|
27
|
-
timeoutMs: number,
|
|
28
|
-
options?: {|
|
|
29
|
-
schedulePolicy?: "schedule-immediately" | "schedule-on-demand",
|
|
30
|
-
clearPolicy?: "resolve-on-clear" | "cancel-on-clear",
|
|
31
|
-
|},
|
|
32
|
-
): ITimeout;
|
|
33
|
-
|
|
34
|
-
interface ITimeout {
|
|
35
|
-
get isSet(): boolean;
|
|
36
|
-
set(): void;
|
|
37
|
-
clear(policy?: ClearPolicy): void;
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
By default the timeout will be set immediately up creation. The `options` parameter can
|
|
42
|
-
be used to control when when the timeout is schedule and whether or not `action` should be
|
|
43
|
-
called when the timeout is cleared.
|
|
44
|
-
|
|
45
|
-
Notes:
|
|
46
|
-
|
|
47
|
-
- Because `clear` takes a param, it's import that you don't pass it directly to an event handler,
|
|
48
|
-
e.g. `<Button onClick={clear} />` will not work as expected.
|
|
49
|
-
- Calling `set` after the timeout has expired will restart the timeout.
|
|
50
|
-
- Updating the second paramter, `timeoutMs`, will also restart the timeout.
|
|
51
|
-
- When the component using this hooks is unmounted, the timeout will automatically be cleared.
|
|
52
|
-
- Calling `set` after the timeout is set but before it expires means that the timeout will be
|
|
53
|
-
reset and will call `action`, `timeoutMs` after the most recent call to `set` was made.
|
|
54
|
-
|
|
55
|
-
export const Immediately = () => {
|
|
56
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
57
|
-
const callback = React.useCallback(() => {
|
|
58
|
-
setCallCount((callCount) => callCount + 1);
|
|
59
|
-
}, []);
|
|
60
|
-
const {isSet, set, clear} = useScheduledTimeout(callback, 1000);
|
|
61
|
-
return (
|
|
62
|
-
<View>
|
|
63
|
-
<View>isSet = {isSet.toString()}</View>
|
|
64
|
-
<View>callCount = {callCount}</View>
|
|
65
|
-
<View style={{flexDirection: "row"}}>
|
|
66
|
-
<Button onClick={set}>Set timeout</Button>
|
|
67
|
-
<Button onClick={clear}>Clear timeout</Button>
|
|
68
|
-
</View>
|
|
69
|
-
</View>
|
|
70
|
-
);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
<Canvas>
|
|
74
|
-
<Story name="Immediately">
|
|
75
|
-
<Immediately />
|
|
76
|
-
</Story>
|
|
77
|
-
</Canvas>
|
|
78
|
-
|
|
79
|
-
```jsx
|
|
80
|
-
const Immediately = () => {
|
|
81
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
82
|
-
const callback = React.useCallback(() => {
|
|
83
|
-
setCallCount((callCount) => callCount + 1);
|
|
84
|
-
}, []);
|
|
85
|
-
const {isSet, set, clear} = useScheduledTimeout(callback, 1000);
|
|
86
|
-
return (
|
|
87
|
-
<View>
|
|
88
|
-
<View>isSet = {isSet.toString()}</View>
|
|
89
|
-
<View>callCount = {callCount}</View>
|
|
90
|
-
<View style={{flexDirection: "row"}}>
|
|
91
|
-
<Button onClick={() => set()}>Set timeout</Button>
|
|
92
|
-
<Button onClick={() => clear()}>Clear timeout</Button>
|
|
93
|
-
</View>
|
|
94
|
-
</View>
|
|
95
|
-
);
|
|
96
|
-
};
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
export const OnDemandAndResolveOnClear = () => {
|
|
100
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
101
|
-
const callback = React.useCallback(() => {
|
|
102
|
-
console.log("action called");
|
|
103
|
-
setCallCount((callCount) => callCount + 1);
|
|
104
|
-
}, []);
|
|
105
|
-
const {isSet, set, clear} = useScheduledTimeout(callback, 1000, {
|
|
106
|
-
clearPolicy: ClearPolicy.Resolve,
|
|
107
|
-
schedulePolicy: SchedulePolicy.OnDemand,
|
|
108
|
-
});
|
|
109
|
-
return (
|
|
110
|
-
<View>
|
|
111
|
-
<View>isSet = {isSet.toString()}</View>
|
|
112
|
-
<View>callCount = {callCount}</View>
|
|
113
|
-
<View style={{flexDirection: "row"}}>
|
|
114
|
-
<Button onClick={() => set()}>Set timeout</Button>
|
|
115
|
-
<Button onClick={() => clear()}>Clear timeout</Button>
|
|
116
|
-
</View>
|
|
117
|
-
</View>
|
|
118
|
-
);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
<Canvas>
|
|
122
|
-
<Story name="OnDemandAndResolveOnClear">
|
|
123
|
-
<OnDemandAndResolveOnClear />
|
|
124
|
-
</Story>
|
|
125
|
-
</Canvas>
|
|
126
|
-
|
|
127
|
-
```jsx
|
|
128
|
-
const OnDemandAndResolveOnClear = () => {
|
|
129
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
130
|
-
const callback = React.useCallback(() => {
|
|
131
|
-
setCallCount((callCount) => callCount + 1);
|
|
132
|
-
}, []);
|
|
133
|
-
const {isSet, set, clear} = useScheduledTimeout(callback, 1000, {
|
|
134
|
-
clearPolicy: ClearPolicy.Resolve,
|
|
135
|
-
schedulePolicy: SchedulePolicy.OnDemand,
|
|
136
|
-
});
|
|
137
|
-
return (
|
|
138
|
-
<View>
|
|
139
|
-
<View>isSet = {isSet.toString()}</View>
|
|
140
|
-
<View>callCount = {callCount}</View>
|
|
141
|
-
<View style={{flexDirection: "row"}}>
|
|
142
|
-
<Button onClick={() => set()}>Set timeout</Button>
|
|
143
|
-
<Button onClick={() => clear()}>Clear timeout</Button>
|
|
144
|
-
</View>
|
|
145
|
-
</View>
|
|
146
|
-
);
|
|
147
|
-
};
|
|
148
|
-
```
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import {Meta, Story, Source, Canvas} from "@storybook/addon-docs";
|
|
2
|
-
|
|
3
|
-
import {Body, HeadingSmall} from "@khanacademy/wonder-blocks-typography";
|
|
4
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
-
|
|
7
|
-
import {useTimeout} from "./use-timeout.js";
|
|
8
|
-
|
|
9
|
-
<Meta
|
|
10
|
-
title="Timing/useTimeout"
|
|
11
|
-
parameters={{
|
|
12
|
-
chromatic: {
|
|
13
|
-
disableSnapshot: true,
|
|
14
|
-
},
|
|
15
|
-
}}
|
|
16
|
-
/>
|
|
17
|
-
|
|
18
|
-
# `useTimeout`
|
|
19
|
-
|
|
20
|
-
`useTimeout` is a hook that provides a simple API for using timers safely.
|
|
21
|
-
It is defined as follows:
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
function useTimeout(
|
|
25
|
-
action: () => mixed,
|
|
26
|
-
timeoutMs: number,
|
|
27
|
-
active: boolean,
|
|
28
|
-
): void;
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Notes:
|
|
32
|
-
|
|
33
|
-
- Setting `active` to `true` will start the timeout and setting it to `false`
|
|
34
|
-
will stop it
|
|
35
|
-
- Changing the value of `timeoutMs` will reset the timeout, changing `action`
|
|
36
|
-
will not.
|
|
37
|
-
|
|
38
|
-
export const BasicUsage = () => {
|
|
39
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
40
|
-
const [active, setActive] = React.useState(false);
|
|
41
|
-
const callback = React.useCallback(() => {
|
|
42
|
-
setCallCount((callCount) => callCount + 1);
|
|
43
|
-
}, []);
|
|
44
|
-
useTimeout(callback, 1000, active);
|
|
45
|
-
return (
|
|
46
|
-
<View>
|
|
47
|
-
<View>callCount = {callCount}</View>
|
|
48
|
-
<View>active = {active.toString()}</View>
|
|
49
|
-
<Button onClick={() => setActive(!active)} style={{width: 200}}>
|
|
50
|
-
Toggle active
|
|
51
|
-
</Button>
|
|
52
|
-
</View>
|
|
53
|
-
);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
<Canvas>
|
|
57
|
-
<Story name="BasicUsage">
|
|
58
|
-
<BasicUsage />
|
|
59
|
-
</Story>
|
|
60
|
-
</Canvas>
|
|
61
|
-
|
|
62
|
-
```jsx
|
|
63
|
-
export const BasicUsage = () => {
|
|
64
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
65
|
-
const [active, setActive] = React.useState(false);
|
|
66
|
-
const callback = React.useCallback(() => {
|
|
67
|
-
setCallCount((callCount) => callCount + 1);
|
|
68
|
-
}, []);
|
|
69
|
-
useTimeout(callback, 1000, active);
|
|
70
|
-
return (
|
|
71
|
-
<View>
|
|
72
|
-
<View>callCount = {callCount}</View>
|
|
73
|
-
<View>active = {active.toString()}</View>
|
|
74
|
-
<Button onClick={() => setActive(!active)} style={{width: 200}}>
|
|
75
|
-
Toggle active
|
|
76
|
-
</Button>
|
|
77
|
-
</View>
|
|
78
|
-
);
|
|
79
|
-
};
|
|
80
|
-
```
|