@wisemen/vue-core-custom-views 0.1.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.
Files changed (35) hide show
  1. package/LICENSE.md +59 -0
  2. package/dist/actions/customViewCreateView.action.d.ts +1 -0
  3. package/dist/actions/customViewDeleteView.action.d.ts +1 -0
  4. package/dist/actions/customViewEditView.action.d.ts +1 -0
  5. package/dist/actions/customViewSaveToCurrentView.action.d.ts +1 -0
  6. package/dist/adapters/state/customViewFilterStateAdapter.d.ts +2 -0
  7. package/dist/adapters/state/customViewSearchStateAdapter.d.ts +2 -0
  8. package/dist/adapters/state/customViewTableColumnsStateAdapter.d.ts +2 -0
  9. package/dist/adapters/storage/customViewLocalStorageAdapter.d.ts +2 -0
  10. package/dist/components/CustomViewColorPicker.d.ts +7 -0
  11. package/dist/components/CustomViewCreateDialog.d.ts +7 -0
  12. package/dist/components/CustomViewIconPicker.d.ts +7 -0
  13. package/dist/components/CustomViewUpdateDialog.d.ts +10 -0
  14. package/dist/components/views/CustomViewViews.d.ts +2 -0
  15. package/dist/components/views/CustomViewViewsItem.d.ts +12 -0
  16. package/dist/composables/context.composable.d.ts +8 -0
  17. package/dist/composables/customViewManager.composable.d.ts +22 -0
  18. package/dist/context/customViewManager.context.d.ts +5 -0
  19. package/dist/index.cjs +1 -0
  20. package/dist/index.d.ts +18 -0
  21. package/dist/index.js +2063 -0
  22. package/dist/locales/en-US.json.d.ts +27 -0
  23. package/dist/locales/nl-BE.json.d.ts +27 -0
  24. package/dist/locales.cjs +1 -0
  25. package/dist/locales.d.ts +50 -0
  26. package/dist/locales.js +54 -0
  27. package/dist/style.css +2 -0
  28. package/dist/types/customView.type.d.ts +20 -0
  29. package/dist/types/customViewColor.type.d.ts +10 -0
  30. package/dist/types/customViewIcon.type.d.ts +38 -0
  31. package/dist/types/customViewStateAdapter.type.d.ts +13 -0
  32. package/dist/types/customViewStorageAdapter.type.d.ts +5 -0
  33. package/dist/utils/customViewColor.util.d.ts +3 -0
  34. package/dist/utils/customViewIcon.util.d.ts +4 -0
  35. package/package.json +103 -0
