@lucca-front/ng 19.2.1 → 19.2.3

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 (43) hide show
  1. package/core/misc.d.ts +2 -0
  2. package/core/public-api.d.ts +4 -3
  3. package/core-select/user/users.directive.d.ts +1 -1
  4. package/date2/abstract-date-component.d.ts +8 -5
  5. package/date2/calendar2/date-range.d.ts +7 -3
  6. package/date2/date-input/date-input.component.d.ts +3 -3
  7. package/date2/date-range-input/date-range-input.component.d.ts +5 -5
  8. package/date2/date.const.d.ts +6 -0
  9. package/date2/public-api.d.ts +3 -3
  10. package/date2/utils.d.ts +6 -1
  11. package/fesm2022/lucca-front-ng-core-select-user.mjs +2 -2
  12. package/fesm2022/lucca-front-ng-core-select-user.mjs.map +1 -1
  13. package/fesm2022/lucca-front-ng-core.mjs +36 -33
  14. package/fesm2022/lucca-front-ng-core.mjs.map +1 -1
  15. package/fesm2022/lucca-front-ng-date.mjs +2 -2
  16. package/fesm2022/lucca-front-ng-date.mjs.map +1 -1
  17. package/fesm2022/lucca-front-ng-date2.mjs +162 -87
  18. package/fesm2022/lucca-front-ng-date2.mjs.map +1 -1
  19. package/fesm2022/lucca-front-ng-dialog.mjs +1 -1
  20. package/fesm2022/lucca-front-ng-dialog.mjs.map +1 -1
  21. package/fesm2022/lucca-front-ng-filter-pills.mjs +2 -2
  22. package/fesm2022/lucca-front-ng-filter-pills.mjs.map +1 -1
  23. package/fesm2022/lucca-front-ng-form-field.mjs +34 -28
  24. package/fesm2022/lucca-front-ng-form-field.mjs.map +1 -1
  25. package/fesm2022/lucca-front-ng-forms-phone-number-input.mjs +2 -2
  26. package/fesm2022/lucca-front-ng-forms-phone-number-input.mjs.map +1 -1
  27. package/fesm2022/lucca-front-ng-forms.mjs +2 -2
  28. package/fesm2022/lucca-front-ng-forms.mjs.map +1 -1
  29. package/fesm2022/lucca-front-ng-multi-select.mjs +16 -4
  30. package/fesm2022/lucca-front-ng-multi-select.mjs.map +1 -1
  31. package/fesm2022/lucca-front-ng-popup-employee.mjs +2 -2
  32. package/fesm2022/lucca-front-ng-popup-employee.mjs.map +1 -1
  33. package/fesm2022/lucca-front-ng-simple-select.mjs +2 -2
  34. package/fesm2022/lucca-front-ng-simple-select.mjs.map +1 -1
  35. package/fesm2022/lucca-front-ng-skeleton.mjs +2 -2
  36. package/fesm2022/lucca-front-ng-skeleton.mjs.map +1 -1
  37. package/fesm2022/lucca-front-ng-time.mjs +1 -4
  38. package/fesm2022/lucca-front-ng-time.mjs.map +1 -1
  39. package/fesm2022/lucca-front-ng-user.mjs +2 -2
  40. package/fesm2022/lucca-front-ng-user.mjs.map +1 -1
  41. package/form-field/form-field.component.d.ts +3 -3
  42. package/package.json +21 -21
  43. package/time/core/misc.utils.d.ts +0 -2
@@ -1,9 +1,9 @@
1
1
  import { getLocaleWeekEndRange, getLocaleFirstDayOfWeek, NgClass, NgTemplateOutlet } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, inject, LOCALE_ID, TemplateRef, ViewContainerRef, Directive, Input, ElementRef, input, computed, HostBinding, HostListener, booleanAttribute, model, output, viewChildren, effect, Component, ViewEncapsulation, ChangeDetectionStrategy, signal, viewChild, untracked, forwardRef } from '@angular/core';
4
- import { getIntl, LuClass, ɵeffectWithDeps as _effectWithDeps, PortalDirective } from '@lucca-front/ng/core';
4
+ import { isNil, getIntl, LuClass, ɵeffectWithDeps as _effectWithDeps, PortalDirective } from '@lucca-front/ng/core';
5
5
  import { LuTooltipTriggerDirective } from '@lucca-front/ng/tooltip';
