@contember/echo 0.0.18

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 (78) hide show
  1. package/README.md +101 -0
  2. package/dist/components/Echo.d.ts +3 -0
  3. package/dist/components/EchoLayout.d.ts +7 -0
  4. package/dist/components/Launcher.d.ts +6 -0
  5. package/dist/components/Overlay.d.ts +4 -0
  6. package/dist/components/atoms/Button.d.ts +9 -0
  7. package/dist/components/atoms/index.d.ts +1 -0
  8. package/dist/components/icons/CheckCircleIcon.d.ts +3 -0
  9. package/dist/components/icons/ChevronRightIcon.d.ts +3 -0
  10. package/dist/components/icons/ContemberIcon.d.ts +3 -0
  11. package/dist/components/icons/ExternalLinkIcon.d.ts +3 -0
  12. package/dist/components/icons/HighlightIcon.d.ts +3 -0
  13. package/dist/components/icons/MessageIcon.d.ts +3 -0
  14. package/dist/components/icons/PenIcon.d.ts +3 -0
  15. package/dist/components/icons/TrashIcon.d.ts +3 -0
  16. package/dist/components/icons/XCircleIcon.d.ts +3 -0
  17. package/dist/components/icons/XIcon.d.ts +3 -0
  18. package/dist/components/icons/index.d.ts +9 -0
  19. package/dist/config/defaultText.d.ts +2 -0
  20. package/dist/config/drawingConfig.d.ts +18 -0
  21. package/dist/contexts/EchoContext.d.ts +12 -0
  22. package/dist/contexts/index.d.ts +1 -0
  23. package/dist/echo.es.js +8069 -0
  24. package/dist/echo.umd.js +1112 -0
  25. package/dist/features/drawing/components/ColorSelector.d.ts +2 -0
  26. package/dist/features/drawing/components/DrawingLayer.d.ts +2 -0
  27. package/dist/features/drawing/components/DrawingToolbar.d.ts +2 -0
  28. package/dist/features/drawing/components/DrawingTooltip.d.ts +2 -0
  29. package/dist/features/drawing/components/Shape.d.ts +10 -0
  30. package/dist/features/drawing/components/ShapeActions.d.ts +2 -0
  31. package/dist/features/drawing/components/index.d.ts +5 -0
  32. package/dist/features/drawing/hooks/index.d.ts +3 -0
  33. package/dist/features/drawing/hooks/useDrag.d.ts +17 -0
  34. package/dist/features/drawing/hooks/useDrawing.d.ts +11 -0
  35. package/dist/features/drawing/hooks/useViewport.d.ts +4 -0
  36. package/dist/features/drawing/index.d.ts +5 -0
  37. package/dist/features/drawing/styles/ColorSelector.styles.d.ts +2 -0
  38. package/dist/features/drawing/styles/DrawingLayer.styles.d.ts +2 -0
  39. package/dist/features/drawing/styles/DrawingToolbar.styles.d.ts +2 -0
  40. package/dist/features/drawing/styles/DrawingTooltip.styles.d.ts +2 -0
  41. package/dist/features/drawing/styles/ShapeActions.styles.d.ts +2 -0
  42. package/dist/features/drawing/styles/index.d.ts +6 -0
  43. package/dist/features/drawing/types/index.d.ts +21 -0
  44. package/dist/features/drawing/utils/events.d.ts +5 -0
  45. package/dist/features/drawing/utils/index.d.ts +2 -0
  46. package/dist/features/drawing/utils/svg.d.ts +12 -0
  47. package/dist/features/feedback/components/FeedbackForm.d.ts +2 -0
  48. package/dist/features/feedback/components/index.d.ts +1 -0
  49. package/dist/features/feedback/index.d.ts +2 -0
  50. package/dist/features/feedback/styles/FeedbackForm.styles.d.ts +2 -0
  51. package/dist/features/feedback/styles/index.d.ts +1 -0
  52. package/dist/features/launcher/components/EchoButton.d.ts +2 -0
  53. package/dist/features/launcher/components/Notification.d.ts +2 -0
  54. package/dist/features/launcher/components/SavedPagesDropdown.d.ts +2 -0
  55. package/dist/features/launcher/components/WelcomeMessage.d.ts +2 -0
  56. package/dist/features/launcher/styles/EchoLauncherButton.styles.d.ts +2 -0
  57. package/dist/features/launcher/styles/Notification.styles.d.ts +2 -0
  58. package/dist/features/launcher/styles/SavedPagesDropdown.styles.d.ts +2 -0
  59. package/dist/features/launcher/styles/WelcomeMessage.styles.d.ts +2 -0
  60. package/dist/features/launcher/styles/index.d.ts +4 -0
  61. package/dist/index.d.ts +8 -0
  62. package/dist/stores/echoStore.d.ts +55 -0
  63. package/dist/stores/index.d.ts +2 -0
  64. package/dist/stores/welcomeMessageStore.d.ts +4 -0
  65. package/dist/styles/Echo.styles.d.ts +2 -0
  66. package/dist/styles/index.d.ts +2 -0
  67. package/dist/styles/zIndex.d.ts +13 -0
  68. package/dist/types.d.ts +93 -0
  69. package/dist/utils/color.d.ts +2 -0
  70. package/dist/utils/console.d.ts +4 -0
  71. package/dist/utils/debounce.d.ts +1 -0
  72. package/dist/utils/device.d.ts +1 -0
  73. package/dist/utils/geometry.d.ts +7 -0
  74. package/dist/utils/index.d.ts +5 -0
  75. package/dist/utils/screenshot.d.ts +6 -0
  76. package/dist/utils/shape.d.ts +2 -0
  77. package/dist/utils/storage.d.ts +28 -0
  78. package/package.json +35 -0