@@ -0,0 +1,27 @@
1
+ declare const _default: {
2
+ "action.custom_view.create": "Create new view",
3
+ "action.custom_view.delete": "Delete",
4
+ "action.custom_view.delete_confirm_description": "Are you sure you want to delete {name}?",
5
+ "action.custom_view.delete_confirm_label": "Delete",
6
+ "action.custom_view.delete_confirm_title": "Delete view",
7
+ "action.custom_view.edit": "Edit",
8
+ "action.custom_view.group_name": "Views",
9
+ "action.custom_view.save_to_current": "Save to this view",
10
+ "component.custom_view_color_picker.label": "Color",
11
+ "component.custom_view_create_dialog.description": "Give your view a name, icon and color",
12
+ "component.custom_view_create_dialog.name_label": "Name",
13
+ "component.custom_view_create_dialog.name_placeholder": "Enter a name for your view",
14
+ "component.custom_view_create_dialog.submit": "Save",
15
+ "component.custom_view_create_dialog.title": "Create new view",
16
+ "component.custom_view_icon_picker.label": "Icon",
17
+ "component.custom_view_icon_picker.view_icon_label": "View icon",
18
+ "component.custom_view_list.save": "Save",
19
+ "component.custom_view_update_dialog.description": "Give your view a name, icon and color",
20
+ "component.custom_view_update_dialog.name_label": "Name",
21
+ "component.custom_view_update_dialog.name_placeholder": "Enter a name for your view",
22
+ "component.custom_view_update_dialog.submit": "Save",
23
+ "component.custom_view_update_dialog.title": "Update view"
24
+ }
25
+ ;
26
+
27
+ export default _default;
@@ -0,0 +1,27 @@
1
+ declare const _default: {
2
+ "action.custom_view.create": "Nieuwe weergave aanmaken",
3
+ "action.custom_view.delete": "Verwijderen",
4
+ "action.custom_view.delete_confirm_description": "Weet je zeker dat je {name} wilt verwijderen?",
5
+ "action.custom_view.delete_confirm_label": "Verwijderen",
6
+ "action.custom_view.delete_confirm_title": "Weergave verwijderen",
7
+ "action.custom_view.edit": "Bewerken",
8
+ "action.custom_view.group_name": "Weergaven",
9
+ "action.custom_view.save_to_current": "In deze weergave opslaan",
10
+ "component.custom_view_color_picker.label": "Kleur",
11
+ "component.custom_view_create_dialog.description": "Geef je weergave een naam, pictogram en kleur",
12
+ "component.custom_view_create_dialog.name_label": "Naam",
13
+ "component.custom_view_create_dialog.name_placeholder": "Voer een naam in voor je weergave",
14
+ "component.custom_view_create_dialog.submit": "Opslaan",
15
+ "component.custom_view_create_dialog.title": "Nieuwe weergave aanmaken",
16
+ "component.custom_view_icon_picker.label": "Pictogram",
17
+ "component.custom_view_icon_picker.view_icon_label": "Weergave-pictogram",
18
+ "component.custom_view_list.save": "Opslaan",
19
+ "component.custom_view_update_dialog.description": "Geef je weergave een naam, pictogram en kleur",
20
+ "component.custom_view_update_dialog.name_label": "Naam",
21
+ "component.custom_view_update_dialog.name_placeholder": "Voer een naam in voor je weergave",
22
+ "component.custom_view_update_dialog.submit": "Opslaan",
23
+ "component.custom_view_update_dialog.title": "Weergave bewerken"
24
+ }
25
+ ;
26
+
27
+ export default _default;
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={"en-US":{"action.custom_view.create":`Create new view`,"action.custom_view.delete":`Delete`,"action.custom_view.delete_confirm_description":`Are you sure you want to delete {name}?`,"action.custom_view.delete_confirm_label":`Delete`,"action.custom_view.delete_confirm_title":`Delete view`,"action.custom_view.edit":`Edit`,"action.custom_view.group_name":`Views`,"action.custom_view.save_to_current":`Save to this view`,"component.custom_view_color_picker.label":`Color`,"component.custom_view_create_dialog.description":`Give your view a name, icon and color`,"component.custom_view_create_dialog.name_label":`Name`,"component.custom_view_create_dialog.name_placeholder":`Enter a name for your view`,"component.custom_view_create_dialog.submit":`Save`,"component.custom_view_create_dialog.title":`Create new view`,"component.custom_view_icon_picker.label":`Icon`,"component.custom_view_icon_picker.view_icon_label":`View icon`,"component.custom_view_list.save":`Save`,"component.custom_view_update_dialog.description":`Give your view a name, icon and color`,"component.custom_view_update_dialog.name_label":`Name`,"component.custom_view_update_dialog.name_placeholder":`Enter a name for your view`,"component.custom_view_update_dialog.submit":`Save`,"component.custom_view_update_dialog.title":`Update view`},"nl-BE":{"action.custom_view.create":`Nieuwe weergave aanmaken`,"action.custom_view.delete":`Verwijderen`,"action.custom_view.delete_confirm_description":`Weet je zeker dat je {name} wilt verwijderen?`,"action.custom_view.delete_confirm_label":`Verwijderen`,"action.custom_view.delete_confirm_title":`Weergave verwijderen`,"action.custom_view.edit":`Bewerken`,"action.custom_view.group_name":`Weergaven`,"action.custom_view.save_to_current":`In deze weergave opslaan`,"component.custom_view_color_picker.label":`Kleur`,"component.custom_view_create_dialog.description":`Geef je weergave een naam, pictogram en kleur`,"component.custom_view_create_dialog.name_label":`Naam`,"component.custom_view_create_dialog.name_placeholder":`Voer een naam in voor je weergave`,"component.custom_view_create_dialog.submit":`Opslaan`,"component.custom_view_create_dialog.title":`Nieuwe weergave aanmaken`,"component.custom_view_icon_picker.label":`Pictogram`,"component.custom_view_icon_picker.view_icon_label":`Weergave-pictogram`,"component.custom_view_list.save":`Opslaan`,"component.custom_view_update_dialog.description":`Geef je weergave een naam, pictogram en kleur`,"component.custom_view_update_dialog.name_label":`Naam`,"component.custom_view_update_dialog.name_placeholder":`Voer een naam in voor je weergave`,"component.custom_view_update_dialog.submit":`Opslaan`,"component.custom_view_update_dialog.title":`Weergave bewerken`}};exports.customViewsLocales=e;
@@ -0,0 +1,50 @@
1
+ export declare const customViewsLocales: {
2
+ 'en-US': {
3
+ "action.custom_view.create": string;
4
+ "action.custom_view.delete": string;
5
+ "action.custom_view.delete_confirm_description": string;
6
+ "action.custom_view.delete_confirm_label": string;
7
+ "action.custom_view.delete_confirm_title": string;
8
+ "action.custom_view.edit": string;
9
+ "action.custom_view.group_name": string;
10
+ "action.custom_view.save_to_current": string;
11
+ "component.custom_view_color_picker.label": string;
12
+ "component.custom_view_create_dialog.description": string;
13
+ "component.custom_view_create_dialog.name_label": string;
14
+ "component.custom_view_create_dialog.name_placeholder": string;
15
+ "component.custom_view_create_dialog.submit": string;
16
+ "component.custom_view_create_dialog.title": string;
17
+ "component.custom_view_icon_picker.label": string;
18
+ "component.custom_view_icon_picker.view_icon_label": string;
19
+ "component.custom_view_list.save": string;
20
+ "component.custom_view_update_dialog.description": string;
21
+ "component.custom_view_update_dialog.name_label": string;
22
+ "component.custom_view_update_dialog.name_placeholder": string;
23
+ "component.custom_view_update_dialog.submit": string;
24
+ "component.custom_view_update_dialog.title": string;
25
+ };
26
+ 'nl-BE': {
27
+ "action.custom_view.create": string;
28
+ "action.custom_view.delete": string;
29
+ "action.custom_view.delete_confirm_description": string;
30
+ "action.custom_view.delete_confirm_label": string;
31
+ "action.custom_view.delete_confirm_title": string;
32
+ "action.custom_view.edit": string;
33
+ "action.custom_view.group_name": string;
34
+ "action.custom_view.save_to_current": string;
35
+ "component.custom_view_color_picker.label": string;
36
+ "component.custom_view_create_dialog.description": string;
37
+ "component.custom_view_create_dialog.name_label": string;
38
+ "component.custom_view_create_dialog.name_placeholder": string;
39
+ "component.custom_view_create_dialog.submit": string;
40
+ "component.custom_view_create_dialog.title": string;
41
+ "component.custom_view_icon_picker.label": string;
42
+ "component.custom_view_icon_picker.view_icon_label": string;
43
+ "component.custom_view_list.save": string;
44
+ "component.custom_view_update_dialog.description": string;
45
+ "component.custom_view_update_dialog.name_label": string;
46
+ "component.custom_view_update_dialog.name_placeholder": string;
47
+ "component.custom_view_update_dialog.submit": string;
48
+ "component.custom_view_update_dialog.title": string;
49
+ };
50
+ };
@@ -0,0 +1,54 @@
1
+ //#endregion
2
+ //#region src/locales.ts
3
+ var e = {
4
+ "en-US": {
5
+ "action.custom_view.create": "Create new view",
6
+ "action.custom_view.delete": "Delete",
7
+ "action.custom_view.delete_confirm_description": "Are you sure you want to delete {name}?",
8
+ "action.custom_view.delete_confirm_label": "Delete",
9
+ "action.custom_view.delete_confirm_title": "Delete view",
10
+ "action.custom_view.edit": "Edit",
11
+ "action.custom_view.group_name": "Views",
12
+ "action.custom_view.save_to_current": "Save to this view",
13
+ "component.custom_view_color_picker.label": "Color",
14
+ "component.custom_view_create_dialog.description": "Give your view a name, icon and color",
15
+ "component.custom_view_create_dialog.name_label": "Name",
16
+ "component.custom_view_create_dialog.name_placeholder": "Enter a name for your view",
17
+ "component.custom_view_create_dialog.submit": "Save",
18
+ "component.custom_view_create_dialog.title": "Create new view",
19
+ "component.custom_view_icon_picker.label": "Icon",
20
+ "component.custom_view_icon_picker.view_icon_label": "View icon",
21
+ "component.custom_view_list.save": "Save",
22
+ "component.custom_view_update_dialog.description": "Give your view a name, icon and color",
23
+ "component.custom_view_update_dialog.name_label": "Name",
24
+ "component.custom_view_update_dialog.name_placeholder": "Enter a name for your view",
25
+ "component.custom_view_update_dialog.submit": "Save",
26
+ "component.custom_view_update_dialog.title": "Update view"
27
+ },
28
+ "nl-BE": {
29
+ "action.custom_view.create": "Nieuwe weergave aanmaken",
30
+ "action.custom_view.delete": "Verwijderen",
31
+ "action.custom_view.delete_confirm_description": "Weet je zeker dat je {name} wilt verwijderen?",
32
+ "action.custom_view.delete_confirm_label": "Verwijderen",
33
+ "action.custom_view.delete_confirm_title": "Weergave verwijderen",
34
+ "action.custom_view.edit": "Bewerken",
35
+ "action.custom_view.group_name": "Weergaven",
36
+ "action.custom_view.save_to_current": "In deze weergave opslaan",
37
+ "component.custom_view_color_picker.label": "Kleur",
38
+ "component.custom_view_create_dialog.description": "Geef je weergave een naam, pictogram en kleur",
39
+ "component.custom_view_create_dialog.name_label": "Naam",
40
+ "component.custom_view_create_dialog.name_placeholder": "Voer een naam in voor je weergave",
41
+ "component.custom_view_create_dialog.submit": "Opslaan",
42
+ "component.custom_view_create_dialog.title": "Nieuwe weergave aanmaken",
43
+ "component.custom_view_icon_picker.label": "Pictogram",
44
+ "component.custom_view_icon_picker.view_icon_label": "Weergave-pictogram",
45
+ "component.custom_view_list.save": "Opslaan",
46
+ "component.custom_view_update_dialog.description": "Geef je weergave een naam, pictogram en kleur",
47
+ "component.custom_view_update_dialog.name_label": "Naam",
48
+ "component.custom_view_update_dialog.name_placeholder": "Voer een naam in voor je weergave",
49
+ "component.custom_view_update_dialog.submit": "Opslaan",
50
+ "component.custom_view_update_dialog.title": "Weergave bewerken"
51
+ }
52
+ };
53
+ //#endregion
54
+ export { e as customViewsLocales };
package/dist/style.css ADDED
@@ -0,0 +1,2 @@
1
+ @source "./";
2
+ /*$vite$:1*/
@@ -0,0 +1,20 @@
1
+ import { CustomViewColor } from './customViewColor.type';
2
+ import { CustomViewIcon } from './customViewIcon.type';
3
+ export interface CustomView<TState extends Record<string, unknown> = any> {
4
+ id: string;
5
+ isEditable: boolean;
6
+ name: string;
7
+ color: CustomViewColor;
8
+ icon: CustomViewIcon | null;
9
+ state: TState;
10
+ }
11
+ export interface CreateCustomViewMeta {
12
+ name: string;
13
+ color: CustomViewColor;
14
+ icon: CustomViewIcon;
15
+ }
16
+ export interface UpdateCustomViewMeta {
17
+ name: string;
18
+ color: CustomViewColor;
19
+ icon?: CustomViewIcon;
20
+ }
@@ -0,0 +1,10 @@
1
+ export declare const CUSTOM_VIEW_COLOR: {
2
+ readonly CYAN: "cyan";
3
+ readonly DEFAULT: "default";
4
+ readonly GREEN: "green";
5
+ readonly PINK: "pink";
6
+ readonly PURPLE: "purple";
7
+ readonly RED: "red";
8
+ readonly YELLOW: "yellow";
9
+ };
10
+ export type CustomViewColor = (typeof CUSTOM_VIEW_COLOR)[keyof typeof CUSTOM_VIEW_COLOR];
@@ -0,0 +1,38 @@
1
+ export declare const CUSTOM_VIEW_ICON: {
2
+ readonly ACTIVITY: "activity";
3
+ readonly ALERT_TRIANGLE: "alertTriangle";
4
+ readonly BOOKMARK: "bookmark";
5
+ readonly CALENDAR: "calendar";
6
+ readonly CHECK_CIRCLE: "checkCircle";
7
+ readonly CHECK_SQUARE: "checkSquare";
8
+ readonly CLOCK: "clock";
9
+ readonly CLOCK_REWIND: "clockRewind";
10
+ readonly CUBE: "cube";
11
+ readonly DATABASE: "database";
12
+ readonly EDIT: "edit";
13
+ readonly FLAG: "flag";
14
+ readonly HEART: "heart";
15
+ readonly HOME: "home";
16
+ readonly HOURGLASS: "hourglass";
17
+ readonly INFO_SQUARE: "infoSquare";
18
+ readonly LAYERS: "layers";
19
+ readonly LINK_04: "link04";
20
+ readonly LOCK: "lock";
21
+ readonly MAGIC_WAND: "magicWand";
22
+ readonly MAIL_01: "mail01";
23
+ readonly MAIL_04: "mail04";
24
+ readonly MARKER_PIN: "markerPin";
25
+ readonly PIN: "pin";
26
+ readonly PLACEHOLDER: "placeholder";
27
+ readonly PLANE: "plane";
28
+ readonly ROUTE: "route";
29
+ readonly STAR: "star";
30
+ readonly STARS: "stars";
31
+ readonly TRASH: "trash";
32
+ readonly TREND_DOWN: "trendDown";
33
+ readonly TREND_UP: "trendUp";
34
+ readonly UNLOCK: "unlock";
35
+ readonly USER: "user";
36
+ readonly ZAP: "zap";
37
+ };
38
+ export type CustomViewIcon = (typeof CUSTOM_VIEW_ICON)[keyof typeof CUSTOM_VIEW_ICON];
@@ -0,0 +1,13 @@
1
+ export interface CustomViewStateAdapter<TKey extends string, T> {
2
+ isDirty: (saved: T | null, current: T) => boolean;
3
+ apply: (state: T | null) => void;
4
+ deserialize: (raw: unknown) => T;
5
+ getCurrentState: () => T;
6
+ getDefaultState: () => T;
7
+ key: TKey;
8
+ serialize: (value: T) => unknown;
9
+ }
10
+ export declare function createCustomViewStateAdapter<const TKey extends string, TState>(adapter: CustomViewStateAdapter<TKey, TState>): CustomViewStateAdapter<TKey, TState>;
11
+ export type AdaptersToState<TAdapters extends CustomViewStateAdapter<string, any>[]> = {
12
+ [A in TAdapters[number] as A['key']]: A extends CustomViewStateAdapter<A['key'], infer TValue> ? TValue : never;
13
+ };
@@ -0,0 +1,5 @@
1
+ import { CustomView } from './customView.type';
2
+ export interface CustomViewStorageAdapter {
3
+ load: () => CustomView[];
4
+ save: (views: CustomView[]) => void;
5
+ }
@@ -0,0 +1,3 @@
1
+ import { CustomViewColor } from '../types/customViewColor.type';
2
+ export declare const CUSTOM_VIEW_COLORS_MAP: Map<CustomViewColor, string>;
3
+ export declare function getCustomViewColor(key: CustomViewColor): string;
@@ -0,0 +1,4 @@
1
+ import { Component } from 'vue';
2
+ import { CustomViewIcon } from '../types/customViewIcon.type';
3
+ export declare const CUSTOM_VIEW_ICONS_MAP: Map<CustomViewIcon, Component>;
4
+ export declare function getCustomViewIconComponent(key: CustomViewIcon): Component;
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "@wisemen/vue-core-custom-views",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "type": "module",
7
+ "version": "0.1.0",
8
+ "private": false,
9
+ "license": "SEE LICENSE IN LICENSE.md",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/wisemen-digital/wisemen-core",
13
+ "directory": "packages/web/custom-views"
14
+ },
15
+ "sideEffects": [
16
+ "*.css"
17
+ ],
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./locales": {
24
+ "types": "./dist/locales.d.ts",
25
+ "import": "./dist/locales.js"
26
+ },
27
+ "./style.css": "./dist/style.css",
28
+ "./package.json": "./package.json"
29
+ },
30
+ "main": "./dist/index.umd.cjs",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "typings": "./dist/index.d.ts",
34
+ "files": [
35
+ "./dist"
36
+ ],
37
+ "peerDependencies": {
38
+ "@tanstack/vue-hotkeys": "^0.10.0",
39
+ "@vueuse/core": "14.1.0",
40
+ "@vueuse/router": "14.1.0",
41
+ "@wisemen/vue-core-actions": ">=0.2.0",
42
+ "@wisemen/vue-core-design-system": ">=1.4.0",
43
+ "@wisemen/vue-core-filters": ">=5.0.0",
44
+ "@wisemen/vue-core-icons": ">=0.0.2",
45
+ "@wisemen/vue-core-utils": ">=0.1.0",
46
+ "formango": "^3.2.4",
47
+ "reka-ui": "^2.9.7",
48
+ "tailwindcss": "4.1.18",
49
+ "vue": "^3.5.27",
50
+ "vue-draggable-plus": "^0.6.1",
51
+ "vue-i18n": "^11.2.8"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "@wisemen/vue-core-filters": {
55
+ "optional": true
56
+ }
57
+ },
58
+ "devDependencies": {
59
+ "@tailwindcss/vite": "4.1.18",
60
+ "@tanstack/vue-hotkeys": "^0.10.0",
61
+ "@types/node": "24.8.1",
62
+ "@vitejs/plugin-vue": "6.0.3",
63
+ "@vue/test-utils": "2.4.6",
64
+ "@vue/tsconfig": "0.8.1",
65
+ "@vueuse/core": "14.1.0",
66
+ "@vueuse/router": "14.1.0",
67
+ "@wisemen/vue-core-dates": "^0.0.2",
68
+ "eslint": "9.39.4",
69
+ "formango": "^3.2.4",
70
+ "reka-ui": "2.9.7",
71
+ "tailwindcss": "4.1.18",
72
+ "temporal-polyfill": "^0.3.0",
73
+ "typescript": "5.9.3",
74
+ "vite": "8.0.14",
75
+ "vite-plugin-dts": "4.5.4",
76
+ "vitest": "4.1.0",
77
+ "vue": "3.5.27",
78
+ "vue-draggable-plus": "^0.6.1",
79
+ "vue-i18n": "^11.2.8",
80
+ "vue-tsc": "3.2.2",
81
+ "zod": "4.3.5",
82
+ "@wisemen/eslint-config-vue": "2.1.4",
83
+ "@wisemen/vue-core-design-system": "1.4.0",
84
+ "@wisemen/vue-core-actions": "0.2.0",
85
+ "@wisemen/vue-core-filters": "9.0.0",
86
+ "@wisemen/vue-core-icons": "0.0.2",
87
+ "@wisemen/vue-core-tailwind-config": "0.0.5",
88
+ "@wisemen/vue-core-utils": "0.1.0"
89
+ },
90
+ "scripts": {
91
+ "build": "vite build",
92
+ "build-only": "vite build",
93
+ "type-check": "vue-tsc --noEmit",
94
+ "pub:release": "pnpm publish --access public",
95
+ "pub:beta": "pnpm publish --no-git-checks --access public --tag beta",
96
+ "pub:next": "pnpm publish --no-git-checks --access public --tag next",
97
+ "test:unit": "vitest --run",
98
+ "test": "vitest --run",
99
+ "lint": "eslint .",
100
+ "lint:fix": "eslint . --fix",
101
+ "cleanup": "rimraf dist/ node_modules/ .turbo/"
102
+ }
103
+ }