6
- import { isSameDay, isSameMonth, isSameYear, startOfMonth, startOfYear, startOfDecade, addYears, addMonths, subYears, subMonths, endOfWeek, startOfWeek, sub, add, eachDayOfInterval, endOfMonth, lastDayOfMonth, eachMonthOfInterval, endOfYear, eachYearOfInterval, endOfDecade, startOfDay, endOfDay, isAfter, isWithinInterval, addHours, parse, isBefore, subWeeks, startOfQuarter, subQuarters, endOfQuarter } from 'date-fns';
6
+ import { isSameDay, isSameMonth, isSameYear, startOfMonth, startOfYear, startOfDecade, parse, format, addYears, addMonths, subYears, subMonths, endOfWeek, startOfWeek, sub, add, eachDayOfInterval, endOfMonth, lastDayOfMonth, eachMonthOfInterval, endOfYear, eachYearOfInterval, endOfDecade, startOfDay, endOfDay, isAfter, isWithinInterval, addHours, isBefore, subWeeks, startOfQuarter, subQuarters, endOfQuarter } from 'date-fns';
7
7
  import { ConnectionPositionPair } from '@angular/cdk/overlay';
8
8
  import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
9
9
  import { FILTER_PILL_INPUT_COMPONENT, FilterPillDisplayerDirective } from '@lucca-front/ng/filter-pills';
@@ -88,6 +88,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
88
88
  args: ['luRepeatTimes']
89
89
  }] } });
90
90
 
91
+ const DATE_FORMAT = {
92
+ DATE: 'date',
93
+ DATE_ISO: 'date-iso',
94
+ };
95
+ const DATE_ISO_FORMAT = 'yyyy-MM-dd';
96
+
91
97
  function getIntlWeekDay(date) {
92
98
  return (date.getDay() || 7);
93
99
  }
@@ -118,6 +124,51 @@ function compareCalendarPeriods(mode, a, b) {
118
124
  function startOfPeriod(mode, date) {
119
125
  return modeToPeriodStart[mode](date);
120
126
  }
127
+ function stringToDateISO(value) {
128
+ const res = parse(value, DATE_ISO_FORMAT, new Date());
129
+ if (isNaN(+res)) {
130
+ throw new Error('Invalid date: your input should be a valid iso date string (yyyy-MM-dd), received: ' + value);
131
+ }
132
+ return res;
133
+ }
134
+ function transformDateInputToDate(value) {
135
+ if (isNil(value)) {
136
+ return null;
137
+ }
138
+ if (value instanceof Date) {
139
+ return value;
140
+ }
141
+ return stringToDateISO(value);
142
+ }
143
+ function transformDateToDateISO(value) {
144
+ if (isNil(value)) {
145
+ return null;
146
+ }
147
+ return format(value, DATE_ISO_FORMAT);
148
+ }
149
+ function isDateRangeInput(value) {
150
+ return !(value.start instanceof Date);
151
+ }
152
+ function transformDateRangeInputToDateRange(value) {
153
+ if (isNil(value)) {
154
+ return null;
155
+ }
156
+ if (!isDateRangeInput(value)) {
157
+ return value;
158
+ }
159
+ return {
160
+ ...value,
161
+ start: transformDateInputToDate(value.start),
162
+ end: transformDateInputToDate(value.end),
163
+ };
164
+ }
165
+ function transformDateRangeToDateRangeInput(value) {
166
+ return {
167
+ ...value,
168
+ start: transformDateToDateISO(value.start),
169
+ end: transformDateToDateISO(value.end),
170
+ };
171
+ }
121
172
 
122
173
  const CALENDAR_CELLS = new InjectionToken('Calendar2:Calendar2Cells');
123
174
  const CALENDAR_TABBABLE_DATE = new InjectionToken('Calendar2:TabbableDate');
@@ -394,7 +445,7 @@ class Calendar2Component {
394
445
  if (this.tabbableDate() === null) {
395
446
  this.tabbableDate.set(this.date());
396
447
  }
397
- }, { allowSignalWrites: true });
448
+ });
398
449
  }
