reacthub-pixitweenjs 0.2.5 → 0.2.7

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.
Files changed (33) hide show
  1. package/.storybook/preview.tsx +6 -0
  2. package/CHANGELOG.md +26 -0
  3. package/README.md +1 -1
  4. package/package.json +4 -1
  5. package/src/components/PixiAudioSprite/PixiAudioSprite.tsx +5 -15
  6. package/src/components/PixiGifSprite/PixiGifSprite.stories.tsx +41 -4
  7. package/src/components/PixiGifSprite/PixiGifSprite.tsx +64 -95
  8. package/src/components/PixiImageSprite/PixiImageSprite.stories.tsx +53 -7
  9. package/src/components/PixiImageSprite/PixiImageSprite.tsx +27 -307
  10. package/src/components/PixiSVGSprite/PixiSvgPathSprite.stories.tsx +51 -14
  11. package/src/components/PixiSVGSprite/PixiSvgPathSprite.tsx +33 -253
  12. package/src/components/PixiTextSprite/PixiTextSprite.stories.tsx +228 -0
  13. package/src/components/PixiTextSprite/PixiTextSprite.tsx +361 -0
  14. package/src/components/PixiTextSprite/index.ts +1 -0
  15. package/src/components/PixiVideoSprite/PixiVideoSprite.stories.tsx +39 -0
  16. package/src/components/PixiVideoSprite/PixiVideoSprite.tsx +595 -684
  17. package/src/hocs/AbstractContainer.tsx +199 -0
  18. package/src/hocs/WithFilterContainer.tsx +159 -0
  19. package/src/main.tsx +8 -7
  20. package/src/providers/GsapPixieContextProvider.tsx +14 -20
  21. package/src/stories/Installation.mdx +3 -3
  22. package/src/types/Animations.tsx +41 -0
  23. package/src/types/BaseProps.tsx +56 -0
  24. package/src/types/BlendModes.tsx +19 -0
  25. package/src/types/Effects.tsx +10 -0
  26. package/src/utils/AppStateProvider.tsx +3 -3
  27. package/src/utils/AppStateStage.tsx +1 -13
  28. package/src/utils/AppWrapper.tsx +4 -0
  29. package/src/utils/GsapAnim.tsx +1 -7
  30. package/src/utils/InteractionManager.tsx +36 -0
  31. package/src/utils/PixiTransformer.tsx +68 -3
  32. package/src/utils/VideoSeekBar.tsx +4 -11
  33. package/src/hooks/usePixiTransformer.tsx +0 -168
@@ -1,5 +1,11 @@
1
1
  import React from "react";
2
2
  import { AppWrapper } from "../src/utils/AppWrapper";
3
+ import whyDidYouRender from "@welldone-software/why-did-you-render";
4
+
5
+ whyDidYouRender(React, {
6
+ trackAllPureComponents: true,
7
+ });
8
+
3
9
  /** @type { import('@storybook/react').Preview } */
