valtech-components 2.0.679 → 2.0.681
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/esm2022/lib/services/auth/auth.service.mjs +2 -11
- package/esm2022/lib/services/auth/types.mjs +1 -1
- package/esm2022/lib/version.mjs +2 -2
- package/esm2022/public-api.mjs +1 -7
- package/fesm2022/valtech-components.mjs +4 -783
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/services/auth/auth.service.d.ts +1 -6
- package/lib/services/auth/types.d.ts +0 -18
- package/lib/version.d.ts +1 -1
- package/package.json +2 -6
- package/public-api.d.ts +0 -4
- package/esm2022/lib/components/molecules/image-crop/image-crop.component.mjs +0 -174
- package/esm2022/lib/components/molecules/image-crop/index.mjs +0 -2
- package/esm2022/lib/components/organisms/avatar-upload/avatar-upload.component.mjs +0 -345
- package/esm2022/lib/components/organisms/avatar-upload/types.mjs +0 -15
- package/esm2022/lib/services/image/image.service.mjs +0 -244
- package/esm2022/lib/services/image/index.mjs +0 -3
- package/esm2022/lib/services/image/types.mjs +0 -13
- package/lib/components/molecules/image-crop/image-crop.component.d.ts +0 -59
- package/lib/components/molecules/image-crop/index.d.ts +0 -1
- package/lib/components/organisms/avatar-upload/avatar-upload.component.d.ts +0 -82
- package/lib/components/organisms/avatar-upload/types.d.ts +0 -62
- package/lib/services/image/image.service.d.ts +0 -76
- package/lib/services/image/index.d.ts +0 -2
- package/lib/services/image/types.d.ts +0 -74
- package/src/lib/services/firebase/firebase-messaging-sw.js +0 -134
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import { Injectable } from '@angular/core';
|
|
2
|
-
import { IMAGE_DEFAULTS, } from './types';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
/**
|
|
5
|
-
* ImageService
|
|
6
|
-
*
|
|
7
|
-
* Service for image processing including compression, thumbnails, cropping and validation.
|
|
8
|
-
* Uses HTML Canvas for all operations - no external dependencies.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```typescript
|
|
12
|
-
* const imageService = inject(ImageService);
|
|
13
|
-
*
|
|
14
|
-
* // Compress an image
|
|
15
|
-
* const compressed = await imageService.compress(file, { maxWidth: 800, quality: 0.8 });
|
|
16
|
-
*
|
|
17
|
-
* // Generate thumbnail
|
|
18
|
-
* const thumb = await imageService.thumbnail(file, 150);
|
|
19
|
-
*
|
|
20
|
-
* // Validate before processing
|
|
21
|
-
* const validation = imageService.validate(file, { maxSize: 5 * 1024 * 1024 });
|
|
22
|
-
* if (!validation.valid) {
|
|
23
|
-
* console.error(validation.message);
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export class ImageService {
|
|
28
|
-
/**
|
|
29
|
-
* Compress an image maintaining aspect ratio
|
|
30
|
-
* @param file - File or Blob to compress
|
|
31
|
-
* @param options - Compression options
|
|
32
|
-
* @returns Promise with processed image data
|
|
33
|
-
*/
|
|
34
|
-
async compress(file, options) {
|
|
35
|
-
const opts = {
|
|
36
|
-
maxWidth: options?.maxWidth ?? IMAGE_DEFAULTS.maxWidth,
|
|
37
|
-
maxHeight: options?.maxHeight ?? IMAGE_DEFAULTS.maxHeight,
|
|
38
|
-
quality: options?.quality ?? IMAGE_DEFAULTS.quality,
|
|
39
|
-
mimeType: options?.mimeType ?? IMAGE_DEFAULTS.mimeType,
|
|
40
|
-
};
|
|
41
|
-
const img = await this.loadImage(file);
|
|
42
|
-
const { width, height } = this.calculateDimensions(img.width, img.height, opts.maxWidth, opts.maxHeight);
|
|
43
|
-
const canvas = document.createElement('canvas');
|
|
44
|
-
canvas.width = width;
|
|
45
|
-
canvas.height = height;
|
|
46
|
-
const ctx = canvas.getContext('2d');
|
|
47
|
-
ctx.drawImage(img, 0, 0, width, height);
|
|
48
|
-
const blob = await this.canvasToBlob(canvas, opts.mimeType, opts.quality);
|
|
49
|
-
const dataUrl = canvas.toDataURL(opts.mimeType, opts.quality);
|
|
50
|
-
return {
|
|
51
|
-
blob,
|
|
52
|
-
dataUrl,
|
|
53
|
-
width,
|
|
54
|
-
height,
|
|
55
|
-
size: blob.size,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Generate a square thumbnail from an image
|
|
60
|
-
* @param file - File or Blob to process
|
|
61
|
-
* @param size - Thumbnail size in pixels (default: 150)
|
|
62
|
-
* @returns Promise with processed thumbnail
|
|
63
|
-
*/
|
|
64
|
-
async thumbnail(file, size) {
|
|
65
|
-
const thumbSize = size ?? IMAGE_DEFAULTS.thumbnailSize;
|
|
66
|
-
const img = await this.loadImage(file);
|
|
67
|
-
// Calculate square crop from center
|
|
68
|
-
const minDim = Math.min(img.width, img.height);
|
|
69
|
-
const cropX = (img.width - minDim) / 2;
|
|
70
|
-
const cropY = (img.height - minDim) / 2;
|
|
71
|
-
const canvas = document.createElement('canvas');
|
|
72
|
-
canvas.width = thumbSize;
|
|
73
|
-
canvas.height = thumbSize;
|
|
74
|
-
const ctx = canvas.getContext('2d');
|
|
75
|
-
ctx.drawImage(img, cropX, cropY, minDim, minDim, 0, 0, thumbSize, thumbSize);
|
|
76
|
-
const blob = await this.canvasToBlob(canvas, IMAGE_DEFAULTS.mimeType, 0.7 // Lower quality for thumbnails
|
|
77
|
-
);
|
|
78
|
-
const dataUrl = canvas.toDataURL(IMAGE_DEFAULTS.mimeType, 0.7);
|
|
79
|
-
return {
|
|
80
|
-
blob,
|
|
81
|
-
dataUrl,
|
|
82
|
-
width: thumbSize,
|
|
83
|
-
height: thumbSize,
|
|
84
|
-
size: blob.size,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Crop an image with specific coordinates
|
|
89
|
-
* @param file - File or Blob to crop
|
|
90
|
-
* @param cropData - Crop coordinates and dimensions
|
|
91
|
-
* @param options - Optional compression options for output
|
|
92
|
-
* @returns Promise with cropped image
|
|
93
|
-
*/
|
|
94
|
-
async crop(file, cropData, options) {
|
|
95
|
-
const img = await this.loadImage(file);
|
|
96
|
-
const opts = {
|
|
97
|
-
quality: options?.quality ?? IMAGE_DEFAULTS.quality,
|
|
98
|
-
mimeType: options?.mimeType ?? IMAGE_DEFAULTS.mimeType,
|
|
99
|
-
};
|
|
100
|
-
const canvas = document.createElement('canvas');
|
|
101
|
-
canvas.width = cropData.width;
|
|
102
|
-
canvas.height = cropData.height;
|
|
103
|
-
const ctx = canvas.getContext('2d');
|
|
104
|
-
ctx.drawImage(img, cropData.x, cropData.y, cropData.width, cropData.height, 0, 0, cropData.width, cropData.height);
|
|
105
|
-
// Apply max dimensions if specified
|
|
106
|
-
if (options?.maxWidth || options?.maxHeight) {
|
|
107
|
-
return this.compress(await this.canvasToBlob(canvas, opts.mimeType, 1), options);
|
|
108
|
-
}
|
|
109
|
-
const blob = await this.canvasToBlob(canvas, opts.mimeType, opts.quality);
|
|
110
|
-
const dataUrl = canvas.toDataURL(opts.mimeType, opts.quality);
|
|
111
|
-
return {
|
|
112
|
-
blob,
|
|
113
|
-
dataUrl,
|
|
114
|
-
width: cropData.width,
|
|
115
|
-
height: cropData.height,
|
|
116
|
-
size: blob.size,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Validate an image file before processing
|
|
121
|
-
* @param file - File to validate
|
|
122
|
-
* @param options - Validation options
|
|
123
|
-
* @returns Validation result with error details if invalid
|
|
124
|
-
*/
|
|
125
|
-
validate(file, options) {
|
|
126
|
-
const opts = {
|
|
127
|
-
maxSize: options?.maxSize ?? IMAGE_DEFAULTS.maxSize,
|
|
128
|
-
allowedTypes: options?.allowedTypes ?? IMAGE_DEFAULTS.allowedTypes,
|
|
129
|
-
};
|
|
130
|
-
// Check file type
|
|
131
|
-
if (!opts.allowedTypes.includes(file.type)) {
|
|
132
|
-
return {
|
|
133
|
-
valid: false,
|
|
134
|
-
error: 'invalidType',
|
|
135
|
-
message: `Formato no válido. Usa: ${opts.allowedTypes.map(t => t.split('/')[1].toUpperCase()).join(', ')}`,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
// Check file size
|
|
139
|
-
if (file.size > opts.maxSize) {
|
|
140
|
-
const maxMB = Math.round(opts.maxSize / (1024 * 1024));
|
|
141
|
-
return {
|
|
142
|
-
valid: false,
|
|
143
|
-
error: 'fileTooLarge',
|
|
144
|
-
message: `La imagen es muy grande. Máximo ${maxMB}MB`,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
return { valid: true };
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Validate image dimensions (async - requires loading image)
|
|
151
|
-
* @param file - File to validate
|
|
152
|
-
* @param options - Validation options with minWidth/minHeight
|
|
153
|
-
* @returns Promise with validation result
|
|
154
|
-
*/
|
|
155
|
-
async validateDimensions(file, options) {
|
|
156
|
-
const img = await this.loadImage(file);
|
|
157
|
-
if (options.minWidth && img.width < options.minWidth) {
|
|
158
|
-
return {
|
|
159
|
-
valid: false,
|
|
160
|
-
error: 'imageTooSmall',
|
|
161
|
-
message: `La imagen debe tener al menos ${options.minWidth}px de ancho`,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (options.minHeight && img.height < options.minHeight) {
|
|
165
|
-
return {
|
|
166
|
-
valid: false,
|
|
167
|
-
error: 'imageTooSmall',
|
|
168
|
-
message: `La imagen debe tener al menos ${options.minHeight}px de alto`,
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
return { valid: true };
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Convert a Blob/File to a data URL
|
|
175
|
-
*/
|
|
176
|
-
async toDataUrl(file) {
|
|
177
|
-
return new Promise((resolve, reject) => {
|
|
178
|
-
const reader = new FileReader();
|
|
179
|
-
reader.onload = () => resolve(reader.result);
|
|
180
|
-
reader.onerror = reject;
|
|
181
|
-
reader.readAsDataURL(file);
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Convert a data URL to a Blob
|
|
186
|
-
*/
|
|
187
|
-
dataUrlToBlob(dataUrl) {
|
|
188
|
-
const arr = dataUrl.split(',');
|
|
189
|
-
const mime = arr[0].match(/:(.*?);/)[1];
|
|
190
|
-
const bstr = atob(arr[1]);
|
|
191
|
-
let n = bstr.length;
|
|
192
|
-
const u8arr = new Uint8Array(n);
|
|
193
|
-
while (n--) {
|
|
194
|
-
u8arr[n] = bstr.charCodeAt(n);
|
|
195
|
-
}
|
|
196
|
-
return new Blob([u8arr], { type: mime });
|
|
197
|
-
}
|
|
198
|
-
// ============== Private Helpers ==============
|
|
199
|
-
loadImage(file) {
|
|
200
|
-
return new Promise((resolve, reject) => {
|
|
201
|
-
const img = new Image();
|
|
202
|
-
img.onload = () => {
|
|
203
|
-
URL.revokeObjectURL(img.src);
|
|
204
|
-
resolve(img);
|
|
205
|
-
};
|
|
206
|
-
img.onerror = reject;
|
|
207
|
-
img.src = URL.createObjectURL(file);
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
calculateDimensions(originalWidth, originalHeight, maxWidth, maxHeight) {
|
|
211
|
-
let width = originalWidth;
|
|
212
|
-
let height = originalHeight;
|
|
213
|
-
// Scale down if necessary, maintaining aspect ratio
|
|
214
|
-
if (width > maxWidth) {
|
|
215
|
-
height = (height * maxWidth) / width;
|
|
216
|
-
width = maxWidth;
|
|
217
|
-
}
|
|
218
|
-
if (height > maxHeight) {
|
|
219
|
-
width = (width * maxHeight) / height;
|
|
220
|
-
height = maxHeight;
|
|
221
|
-
}
|
|
222
|
-
return {
|
|
223
|
-
width: Math.round(width),
|
|
224
|
-
height: Math.round(height),
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
canvasToBlob(canvas, mimeType, quality) {
|
|
228
|
-
return new Promise((resolve, reject) => {
|
|
229
|
-
canvas.toBlob((blob) => {
|
|
230
|
-
if (blob)
|
|
231
|
-
resolve(blob);
|
|
232
|
-
else
|
|
233
|
-
reject(new Error('Failed to create blob from canvas'));
|
|
234
|
-
}, mimeType, quality);
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
238
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, providedIn: 'root' }); }
|
|
239
|
-
}
|
|
240
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ImageService, decorators: [{
|
|
241
|
-
type: Injectable,
|
|
242
|
-
args: [{ providedIn: 'root' }]
|
|
243
|
-
}] });
|
|
244
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2Uuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZXMvaW1hZ2UvaW1hZ2Uuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFFTCxjQUFjLEdBS2YsTUFBTSxTQUFTLENBQUM7O0FBRWpCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBc0JHO0FBRUgsTUFBTSxPQUFPLFlBQVk7SUFDdkI7Ozs7O09BS0c7SUFDSCxLQUFLLENBQUMsUUFBUSxDQUNaLElBQWlCLEVBQ2pCLE9BQThCO1FBRTlCLE1BQU0sSUFBSSxHQUFHO1lBQ1gsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLElBQUksY0FBYyxDQUFDLFFBQVE7WUFDdEQsU0FBUyxFQUFFLE9BQU8sRUFBRSxTQUFTLElBQUksY0FBYyxDQUFDLFNBQVM7WUFDekQsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLElBQUksY0FBYyxDQUFDLE9BQU87WUFDbkQsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLElBQUksY0FBYyxDQUFDLFFBQVE7U0FDdkQsQ0FBQztRQUVGLE1BQU0sR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN2QyxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FDaEQsR0FBRyxDQUFDLEtBQUssRUFDVCxHQUFHLENBQUMsTUFBTSxFQUNWLElBQUksQ0FBQyxRQUFRLEVBQ2IsSUFBSSxDQUFDLFNBQVMsQ0FDZixDQUFDO1FBRUYsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoRCxNQUFNLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUNyQixNQUFNLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUV2QixNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBRSxDQUFDO1FBQ3JDLEdBQUcsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBRXhDLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDMUUsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU5RCxPQUFPO1lBQ0wsSUFBSTtZQUNKLE9BQU87WUFDUCxLQUFLO1lBQ0wsTUFBTTtZQUNOLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSTtTQUNoQixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFpQixFQUFFLElBQWE7UUFDOUMsTUFBTSxTQUFTLEdBQUcsSUFBSSxJQUFJLGNBQWMsQ0FBQyxhQUFhLENBQUM7UUFDdkQsTUFBTSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRXZDLG9DQUFvQztRQUNwQyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQy9DLE1BQU0sS0FBSyxHQUFHLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdkMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUV4QyxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2hELE1BQU0sQ0FBQyxLQUFLLEdBQUcsU0FBUyxDQUFDO1FBQ3pCLE1BQU0sQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDO1FBRTFCLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFFLENBQUM7UUFDckMsR0FBRyxDQUFDLFNBQVMsQ0FDWCxHQUFHLEVBQ0gsS0FBSyxFQUNMLEtBQUssRUFDTCxNQUFNLEVBQ04sTUFBTSxFQUNOLENBQUMsRUFDRCxDQUFDLEVBQ0QsU0FBUyxFQUNULFNBQVMsQ0FDVixDQUFDO1FBRUYsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUNsQyxNQUFNLEVBQ04sY0FBYyxDQUFDLFFBQVEsRUFDdkIsR0FBRyxDQUFDLCtCQUErQjtTQUNwQyxDQUFDO1FBQ0YsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBRS9ELE9BQU87WUFDTCxJQUFJO1lBQ0osT0FBTztZQUNQLEtBQUssRUFBRSxTQUFTO1lBQ2hCLE1BQU0sRUFBRSxTQUFTO1lBQ2pCLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSTtTQUNoQixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQ1IsSUFBaUIsRUFDakIsUUFBa0IsRUFDbEIsT0FBOEI7UUFFOUIsTUFBTSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3ZDLE1BQU0sSUFBSSxHQUFHO1lBQ1gsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLElBQUksY0FBYyxDQUFDLE9BQU87WUFDbkQsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLElBQUksY0FBYyxDQUFDLFFBQVE7U0FDdkQsQ0FBQztRQUVGLE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDaEQsTUFBTSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDO1FBQzlCLE1BQU0sQ0FBQyxNQUFNLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQztRQUVoQyxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBRSxDQUFDO1FBQ3JDLEdBQUcsQ0FBQyxTQUFTLENBQ1gsR0FBRyxFQUNILFFBQVEsQ0FBQyxDQUFDLEVBQ1YsUUFBUSxDQUFDLENBQUMsRUFDVixRQUFRLENBQUMsS0FBSyxFQUNkLFFBQVEsQ0FBQyxNQUFNLEVBQ2YsQ0FBQyxFQUNELENBQUMsRUFDRCxRQUFRLENBQUMsS0FBSyxFQUNkLFFBQVEsQ0FBQyxNQUFNLENBQ2hCLENBQUM7UUFFRixvQ0FBb0M7UUFDcEMsSUFBSSxPQUFPLEVBQUUsUUFBUSxJQUFJLE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQztZQUM1QyxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ25GLENBQUM7UUFFRCxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzFFLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFOUQsT0FBTztZQUNMLElBQUk7WUFDSixPQUFPO1lBQ1AsS0FBSyxFQUFFLFFBQVEsQ0FBQyxLQUFLO1lBQ3JCLE1BQU0sRUFBRSxRQUFRLENBQUMsTUFBTTtZQUN2QixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7U0FDaEIsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILFFBQVEsQ0FBQyxJQUFVLEVBQUUsT0FBOEI7UUFDakQsTUFBTSxJQUFJLEdBQUc7WUFDWCxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sSUFBSSxjQUFjLENBQUMsT0FBTztZQUNuRCxZQUFZLEVBQUUsT0FBTyxFQUFFLFlBQVksSUFBSSxjQUFjLENBQUMsWUFBWTtTQUNuRSxDQUFDO1FBRUYsa0JBQWtCO1FBQ2xCLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUMzQyxPQUFPO2dCQUNMLEtBQUssRUFBRSxLQUFLO2dCQUNaLEtBQUssRUFBRSxhQUFhO2dCQUNwQixPQUFPLEVBQUUsMkJBQTJCLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRTthQUMzRyxDQUFDO1FBQ0osQ0FBQztRQUVELGtCQUFrQjtRQUNsQixJQUFJLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQzdCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sR0FBRyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3ZELE9BQU87Z0JBQ0wsS0FBSyxFQUFFLEtBQUs7Z0JBQ1osS0FBSyxFQUFFLGNBQWM7Z0JBQ3JCLE9BQU8sRUFBRSxtQ0FBbUMsS0FBSyxJQUFJO2FBQ3RELENBQUM7UUFDSixDQUFDO1FBRUQsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxLQUFLLENBQUMsa0JBQWtCLENBQ3RCLElBQVUsRUFDVixPQUE2RDtRQUU3RCxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFdkMsSUFBSSxPQUFPLENBQUMsUUFBUSxJQUFJLEdBQUcsQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3JELE9BQU87Z0JBQ0wsS0FBSyxFQUFFLEtBQUs7Z0JBQ1osS0FBSyxFQUFFLGVBQWU7Z0JBQ3RCLE9BQU8sRUFBRSxpQ0FBaUMsT0FBTyxDQUFDLFFBQVEsYUFBYTthQUN4RSxDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksT0FBTyxDQUFDLFNBQVMsSUFBSSxHQUFHLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN4RCxPQUFPO2dCQUNMLEtBQUssRUFBRSxLQUFLO2dCQUNaLEtBQUssRUFBRSxlQUFlO2dCQUN0QixPQUFPLEVBQUUsaUNBQWlDLE9BQU8sQ0FBQyxTQUFTLFlBQVk7YUFDeEUsQ0FBQztRQUNKLENBQUM7UUFFRCxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBaUI7UUFDL0IsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNyQyxNQUFNLE1BQU0sR0FBRyxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2hDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFnQixDQUFDLENBQUM7WUFDdkQsTUFBTSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7WUFDeEIsTUFBTSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM3QixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNILGFBQWEsQ0FBQyxPQUFlO1FBQzNCLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDL0IsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUIsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUNwQixNQUFNLEtBQUssR0FBRyxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNoQyxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDWCxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNoQyxDQUFDO1FBQ0QsT0FBTyxJQUFJLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVELGdEQUFnRDtJQUV4QyxTQUFTLENBQUMsSUFBaUI7UUFDakMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNyQyxNQUFNLEdBQUcsR0FBRyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3hCLEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFO2dCQUNoQixHQUFHLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDN0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ2YsQ0FBQyxDQUFDO1lBQ0YsR0FBRyxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7WUFDckIsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3RDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLG1CQUFtQixDQUN6QixhQUFxQixFQUNyQixjQUFzQixFQUN0QixRQUFnQixFQUNoQixTQUFpQjtRQUVqQixJQUFJLEtBQUssR0FBRyxhQUFhLENBQUM7UUFDMUIsSUFBSSxNQUFNLEdBQUcsY0FBYyxDQUFDO1FBRTVCLG9EQUFvRDtRQUNwRCxJQUFJLEtBQUssR0FBRyxRQUFRLEVBQUUsQ0FBQztZQUNyQixNQUFNLEdBQUcsQ0FBQyxNQUFNLEdBQUcsUUFBUSxDQUFDLEdBQUcsS0FBSyxDQUFDO1lBQ3JDLEtBQUssR0FBRyxRQUFRLENBQUM7UUFDbkIsQ0FBQztRQUVELElBQUksTUFBTSxHQUFHLFNBQVMsRUFBRSxDQUFDO1lBQ3ZCLEtBQUssR0FBRyxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUMsR0FBRyxNQUFNLENBQUM7WUFDckMsTUFBTSxHQUFHLFNBQVMsQ0FBQztRQUNyQixDQUFDO1FBRUQsT0FBTztZQUNMLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztZQUN4QixNQUFNLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7U0FDM0IsQ0FBQztJQUNKLENBQUM7SUFFTyxZQUFZLENBQ2xCLE1BQXlCLEVBQ3pCLFFBQWdCLEVBQ2hCLE9BQWU7UUFFZixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ3JDLE1BQU0sQ0FBQyxNQUFNLENBQ1gsQ0FBQyxJQUFJLEVBQUUsRUFBRTtnQkFDUCxJQUFJLElBQUk7b0JBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDOztvQkFDbkIsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUMsQ0FBQztZQUM5RCxDQUFDLEVBQ0QsUUFBUSxFQUNSLE9BQU8sQ0FDUixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDOytHQXBTVSxZQUFZO21IQUFaLFlBQVksY0FEQyxNQUFNOzs0RkFDbkIsWUFBWTtrQkFEeEIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBDcm9wRGF0YSxcbiAgSU1BR0VfREVGQVVMVFMsXG4gIEltYWdlQ29tcHJlc3NPcHRpb25zLFxuICBJbWFnZVZhbGlkYXRlT3B0aW9ucyxcbiAgSW1hZ2VWYWxpZGF0aW9uUmVzdWx0LFxuICBQcm9jZXNzZWRJbWFnZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogSW1hZ2VTZXJ2aWNlXG4gKlxuICogU2VydmljZSBmb3IgaW1hZ2UgcHJvY2Vzc2luZyBpbmNsdWRpbmcgY29tcHJlc3Npb24sIHRodW1ibmFpbHMsIGNyb3BwaW5nIGFuZCB2YWxpZGF0aW9uLlxuICogVXNlcyBIVE1MIENhbnZhcyBmb3IgYWxsIG9wZXJhdGlvbnMgLSBubyBleHRlcm5hbCBkZXBlbmRlbmNpZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGltYWdlU2VydmljZSA9IGluamVjdChJbWFnZVNlcnZpY2UpO1xuICpcbiAqIC8vIENvbXByZXNzIGFuIGltYWdlXG4gKiBjb25zdCBjb21wcmVzc2VkID0gYXdhaXQgaW1hZ2VTZXJ2aWNlLmNvbXByZXNzKGZpbGUsIHsgbWF4V2lkdGg6IDgwMCwgcXVhbGl0eTogMC44IH0pO1xuICpcbiAqIC8vIEdlbmVyYXRlIHRodW1ibmFpbFxuICogY29uc3QgdGh1bWIgPSBhd2FpdCBpbWFnZVNlcnZpY2UudGh1bWJuYWlsKGZpbGUsIDE1MCk7XG4gKlxuICogLy8gVmFsaWRhdGUgYmVmb3JlIHByb2Nlc3NpbmdcbiAqIGNvbnN0IHZhbGlkYXRpb24gPSBpbWFnZVNlcnZpY2UudmFsaWRhdGUoZmlsZSwgeyBtYXhTaXplOiA1ICogMTAyNCAqIDEwMjQgfSk7XG4gKiBpZiAoIXZhbGlkYXRpb24udmFsaWQpIHtcbiAqICAgY29uc29sZS5lcnJvcih2YWxpZGF0aW9uLm1lc3NhZ2UpO1xuICogfVxuICogYGBgXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgSW1hZ2VTZXJ2aWNlIHtcbiAgLyoqXG4gICAqIENvbXByZXNzIGFuIGltYWdlIG1haW50YWluaW5nIGFzcGVjdCByYXRpb1xuICAgKiBAcGFyYW0gZmlsZSAtIEZpbGUgb3IgQmxvYiB0byBjb21wcmVzc1xuICAgKiBAcGFyYW0gb3B0aW9ucyAtIENvbXByZXNzaW9uIG9wdGlvbnNcbiAgICogQHJldHVybnMgUHJvbWlzZSB3aXRoIHByb2Nlc3NlZCBpbWFnZSBkYXRhXG4gICAqL1xuICBhc3luYyBjb21wcmVzcyhcbiAgICBmaWxlOiBGaWxlIHwgQmxvYixcbiAgICBvcHRpb25zPzogSW1hZ2VDb21wcmVzc09wdGlvbnNcbiAgKTogUHJvbWlzZTxQcm9jZXNzZWRJbWFnZT4ge1xuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICBtYXhXaWR0aDogb3B0aW9ucz8ubWF4V2lkdGggPz8gSU1BR0VfREVGQVVMVFMubWF4V2lkdGgsXG4gICAgICBtYXhIZWlnaHQ6IG9wdGlvbnM/Lm1heEhlaWdodCA/PyBJTUFHRV9ERUZBVUxUUy5tYXhIZWlnaHQsXG4gICAgICBxdWFsaXR5OiBvcHRpb25zPy5xdWFsaXR5ID8/IElNQUdFX0RFRkFVTFRTLnF1YWxpdHksXG4gICAgICBtaW1lVHlwZTogb3B0aW9ucz8ubWltZVR5cGUgPz8gSU1BR0VfREVGQVVMVFMubWltZVR5cGUsXG4gICAgfTtcblxuICAgIGNvbnN0IGltZyA9IGF3YWl0IHRoaXMubG9hZEltYWdlKGZpbGUpO1xuICAgIGNvbnN0IHsgd2lkdGgsIGhlaWdodCB9ID0gdGhpcy5jYWxjdWxhdGVEaW1lbnNpb25zKFxuICAgICAgaW1nLndpZHRoLFxuICAgICAgaW1nLmhlaWdodCxcbiAgICAgIG9wdHMubWF4V2lkdGgsXG4gICAgICBvcHRzLm1heEhlaWdodFxuICAgICk7XG5cbiAgICBjb25zdCBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICBjYW52YXMud2lkdGggPSB3aWR0aDtcbiAgICBjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xuXG4gICAgY29uc3QgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJykhO1xuICAgIGN0eC5kcmF3SW1hZ2UoaW1nLCAwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcblxuICAgIGNvbnN0IGJsb2IgPSBhd2FpdCB0aGlzLmNhbnZhc1RvQmxvYihjYW52YXMsIG9wdHMubWltZVR5cGUsIG9wdHMucXVhbGl0eSk7XG4gICAgY29uc3QgZGF0YVVybCA9IGNhbnZhcy50b0RhdGFVUkwob3B0cy5taW1lVHlwZSwgb3B0cy5xdWFsaXR5KTtcblxuICAgIHJldHVybiB7XG4gICAgICBibG9iLFxuICAgICAgZGF0YVVybCxcbiAgICAgIHdpZHRoLFxuICAgICAgaGVpZ2h0LFxuICAgICAgc2l6ZTogYmxvYi5zaXplLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGUgYSBzcXVhcmUgdGh1bWJuYWlsIGZyb20gYW4gaW1hZ2VcbiAgICogQHBhcmFtIGZpbGUgLSBGaWxlIG9yIEJsb2IgdG8gcHJvY2Vzc1xuICAgKiBAcGFyYW0gc2l6ZSAtIFRodW1ibmFpbCBzaXplIGluIHBpeGVscyAoZGVmYXVsdDogMTUwKVxuICAgKiBAcmV0dXJucyBQcm9taXNlIHdpdGggcHJvY2Vzc2VkIHRodW1ibmFpbFxuICAgKi9cbiAgYXN5bmMgdGh1bWJuYWlsKGZpbGU6IEZpbGUgfCBCbG9iLCBzaXplPzogbnVtYmVyKTogUHJvbWlzZTxQcm9jZXNzZWRJbWFnZT4ge1xuICAgIGNvbnN0IHRodW1iU2l6ZSA9IHNpemUgPz8gSU1BR0VfREVGQVVMVFMudGh1bWJuYWlsU2l6ZTtcbiAgICBjb25zdCBpbWcgPSBhd2FpdCB0aGlzLmxvYWRJbWFnZShmaWxlKTtcblxuICAgIC8vIENhbGN1bGF0ZSBzcXVhcmUgY3JvcCBmcm9tIGNlbnRlclxuICAgIGNvbnN0IG1pbkRpbSA9IE1hdGgubWluKGltZy53aWR0aCwgaW1nLmhlaWdodCk7XG4gICAgY29uc3QgY3JvcFggPSAoaW1nLndpZHRoIC0gbWluRGltKSAvIDI7XG4gICAgY29uc3QgY3JvcFkgPSAoaW1nLmhlaWdodCAtIG1pbkRpbSkgLyAyO1xuXG4gICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgY2FudmFzLndpZHRoID0gdGh1bWJTaXplO1xuICAgIGNhbnZhcy5oZWlnaHQgPSB0aHVtYlNpemU7XG5cbiAgICBjb25zdCBjdHggPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnKSE7XG4gICAgY3R4LmRyYXdJbWFnZShcbiAgICAgIGltZyxcbiAgICAgIGNyb3BYLFxuICAgICAgY3JvcFksXG4gICAgICBtaW5EaW0sXG4gICAgICBtaW5EaW0sXG4gICAgICAwLFxuICAgICAgMCxcbiAgICAgIHRodW1iU2l6ZSxcbiAgICAgIHRodW1iU2l6ZVxuICAgICk7XG5cbiAgICBjb25zdCBibG9iID0gYXdhaXQgdGhpcy5jYW52YXNUb0Jsb2IoXG4gICAgICBjYW52YXMsXG4gICAgICBJTUFHRV9ERUZBVUxUUy5taW1lVHlwZSxcbiAgICAgIDAuNyAvLyBMb3dlciBxdWFsaXR5IGZvciB0aHVtYm5haWxzXG4gICAgKTtcbiAgICBjb25zdCBkYXRhVXJsID0gY2FudmFzLnRvRGF0YVVSTChJTUFHRV9ERUZBVUxUUy5taW1lVHlwZSwgMC43KTtcblxuICAgIHJldHVybiB7XG4gICAgICBibG9iLFxuICAgICAgZGF0YVVybCxcbiAgICAgIHdpZHRoOiB0aHVtYlNpemUsXG4gICAgICBoZWlnaHQ6IHRodW1iU2l6ZSxcbiAgICAgIHNpemU6IGJsb2Iuc2l6ZSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENyb3AgYW4gaW1hZ2Ugd2l0aCBzcGVjaWZpYyBjb29yZGluYXRlc1xuICAgKiBAcGFyYW0gZmlsZSAtIEZpbGUgb3IgQmxvYiB0byBjcm9wXG4gICAqIEBwYXJhbSBjcm9wRGF0YSAtIENyb3AgY29vcmRpbmF0ZXMgYW5kIGRpbWVuc2lvbnNcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25hbCBjb21wcmVzc2lvbiBvcHRpb25zIGZvciBvdXRwdXRcbiAgICogQHJldHVybnMgUHJvbWlzZSB3aXRoIGNyb3BwZWQgaW1hZ2VcbiAgICovXG4gIGFzeW5jIGNyb3AoXG4gICAgZmlsZTogRmlsZSB8IEJsb2IsXG4gICAgY3JvcERhdGE6IENyb3BEYXRhLFxuICAgIG9wdGlvbnM/OiBJbWFnZUNvbXByZXNzT3B0aW9uc1xuICApOiBQcm9taXNlPFByb2Nlc3NlZEltYWdlPiB7XG4gICAgY29uc3QgaW1nID0gYXdhaXQgdGhpcy5sb2FkSW1hZ2UoZmlsZSk7XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHF1YWxpdHk6IG9wdGlvbnM/LnF1YWxpdHkgPz8gSU1BR0VfREVGQVVMVFMucXVhbGl0eSxcbiAgICAgIG1pbWVUeXBlOiBvcHRpb25zPy5taW1lVHlwZSA/PyBJTUFHRV9ERUZBVUxUUy5taW1lVHlwZSxcbiAgICB9O1xuXG4gICAgY29uc3QgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgY2FudmFzLndpZHRoID0gY3JvcERhdGEud2lkdGg7XG4gICAgY2FudmFzLmhlaWdodCA9IGNyb3BEYXRhLmhlaWdodDtcblxuICAgIGNvbnN0IGN0eCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpITtcbiAgICBjdHguZHJhd0ltYWdlKFxuICAgICAgaW1nLFxuICAgICAgY3JvcERhdGEueCxcbiAgICAgIGNyb3BEYXRhLnksXG4gICAgICBjcm9wRGF0YS53aWR0aCxcbiAgICAgIGNyb3BEYXRhLmhlaWdodCxcbiAgICAgIDAsXG4gICAgICAwLFxuICAgICAgY3JvcERhdGEud2lkdGgsXG4gICAgICBjcm9wRGF0YS5oZWlnaHRcbiAgICApO1xuXG4gICAgLy8gQXBwbHkgbWF4IGRpbWVuc2lvbnMgaWYgc3BlY2lmaWVkXG4gICAgaWYgKG9wdGlvbnM/Lm1heFdpZHRoIHx8IG9wdGlvbnM/Lm1heEhlaWdodCkge1xuICAgICAgcmV0dXJuIHRoaXMuY29tcHJlc3MoYXdhaXQgdGhpcy5jYW52YXNUb0Jsb2IoY2FudmFzLCBvcHRzLm1pbWVUeXBlLCAxKSwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgY29uc3QgYmxvYiA9IGF3YWl0IHRoaXMuY2FudmFzVG9CbG9iKGNhbnZhcywgb3B0cy5taW1lVHlwZSwgb3B0cy5xdWFsaXR5KTtcbiAgICBjb25zdCBkYXRhVXJsID0gY2FudmFzLnRvRGF0YVVSTChvcHRzLm1pbWVUeXBlLCBvcHRzLnF1YWxpdHkpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGJsb2IsXG4gICAgICBkYXRhVXJsLFxuICAgICAgd2lkdGg6IGNyb3BEYXRhLndpZHRoLFxuICAgICAgaGVpZ2h0OiBjcm9wRGF0YS5oZWlnaHQsXG4gICAgICBzaXplOiBibG9iLnNpemUsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbiBpbWFnZSBmaWxlIGJlZm9yZSBwcm9jZXNzaW5nXG4gICAqIEBwYXJhbSBmaWxlIC0gRmlsZSB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIFZhbGlkYXRpb24gb3B0aW9uc1xuICAgKiBAcmV0dXJucyBWYWxpZGF0aW9uIHJlc3VsdCB3aXRoIGVycm9yIGRldGFpbHMgaWYgaW52YWxpZFxuICAgKi9cbiAgdmFsaWRhdGUoZmlsZTogRmlsZSwgb3B0aW9ucz86IEltYWdlVmFsaWRhdGVPcHRpb25zKTogSW1hZ2VWYWxpZGF0aW9uUmVzdWx0IHtcbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgbWF4U2l6ZTogb3B0aW9ucz8ubWF4U2l6ZSA/PyBJTUFHRV9ERUZBVUxUUy5tYXhTaXplLFxuICAgICAgYWxsb3dlZFR5cGVzOiBvcHRpb25zPy5hbGxvd2VkVHlwZXMgPz8gSU1BR0VfREVGQVVMVFMuYWxsb3dlZFR5cGVzLFxuICAgIH07XG5cbiAgICAvLyBDaGVjayBmaWxlIHR5cGVcbiAgICBpZiAoIW9wdHMuYWxsb3dlZFR5cGVzLmluY2x1ZGVzKGZpbGUudHlwZSkpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhbGlkOiBmYWxzZSxcbiAgICAgICAgZXJyb3I6ICdpbnZhbGlkVHlwZScsXG4gICAgICAgIG1lc3NhZ2U6IGBGb3JtYXRvIG5vIHbDoWxpZG8uIFVzYTogJHtvcHRzLmFsbG93ZWRUeXBlcy5tYXAodCA9PiB0LnNwbGl0KCcvJylbMV0udG9VcHBlckNhc2UoKSkuam9pbignLCAnKX1gLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBmaWxlIHNpemVcbiAgICBpZiAoZmlsZS5zaXplID4gb3B0cy5tYXhTaXplKSB7XG4gICAgICBjb25zdCBtYXhNQiA9IE1hdGgucm91bmQob3B0cy5tYXhTaXplIC8gKDEwMjQgKiAxMDI0KSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWxpZDogZmFsc2UsXG4gICAgICAgIGVycm9yOiAnZmlsZVRvb0xhcmdlJyxcbiAgICAgICAgbWVzc2FnZTogYExhIGltYWdlbiBlcyBtdXkgZ3JhbmRlLiBNw6F4aW1vICR7bWF4TUJ9TUJgLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4geyB2YWxpZDogdHJ1ZSB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGltYWdlIGRpbWVuc2lvbnMgKGFzeW5jIC0gcmVxdWlyZXMgbG9hZGluZyBpbWFnZSlcbiAgICogQHBhcmFtIGZpbGUgLSBGaWxlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gVmFsaWRhdGlvbiBvcHRpb25zIHdpdGggbWluV2lkdGgvbWluSGVpZ2h0XG4gICAqIEByZXR1cm5zIFByb21pc2Ugd2l0aCB2YWxpZGF0aW9uIHJlc3VsdFxuICAgKi9cbiAgYXN5bmMgdmFsaWRhdGVEaW1lbnNpb25zKFxuICAgIGZpbGU6IEZpbGUsXG4gICAgb3B0aW9uczogUGljazxJbWFnZVZhbGlkYXRlT3B0aW9ucywgJ21pbldpZHRoJyB8ICdtaW5IZWlnaHQnPlxuICApOiBQcm9taXNlPEltYWdlVmFsaWRhdGlvblJlc3VsdD4ge1xuICAgIGNvbnN0IGltZyA9IGF3YWl0IHRoaXMubG9hZEltYWdlKGZpbGUpO1xuXG4gICAgaWYgKG9wdGlvbnMubWluV2lkdGggJiYgaW1nLndpZHRoIDwgb3B0aW9ucy5taW5XaWR0aCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsaWQ6IGZhbHNlLFxuICAgICAgICBlcnJvcjogJ2ltYWdlVG9vU21hbGwnLFxuICAgICAgICBtZXNzYWdlOiBgTGEgaW1hZ2VuIGRlYmUgdGVuZXIgYWwgbWVub3MgJHtvcHRpb25zLm1pbldpZHRofXB4IGRlIGFuY2hvYCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMubWluSGVpZ2h0ICYmIGltZy5oZWlnaHQgPCBvcHRpb25zLm1pbkhlaWdodCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsaWQ6IGZhbHNlLFxuICAgICAgICBlcnJvcjogJ2ltYWdlVG9vU21hbGwnLFxuICAgICAgICBtZXNzYWdlOiBgTGEgaW1hZ2VuIGRlYmUgdGVuZXIgYWwgbWVub3MgJHtvcHRpb25zLm1pbkhlaWdodH1weCBkZSBhbHRvYCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgdmFsaWQ6IHRydWUgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IGEgQmxvYi9GaWxlIHRvIGEgZGF0YSBVUkxcbiAgICovXG4gIGFzeW5jIHRvRGF0YVVybChmaWxlOiBGaWxlIHwgQmxvYik6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XG4gICAgICByZWFkZXIub25sb2FkID0gKCkgPT4gcmVzb2x2ZShyZWFkZXIucmVzdWx0IGFzIHN0cmluZyk7XG4gICAgICByZWFkZXIub25lcnJvciA9IHJlamVjdDtcbiAgICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKGZpbGUpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBkYXRhIFVSTCB0byBhIEJsb2JcbiAgICovXG4gIGRhdGFVcmxUb0Jsb2IoZGF0YVVybDogc3RyaW5nKTogQmxvYiB7XG4gICAgY29uc3QgYXJyID0gZGF0YVVybC5zcGxpdCgnLCcpO1xuICAgIGNvbnN0IG1pbWUgPSBhcnJbMF0ubWF0Y2goLzooLio/KTsvKSFbMV07XG4gICAgY29uc3QgYnN0ciA9IGF0b2IoYXJyWzFdKTtcbiAgICBsZXQgbiA9IGJzdHIubGVuZ3RoO1xuICAgIGNvbnN0IHU4YXJyID0gbmV3IFVpbnQ4QXJyYXkobik7XG4gICAgd2hpbGUgKG4tLSkge1xuICAgICAgdThhcnJbbl0gPSBic3RyLmNoYXJDb2RlQXQobik7XG4gICAgfVxuICAgIHJldHVybiBuZXcgQmxvYihbdThhcnJdLCB7IHR5cGU6IG1pbWUgfSk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PSBQcml2YXRlIEhlbHBlcnMgPT09PT09PT09PT09PT1cblxuICBwcml2YXRlIGxvYWRJbWFnZShmaWxlOiBGaWxlIHwgQmxvYik6IFByb21pc2U8SFRNTEltYWdlRWxlbWVudD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBpbWcgPSBuZXcgSW1hZ2UoKTtcbiAgICAgIGltZy5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICAgIFVSTC5yZXZva2VPYmplY3RVUkwoaW1nLnNyYyk7XG4gICAgICAgIHJlc29sdmUoaW1nKTtcbiAgICAgIH07XG4gICAgICBpbWcub25lcnJvciA9IHJlamVjdDtcbiAgICAgIGltZy5zcmMgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGZpbGUpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjYWxjdWxhdGVEaW1lbnNpb25zKFxuICAgIG9yaWdpbmFsV2lkdGg6IG51bWJlcixcbiAgICBvcmlnaW5hbEhlaWdodDogbnVtYmVyLFxuICAgIG1heFdpZHRoOiBudW1iZXIsXG4gICAgbWF4SGVpZ2h0OiBudW1iZXJcbiAgKTogeyB3aWR0aDogbnVtYmVyOyBoZWlnaHQ6IG51bWJlciB9IHtcbiAgICBsZXQgd2lkdGggPSBvcmlnaW5hbFdpZHRoO1xuICAgIGxldCBoZWlnaHQgPSBvcmlnaW5hbEhlaWdodDtcblxuICAgIC8vIFNjYWxlIGRvd24gaWYgbmVjZXNzYXJ5LCBtYWludGFpbmluZyBhc3BlY3QgcmF0aW9cbiAgICBpZiAod2lkdGggPiBtYXhXaWR0aCkge1xuICAgICAgaGVpZ2h0ID0gKGhlaWdodCAqIG1heFdpZHRoKSAvIHdpZHRoO1xuICAgICAgd2lkdGggPSBtYXhXaWR0aDtcbiAgICB9XG5cbiAgICBpZiAoaGVpZ2h0ID4gbWF4SGVpZ2h0KSB7XG4gICAgICB3aWR0aCA9ICh3aWR0aCAqIG1heEhlaWdodCkgLyBoZWlnaHQ7XG4gICAgICBoZWlnaHQgPSBtYXhIZWlnaHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHdpZHRoOiBNYXRoLnJvdW5kKHdpZHRoKSxcbiAgICAgIGhlaWdodDogTWF0aC5yb3VuZChoZWlnaHQpLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGNhbnZhc1RvQmxvYihcbiAgICBjYW52YXM6IEhUTUxDYW52YXNFbGVtZW50LFxuICAgIG1pbWVUeXBlOiBzdHJpbmcsXG4gICAgcXVhbGl0eTogbnVtYmVyXG4gICk6IFByb21pc2U8QmxvYj4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjYW52YXMudG9CbG9iKFxuICAgICAgICAoYmxvYikgPT4ge1xuICAgICAgICAgIGlmIChibG9iKSByZXNvbHZlKGJsb2IpO1xuICAgICAgICAgIGVsc2UgcmVqZWN0KG5ldyBFcnJvcignRmFpbGVkIHRvIGNyZWF0ZSBibG9iIGZyb20gY2FudmFzJykpO1xuICAgICAgICB9LFxuICAgICAgICBtaW1lVHlwZSxcbiAgICAgICAgcXVhbGl0eVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxufVxuIl19
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
export * from './image.service';
|
|
2
|
-
export * from './types';
|
|
3
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ltYWdlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2ltYWdlLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi90eXBlcyc7XG4iXX0=
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default values for image processing
|
|
3
|
-
*/
|
|
4
|
-
export const IMAGE_DEFAULTS = {
|
|
5
|
-
maxWidth: 800,
|
|
6
|
-
maxHeight: 800,
|
|
7
|
-
quality: 0.8,
|
|
8
|
-
mimeType: 'image/jpeg',
|
|
9
|
-
maxSize: 10 * 1024 * 1024, // 10MB
|
|
10
|
-
allowedTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif'],
|
|
11
|
-
thumbnailSize: 150,
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ltYWdlL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQW1FQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRztJQUM1QixRQUFRLEVBQUUsR0FBRztJQUNiLFNBQVMsRUFBRSxHQUFHO0lBQ2QsT0FBTyxFQUFFLEdBQUc7SUFDWixRQUFRLEVBQUUsWUFBcUI7SUFDL0IsT0FBTyxFQUFFLEVBQUUsR0FBRyxJQUFJLEdBQUcsSUFBSSxFQUFFLE9BQU87SUFDbEMsWUFBWSxFQUFFLENBQUMsWUFBWSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsV0FBVyxDQUFDO0lBQ3BFLGFBQWEsRUFBRSxHQUFHO0NBQ25CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE9wdGlvbnMgZm9yIGltYWdlIGNvbXByZXNzaW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSW1hZ2VDb21wcmVzc09wdGlvbnMge1xuICAvKiogTWF4aW11bSB3aWR0aCBpbiBwaXhlbHMgKGRlZmF1bHQ6IDgwMCkgKi9cbiAgbWF4V2lkdGg/OiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIGhlaWdodCBpbiBwaXhlbHMgKGRlZmF1bHQ6IDgwMCkgKi9cbiAgbWF4SGVpZ2h0PzogbnVtYmVyO1xuICAvKiogUXVhbGl0eSAwLTEgKGRlZmF1bHQ6IDAuOCkgKi9cbiAgcXVhbGl0eT86IG51bWJlcjtcbiAgLyoqIE91dHB1dCBNSU1FIHR5cGUgKGRlZmF1bHQ6ICdpbWFnZS9qcGVnJykgKi9cbiAgbWltZVR5cGU/OiAnaW1hZ2UvanBlZycgfCAnaW1hZ2UvcG5nJyB8ICdpbWFnZS93ZWJwJztcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBpbWFnZSB2YWxpZGF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSW1hZ2VWYWxpZGF0ZU9wdGlvbnMge1xuICAvKiogTWF4aW11bSBmaWxlIHNpemUgaW4gYnl0ZXMgKGRlZmF1bHQ6IDEwTUIpICovXG4gIG1heFNpemU/OiBudW1iZXI7XG4gIC8qKiBBbGxvd2VkIE1JTUUgdHlwZXMgKGRlZmF1bHQ6IFsnaW1hZ2UvanBlZycsICdpbWFnZS9wbmcnLCAnaW1hZ2Uvd2VicCcsICdpbWFnZS9naWYnXSkgKi9cbiAgYWxsb3dlZFR5cGVzPzogc3RyaW5nW107XG4gIC8qKiBNaW5pbXVtIHdpZHRoIGluIHBpeGVscyAqL1xuICBtaW5XaWR0aD86IG51bWJlcjtcbiAgLyoqIE1pbmltdW0gaGVpZ2h0IGluIHBpeGVscyAqL1xuICBtaW5IZWlnaHQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIGltYWdlIHZhbGlkYXRpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJbWFnZVZhbGlkYXRpb25SZXN1bHQge1xuICB2YWxpZDogYm9vbGVhbjtcbiAgZXJyb3I/OiAnaW52YWxpZFR5cGUnIHwgJ2ZpbGVUb29MYXJnZScgfCAnaW1hZ2VUb29TbWFsbCc7XG4gIG1lc3NhZ2U/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUHJvY2Vzc2VkIGltYWdlIHJlc3VsdFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFByb2Nlc3NlZEltYWdlIHtcbiAgLyoqIFByb2Nlc3NlZCBpbWFnZSBhcyBCbG9iICovXG4gIGJsb2I6IEJsb2I7XG4gIC8qKiBEYXRhIFVSTCBmb3IgcHJldmlldyAqL1xuICBkYXRhVXJsOiBzdHJpbmc7XG4gIC8qKiBGaW5hbCB3aWR0aCBpbiBwaXhlbHMgKi9cbiAgd2lkdGg6IG51bWJlcjtcbiAgLyoqIEZpbmFsIGhlaWdodCBpbiBwaXhlbHMgKi9cbiAgaGVpZ2h0OiBudW1iZXI7XG4gIC8qKiBGaWxlIHNpemUgaW4gYnl0ZXMgKi9cbiAgc2l6ZTogbnVtYmVyO1xufVxuXG4vKipcbiAqIENyb3AgZGF0YSBmb3IgbWFudWFsIGNyb3BwaW5nXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3JvcERhdGEge1xuICAvKiogWCBwb3NpdGlvbiBvZiBjcm9wIGFyZWEgKi9cbiAgeDogbnVtYmVyO1xuICAvKiogWSBwb3NpdGlvbiBvZiBjcm9wIGFyZWEgKi9cbiAgeTogbnVtYmVyO1xuICAvKiogV2lkdGggb2YgY3JvcCBhcmVhICovXG4gIHdpZHRoOiBudW1iZXI7XG4gIC8qKiBIZWlnaHQgb2YgY3JvcCBhcmVhICovXG4gIGhlaWdodDogbnVtYmVyO1xufVxuXG4vKipcbiAqIERlZmF1bHQgdmFsdWVzIGZvciBpbWFnZSBwcm9jZXNzaW5nXG4gKi9cbmV4cG9ydCBjb25zdCBJTUFHRV9ERUZBVUxUUyA9IHtcbiAgbWF4V2lkdGg6IDgwMCxcbiAgbWF4SGVpZ2h0OiA4MDAsXG4gIHF1YWxpdHk6IDAuOCxcbiAgbWltZVR5cGU6ICdpbWFnZS9qcGVnJyBhcyBjb25zdCxcbiAgbWF4U2l6ZTogMTAgKiAxMDI0ICogMTAyNCwgLy8gMTBNQlxuICBhbGxvd2VkVHlwZXM6IFsnaW1hZ2UvanBlZycsICdpbWFnZS9wbmcnLCAnaW1hZ2Uvd2VicCcsICdpbWFnZS9naWYnXSxcbiAgdGh1bWJuYWlsU2l6ZTogMTUwLFxufTtcbiJdfQ==
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from '@angular/core';
|
|
2
|
-
import { ImageCroppedEvent } from 'ngx-image-cropper';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
/**
|
|
5
|
-
* ImageCropComponent
|
|
6
|
-
*
|
|
7
|
-
* A modal-ready component for cropping images with a specified aspect ratio.
|
|
8
|
-
* Uses ngx-image-cropper internally and provides a simple interface.
|
|
9
|
-
*
|
|
10
|
-
* @example Inside an ion-modal
|
|
11
|
-
* ```html
|
|
12
|
-
* <ion-modal [isOpen]="showCropModal">
|
|
13
|
-
* <ng-template>
|
|
14
|
-
* <val-image-crop
|
|
15
|
-
* [image]="selectedFile"
|
|
16
|
-
* [aspectRatio]="1"
|
|
17
|
-
* [roundCropper]="true"
|
|
18
|
-
* (cropComplete)="onCropComplete($event)"
|
|
19
|
-
* (cancel)="showCropModal = false"
|
|
20
|
-
* />
|
|
21
|
-
* </ng-template>
|
|
22
|
-
* </ion-modal>
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
export declare class ImageCropComponent {
|
|
26
|
-
private i18n;
|
|
27
|
-
/** Image file to crop */
|
|
28
|
-
readonly image: import("@angular/core").InputSignal<File>;
|
|
29
|
-
/** Aspect ratio (1 for square, 16/9 for widescreen, etc.) */
|
|
30
|
-
readonly aspectRatio: import("@angular/core").InputSignal<number>;
|
|
31
|
-
/** Use round cropper (for avatars) */
|
|
32
|
-
readonly roundCropper: import("@angular/core").InputSignal<boolean>;
|
|
33
|
-
/** Resize output to specific width (0 = no resize) */
|
|
34
|
-
readonly resizeToWidth: import("@angular/core").InputSignal<number>;
|
|
35
|
-
/** i18n namespace for labels */
|
|
36
|
-
readonly i18nNamespace: import("@angular/core").InputSignal<string>;
|
|
37
|
-
/** Emitted when crop is confirmed with the cropped blob */
|
|
38
|
-
cropComplete: EventEmitter<Blob>;
|
|
39
|
-
/** Emitted when user cancels the crop */
|
|
40
|
-
cancel: EventEmitter<void>;
|
|
41
|
-
/** Emitted when image fails to load */
|
|
42
|
-
loadFailed: EventEmitter<void>;
|
|
43
|
-
/** Internal signal for cropped blob */
|
|
44
|
-
protected croppedBlob: import("@angular/core").WritableSignal<Blob>;
|
|
45
|
-
/** Computed text for cancel button */
|
|
46
|
-
protected cancelText: import("@angular/core").Signal<string>;
|
|
47
|
-
/** Computed text for confirm button */
|
|
48
|
-
protected confirmText: import("@angular/core").Signal<string>;
|
|
49
|
-
/** Computed text for title */
|
|
50
|
-
protected titleText: import("@angular/core").Signal<string>;
|
|
51
|
-
/** Handle crop event from ngx-image-cropper */
|
|
52
|
-
onImageCropped(event: ImageCroppedEvent): void;
|
|
53
|
-
/** Confirm and emit the cropped blob */
|
|
54
|
-
confirmCrop(): void;
|
|
55
|
-
/** Handle load failure */
|
|
56
|
-
onLoadFailed(): void;
|
|
57
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<ImageCropComponent, never>;
|
|
58
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<ImageCropComponent, "val-image-crop", never, { "image": { "alias": "image"; "required": true; "isSignal": true; }; "aspectRatio": { "alias": "aspectRatio"; "required": false; "isSignal": true; }; "roundCropper": { "alias": "roundCropper"; "required": false; "isSignal": true; }; "resizeToWidth": { "alias": "resizeToWidth"; "required": false; "isSignal": true; }; "i18nNamespace": { "alias": "i18nNamespace"; "required": false; "isSignal": true; }; }, { "cropComplete": "cropComplete"; "cancel": "cancel"; "loadFailed": "loadFailed"; }, never, never, true, never>;
|
|
59
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './image-crop.component';
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { ElementRef, EventEmitter } from '@angular/core';
|
|
2
|
-
import { AvatarUploadError, AvatarUploadMetadata, AvatarUploadResult } from './types';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
/**
|
|
5
|
-
* AvatarUploadComponent
|
|
6
|
-
*
|
|
7
|
-
* A complete avatar upload solution with:
|
|
8
|
-
* - Image selection from device
|
|
9
|
-
* - Crop modal with round preview
|
|
10
|
-
* - Automatic compression and thumbnail generation
|
|
11
|
-
* - Upload to Firebase Storage
|
|
12
|
-
* - Backend sync via AuthService
|
|
13
|
-
*
|
|
14
|
-
* @example Basic usage
|
|
15
|
-
* ```html
|
|
16
|
-
* <val-avatar-upload
|
|
17
|
-
* [props]="{
|
|
18
|
-
* currentUrl: user()?.avatarUrl,
|
|
19
|
-
* initials: 'JD',
|
|
20
|
-
* size: 120
|
|
21
|
-
* }"
|
|
22
|
-
* (uploaded)="onAvatarUploaded($event)"
|
|
23
|
-
* (error)="onError($event)"
|
|
24
|
-
* />
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export declare class AvatarUploadComponent {
|
|
28
|
-
private imageService;
|
|
29
|
-
private storageService;
|
|
30
|
-
private authService;
|
|
31
|
-
private i18n;
|
|
32
|
-
fileInput: ElementRef<HTMLInputElement>;
|
|
33
|
-
/** Component configuration */
|
|
34
|
-
readonly props: import("@angular/core").InputSignal<AvatarUploadMetadata>;
|
|
35
|
-
/** Emitted after successful upload and backend sync */
|
|
36
|
-
uploaded: EventEmitter<AvatarUploadResult>;
|
|
37
|
-
/** Emitted on any error during the process */
|
|
38
|
-
error: EventEmitter<AvatarUploadError>;
|
|
39
|
-
/** Emitted when upload starts */
|
|
40
|
-
uploadStart: EventEmitter<void>;
|
|
41
|
-
protected loading: import("@angular/core").WritableSignal<boolean>;
|
|
42
|
-
protected showCropModal: import("@angular/core").WritableSignal<boolean>;
|
|
43
|
-
protected selectedFile: import("@angular/core").WritableSignal<File>;
|
|
44
|
-
protected previewUrl: import("@angular/core").WritableSignal<string>;
|
|
45
|
-
protected imageLoadError: import("@angular/core").WritableSignal<boolean>;
|
|
46
|
-
/** Merged config with defaults */
|
|
47
|
-
protected config: import("@angular/core").Signal<{
|
|
48
|
-
currentUrl?: string;
|
|
49
|
-
initials?: string;
|
|
50
|
-
backgroundColor: string;
|
|
51
|
-
size: number;
|
|
52
|
-
editable: boolean;
|
|
53
|
-
storagePath: string;
|
|
54
|
-
i18nNamespace: string;
|
|
55
|
-
maxFileSize: number;
|
|
56
|
-
compressQuality: number;
|
|
57
|
-
maxWidth: number;
|
|
58
|
-
thumbnailSize: number;
|
|
59
|
-
}>;
|
|
60
|
-
/** URL to display (preview takes priority over current) */
|
|
61
|
-
protected displayUrl: import("@angular/core").Signal<string>;
|
|
62
|
-
/** Aria label for edit button */
|
|
63
|
-
protected editButtonLabel: import("@angular/core").Signal<string>;
|
|
64
|
-
/** Open file picker dialog */
|
|
65
|
-
openFilePicker(): void;
|
|
66
|
-
/** Handle file selection */
|
|
67
|
-
onFileSelected(event: Event): void;
|
|
68
|
-
/** Handle crop completion */
|
|
69
|
-
onCropComplete(croppedBlob: Blob): Promise<void>;
|
|
70
|
-
/** Handle crop cancel */
|
|
71
|
-
onCropCancel(): void;
|
|
72
|
-
/** Handle crop load failure */
|
|
73
|
-
onCropLoadFailed(): void;
|
|
74
|
-
/** Handle image load error */
|
|
75
|
-
onImageError(): void;
|
|
76
|
-
/** Process cropped image and upload */
|
|
77
|
-
private processAndUpload;
|
|
78
|
-
/** Emit error event */
|
|
79
|
-
private emitError;
|
|
80
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<AvatarUploadComponent, never>;
|
|
81
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<AvatarUploadComponent, "val-avatar-upload", never, { "props": { "alias": "props"; "required": false; "isSignal": true; }; }, { "uploaded": "uploaded"; "error": "error"; "uploadStart": "uploadStart"; }, never, never, true, never>;
|
|
82
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration for AvatarUploadComponent
|
|
3
|
-
*/
|
|
4
|
-
export interface AvatarUploadMetadata {
|
|
5
|
-
/** Current avatar URL */
|
|
6
|
-
currentUrl?: string;
|
|
7
|
-
/** Initials to show when no avatar (e.g., "JD" for John Doe) */
|
|
8
|
-
initials?: string;
|
|
9
|
-
/** Background color for initials avatar */
|
|
10
|
-
backgroundColor?: string;
|
|
11
|
-
/** Avatar size in pixels (default: 100) */
|
|
12
|
-
size?: number;
|
|
13
|
-
/** Show edit button (default: true) */
|
|
14
|
-
editable?: boolean;
|
|
15
|
-
/** Storage path prefix without userId (default: 'avatars') */
|
|
16
|
-
storagePath?: string;
|
|
17
|
-
/** i18n namespace for labels (default: 'AvatarUpload') */
|
|
18
|
-
i18nNamespace?: string;
|
|
19
|
-
/** Max file size in bytes (default: 10MB) */
|
|
20
|
-
maxFileSize?: number;
|
|
21
|
-
/** Quality for compressed image 0-1 (default: 0.8) */
|
|
22
|
-
compressQuality?: number;
|
|
23
|
-
/** Max width for avatar (default: 800) */
|
|
24
|
-
maxWidth?: number;
|
|
25
|
-
/** Thumbnail size (default: 150) */
|
|
26
|
-
thumbnailSize?: number;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Result emitted after successful upload
|
|
30
|
-
*/
|
|
31
|
-
export interface AvatarUploadResult {
|
|
32
|
-
/** Full-size avatar URL */
|
|
33
|
-
avatarUrl: string;
|
|
34
|
-
/** Thumbnail URL */
|
|
35
|
-
thumbnailUrl: string;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Error types that can occur during upload
|
|
39
|
-
*/
|
|
40
|
-
export type AvatarUploadErrorType = 'invalidType' | 'fileTooLarge' | 'uploadFailed' | 'backendFailed' | 'cancelled';
|
|
41
|
-
/**
|
|
42
|
-
* Error object emitted on failure
|
|
43
|
-
*/
|
|
44
|
-
export interface AvatarUploadError {
|
|
45
|
-
type: AvatarUploadErrorType;
|
|
46
|
-
message: string;
|
|
47
|
-
originalError?: unknown;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Default values
|
|
51
|
-
*/
|
|
52
|
-
export declare const AVATAR_UPLOAD_DEFAULTS: {
|
|
53
|
-
size: number;
|
|
54
|
-
editable: boolean;
|
|
55
|
-
storagePath: string;
|
|
56
|
-
i18nNamespace: string;
|
|
57
|
-
maxFileSize: number;
|
|
58
|
-
compressQuality: number;
|
|
59
|
-
maxWidth: number;
|
|
60
|
-
thumbnailSize: number;
|
|
61
|
-
backgroundColor: string;
|
|
62
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { CropData, ImageCompressOptions, ImageValidateOptions, ImageValidationResult, ProcessedImage } from './types';
|
|
2
|
-
import * as i0 from "@angular/core";
|
|
3
|
-
/**
|
|
4
|
-
* ImageService
|
|
5
|
-
*
|
|
6
|
-
* Service for image processing including compression, thumbnails, cropping and validation.
|
|
7
|
-
* Uses HTML Canvas for all operations - no external dependencies.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* const imageService = inject(ImageService);
|
|
12
|
-
*
|
|
13
|
-
* // Compress an image
|
|
14
|
-
* const compressed = await imageService.compress(file, { maxWidth: 800, quality: 0.8 });
|
|
15
|
-
*
|
|
16
|
-
* // Generate thumbnail
|
|
17
|
-
* const thumb = await imageService.thumbnail(file, 150);
|
|
18
|
-
*
|
|
19
|
-
* // Validate before processing
|
|
20
|
-
* const validation = imageService.validate(file, { maxSize: 5 * 1024 * 1024 });
|
|
21
|
-
* if (!validation.valid) {
|
|
22
|
-
* console.error(validation.message);
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
export declare class ImageService {
|
|
27
|
-
/**
|
|
28
|
-
* Compress an image maintaining aspect ratio
|
|
29
|
-
* @param file - File or Blob to compress
|
|
30
|
-
* @param options - Compression options
|
|
31
|
-
* @returns Promise with processed image data
|
|
32
|
-
*/
|
|
33
|
-
compress(file: File | Blob, options?: ImageCompressOptions): Promise<ProcessedImage>;
|
|
34
|
-
/**
|
|
35
|
-
* Generate a square thumbnail from an image
|
|
36
|
-
* @param file - File or Blob to process
|
|
37
|
-
* @param size - Thumbnail size in pixels (default: 150)
|
|
38
|
-
* @returns Promise with processed thumbnail
|
|
39
|
-
*/
|
|
40
|
-
thumbnail(file: File | Blob, size?: number): Promise<ProcessedImage>;
|
|
41
|
-
/**
|
|
42
|
-
* Crop an image with specific coordinates
|
|
43
|
-
* @param file - File or Blob to crop
|
|
44
|
-
* @param cropData - Crop coordinates and dimensions
|
|
45
|
-
* @param options - Optional compression options for output
|
|
46
|
-
* @returns Promise with cropped image
|
|
47
|
-
*/
|
|
48
|
-
crop(file: File | Blob, cropData: CropData, options?: ImageCompressOptions): Promise<ProcessedImage>;
|
|
49
|
-
/**
|
|
50
|
-
* Validate an image file before processing
|
|
51
|
-
* @param file - File to validate
|
|
52
|
-
* @param options - Validation options
|
|
53
|
-
* @returns Validation result with error details if invalid
|
|
54
|
-
*/
|
|
55
|
-
validate(file: File, options?: ImageValidateOptions): ImageValidationResult;
|
|
56
|
-
/**
|
|
57
|
-
* Validate image dimensions (async - requires loading image)
|
|
58
|
-
* @param file - File to validate
|
|
59
|
-
* @param options - Validation options with minWidth/minHeight
|
|
60
|
-
* @returns Promise with validation result
|
|
61
|
-
*/
|
|
62
|
-
validateDimensions(file: File, options: Pick<ImageValidateOptions, 'minWidth' | 'minHeight'>): Promise<ImageValidationResult>;
|
|
63
|
-
/**
|
|
64
|
-
* Convert a Blob/File to a data URL
|
|
65
|
-
*/
|
|
66
|
-
toDataUrl(file: File | Blob): Promise<string>;
|
|
67
|
-
/**
|
|
68
|
-
* Convert a data URL to a Blob
|
|
69
|
-
*/
|
|
70
|
-
dataUrlToBlob(dataUrl: string): Blob;
|
|
71
|
-
private loadImage;
|
|
72
|
-
private calculateDimensions;
|
|
73
|
-
private canvasToBlob;
|
|
74
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<ImageService, never>;
|
|
75
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<ImageService>;
|
|
76
|
-
}
|