399
450
  focusTabbableDate() {
400
451
  this.calendar2CellInstances()
@@ -667,15 +718,21 @@ class AbstractDateComponent {
667
718
  this.intlDateTimeFormatYear = new Intl.DateTimeFormat(this.locale, { year: 'numeric' });
668
719
  this.intl = getIntl(LU_DATE2_TRANSLATIONS);
669
720
  this.disabled = false;
670
- this.ranges = input([]);
721
+ this.format = input(DATE_FORMAT.DATE);
722
+ this.inDateISOFormat = computed(() => this.format() === DATE_FORMAT.DATE_ISO);
723
+ this.ranges = input([], { transform: (v) => v.map(transformDateRangeInputToDateRange) });
671
724
  this.hideToday = input(false, { transform: booleanAttribute });
672
725
  this.hasTodayButton = input(false, { transform: booleanAttribute });
673
726
  this.clearable = input(false, { transform: booleanAttribute });
674
727
  this.mode = input('day');
675
728
  this.hideWeekend = input(false, { transform: booleanAttribute });
676
729
  this.getCellInfo = input();
677
- this.min = input(new Date('1/1/1000'));
678
- this.max = input(null);
730
+ this.min = input(new Date('1/1/1000'), {
731
+ transform: transformDateInputToDate,
732
+ });
733
+ this.max = input(null, {
734
+ transform: transformDateInputToDate,
735
+ });
679
736
  this.calendarMode = signal('day');
680
737
  this.dateFormatLocalized = computed(() => {
681
738
  return getLocalizedDateFormat(this.locale, this.mode());
@@ -745,7 +802,7 @@ class AbstractDateComponent {
745
802
  }
746
803
  }
747
804
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AbstractDateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
748
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.3", type: AbstractDateComponent, isStandalone: true, selector: "ng-component", inputs: { ranges: { classPropertyName: "ranges", publicName: "ranges", isSignal: true, isRequired: false, transformFunction: null }, hideToday: { classPropertyName: "hideToday", publicName: "hideToday", isSignal: true, isRequired: false, transformFunction: null }, hasTodayButton: { classPropertyName: "hasTodayButton", publicName: "hasTodayButton", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, hideWeekend: { classPropertyName: "hideWeekend", publicName: "hideWeekend", isSignal: true, isRequired: false, transformFunction: null }, getCellInfo: { classPropertyName: "getCellInfo", publicName: "getCellInfo", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true }); }
805
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.3", type: AbstractDateComponent, isStandalone: true, selector: "ng-component", inputs: { format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, ranges: { classPropertyName: "ranges", publicName: "ranges", isSignal: true, isRequired: false, transformFunction: null }, hideToday: { classPropertyName: "hideToday", publicName: "hideToday", isSignal: true, isRequired: false, transformFunction: null }, hasTodayButton: { classPropertyName: "hasTodayButton", publicName: "hasTodayButton", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, hideWeekend: { classPropertyName: "hideWeekend", publicName: "hideWeekend", isSignal: true, isRequired: false, transformFunction: null }, getCellInfo: { classPropertyName: "getCellInfo", publicName: "getCellInfo", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true }); }
749
806
  }
750
807
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AbstractDateComponent, decorators: [{
751
808
  type: Component,
@@ -799,9 +856,15 @@ class DateInputComponent extends AbstractDateComponent {
799
856
  }
800
857
  return formatter.format(this.selectedDate());
801
858
  }
802
- return this.userTextInput();
859
+ const textInput = this.userTextInput();
860
+ // If we are initializing the component, we don't want to display the value
861
+ if (textInput === 'ɵ') {
862
+ return '';
863
+ }
864
+ return textInput;
803
865
  });
804
- this.userTextInput = signal('');
866
+ // We need to use a "magic key" here to avoid sending a null value change on initialization
867
+ this.userTextInput = signal('ɵ');
805
868
  this.combinedGetCellInfo = (date, mode) => {
806
869
  const infoFromInput = this.getCellInfo()?.(date, mode);
807
870
  return {
@@ -817,6 +880,10 @@ class DateInputComponent extends AbstractDateComponent {
817
880
  this.isFilterPillEmpty = computed(() => !this.selectedDate());
818
881
  effect(() => {
819
882
  const inputValue = this.userTextInput();
883
+ // If we are initializing the component, we don't want to parse the value
884
+ if (inputValue === 'ɵ') {
885
+ return;
886
+ }
820
887
  if (inputValue.length > 0) {
821
888
  let parsed;
822
889
  try {
@@ -837,7 +904,7 @@ class DateInputComponent extends AbstractDateComponent {
837
904
  else {
838
905
  this.selectedDate.set(null);
839
906
  }
840
- }, { allowSignalWrites: true });
907
+ });
841
908
  effect(() => {
842
909
  if (!this.#safeCompareDate(untracked(this.dateFromWriteValue), this.selectedDate())) {
843
910
  this.#onChange?.(this.selectedDate());
@@ -911,6 +978,7 @@ class DateInputComponent extends AbstractDateComponent {
911
978
  if (control.value === null || control.value === undefined) {
912
979
  return null;
913
980
  }
981
+ const date = transformDateInputToDate(control.value);
914
982
  // try to parse the display value cause formControl.value is undefined if date is not parsable
915
983
  try {
916
984
  parse(this.displayValue(), this.dateFormat, startOfDay(new Date()));
@@ -920,29 +988,32 @@ class DateInputComponent extends AbstractDateComponent {
920
988
  return { date: true };
921
989
  }
922
990
  // Check date validity
923
- if (!this.isValidDate(control.value)) {
991
+ if (!this.isValidDate(date)) {
924
992
  return { date: true };
925
993
  }
926
994
  // Check min and max
927
- if (this.min() && isBefore(control.value, this.min())) {
995
+ if (this.min() && isBefore(date, this.min())) {
928
996
  return { min: true };
929
997
  }
930
- else if (this.max() && isAfter(control.value, this.max())) {
998
+ else if (this.max() && isAfter(date, this.max())) {
931
999
  return { max: true };
932
1000
  }
933
1001
  // Everything is valid
934
1002
  return null;
935
1003
  }
936
1004
  writeValue(date) {
937
- if (date) {
938
- const start = startOfDay(date);
1005
+ if (date != null) {
1006
+ const _date = transformDateInputToDate(date);
1007
+ const start = startOfDay(_date);
939
1008
  this.dateFromWriteValue.set(start);
940
1009
  this.selectedDate.set(start);
941
1010
  this.currentDate.set(start);
942
1011
  }
943
1012
  }
944
1013
  registerOnChange(fn) {
945
- this.#onChange = fn;
1014
+ this.#onChange = (date) => {
1015
+ fn(date && this.inDateISOFormat() ? transformDateToDateISO(date) : date);
1016
+ };
946
1017
  }
947
1018
  setDisabledState(isDisabled) {
948
1019
  this.filterPillDisabled.set(isDisabled);
@@ -1010,6 +1081,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
1010
1081
  args: ['class.mod-filterPill']
1011
1082
  }] } });
1012
1083
 
1084
+ const PremadeShortcuts = {
1085
+ SinceStartOfWeek: (locale) => {
1086
+ return {
1087
+ // TODO find a reliable way to obtain this, Angular has a deprecated method, date-fns can't get locale from string, Intl's weekDay isn't in firefox
1088
+ start: startOfWeek(new Date(), { weekStartsOn: getLocaleFirstDayOfWeek(locale) }),
1089
+ end: startOfDay(new Date()),
1090
+ };
1091
+ },
1092
+ LastWeek: (locale) => {
1093
+ const startOfLastWeek = startOfWeek(subWeeks(new Date(), 1), { weekStartsOn: getLocaleFirstDayOfWeek(locale) });
1094
+ return {
1095
+ // TODO find a reliable way to obtain this, Angular has a deprecated method, date-fns can't get locale from string, Intl's weekDay isn't in firefox
1096
+ start: startOfLastWeek,
1097
+ end: endOfWeek(startOfLastWeek, { weekStartsOn: getLocaleFirstDayOfWeek(locale) }),
1098
+ };
1099
+ },
1100
+ SinceStartOfMonth: () => {
1101
+ return {
1102
+ start: startOfMonth(new Date()),
1103
+ end: endOfDay(new Date()),
1104
+ };
1105
+ },
1106
+ LastMonth: () => {
1107
+ const startOfLastMonth = startOfMonth(subMonths(new Date(), 1));
1108
+ return {
1109
+ start: startOfLastMonth,
1110
+ end: endOfMonth(startOfLastMonth),
1111
+ };
1112
+ },
1113
+ SinceStartOfQuarter: () => {
1114
+ return {
1115
+ start: startOfQuarter(new Date()),
1116
+ end: endOfDay(new Date()),
1117
+ };
1118
+ },
1119
+ LastQuarter: () => {
1120
+ const startOfLastQuarter = startOfQuarter(subQuarters(new Date(), 1));
1121
+ return {
1122
+ start: startOfLastQuarter,
1123
+ end: endOfQuarter(startOfLastQuarter),
1124
+ };
1125
+ },
1126
+ SinceStartOfYear: () => {
1127
+ return {
1128
+ start: startOfYear(new Date()),
1129
+ end: endOfDay(new Date()),
1130
+ };
1131
+ },
1132
+ LastYear: () => {
1133
+ const startOfLastYear = startOfYear(subYears(new Date(), 1));
1134
+ return {
1135
+ start: startOfLastYear,
1136
+ end: endOfYear(startOfLastYear),
1137
+ };
1138
+ },
1139
+ LastTwelveMonths: () => {
1140
+ return {
1141
+ start: subMonths(new Date(), 12),
1142
+ end: new Date(),
1143
+ };
1144
+ },
1145
+ };
1146
+
1013
1147
  let nextId = 0;
1014
1148
  class DateRangeInputComponent extends AbstractDateComponent {
1015
1149
  #luClass;
@@ -1213,7 +1347,7 @@ class DateRangeInputComponent extends AbstractDateComponent {
1213
1347
  else {
1214
1348
  this.selectedRange.set(currentRange);
1215
1349
  }
1216
- }, { allowSignalWrites: true });
1350
+ });
1217
1351
  }
1218
1352
  inputBlur() {
1219
1353
  this.onTouched?.();
@@ -1332,16 +1466,20 @@ class DateRangeInputComponent extends AbstractDateComponent {
1332
1466
  if (!control.value) {
1333
1467
  return null;
1334
1468
  }
1335
- return this.isValidDate(control.value?.start) ? null : { date: true };
1336
- }
1337
- writeValue(value) {
1338
- if (value) {
1339
- this.selectedRange.set(value);
1340
- this.currentDate.set(startOfDay(value.start));
1469
+ const dateRange = transformDateRangeInputToDateRange(control.value);
1470
+ return this.isValidDate(dateRange.start) ? null : { date: true };
1471
+ }
1472
+ writeValue(dateRange) {
1473
+ if (dateRange != null) {
1474
+ const _dateRange = transformDateRangeInputToDateRange(dateRange);
1475
+ this.selectedRange.set(_dateRange);
1476
+ this.currentDate.set(startOfDay(dateRange.start));
1341
1477
  }
1342
1478
  }
1343
1479
  registerOnChange(fn) {
1344
- this.#onChange = fn;
1480
+ this.#onChange = (dateRange) => {
1481
+ fn(dateRange && this.inDateISOFormat() ? transformDateRangeToDateRangeInput(dateRange) : dateRange);
1482
+ };
1345
1483
  }
1346
1484
  setDisabledState(isDisabled) {
1347
1485
  this.filterPillDisabled.set(isDisabled);
@@ -1431,69 +1569,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
1431
1569
  args: ['class.mod-filterPill']
1432
1570
  }] } });
1433
1571
 
1434
- const PremadeShortcuts = {
1435
- SinceStartOfWeek: (locale) => {
1436
- return {
1437
- // TODO find a reliable way to obtain this, Angular has a deprecated method, date-fns can't get locale from string, Intl's weekDay isn't in firefox
1438
- start: startOfWeek(new Date(), { weekStartsOn: getLocaleFirstDayOfWeek(locale) }),
1439
- end: startOfDay(new Date()),
1440
- };
1441
- },
1442
- LastWeek: (locale) => {
1443
- const startOfLastWeek = startOfWeek(subWeeks(new Date(), 1), { weekStartsOn: getLocaleFirstDayOfWeek(locale) });
1444
- return {
1445
- // TODO find a reliable way to obtain this, Angular has a deprecated method, date-fns can't get locale from string, Intl's weekDay isn't in firefox
1446
- start: startOfLastWeek,
1447
- end: endOfWeek(startOfLastWeek, { weekStartsOn: getLocaleFirstDayOfWeek(locale) }),
1448
- };
1449
- },
1450
- SinceStartOfMonth: () => {
1451
- return {
1452
- start: startOfMonth(new Date()),
1453
- end: endOfDay(new Date()),
1454
- };
1455
- },
1456
- LastMonth: () => {
1457
- const startOfLastMonth = startOfMonth(subMonths(new Date(), 1));
1458
- return {
1459
- start: startOfLastMonth,
1460
- end: endOfMonth(startOfLastMonth),
1461
- };
1462
- },
1463
- SinceStartOfQuarter: () => {
1464
- return {
1465
- start: startOfQuarter(new Date()),
1466
- end: endOfDay(new Date()),
1467
- };
1468
- },
1469
- LastQuarter: () => {
1470
- const startOfLastQuarter = startOfQuarter(subQuarters(new Date(), 1));
1471
- return {
1472
- start: startOfLastQuarter,
1473
- end: endOfQuarter(startOfLastQuarter),
1474
- };
1475
- },
1476
- SinceStartOfYear: () => {
1477
- return {
1478
- start: startOfYear(new Date()),
1479
- end: endOfDay(new Date()),
1480
- };
1481
- },
1482
- LastYear: () => {
1483
- const startOfLastYear = startOfYear(subYears(new Date(), 1));
1484
- return {
1485
- start: startOfLastYear,
1486
- end: endOfYear(startOfLastYear),
1487
- };
1488
- },
1489
- LastTwelveMonths: () => {
1490
- return {
1491
- start: subMonths(new Date(), 12),
1492
- end: new Date(),
1493
- };
1494
- },
1495
- };
1496
-
1497
1572
  /**
1498
1573
  * Generated bundle index. Do not edit.
1499
1574
  */