@@ -0,0 +1,2 @@
1
+ import { type Component } from 'solid-js';
2
+ export declare const ColorSelector: Component;
@@ -0,0 +1,2 @@
1
+ import { type Component } from 'solid-js';
2
+ export declare const DrawingLayer: Component;
@@ -0,0 +1,2 @@
1
+ import { type Component } from 'solid-js';
2
+ export declare const DrawingToolbar: Component;
@@ -0,0 +1,2 @@
1
+ import { type Component } from 'solid-js';
2
+ export declare const DrawingTooltip: Component;
@@ -0,0 +1,10 @@
1
+ import type { Component } from 'solid-js';
2
+ import type { Shape as ShapeType } from '~/types';
3
+ interface ShapeProps {
4
+ shape: ShapeType;
5
+ selectedShapeId: string | null;
6
+ onShapeClick?: (id: string) => void;
7
+ isMask?: boolean;
8
+ }
9
+ export declare const Shape: Component<ShapeProps>;
10
+ export {};
@@ -0,0 +1,2 @@
1
+ import { type Component } from 'solid-js';
2
+ export declare const ShapeActions: Component;
@@ -0,0 +1,5 @@
1
+ export * from './DrawingLayer';
2
+ export * from './DrawingTooltip';
3
+ export * from './Shape';
4
+ export * from './ShapeActions';
5
+ export * from './DrawingToolbar';
@@ -0,0 +1,3 @@
1
+ export * from './useDrawing';
2
+ export * from './useDrag';
3
+ export * from './useViewport';
@@ -0,0 +1,17 @@
1
+ import type { Point } from '~/types';
2
+ export declare const useDrag: () => {
3
+ state: {
4
+ isDragging: import("solid-js").Accessor<boolean>;
5
+ dragStartPos: import("solid-js").Accessor<Point | null>;
6
+ initialClickPos: import("solid-js").Accessor<Point | null>;
7
+ dragOffset: import("solid-js").Accessor<Point | null>;
8
+ };
9
+ actions: {
10
+ startDrag: (point: Point) => void;
11
+ stopDrag: () => void;
12
+ setInitialClick: (point: Point | null) => void;
13
+ updateDragOffset: (shape: {
14
+ points: Point[];
15
+ }, point: Point) => void;
16
+ };
17
+ };
@@ -0,0 +1,11 @@
1
+ export declare const useDrawing: () => {
2
+ state: import("../../../stores").DrawingState;
3
+ actions: {
4
+ handleStart: (e: MouseEvent | TouchEvent) => void;
5
+ handleMove: (e: MouseEvent | TouchEvent) => void;
6
+ handleEnd: (e: MouseEvent | TouchEvent) => void;
7
+ handleEnter: (e: MouseEvent | TouchEvent) => void;
8
+ handleLeave: (e: MouseEvent | TouchEvent) => void;
9
+ handleShapeClick: (shapeId: string) => void;
10
+ };
11
+ };
@@ -0,0 +1,4 @@
1
+ export declare const useViewport: () => {
2
+ width: import("solid-js").Accessor<number>;
3
+ height: import("solid-js").Accessor<number>;
4
+ };
@@ -0,0 +1,5 @@
1
+ export * from './components';
2
+ export * from './styles';
3
+ export * from './hooks';
4
+ export * from './types';
5
+ export * from './utils';
@@ -0,0 +1,2 @@
1
+ import type { StylesConfig } from '~/types';
2
+ export declare const colorSelectorStyles: (config: StylesConfig) => string;
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const drawingLayerStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const drawingToolbarStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const tooltipStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const shapeActionsStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,6 @@
1
+ export * from './DrawingLayer.styles';
2
+ export * from './ShapeActions.styles';
3
+ export * from './ColorSelector.styles';
4
+ export * from './DrawingLayer.styles';
5
+ export * from './DrawingToolbar.styles';
6
+ export * from './DrawingTooltip.styles';
@@ -0,0 +1,21 @@
1
+ import { Point, Shape } from '~/types';
2
+ export interface DrawingState {
3
+ isDrawing: boolean;
4
+ currentPoints: Point[];
5
+ currentPath: string;
6
+ selectedShapeId: string | null;
7
+ mousePosition: Point | null;
8
+ showTooltip: boolean;
9
+ hasDrawn: boolean;
10
+ selectedTool: string;
11
+ selectedColor: string;
12
+ shapes: Shape[];
13
+ isDragging: boolean;
14
+ dragStartPos: Point | null;
15
+ initialClickPos: Point | null;
16
+ dragOffset: Point | null;
17
+ }
18
+ export interface ViewportState {
19
+ width: number;
20
+ height: number;
21
+ }
@@ -0,0 +1,5 @@
1
+ import type { Point } from '~/types';
2
+ export declare const getPointFromEvent: (e: MouseEvent | TouchEvent, { useClientCoords }?: {
3
+ useClientCoords?: boolean;
4
+ }) => Point;
5
+ export declare const getDistance: (p1: Point, p2: Point) => number;
@@ -0,0 +1,2 @@
1
+ export * from './events';
2
+ export * from './svg';
@@ -0,0 +1,12 @@
1
+ import type { ViewportState } from '../types';
2
+ export declare const generateCutoutPath: (viewport: ViewportState, currentPoints: {
3
+ x: number;
4
+ y: number;
5
+ }[], shapes: {
6
+ type: string;
7
+ points: {
8
+ x: number;
9
+ y: number;
10
+ }[];
11
+ }[]) => string;
12
+ export declare const getPenCursor: (color: string) => string;
@@ -0,0 +1,2 @@
1
+ import type { Component } from 'solid-js';
2
+ export declare const FeedbackForm: Component;
@@ -0,0 +1 @@
1
+ export * from './FeedbackForm';
@@ -0,0 +1,2 @@
1
+ export * from './components';
2
+ export * from './styles';
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const feedbackFormStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1 @@
1
+ export * from './FeedbackForm.styles';
@@ -0,0 +1,2 @@
1
+ import type { Component } from 'solid-js';
2
+ export declare const EchoButton: Component;
@@ -0,0 +1,2 @@
1
+ import type { Component } from 'solid-js';
2
+ export declare const Notification: Component;
@@ -0,0 +1,2 @@
1
+ import { type Component } from 'solid-js';
2
+ export declare const SavedPagesDropdown: Component;
@@ -0,0 +1,2 @@
1
+ import type { Component } from 'solid-js';
2
+ export declare const WelcomeMessage: Component;
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const echoLauncherButtonStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const notificationStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const savedPagesDropdownStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const welcomeMessageStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,4 @@
1
+ export * from './EchoLauncherButton.styles';
2
+ export * from './SavedPagesDropdown.styles';
3
+ export * from './WelcomeMessage.styles';
4
+ export * from './Notification.styles';
@@ -0,0 +1,8 @@
1
+ import { type EchoOptions, type FeedbackData, type Position } from './types';
2
+ /**
3
+ * Initialize the Echo feedback widget.
4
+ * @throws {Error} If initialization fails or invalid options are provided
5
+ * @returns {() => void} Cleanup function to remove the widget
6
+ */
7
+ export declare function initEcho(options: EchoOptions): () => void;
8
+ export type { FeedbackData, EchoOptions, Position };
@@ -0,0 +1,55 @@
1
+ import type { DrawingTool, FeedbackData, Notification, Point, Screenshot, Shape, TextConfig } from '~/types';
2
+ export interface FeedbackState {
3
+ comment: string;
4
+ screenshot?: Screenshot;
5
+ isCapturing: boolean;
6
+ isMinimized: boolean;
7
+ }
8
+ export interface DrawingState {
9
+ isDrawing: boolean;
10
+ selectedShapeId: string | null;
11
+ selectedTool: DrawingTool;
12
+ selectedColor: string;
13
+ shapes: Shape[];
14
+ currentPoints: Point[];
15
+ currentPath: string;
16
+ showTooltip: boolean;
17
+ mousePosition: Point;
18
+ hasDrawn: boolean;
19
+ isDragging: boolean;
20
+ dragStartPos: Point | null;
21
+ initialClickPos: Point | null;
22
+ dragOffset: Point | null;
23
+ }
24
+ export interface WidgetState {
25
+ isOpen: boolean;
26
+ primaryColor: string;
27
+ onSubmit: (data: FeedbackData) => void | Promise<void>;
28
+ notification: Notification;
29
+ dimensions: {
30
+ width: number;
31
+ height: number;
32
+ };
33
+ isPagesDropdownOpen: boolean;
34
+ pagesCount: number;
35
+ }
36
+ interface EchoStoreConfig {
37
+ primaryColor: string;
38
+ onSubmit: (data: FeedbackData) => Promise<void>;
39
+ text: TextConfig;
40
+ }
41
+ export interface EchoStore {
42
+ feedback: FeedbackState;
43
+ setFeedback: (state: Partial<FeedbackState>, isClearing?: boolean) => void;
44
+ drawing: DrawingState;
45
+ setDrawing: (state: Partial<DrawingState>, isClearing?: boolean) => void;
46
+ widget: WidgetState;
47
+ setWidget: (state: Partial<WidgetState>) => void;
48
+ text: TextConfig;
49
+ methods: {
50
+ reset: () => void;
51
+ postSubmit: (result: Notification) => void;
52
+ };
53
+ }
54
+ export declare const createEchoStore: (config: EchoStoreConfig) => EchoStore;
55
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './echoStore';
2
+ export * from './welcomeMessageStore';
@@ -0,0 +1,4 @@
1
+ export declare const welcomeMessageStore: {
2
+ isClosing: import("solid-js").Accessor<boolean>;
3
+ setIsClosing: import("solid-js").Setter<boolean>;
4
+ };
@@ -0,0 +1,2 @@
1
+ import type { EnrichedStylesConfig } from '~/types';
2
+ export declare const echoStyles: (config: EnrichedStylesConfig) => string;
@@ -0,0 +1,2 @@
1
+ export * from './Echo.styles';
2
+ export * from './zIndex';
@@ -0,0 +1,13 @@
1
+ declare const zIndex: {
2
+ readonly root: 999999;
3
+ readonly overlay: 1;
4
+ readonly launcher: 2;
5
+ readonly widgetButton: 2;
6
+ readonly notification: 2;
7
+ readonly welcomeMessage: 2;
8
+ readonly feedbackForm: 4;
9
+ readonly drawingToolbar: 3;
10
+ readonly shapeActions: 3;
11
+ readonly drawingTooltip: 3;
12
+ };
13
+ export { zIndex };
@@ -0,0 +1,93 @@
1
+ export type Screenshot = `data:image/webp;base64,${string}` | `data:image/png;base64,${string}`;
2
+ export interface BrowserInfo {
3
+ width: number;
4
+ height: number;
5
+ screenWidth: number;
6
+ screenHeight: number;
7
+ }
8
+ export interface Metadata {
9
+ url: string;
10
+ userAgent: string;
11
+ timestamp: string;
12
+ browserInfo: BrowserInfo;
13
+ }
14
+ export interface ConsoleEntry {
15
+ type: 'log' | 'warn' | 'error';
16
+ message: string;
17
+ timestamp: string;
18
+ }
19
+ export interface FeedbackData {
20
+ comment: string;
21
+ screenshot?: Screenshot;
22
+ metadata: Metadata;
23
+ console: ConsoleEntry[];
24
+ }
25
+ export type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
26
+ export interface TextConfig {
27
+ welcomeMessage: {
28
+ text: string;
29
+ closeAriaLabel: string;
30
+ };
31
+ feedbackForm: {
32
+ title: string;
33
+ placeholder: string;
34
+ screenshotAlt: string;
35
+ submitButton: string;
36
+ minimizeTitle: string;
37
+ expandTitle: string;
38
+ closeTitle: string;
39
+ showFormTitle: string;
40
+ };
41
+ notification: {
42
+ successTitle: string;
43
+ errorTitle: string;
44
+ errorMessage: string;
45
+ hideTitle: string;
46
+ };
47
+ drawingTooltip: {
48
+ text: string;
49
+ };
50
+ }
51
+ export type EchoOptions = {
52
+ onSubmit: (data: FeedbackData) => Promise<void>;
53
+ position?: Position;
54
+ primaryColor?: `#${string}`;
55
+ textConfig?: Partial<TextConfig>;
56
+ children?: any;
57
+ };
58
+ export declare const POSITIONS: Record<Position, {
59
+ [key: string]: string;
60
+ }>;
61
+ export interface Point {
62
+ x: number;
63
+ y: number;
64
+ }
65
+ export type ShapeType = 'rectangle' | 'path';
66
+ export type DrawingTool = 'highlight' | 'pen';
67
+ export interface Shape {
68
+ id: string;
69
+ type: ShapeType;
70
+ color: string;
71
+ points: Point[];
72
+ }
73
+ export interface IconProps {
74
+ size?: number;
75
+ stroke?: string;
76
+ strokeWidth?: number;
77
+ class?: string;
78
+ style?: any;
79
+ fill?: string;
80
+ }
81
+ export interface StylesConfig {
82
+ primaryColor: string;
83
+ }
84
+ export interface EnrichedStylesConfig extends StylesConfig {
85
+ primaryTextColor: string;
86
+ primaryColorLighter: string;
87
+ primaryColorLightest: string;
88
+ }
89
+ export interface Notification {
90
+ show: boolean;
91
+ type: 'success' | 'error' | null;
92
+ message: string | null;
93
+ }
@@ -0,0 +1,2 @@
1
+ export declare const calculateLuminance: (hexColor: string) => number;
2
+ export declare const getContrastColor: (hexColor: string) => string;
@@ -0,0 +1,4 @@
1
+ import type { ConsoleEntry } from '~/types';
2
+ export declare const setupConsole: () => void;
3
+ export declare const cleanupConsole: () => void;
4
+ export declare const getConsoleBuffer: () => ConsoleEntry[];
@@ -0,0 +1 @@
1
+ export declare const debounce: <T extends (...args: any[]) => void>(func: T, wait: number) => (...args: Parameters<T>) => void;
@@ -0,0 +1 @@
1
+ export declare const isMobileDevice: () => boolean;
@@ -0,0 +1,7 @@
1
+ import type { Point } from '~/types';
2
+ export declare const getRectFromPoints: (points: Point[]) => {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ } | null;
@@ -0,0 +1,5 @@
1
+ export * from './device';
2
+ export * from './screenshot';
3
+ export * from './geometry';
4
+ export * from './shape';
5
+ export * from './storage';
@@ -0,0 +1,6 @@
1
+ import type { Screenshot, Shape } from '~/types';
2
+ interface CaptureScreenshotConfig {
3
+ annotations: Shape[];
4
+ }
5
+ export declare const captureScreenshot: ({ annotations }: CaptureScreenshotConfig) => Promise<Screenshot | undefined>;
6
+ export {};
@@ -0,0 +1,2 @@
1
+ import { Shape } from '~/types';
2
+ export declare const renderShape: (shape: Shape, isMask?: boolean) => import("solid-js").JSX.Element;
@@ -0,0 +1,28 @@
1
+ import type { DrawingState, FeedbackState } from '~/stores/echoStore';
2
+ import type { Shape } from '~/types';
3
+ interface StoredPageState {
4
+ feedback: {
5
+ comment: string;
6
+ };
7
+ drawing: {
8
+ shapes: Shape[];
9
+ };
10
+ latestQuery?: string;
11
+ }
12
+ export declare const dispatchStorageChange: () => void;
13
+ export declare const getStorageKey: (key: string) => string;
14
+ export declare const getFromStorage: <T>(key: string, defaultValue: T) => T;
15
+ export declare const setToStorage: <T>(key: string, value: T) => void;
16
+ export declare const getPageKey: () => string;
17
+ export declare const savePageState: (pageKey: string, state: {
18
+ feedback: FeedbackState;
19
+ drawing: DrawingState;
20
+ }) => void;
21
+ export declare const loadPageState: (pageKey: string) => StoredPageState | null;
22
+ export declare const clearPageState: (pageKey: string) => void;
23
+ export declare const getStoredPagesCount: () => number;
24
+ export declare const getStoredPages: () => {
25
+ path: string;
26
+ state: StoredPageState;
27
+ }[];
28
+ export {};
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@contember/echo",
3
+ "version": "0.0.18",
4
+ "type": "module",
5
+ "author": "neumie@neumie.dev",
6
+ "keywords": [
7
+ "feedback",
8
+ "solid",
9
+ "contember"
10
+ ],
11
+ "main": "dist/echo.umd.js",
12
+ "module": "dist/echo.es.js",
13
+ "types": "dist/index.d.ts",
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "dev": "vite",
19
+ "build": "tsc && vite build && tsc --emitDeclarationOnly ",
20
+ "preview": "vite preview",
21
+ "watch": "concurrently \"tsc --watch\" \"vite build --watch\""
22
+ },
23
+ "dependencies": {
24
+ "html2canvas": "^1.4.1",
25
+ "solid-js": "^1.8.15"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^20.17.12",
29
+ "concurrently": "^9.1.2",
30
+ "typescript": "^5.0.0",
31
+ "vite": "^5.0.0",
32
+ "vite-plugin-solid": "^2.10.1",
33
+ "vite-tsconfig-paths": "^5.1.4"
34
+ }
35
+ }