app-studio 0.6.60 → 0.7.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/dist/app-studio.cjs.development.js +47 -15
- package/dist/app-studio.cjs.development.js.map +1 -1
- package/dist/app-studio.cjs.production.min.js +1 -1
- package/dist/app-studio.esm.js +47 -15
- package/dist/app-studio.esm.js.map +1 -1
- package/dist/app-studio.umd.development.js +47 -15
- package/dist/app-studio.umd.development.js.map +1 -1
- package/dist/app-studio.umd.production.min.js +1 -1
- package/dist/hooks/useScroll.d.ts +2 -0
- package/dist/providers/WindowSize.d.ts +1 -1
- package/dist/stories/Animation.stories.d.ts +5 -0
- package/dist/stories/IframeSupport.stories.d.ts +1 -0
- package/dist/stories/ScrollTimeline.stories.d.ts +0 -1
- package/package.json +1 -1
|
@@ -1807,7 +1807,9 @@ const cssProperties = /*#__PURE__*/new Set([
|
|
|
1807
1807
|
// Borders
|
|
1808
1808
|
'border', 'borderWidth', 'borderStyle', 'borderColor', 'borderRadius', 'borderTop', 'borderRight', 'borderBottom', 'borderLeft', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomLeftRadius', 'borderBottomRightRadius',
|
|
1809
1809
|
// Effects
|
|
1810
|
-
'boxShadow', 'textShadow', 'transform', 'transition', 'animation', '
|
|
1810
|
+
'boxShadow', 'textShadow', 'transform', 'transition', 'animation', 'animationName', 'animationDuration', 'animationTimingFunction', 'animationDelay', 'animationIterationCount', 'animationDirection', 'animationFillMode', 'animationPlayState',
|
|
1811
|
+
// Scroll-driven animation properties (CSS Scroll-Driven Animations spec)
|
|
1812
|
+
'animationTimeline', 'animationRange', 'animationRangeStart', 'animationRangeEnd', 'scrollTimeline', 'scrollTimelineName', 'scrollTimelineAxis', 'viewTimeline', 'viewTimelineName', 'viewTimelineAxis', 'viewTimelineInset', 'filter', 'backdropFilter', 'mixBlendMode',
|
|
1811
1813
|
// Layout
|
|
1812
1814
|
'display', 'visibility', 'overflow', 'overflowX', 'overflowY', 'float', 'clear', 'objectFit', 'objectPosition',
|
|
1813
1815
|
// Interactivity
|
|
@@ -1924,8 +1926,10 @@ const generateKeyframes = animation => {
|
|
|
1924
1926
|
playState,
|
|
1925
1927
|
timeline,
|
|
1926
1928
|
range,
|
|
1927
|
-
|
|
1929
|
+
keyframes: explicitKeyframes,
|
|
1930
|
+
...rest
|
|
1928
1931
|
} = animation;
|
|
1932
|
+
const keyframesDef = explicitKeyframes || rest;
|
|
1929
1933
|
// Générer une clé pour le cache basée sur les keyframes
|
|
1930
1934
|
const animationConfigString = JSON.stringify(keyframesDef);
|
|
1931
1935
|
if (keyframesCache.has(animationConfigString)) {
|
|
@@ -1952,14 +1956,14 @@ const generateKeyframes = animation => {
|
|
|
1952
1956
|
const styles = keyframesDef[key];
|
|
1953
1957
|
keyframesContent.push(`${cssKey} { ${styleObjectToCss(styles)} }`);
|
|
1954
1958
|
});
|
|
1955
|
-
const
|
|
1959
|
+
const keyframesCss = `
|
|
1956
1960
|
@keyframes ${keyframesName} {
|
|
1957
1961
|
${keyframesContent.join('\n')}
|
|
1958
1962
|
}
|
|
1959
1963
|
`;
|
|
1960
1964
|
return {
|
|
1961
1965
|
keyframesName,
|
|
1962
|
-
keyframes
|
|
1966
|
+
keyframes: keyframesCss
|
|
1963
1967
|
};
|
|
1964
1968
|
};
|
|
1965
1969
|
|
|
@@ -2212,16 +2216,28 @@ const AnimationUtils = {
|
|
|
2212
2216
|
(manager || utilityClassManager).injectRule(keyframes);
|
|
2213
2217
|
}
|
|
2214
2218
|
result.names.push(keyframesName);
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2219
|
-
|
|
2219
|
+
// For scroll-driven animations (with timeline), use 'auto' duration
|
|
2220
|
+
// For time-based animations, parse the duration normally
|
|
2221
|
+
const hasTimeline = !!animation.timeline;
|
|
2222
|
+
if (hasTimeline) {
|
|
2223
|
+
// Scroll-driven animations should use 'auto' duration
|
|
2224
|
+
// unless explicitly specified
|
|
2225
|
+
result.durations.push(animation.duration || 'auto');
|
|
2226
|
+
// Don't accumulate time for scroll-driven animations
|
|
2227
|
+
result.delays.push(animation.delay || '0s');
|
|
2228
|
+
} else {
|
|
2229
|
+
const durationMs = this.parseDuration(animation.duration || '0s');
|
|
2230
|
+
const delayMs = this.parseDuration(animation.delay || '0s');
|
|
2231
|
+
const totalDelayMs = cumulativeTime + delayMs;
|
|
2232
|
+
cumulativeTime = totalDelayMs + durationMs;
|
|
2233
|
+
result.durations.push(this.formatDuration(durationMs));
|
|
2234
|
+
result.delays.push(this.formatDuration(totalDelayMs));
|
|
2235
|
+
}
|
|
2220
2236
|
result.timingFunctions.push(animation.timingFunction || 'ease');
|
|
2221
|
-
result.delays.push(this.formatDuration(totalDelayMs));
|
|
2222
2237
|
result.iterationCounts.push(animation.iterationCount !== undefined ? `${animation.iterationCount}` : '1');
|
|
2223
2238
|
result.directions.push(animation.direction || 'normal');
|
|
2224
|
-
|
|
2239
|
+
// Default to 'both' fillMode for scroll-driven animations, 'none' for time-based
|
|
2240
|
+
result.fillModes.push(animation.fillMode || (hasTimeline ? 'both' : 'none'));
|
|
2225
2241
|
result.playStates.push(animation.playState || 'running');
|
|
2226
2242
|
result.timelines.push(animation.timeline || '');
|
|
2227
2243
|
result.ranges.push(animation.range || '');
|
|
@@ -5528,7 +5544,7 @@ const useScroll = function (_temp) {
|
|
|
5528
5544
|
}, [handleScroll, disabled, getContext]);
|
|
5529
5545
|
return scrollPosition;
|
|
5530
5546
|
};
|
|
5531
|
-
// Enhanced useScrollAnimation with callback support
|
|
5547
|
+
// Enhanced useScrollAnimation with callback support and iframe support
|
|
5532
5548
|
const useScrollAnimation = function (ref, options) {
|
|
5533
5549
|
if (options === void 0) {
|
|
5534
5550
|
options = {};
|
|
@@ -5538,7 +5554,23 @@ const useScrollAnimation = function (ref, options) {
|
|
|
5538
5554
|
React.useEffect(() => {
|
|
5539
5555
|
const element = ref.current;
|
|
5540
5556
|
if (!element) return;
|
|
5541
|
-
|
|
5557
|
+
// Auto-detect iframe context from element's ownerDocument
|
|
5558
|
+
const elementWindow = element.ownerDocument?.defaultView;
|
|
5559
|
+
const targetWindow = options.targetWindow ?? elementWindow;
|
|
5560
|
+
// If no valid window context, bail out
|
|
5561
|
+
if (!targetWindow) return;
|
|
5562
|
+
// Use the IntersectionObserver from the target window context
|
|
5563
|
+
// This is crucial for iframe support - we need to use the iframe's
|
|
5564
|
+
// IntersectionObserver, not the parent window's
|
|
5565
|
+
const ObserverClass = targetWindow.IntersectionObserver;
|
|
5566
|
+
if (!ObserverClass) return;
|
|
5567
|
+
// Determine effective root:
|
|
5568
|
+
// 1. If explicit root provided, use it
|
|
5569
|
+
// 2. Otherwise use null (default viewport of the target window)
|
|
5570
|
+
// Note: When using the iframe's IntersectionObserver with null root,
|
|
5571
|
+
// it correctly observes relative to the iframe's viewport
|
|
5572
|
+
const effectiveRoot = options.root !== undefined ? options.root : null;
|
|
5573
|
+
const observer = new ObserverClass(entries => {
|
|
5542
5574
|
const entry = entries[0];
|
|
5543
5575
|
setIsInView(entry.isIntersecting);
|
|
5544
5576
|
setProgress(entry.intersectionRatio);
|
|
@@ -5546,11 +5578,11 @@ const useScrollAnimation = function (ref, options) {
|
|
|
5546
5578
|
}, {
|
|
5547
5579
|
threshold: options.threshold ?? 0,
|
|
5548
5580
|
rootMargin: options.rootMargin ?? '0px',
|
|
5549
|
-
root:
|
|
5581
|
+
root: effectiveRoot
|
|
5550
5582
|
});
|
|
5551
5583
|
observer.observe(element);
|
|
5552
5584
|
return () => observer.disconnect();
|
|
5553
|
-
}, [ref, options.threshold, options.rootMargin, options.root, options.onIntersectionChange]);
|
|
5585
|
+
}, [ref, options.threshold, options.rootMargin, options.root, options.targetWindow, options.onIntersectionChange]);
|
|
5554
5586
|
return {
|
|
5555
5587
|
isInView,
|
|
5556
5588
|
progress
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-studio.cjs.development.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-studio.cjs.development.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|