@lumy-pack/scene-sieve 0.1.0 → 0.2.1
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/README.md +128 -42
- package/dist/{commands → cli/commands}/Sieve.d.ts +5 -0
- package/dist/{errors.d.ts → cli/errors/classify-error.d.ts} +5 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/{utils → cli/options}/parse-options.d.ts +11 -2
- package/dist/cli.mjs +1453 -505
- package/dist/constants/package-version.d.ts +2 -0
- package/dist/constants/pipeline-defaults.d.ts +33 -0
- package/dist/core/{analyzer.d.ts → analyzer/analyzer.d.ts} +11 -6
- package/dist/core/{dbscan.d.ts → analyzer/clustering/dbscan.d.ts} +1 -1
- package/dist/core/analyzer/constants/vision-tuning.d.ts +12 -0
- package/dist/core/analyzer/features/feature-diff.d.ts +14 -0
- package/dist/core/analyzer/features/frame-features.d.ts +32 -0
- package/dist/core/analyzer/index.d.ts +3 -0
- package/dist/core/constants/workspace-layout.d.ts +9 -0
- package/dist/core/{extractor.d.ts → extractor/extractor.d.ts} +6 -4
- package/dist/core/extractor/index.d.ts +1 -0
- package/dist/core/index.d.ts +9 -9
- package/dist/core/input-resolver/index.d.ts +1 -0
- package/dist/core/{input-resolver.d.ts → input-resolver/input-resolver.d.ts} +11 -1
- package/dist/core/input-resolver/validation/validate-options.d.ts +8 -0
- package/dist/core/orchestrator/index.d.ts +3 -0
- package/dist/core/orchestrator/orchestrator.d.ts +8 -0
- package/dist/core/{run-in-worker.d.ts → orchestrator/worker/run-in-worker.d.ts} +5 -1
- package/dist/core/pruner/index.d.ts +1 -0
- package/dist/core/{pruner.d.ts → pruner/pruner.d.ts} +2 -2
- package/dist/{utils/math.d.ts → core/pruner/scoring/normalize-scores.d.ts} +4 -0
- package/dist/core/segmenter/index.d.ts +1 -0
- package/dist/core/{segmenter.d.ts → segmenter/segmenter.d.ts} +11 -11
- package/dist/core/utils/metadata/build-edge-metadata.d.ts +11 -0
- package/dist/core/utils/metadata/build-frame-metadata.d.ts +20 -0
- package/dist/core/utils/metadata/build-sieve-metadata.d.ts +14 -0
- package/dist/core/utils/metadata/build-tool-metadata.d.ts +8 -0
- package/dist/core/utils/metadata/build-video-metadata.d.ts +14 -0
- package/dist/core/utils/metadata/change/build-frame-change.d.ts +20 -0
- package/dist/core/utils/metadata/change/select-regions.d.ts +8 -0
- package/dist/core/utils/metadata/change/union-area/y-coverage-tree.d.ts +26 -0
- package/dist/core/utils/metadata/change/union-area.d.ts +7 -0
- package/dist/core/utils/metadata/scale-bounding-box.d.ts +11 -0
- package/dist/core/utils/output/finalize-selection.d.ts +15 -0
- package/dist/core/utils/sheet/build-tile-label-svg.d.ts +8 -0
- package/dist/core/utils/sheet/format-tile-label.d.ts +7 -0
- package/dist/core/utils/sheet/render-contact-sheet.d.ts +19 -0
- package/dist/core/utils/sheet/sample-tile-frames.d.ts +10 -0
- package/dist/core/workspace/index.d.ts +1 -0
- package/dist/core/{workspace.d.ts → workspace/workspace.d.ts} +11 -2
- package/dist/index.cjs +1531 -559
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1533 -558
- package/dist/pipeline-worker.mjs +1213 -404
- package/dist/types/index.d.ts +173 -0
- package/package.json +14 -11
- package/dist/constants.d.ts +0 -32
- package/dist/core/orchestrator.d.ts +0 -2
- /package/dist/{utils → cli/commands}/command-registry.d.ts +0 -0
- /package/dist/{components → cli/components}/PhaseStep.d.ts +0 -0
- /package/dist/{components → cli/components}/ProgressBar.d.ts +0 -0
- /package/dist/core/{pipeline-worker.d.ts → orchestrator/worker/pipeline-worker.d.ts} +0 -0
- /package/dist/{utils → core/pruner/heap}/min-heap.d.ts +0 -0
- /package/dist/{utils → core/segmenter/scheduling}/concurrency.d.ts +0 -0
- /package/dist/{utils → core/utils/filesystem}/paths.d.ts +0 -0
- /package/dist/{utils → logging}/logger.d.ts +0 -0
package/dist/types/index.d.ts
CHANGED
|
@@ -10,10 +10,15 @@ export type SieveInput = {
|
|
|
10
10
|
inputFrames: Buffer[];
|
|
11
11
|
};
|
|
12
12
|
export interface SieveOptionsBase {
|
|
13
|
+
/** Enable a contact sheet with defaults or selected overrides; disabled by default. */
|
|
14
|
+
sheet?: boolean | SheetOptions;
|
|
15
|
+
/** Include adjacent candidate edge diagnostics in the metadata document. */
|
|
16
|
+
includeEdges?: boolean;
|
|
13
17
|
count?: number;
|
|
14
18
|
threshold?: number;
|
|
15
19
|
outputPath?: string;
|
|
16
20
|
fps?: number;
|
|
21
|
+
/** Strict file/buffer candidate frame limit (default: 300); ignored in frames mode. */
|
|
17
22
|
maxFrames?: number;
|
|
18
23
|
scale?: number;
|
|
19
24
|
quality?: number;
|
|
@@ -26,6 +31,10 @@ export interface SieveOptionsBase {
|
|
|
26
31
|
}
|
|
27
32
|
export type SieveOptions = SieveOptionsBase & SieveInput;
|
|
28
33
|
export interface ResolvedOptions {
|
|
34
|
+
/** Complete contact sheet settings, or null when disabled. */
|
|
35
|
+
sheet: Required<SheetOptions> | null;
|
|
36
|
+
/** Whether the document contains candidate edge diagnostics. */
|
|
37
|
+
includeEdges: boolean;
|
|
29
38
|
mode: 'file' | 'buffer' | 'frames';
|
|
30
39
|
inputPath?: string;
|
|
31
40
|
count: number;
|
|
@@ -50,6 +59,12 @@ export interface SieveResult {
|
|
|
50
59
|
outputBuffers?: Buffer[];
|
|
51
60
|
animations?: AnimationMetadata[];
|
|
52
61
|
video?: VideoMetadata;
|
|
62
|
+
/** Selected frames paired with output files or buffers; IDs are one-based. */
|
|
63
|
+
frames?: FrameMetadata[];
|
|
64
|
+
/** Layout of the rendered contact sheet; absent when no sheet exists. */
|
|
65
|
+
sheet?: SheetMetadata;
|
|
66
|
+
/** Encoded contact sheet for buffer and frames modes only. */
|
|
67
|
+
sheetBuffer?: Buffer;
|
|
53
68
|
executionTimeMs: number;
|
|
54
69
|
}
|
|
55
70
|
export interface AnimationMetadata {
|
|
@@ -60,12 +75,24 @@ export interface AnimationMetadata {
|
|
|
60
75
|
durationMs: number;
|
|
61
76
|
}
|
|
62
77
|
export interface VideoMetadata {
|
|
78
|
+
/** Source duration from ffprobe, or the final candidate timestamp in frames mode. */
|
|
63
79
|
originalDurationMs: number;
|
|
80
|
+
/** Effective sampling frequency; frames mode uses one frame per second. */
|
|
64
81
|
fps: number;
|
|
82
|
+
/** Actual output JPEG dimensions; zero when no candidate exists. */
|
|
65
83
|
resolution: {
|
|
66
84
|
width: number;
|
|
67
85
|
height: number;
|
|
68
86
|
};
|
|
87
|
+
/** Number of candidates before pruning. */
|
|
88
|
+
candidatesCount: number;
|
|
89
|
+
/** Number of selected frames after pruning. */
|
|
90
|
+
selectedCount: number;
|
|
91
|
+
/** Input mode and basename only; in-memory inputs have no file name. */
|
|
92
|
+
source: {
|
|
93
|
+
fileName: string | null;
|
|
94
|
+
mode: 'file' | 'buffer' | 'frames';
|
|
95
|
+
};
|
|
69
96
|
}
|
|
70
97
|
export interface FrameNode {
|
|
71
98
|
id: number;
|
|
@@ -84,6 +111,131 @@ export interface ScoreEdge {
|
|
|
84
111
|
* Maps directly to G(t) from the vision analysis pipeline.
|
|
85
112
|
*/
|
|
86
113
|
score: number;
|
|
114
|
+
/** Analysis-space cluster partition; absent on failed pairs and synthetic edges. */
|
|
115
|
+
change?: EdgeChange;
|
|
116
|
+
}
|
|
117
|
+
/** Optional contact sheet overrides, validated before defaults are applied. */
|
|
118
|
+
export interface SheetOptions {
|
|
119
|
+
/** Maximum columns, an integer at least one; defaults to four. */
|
|
120
|
+
columns?: number;
|
|
121
|
+
/** Tile width in pixels, an integer at least sixteen; defaults to 320. */
|
|
122
|
+
tileWidth?: number;
|
|
123
|
+
/** Tile limit, an integer at least two; defaults to forty. */
|
|
124
|
+
maxTiles?: number;
|
|
125
|
+
/** Burn a frame ID and timestamp into each tile; defaults to true. */
|
|
126
|
+
label?: boolean;
|
|
127
|
+
}
|
|
128
|
+
/** Adjacent-pair cluster boxes in analysis coordinates, partitioned by the tracker. */
|
|
129
|
+
export interface EdgeChange {
|
|
130
|
+
/** Non-animation clusters in DBSCAN label order. */
|
|
131
|
+
regions: BoundingBox[];
|
|
132
|
+
/** Clusters whose indices the tracker classified as animation. */
|
|
133
|
+
animatedRegions: BoundingBox[];
|
|
134
|
+
}
|
|
135
|
+
/** Change across the candidate edges between two selected frames. */
|
|
136
|
+
export interface FrameChange {
|
|
137
|
+
/** Previous selected frame ID, one-based. */
|
|
138
|
+
fromFrameId: number;
|
|
139
|
+
/** Candidates pruned between the selected endpoints. */
|
|
140
|
+
skippedCandidates: number;
|
|
141
|
+
/** Maximum raw information gain, rounded to six decimals. */
|
|
142
|
+
peakScore: number;
|
|
143
|
+
/** Sum of raw information gain, rounded to six decimals. */
|
|
144
|
+
sumScore: number;
|
|
145
|
+
/** Non-animation union area fraction, clamped and rounded to four decimals. */
|
|
146
|
+
areaRatio: number;
|
|
147
|
+
/** Up to five distinct largest regions in clamped integer output pixels. */
|
|
148
|
+
regions: BoundingBox[];
|
|
149
|
+
}
|
|
150
|
+
/** Selected frame timing and change signals shared by file and API output. */
|
|
151
|
+
export interface FrameMetadata {
|
|
152
|
+
/** One-based position in the selected sequence. */
|
|
153
|
+
step: number;
|
|
154
|
+
/** Deterministic JPEG name, including for in-memory output pairing. */
|
|
155
|
+
fileName: string;
|
|
156
|
+
/** One-based candidate frame ID. */
|
|
157
|
+
frameId: number;
|
|
158
|
+
/** Rounded candidate timestamp in milliseconds. */
|
|
159
|
+
timestampMs: number;
|
|
160
|
+
/** Nonnegative time until the next selection or the source end. */
|
|
161
|
+
holdsMs: number;
|
|
162
|
+
/** Span summary, or null for the first selection. */
|
|
163
|
+
change: FrameChange | null;
|
|
164
|
+
}
|
|
165
|
+
/** Raw candidate edge diagnostics in graph order. */
|
|
166
|
+
export interface EdgeMetadata {
|
|
167
|
+
/** One-based source candidate ID. */
|
|
168
|
+
sourceFrameId: number;
|
|
169
|
+
/** One-based target candidate ID. */
|
|
170
|
+
targetFrameId: number;
|
|
171
|
+
/** Raw information gain rounded to six decimals. */
|
|
172
|
+
score: number;
|
|
173
|
+
/** Non-animation union area fraction rounded to four decimals. */
|
|
174
|
+
areaRatio: number;
|
|
175
|
+
/** Animation union area fraction rounded to four decimals. */
|
|
176
|
+
animatedAreaRatio: number;
|
|
177
|
+
}
|
|
178
|
+
/** Selection and encoding settings in deterministic serialization order. */
|
|
179
|
+
export interface ToolParams {
|
|
180
|
+
/** Requested extraction frequency, before the candidate cap. */
|
|
181
|
+
fps: number;
|
|
182
|
+
/** Requested maximum selected frame count. */
|
|
183
|
+
count: number;
|
|
184
|
+
/** Normalized pruning threshold. */
|
|
185
|
+
threshold: number;
|
|
186
|
+
/** Analysis image height in pixels. */
|
|
187
|
+
scale: number;
|
|
188
|
+
/** JPEG encoding quality. */
|
|
189
|
+
quality: number;
|
|
190
|
+
/** Strict file/buffer candidate cap. */
|
|
191
|
+
maxFrames: number;
|
|
192
|
+
/** Tracker overlap threshold. */
|
|
193
|
+
iouThreshold: number;
|
|
194
|
+
/** Consecutive frames required for animation classification. */
|
|
195
|
+
animationThreshold: number;
|
|
196
|
+
/** Maximum logical segment duration in seconds. */
|
|
197
|
+
maxSegmentDuration: number;
|
|
198
|
+
}
|
|
199
|
+
/** Tool provenance and reproducible pipeline parameters. */
|
|
200
|
+
export interface ToolMetadata {
|
|
201
|
+
/** Published package identifier. */
|
|
202
|
+
name: '@lumy-pack/scene-sieve';
|
|
203
|
+
/** Version from the runtime package manifest. */
|
|
204
|
+
version: string;
|
|
205
|
+
/** Nine selection and encoding parameters, excluding operational options. */
|
|
206
|
+
params: ToolParams;
|
|
207
|
+
}
|
|
208
|
+
/** Contact sheet layout and sampled frame IDs in tile order. */
|
|
209
|
+
export interface SheetMetadata {
|
|
210
|
+
/** Fixed output name. */
|
|
211
|
+
fileName: 'sheet.jpg';
|
|
212
|
+
/** Effective columns, capped by tile count. */
|
|
213
|
+
columns: number;
|
|
214
|
+
/** Tile width in pixels. */
|
|
215
|
+
tileWidth: number;
|
|
216
|
+
/** Aspect-preserving rounded tile height, at least one pixel. */
|
|
217
|
+
tileHeight: number;
|
|
218
|
+
/** One-based frame IDs ordered left-to-right, then top-to-bottom. */
|
|
219
|
+
frameIds: number[];
|
|
220
|
+
/** Whether the tile limit required uniform sampling. */
|
|
221
|
+
sampled: boolean;
|
|
222
|
+
}
|
|
223
|
+
/** Version-two document; properties are serialized in declaration order. */
|
|
224
|
+
export interface SieveMetadata {
|
|
225
|
+
/** Schema discriminator; absent in version-one documents. */
|
|
226
|
+
metadataVersion: 2;
|
|
227
|
+
/** Runtime tool provenance. */
|
|
228
|
+
tool: ToolMetadata;
|
|
229
|
+
/** Source timing, dimensions and candidate counts. */
|
|
230
|
+
video: VideoMetadata;
|
|
231
|
+
/** Selected frame summaries in temporal order. */
|
|
232
|
+
frames: FrameMetadata[];
|
|
233
|
+
/** Output-space animations with one-based IDs and integer durations. */
|
|
234
|
+
animations: AnimationMetadata[];
|
|
235
|
+
/** Present only when a sheet was rendered. */
|
|
236
|
+
sheet?: SheetMetadata;
|
|
237
|
+
/** Present only when includeEdges was enabled. */
|
|
238
|
+
edges?: EdgeMetadata[];
|
|
87
239
|
}
|
|
88
240
|
export interface BoundingBox {
|
|
89
241
|
x: number;
|
|
@@ -97,6 +249,15 @@ export interface DBSCANResult {
|
|
|
97
249
|
}
|
|
98
250
|
export interface ProcessContext {
|
|
99
251
|
options: ResolvedOptions;
|
|
252
|
+
/** Actual extraction grid frequency; frames mode uses one-second intervals. */
|
|
253
|
+
effectiveFps?: number;
|
|
254
|
+
/** Original video duration reported by ffprobe, in seconds. */
|
|
255
|
+
sourceDurationSec?: number;
|
|
256
|
+
/** Dimensions of analysis-space boxes; absent or zero if no pair was analyzed. */
|
|
257
|
+
analysisResolution?: {
|
|
258
|
+
width: number;
|
|
259
|
+
height: number;
|
|
260
|
+
};
|
|
100
261
|
workspacePath: string;
|
|
101
262
|
frames: FrameNode[];
|
|
102
263
|
graph: ScoreEdge[];
|
|
@@ -108,16 +269,23 @@ export interface ProcessContext {
|
|
|
108
269
|
export interface AnalysisResult {
|
|
109
270
|
edges: ScoreEdge[];
|
|
110
271
|
animations: AnimationMetadata[];
|
|
272
|
+
/** First analyzed image dimensions, or zero dimensions when no pair exists. */
|
|
273
|
+
analysisResolution: {
|
|
274
|
+
width: number;
|
|
275
|
+
height: number;
|
|
276
|
+
};
|
|
111
277
|
}
|
|
112
278
|
export interface SegmentPlan {
|
|
113
279
|
index: number;
|
|
114
280
|
startTime: number;
|
|
115
281
|
endTime: number;
|
|
116
282
|
duration: number;
|
|
283
|
+
/** FFmpeg output limit, including overlap slots; a single segment uses the full budget. */
|
|
117
284
|
allocatedFrames: number;
|
|
118
285
|
effectiveFps: number;
|
|
119
286
|
overlapBefore: number;
|
|
120
287
|
overlapAfter: number;
|
|
288
|
+
/** First extraction grid time in seconds, including overlap. */
|
|
121
289
|
extractStartTime: number;
|
|
122
290
|
extractDuration: number;
|
|
123
291
|
}
|
|
@@ -126,4 +294,9 @@ export interface SegmentResult {
|
|
|
126
294
|
frames: FrameNode[];
|
|
127
295
|
edges: ScoreEdge[];
|
|
128
296
|
animations: AnimationMetadata[];
|
|
297
|
+
/** Analysis coordinates retained through merging for output-only box scaling. */
|
|
298
|
+
analysisResolution: {
|
|
299
|
+
width: number;
|
|
300
|
+
height: number;
|
|
301
|
+
};
|
|
129
302
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumy-pack/scene-sieve",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "CLI tool for extracting key frames from video and GIF files",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
},
|
|
23
23
|
"sideEffects": false,
|
|
24
24
|
"type": "module",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
27
|
+
},
|
|
25
28
|
"exports": {
|
|
26
29
|
".": {
|
|
27
30
|
"types": "./dist/index.d.ts",
|
|
@@ -54,23 +57,23 @@
|
|
|
54
57
|
"version:patch": "yarn version patch"
|
|
55
58
|
},
|
|
56
59
|
"dependencies": {
|
|
57
|
-
"@ffprobe-installer/ffprobe": "^1.
|
|
60
|
+
"@ffprobe-installer/ffprobe": "^2.1.2",
|
|
58
61
|
"@techstark/opencv-js": "4.12.0-release.1",
|
|
59
|
-
"@winglet/common-utils": "^0.
|
|
62
|
+
"@winglet/common-utils": "^0.14.1",
|
|
60
63
|
"commander": "^12.1.0",
|
|
61
|
-
"execa": "^9.
|
|
62
|
-
"ffmpeg-static": "^5.
|
|
63
|
-
"ink": "^
|
|
64
|
+
"execa": "^9.6.1",
|
|
65
|
+
"ffmpeg-static": "^5.3.0",
|
|
66
|
+
"ink": "^6.8.0",
|
|
64
67
|
"ink-spinner": "^5.0.0",
|
|
65
68
|
"picocolors": "^1.1.1",
|
|
66
|
-
"react": "^
|
|
67
|
-
"sharp": "^0.
|
|
69
|
+
"react": "^19.3.0",
|
|
70
|
+
"sharp": "^0.35.4"
|
|
68
71
|
},
|
|
69
72
|
"devDependencies": {
|
|
70
73
|
"@lumy-pack/shared": "0.0.1",
|
|
71
|
-
"@types/node": "^20.
|
|
72
|
-
"@types/react": "^
|
|
74
|
+
"@types/node": "^20.19.43",
|
|
75
|
+
"@types/react": "^19.3.0",
|
|
73
76
|
"@vitest/coverage-v8": "^3.2.4",
|
|
74
|
-
"rolldown": "^1.2.
|
|
77
|
+
"rolldown": "^1.2.8"
|
|
75
78
|
}
|
|
76
79
|
}
|
package/dist/constants.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export declare const APP_NAME = "scene-sieve";
|
|
2
|
-
export declare const DEFAULT_COUNT = 20;
|
|
3
|
-
export declare const DEFAULT_THRESHOLD = 0.5;
|
|
4
|
-
export declare const DEFAULT_FPS = 5;
|
|
5
|
-
export declare const DEFAULT_SCALE = 720;
|
|
6
|
-
export declare const DEFAULT_QUALITY = 80;
|
|
7
|
-
export declare const DEFAULT_MAX_FRAMES = 300;
|
|
8
|
-
export declare const NORMALIZATION_MIN_PERCENTILE = 0.1;
|
|
9
|
-
export declare const NORMALIZATION_MAX_PERCENTILE = 0.9;
|
|
10
|
-
export declare const NORMALIZATION_LOGISTIC_K = 3;
|
|
11
|
-
export declare const NORMALIZATION_ALPHA = 0.4;
|
|
12
|
-
export declare const NORMALIZATION_MAD_COEFFICIENT = 1.4826;
|
|
13
|
-
export declare const NORMALIZATION_MIN_SAMPLE_SIZE = 10;
|
|
14
|
-
export declare const WORKSPACE_PREFIX = "scene-sieve-";
|
|
15
|
-
export declare const TEMP_BASE_DIR: string;
|
|
16
|
-
export declare const FRAME_OUTPUT_EXTENSION = ".jpg";
|
|
17
|
-
export declare const FRAME_FILENAME_PATTERN = "frame_%06d.jpg";
|
|
18
|
-
export declare const OPENCV_BATCH_SIZE = 10;
|
|
19
|
-
export declare const MIN_IFRAME_COUNT = 3;
|
|
20
|
-
export declare const DBSCAN_ALPHA = 0.03;
|
|
21
|
-
export declare const DBSCAN_MIN_PTS = 4;
|
|
22
|
-
export declare const IOU_THRESHOLD = 0.9;
|
|
23
|
-
export declare const DECAY_LAMBDA = 0.95;
|
|
24
|
-
export declare const ANIMATION_FRAME_THRESHOLD = 5;
|
|
25
|
-
export declare const MATCH_DISTANCE_THRESHOLD = 0.25;
|
|
26
|
-
export declare const PIXELDIFF_GAUSSIAN_KERNEL = 3;
|
|
27
|
-
export declare const PIXELDIFF_BINARY_THRESHOLD = 30;
|
|
28
|
-
export declare const PIXELDIFF_CONTOUR_MIN_AREA = 100;
|
|
29
|
-
export declare const PIXELDIFF_SAMPLE_SPACING = 8;
|
|
30
|
-
export declare const DEFAULT_MAX_SEGMENT_DURATION = 300;
|
|
31
|
-
export declare const DEFAULT_SEGMENT_CONCURRENCY = 2;
|
|
32
|
-
export declare function getTempWorkspaceDir(sessionId: string): string;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|