4
10
  const preview = {
5
11
  parameters: {
package/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.2.7](https://github.com/khanzzirfan/reacthub-pixitweenjs/compare/v0.2.6...v0.2.7) (2023-08-27)
6
+
7
+
8
+ ### Features
9
+
10
+ * reupdated the filters and hoc wrappers ([0083847](https://github.com/khanzzirfan/reacthub-pixitweenjs/commit/00838477793b342453341f1dbd3e418c66f02619))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * filters applied on all video and other elements ([19100d0](https://github.com/khanzzirfan/reacthub-pixitweenjs/commit/19100d0f16d7f7be4ad0f4622a1b9f67765b3134))
16
+ * pixi fixed colorization component ([8ca4c32](https://github.com/khanzzirfan/reacthub-pixitweenjs/commit/8ca4c326514eb6c677c1460323afe92c34c25060))
17
+
18
+ ### [0.2.6](https://github.com/khanzzirfan/reacthub-pixitweenjs/compare/v0.2.5...v0.2.6) (2023-08-25)
19
+
20
+
21
+ ### Features
22
+
23
+ * added text , gif and svg sprites ([290e6fd](https://github.com/khanzzirfan/reacthub-pixitweenjs/commit/290e6fda45ad4954c9ca767945c0863362326af4))
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * updated pixi svg sprite ([6fe3619](https://github.com/khanzzirfan/reacthub-pixitweenjs/commit/6fe3619e0eb9faf0a46d10de7154ad428a21e188))
29
+ * updated pixi text editor ([d4cd8d9](https://github.com/khanzzirfan/reacthub-pixitweenjs/commit/d4cd8d97b53fa6210919cd641bfa74d4f7d93f84))
30
+
5
31
  ### [0.2.5](https://github.com/khanzzirfan/reacthub-pixitweenjs/compare/v0.2.4...v0.2.5) (2023-08-23)
6
32
 
7
33
 
package/README.md CHANGED
@@ -37,4 +37,4 @@ PixiTweenJs is designed to help you build animated time-controlled canvas elemen
37
37
 
38
38
  ## Usage
39
39
 
40
- Visit the [storybook](https://64b9d71094fa7aed0c7291cf-sinysbbbmx.chromatic.com/?path=/docs/components-imagesprite--docs)
40
+ Visit the [storybook](https://62ea8f8fe832236b40182334-qwuvdhldjp.chromatic.com/)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reacthub-pixitweenjs",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "reacthub-pixitweenjs is a library that provides a powerful combination of React, PixiJS, GSAP, and image manipulation capabilities in a timeline sequence. With this library, you can easily create stunning animations and interactive graphics for your React applications",
5
5
  "author": "khanzzirfan",
6
6
  "type": "module",
@@ -55,12 +55,14 @@
55
55
  "@testing-library/react": "^14.0.0",
56
56
  "@types/dotenv": "^8.2.0",
57
57
  "@types/howler": "^2.2.8",
58
+ "@types/quill": "^2.0.10",
58
59
  "@types/react": "^18.2.15",
59
60
  "@types/react-dom": "^18.2.7",
60
61
  "@typescript-eslint/eslint-plugin": "^5.62.0",
61
62
  "@typescript-eslint/parser": "^5.62.0",
62
63
  "@vitejs/plugin-react": "^4.0.3",
63
64
  "@vitejs/plugin-react-swc": "^3.3.2",
65
+ "@welldone-software/why-did-you-render": "^7.0.1",
64
66
  "chromatic": "^6.7.3",
65
67
  "debug": "^4.3.4",
66
68
  "dotenv": "^16.0.1",
@@ -83,6 +85,7 @@
83
85
  "pixi-svg": "^3.2.0",
84
86
  "pixi.js": "^7.2.3",
85
87
  "prop-types": "^15.8.1",
88
+ "quill": "^1.3.7",
86
89
  "react": "^18.2.0",
87
90
  "react-custom-events": "^1.1.1",
88
91
  "react-dom": "^18.2.0",
@@ -6,7 +6,7 @@ import {
6
6
  GsapPixieContext,
7
7
  Events,
8
8
  } from "../../providers/GsapPixieContextProvider";
9
- import { Container, useApp } from "@pixi/react";
9
+ import { Container } from "@pixi/react";
10
10
  import { useCustomEventListener } from "react-custom-events";
11
11
  import gsap from "gsap";
12
12
  import { Sound } from "@pixi/sound";
@@ -46,7 +46,7 @@ const PixiAudioSprite: React.FC<PixiAudioSpriteProps> = (props) => {
46
46
  isDragging: false,
47
47
  };
48
48
  //// State
49
- const [isMounted, setIsMounted] = React.useState(false);
49
+ const [, setIsMounted] = React.useState(false);
50
50
 
51
51
  const audioStateRef = useRef<AudioState>(initialState);
52
52
 
@@ -61,9 +61,8 @@ const PixiAudioSprite: React.FC<PixiAudioSpriteProps> = (props) => {
61
61
 
62
62
  /// 1001
63
63
  // console.log("contxt Values", tl);
64
- const { uniqueId, src, startAt, endAt, mute, speed, ...restProps } = props;
64
+ const { uniqueId, src, startAt, endAt, mute, speed } = props;
65
65
 
66
- const app = useApp();
67
66
  const audioContainerRef = React.useRef<Sound>(null);
68
67
 
69
68
  /** Adding custom event listners */
@@ -94,15 +93,6 @@ const PixiAudioSprite: React.FC<PixiAudioSpriteProps> = (props) => {
94
93
  }
95
94
  };
96
95
 
97
- const gsapOnPause = (startAt: number) => {
98
- if (containerRef.current) {
99
- console.log("audio gsapOnStart", startAt);
100
- // @ts-ignore
101
- audioContainerRef.current?.pause();
102
- audioStateRef.current.isPlaying = false;
103
- }
104
- };
105
-
106
96
  const gsapOnComplete = () => {
107
97
  if (containerRef.current) {
108
98
  console.log("audio gsapOnStart", startAt);
@@ -131,7 +121,7 @@ const PixiAudioSprite: React.FC<PixiAudioSpriteProps> = (props) => {
131
121
  }
132
122
  };
133
123
 
134
- const onInterrupt = (startAt: number) => {};
124
+ const onInterrupt = () => {};
135
125
 
136
126
  useEffect(() => {
137
127
  let ctx = gsap.context(() => {});
@@ -178,7 +168,7 @@ const PixiAudioSprite: React.FC<PixiAudioSpriteProps> = (props) => {
178
168
  }, [mute, speed]);
179
169
 
180
170
  const onSoundLoaded = React.useCallback(
181
- (err: any, sound: Sound | undefined) => {
171
+ (_: any, sound: Sound | undefined) => {
182
172
  //@ts-ignore
183
173
  audioContainerRef.current = sound;
184
174
  audioStateRef.current.loaded = true;
@@ -114,11 +114,14 @@ export const Normal: Story = {
114
114
  src: "https://media.giphy.com/media/5VKbvrjxpVJCM/giphy.gif",
115
115
  locked: false,
116
116
  loop: false,
117
+ applyTransformer: false,
118
+ startAt: 0,
119
+ endAt: 4,
117
120
  transformation: {
118
- x: 100,
119
- y: 100,
120
- width: 150,
121
- height: 150,
121
+ x: 200,
122
+ y: 200,
123
+ width: 200,
124
+ height: 200,
122
125
  anchor: 0.5,
123
126
  rotation: 0,
124
127
  alpha: 1,
@@ -127,9 +130,43 @@ export const Normal: Story = {
127
130
  blendMode: 0,
128
131
  colorCorrection: {},
129
132
  },
133
+ initialAlpha: 1,
134
+ },
135
+ };
136
+
137
+ export const Filters: Story = {
138
+ render: (args: any) => (
139
+ <AppStateContextProvider {...args}>
140
+ <PixiGifSprite {...args} />
141
+ </AppStateContextProvider>
142
+ ),
143
+ args: {
144
+ uniqueId: "suryaGify001", // uniqueId of the sprite
145
+ src: "https://media.giphy.com/media/5VKbvrjxpVJCM/giphy.gif",
146
+ locked: false,
147
+ loop: false,
130
148
  applyTransformer: false,
131
149
  startAt: 0,
132
150
  endAt: 4,
151
+ transformation: {
152
+ x: 200,
153
+ y: 200,
154
+ width: 200,
155
+ height: 200,
156
+ anchor: 0.5,
157
+ rotation: 0,
158
+ alpha: 1,
159
+ scale: 1,
160
+ tint: 0xffffff,
161
+ blendMode: 0,
162
+ colorCorrection: {
163
+ enabled: true,
164
+ contrast: 2,
165
+ saturation: 2,
166
+ exposure: 2,
167
+ blurRadius: 1,
168
+ },
169
+ },
133
170
  initialAlpha: 1,
134
171
  },
135
172
  };
@@ -5,7 +5,7 @@ import map from "lodash/map";
5
5
  // @ts-ignore
6
6
  import PropTypes from "prop-types";
7
7
  import { GsapPixieContext } from "../../providers/GsapPixieContextProvider";
8
- import { Container, useApp, withFilters, Graphics } from "@pixi/react";
8
+ import { Container, useApp, Graphics, withFilters } from "@pixi/react";
9
9
  import { AdjustmentFilter } from "@pixi/filter-adjustment";
10
10
  import * as PIXI from "pixi.js";
11
11
  import gsap from "gsap";
@@ -72,42 +72,15 @@ type PixiGifSpriteProps = {
72
72
  onAnchorTransformationEnd?: (endData: any) => void;
73
73
  };
74
74
 
75
- type EffectFunc = () => void;
76
- type Deps = ReadonlyArray<unknown>;
77
-
78
75
  const Filters = withFilters(Container, {
79
76
  blur: PIXI.filters.BlurFilter,
80
77
  adjust: AdjustmentFilter,
81
78
  matrix: PIXI.filters.ColorMatrixFilter,
82
79
  });
83
80
 
84
- /** filter config */
85
- const config = {
86
- dot: {
87
- scale: 1,
88
- angle: 5,
89
- },
90
- blur: {
91
- blur: 0,
92
- quality: 4,
93
- },
94
- };
95
-
96
81
  /** CYAN Filters */
97
82
  const CYAN = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0];
98
83
 
99
- const initialState = {
100
- isPlaying: false,
101
- progress: 0,
102
- speed: 1,
103
- isMuted: false,
104
- isWaiting: false,
105
- loaded: false,
106
- size: { width: 50, height: 50 },
107
- play: false,
108
- current: false,
109
- };
110
-
111
84
  /**
112
85
  * PixiGifSprite Component is used to render gif image
113
86
  * @param props Gif Sprite props
@@ -116,21 +89,19 @@ const initialState = {
116
89
  const PixiGifSprite: React.FC<PixiGifSpriteProps> = (props) => {
117
90
  //// State
118
91
  const [gifFrame, setGifFrame] = React.useState<PIXI.Texture[]>([]);
119
- const [gifDuration, setGifDuration] = React.useState<number>(0);
92
+ const [, setGifDuration] = React.useState<number>(0);
120
93
  const [gifFrameObject, setGifFrameObject] = React.useState<
121
94
  PIXI.FrameObject[]
122
95
  >([]);
123
- const [currentFrame, setCurrentFrame] = useState<number>(0);
124
- const [isComplete, setIsComplete] = useState<boolean>(false);
96
+ const [, setCurrentFrame] = useState<number>(0);
97
+ const [, setIsComplete] = useState<boolean>(false);
125
98
 
126
99
  const [isDragging, setIsDragging] = useState(false);
127
- const [isMouseOverTransformer, setIsMouseOverTransformer] = useState(false);
100
+ const [, setIsMouseOverTransformer] = useState(false);
128
101
 
129
102
  const [gifState, update] = usePlayerState({ autoPlay: false });
130
103
  const graphicRef = React.useRef<PIXI.Graphics>(null);
131
- const gifStatusRef = React.useRef(false);
132
104
 
133
- console.log("allProps", props);
134
105
  //// Refs
135
106
  const animatedSpriteRef = useRef<PIXI.AnimatedSprite>(null);
136
107
  const containerRef = useRef<PIXI.Container>(null);
@@ -142,15 +113,7 @@ const PixiGifSprite: React.FC<PixiGifSpriteProps> = (props) => {
142
113
  const { tl, play: tlPlay } = useContext(GsapPixieContext);
143
114
 
144
115
  /// 1001
145
- console.log("contxt Values", tl);
146
- console.log("gifState", gifState, gifDuration);
147
- const {
148
- index,
149
- frames: gifFrames,
150
- delays: gifDelays,
151
- length,
152
- loaded,
153
- } = gifState;
116
+ const { frames: gifFrames, delays: gifDelays, loaded } = gifState;
154
117
 
155
118
  const {
156
119
  uniqueId,
@@ -167,7 +130,6 @@ const PixiGifSprite: React.FC<PixiGifSpriteProps> = (props) => {
167
130
  y,
168
131
  rotation = 0,
169
132
  scale,
170
- anchor,
171
133
  animation,
172
134
  colorCorrection,
173
135
  effect,
@@ -182,33 +144,17 @@ const PixiGifSprite: React.FC<PixiGifSpriteProps> = (props) => {
182
144
  pointerout,
183
145
  applyTransformer,
184
146
  onAnchorTransformationEnd,
185
- ...restProps
186
147
  } = props;
187
148
 
188
149
  // color corrections
189
150
  const {
190
- enabled = false,
191
- temperature = 1,
192
- hue = 1,
193
151
  contrast = 1,
194
152
  saturation = 1,
195
153
  exposure = 1,
196
- reset,
197
- sharpness = 1,
198
- value = 0,
199
- levels = 1,
200
- luminance = 0,
201
- enhance = 0,
202
154
  blurRadius = 0,
203
- red = 150,
204
- green = 150,
205
- blue = 150,
206
155
  alpha = 1,
207
- scaleInput = 1,
208
156
  } = colorCorrection || {};
209
157
 
210
- const app = useApp();
211
-
212
158
  /** adjustment filter */
213
159
  const adjustments = {
214
160
  brightness: exposure,
@@ -217,6 +163,8 @@ const PixiGifSprite: React.FC<PixiGifSpriteProps> = (props) => {
217
163
  alpha,
218
164
  };
219
165
 
166
+ const app = useApp();
167
+
220
168
  // load and parse gif
221
169
  useWorkerParser(src, update);
222
170
 
@@ -270,14 +218,6 @@ const PixiGifSprite: React.FC<PixiGifSpriteProps> = (props) => {
270
218
  }
271
219
  };
272
220
 
273
- const gsapOnPause = (startAt: number) => {
274
- // console.log(`gsap onStart ${droptype} id`, refId);
275
- // console.log(elementRefs.current[refId]);
276
- if (animatedSpriteRef.current) {
277
- animatedSpriteRef.current.stop();
278
- }
279
- };
280
-
281
221
  const gsapOnComplete = () => {
282
222
  if (animatedSpriteRef.current) {
283
223
  animatedSpriteRef.current.stop();
@@ -403,33 +343,62 @@ const PixiGifSprite: React.FC<PixiGifSpriteProps> = (props) => {
403
343
  </Container>
404
344
  )}
405
345
  {gifFrame && gifFrame.length > 0 && (
406
- <PixiAnimatedSprite
407
- x={x}
408
- y={y}
409
- width={width}
410
- height={height}
411
- rotation={rotation}
412
- animationSpeed={1}
413
- loop={loop}
414
- isPlaying={!!tlPlay}
415
- // @ts-ignore
416
- textures={gifFrameObject}
417
- onComplete={handleComplete}
418
- onFrameChange={(currentFrame: number) =>
419
- setCurrentFrame(currentFrame)
420
- }
421
- anchor={0.5}
422
- {...(!locked &&
423
- !isDragging && {
424
- interactive: true,
425
- buttonMode: true,
426
- pointerdown: pointerdown,
427
- pointerover: pointerover,
428
- pointerout: pointerout,
429
- })}
430
- forwardRef={animatedSpriteRef}
431
- scale={scale}
432
- />
346
+ <Filters
347
+ scale={1}
348
+ blur={{ blur: blurRadius, quality: 4 }}
349
+ adjust={adjustments}
350
+ apply={({ matrix }: { matrix: any }) => {
351
+ if (effect === "BlackAndWhite") {
352
+ matrix.desaturate();
353
+ } else if (effect === "Sepia") {
354
+ matrix.sepia();
355
+ } else if (effect === "RetroVintage") {
356
+ matrix.negative();
357
+ } else if (effect === "NightVision") {
358
+ matrix.negative();
359
+ } else if (effect === "Normal") {
360
+ matrix.reset();
361
+ }
362
+ }}
363
+ matrix={{
364
+ enabled: true,
365
+ // @ts-ignore
366
+ matrix: CYAN,
367
+ }}
368
+ >
369
+ <PixiAnimatedSprite
370
+ x={x}
371
+ y={y}
372
+ width={width}
373
+ height={height}
374
+ rotation={rotation}
375
+ animationSpeed={1}
376
+ loop={loop}
377
+ isPlaying={!!tlPlay}
378
+ // @ts-ignore
379
+ textures={gifFrameObject}
380
+ onComplete={handleComplete}
381
+ onFrameChange={(currentFrame: number) =>
382
+ setCurrentFrame(currentFrame)
383
+ }
384
+ anchor={0.5}
385
+ {...(!locked &&
386
+ !isDragging && {
387
+ interactive: true,
388
+ buttonMode: true,
389
+ pointerdown: pointerdown,
390
+ pointerover: pointerover,
391
+ pointerout: pointerout,
392
+ pointerup: pointerup,
393
+ mousedown: mousedown,
394
+ mouseup: mouseup,
395
+ mouseover: mouseover,
396
+ mouseout: mouseout,
397
+ })}
398
+ forwardRef={animatedSpriteRef}
399
+ scale={scale}
400
+ />
401
+ </Filters>
433
402
  )}
434
403
  </Container>
435
404
  </Container>
@@ -38,6 +38,10 @@ const meta = {
38
38
  colorCorrection: {
39
39
  control: "object",
40
40
  description: "colorCorrection of the sprite",
41
+ enabled: {
42
+ control: "boolean",
43
+ description: "enabled of the sprite with color filter mode applied.",
44
+ },
41
45
  brightness: {
42
46
  control: "number",
43
47
  description: "brightness of the sprite",
@@ -84,9 +88,12 @@ export const Normal: Story = {
84
88
  args: {
85
89
  uniqueId: "surya001", // uniqueId of the sprite
86
90
  src: "https://assets.codepen.io/693612/surya.svg",
91
+ applyTransformer: false,
92
+ startAt: 0,
93
+ endAt: 10,
87
94
  transformation: {
88
- x: 100,
89
- y: 100,
95
+ x: 200,
96
+ y: 200,
90
97
  width: 150,
91
98
  height: 150,
92
99
  anchor: 0.5,
@@ -95,11 +102,14 @@ export const Normal: Story = {
95
102
  scale: 1,
96
103
  tint: 0xffffff,
97
104
  blendMode: 0,
98
- colorCorrection: {},
105
+ colorCorrection: {
106
+ enabled: false,
107
+ contrast: 1,
108
+ saturation: 1,
109
+ exposure: 1,
110
+ blurRadius: 0,
111
+ },
99
112
  },
100
- applyTransformer: false,
101
- startAt: 0,
102
- endAt: 10,
103
113
  initialAlpha: 1,
104
114
  },
105
115
  };
@@ -113,6 +123,9 @@ export const FadeIn: Story = {
113
123
  args: {
114
124
  uniqueId: "surya002", // uniqueId of the sprite
115
125
  src: "https://assets.codepen.io/693612/surya.svg",
126
+ applyTransformer: false,
127
+ startAt: 0,
128
+ endAt: 10,
116
129
  transformation: {
117
130
  x: 100,
118
131
  y: 100,
@@ -127,9 +140,42 @@ export const FadeIn: Story = {
127
140
  animation: "FADE_IN",
128
141
  colorCorrection: {},
129
142
  },
143
+ initialAlpha: 0,
144
+ },
145
+ };
146
+
147
+ // More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
148
+ export const Filters: Story = {
149
+ render: (args: any) => (
150
+ <AppStateContextProvider {...args}>
151
+ <PixiImageSprite {...args} />
152
+ </AppStateContextProvider>
153
+ ),
154
+ args: {
155
+ uniqueId: "image-filters001", // uniqueId of the sprite
156
+ src: "https://assets.codepen.io/693612/surya.svg",
130
157
  applyTransformer: false,
131
158
  startAt: 0,
132
159
  endAt: 10,
133
- initialAlpha: 0,
160
+ transformation: {
161
+ x: 200,
162
+ y: 200,
163
+ width: 150,
164
+ height: 150,
165
+ anchor: 0.5,
166
+ rotation: 0,
167
+ alpha: 1,
168
+ scale: 1,
169
+ tint: 0xffffff,
170
+ blendMode: 0,
171
+ colorCorrection: {
172
+ enabled: true,
173
+ contrast: 1,
174
+ saturation: 2,
175
+ exposure: 1,
176
+ blurRadius: 0,
177
+ },
178
+ },
179
+ initialAlpha: 1,
134
180
  },
135
181
  };