app-studio 0.7.8 → 0.7.9
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 +100 -74
- 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 +100 -74
- package/dist/app-studio.esm.js.map +1 -1
- package/dist/app-studio.umd.development.js +100 -74
- package/dist/app-studio.umd.development.js.map +1 -1
- package/dist/app-studio.umd.production.min.js +1 -1
- package/dist/stories/IframeSupport.stories.d.ts +3 -0
- package/package.json +8 -1
package/dist/app-studio.esm.js
CHANGED
|
@@ -1059,12 +1059,15 @@ const deepMerge = (target, source) => {
|
|
|
1059
1059
|
}
|
|
1060
1060
|
return merged;
|
|
1061
1061
|
};
|
|
1062
|
+
// Stable default references to prevent unnecessary re-renders and cache invalidation
|
|
1063
|
+
const DEFAULT_THEME_OVERRIDE = {};
|
|
1064
|
+
const DEFAULT_COLORS_OVERRIDE = {};
|
|
1062
1065
|
const ThemeProvider = _ref => {
|
|
1063
1066
|
let {
|
|
1064
|
-
theme: themeOverride =
|
|
1067
|
+
theme: themeOverride = DEFAULT_THEME_OVERRIDE,
|
|
1065
1068
|
mode: initialMode = 'light',
|
|
1066
|
-
dark: darkOverride =
|
|
1067
|
-
light: lightOverride =
|
|
1069
|
+
dark: darkOverride = DEFAULT_COLORS_OVERRIDE,
|
|
1070
|
+
light: lightOverride = DEFAULT_COLORS_OVERRIDE,
|
|
1068
1071
|
children,
|
|
1069
1072
|
strict = false,
|
|
1070
1073
|
targetWindow
|
|
@@ -2943,10 +2946,11 @@ const AnalyticsProvider = _ref => {
|
|
|
2943
2946
|
trackEvent,
|
|
2944
2947
|
children
|
|
2945
2948
|
} = _ref;
|
|
2949
|
+
const value = useMemo(() => ({
|
|
2950
|
+
trackEvent
|
|
2951
|
+
}), [trackEvent]);
|
|
2946
2952
|
return /*#__PURE__*/React.createElement(AnalyticsContext.Provider, {
|
|
2947
|
-
value:
|
|
2948
|
-
trackEvent
|
|
2949
|
-
}
|
|
2953
|
+
value: value
|
|
2950
2954
|
}, children);
|
|
2951
2955
|
};
|
|
2952
2956
|
|
|
@@ -2978,12 +2982,10 @@ function hashStyleProps(props) {
|
|
|
2978
2982
|
*/
|
|
2979
2983
|
function useStableStyleMemo(propsToProcess, getColor, mediaQueries, devices, manager, theme) {
|
|
2980
2984
|
const cacheRef = useRef(null);
|
|
2981
|
-
// Compute hash
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
return hashStyleProps(propsToProcess) + '|' + hash(themeHash);
|
|
2986
|
-
}, [propsToProcess, theme]);
|
|
2985
|
+
// Compute hash directly — no useMemo since propsToProcess is always a new
|
|
2986
|
+
// reference (from destructuring), so the memo deps would always change.
|
|
2987
|
+
const themeHash = theme ? JSON.stringify(theme) : '';
|
|
2988
|
+
const currentHash = hashStyleProps(propsToProcess) + '|' + hash(themeHash);
|
|
2987
2989
|
// Only recompute classes if hash changed
|
|
2988
2990
|
if (!cacheRef.current || cacheRef.current.hash !== currentHash) {
|
|
2989
2991
|
const classes = extractUtilityClasses(propsToProcess, getColor, mediaQueries, devices, manager);
|
|
@@ -3075,44 +3077,44 @@ const Element = /*#__PURE__*/React.memo(/*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
3075
3077
|
};
|
|
3076
3078
|
}, [animateOut, manager]);
|
|
3077
3079
|
// Prepare props for processing (apply view/scroll timeline if needed)
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
}
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
}
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
}
|
|
3080
|
+
// No useMemo — `rest` is always a new reference from destructuring, so
|
|
3081
|
+
// memo deps would always change. useStableStyleMemo handles the real
|
|
3082
|
+
// memoization via hash-based comparison.
|
|
3083
|
+
const propsToProcess = {
|
|
3084
|
+
...rest,
|
|
3085
|
+
blend
|
|
3086
|
+
};
|
|
3087
|
+
// Apply view() timeline ONLY if animateOn='View' (not Both or Mount)
|
|
3088
|
+
if (animateOn === 'View' && propsToProcess.animate) {
|
|
3089
|
+
const animations = Array.isArray(propsToProcess.animate) ? propsToProcess.animate : [propsToProcess.animate];
|
|
3090
|
+
propsToProcess.animate = animations.map(anim => {
|
|
3091
|
+
// Only add timeline if not already specified
|
|
3092
|
+
if (!anim.timeline) {
|
|
3093
|
+
return {
|
|
3094
|
+
...anim,
|
|
3095
|
+
timeline: 'view()',
|
|
3096
|
+
range: anim.range || 'entry',
|
|
3097
|
+
fillMode: anim.fillMode || 'both'
|
|
3098
|
+
};
|
|
3099
|
+
}
|
|
3100
|
+
return anim;
|
|
3101
|
+
});
|
|
3102
|
+
}
|
|
3103
|
+
// Apply scroll() timeline if animateOn='Scroll'
|
|
3104
|
+
if (animateOn === 'Scroll' && propsToProcess.animate) {
|
|
3105
|
+
const animations = Array.isArray(propsToProcess.animate) ? propsToProcess.animate : [propsToProcess.animate];
|
|
3106
|
+
propsToProcess.animate = animations.map(anim => {
|
|
3107
|
+
// Only add timeline if not already specified
|
|
3108
|
+
if (!anim.timeline) {
|
|
3109
|
+
return {
|
|
3110
|
+
...anim,
|
|
3111
|
+
timeline: 'scroll()',
|
|
3112
|
+
fillMode: anim.fillMode || 'both'
|
|
3113
|
+
};
|
|
3114
|
+
}
|
|
3115
|
+
return anim;
|
|
3116
|
+
});
|
|
3117
|
+
}
|
|
3116
3118
|
// Use hash-based memoization for style extraction
|
|
3117
3119
|
const utilityClasses = useStableStyleMemo(propsToProcess, getColor, mediaQueries, devices, manager, theme);
|
|
3118
3120
|
const newProps = {
|
|
@@ -5034,14 +5036,28 @@ const WindowSizeProvider = _ref => {
|
|
|
5034
5036
|
width: win?.innerWidth || 0,
|
|
5035
5037
|
height: win?.innerHeight || 0
|
|
5036
5038
|
});
|
|
5039
|
+
const timeoutRef = useRef();
|
|
5037
5040
|
useEffect(() => {
|
|
5038
5041
|
if (!win) return;
|
|
5039
|
-
const handleResize = () =>
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5042
|
+
const handleResize = () => {
|
|
5043
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
5044
|
+
timeoutRef.current = setTimeout(() => {
|
|
5045
|
+
const newWidth = win.innerWidth;
|
|
5046
|
+
const newHeight = win.innerHeight;
|
|
5047
|
+
setSize(prev => {
|
|
5048
|
+
if (prev.width === newWidth && prev.height === newHeight) return prev;
|
|
5049
|
+
return {
|
|
5050
|
+
width: newWidth,
|
|
5051
|
+
height: newHeight
|
|
5052
|
+
};
|
|
5053
|
+
});
|
|
5054
|
+
}, 100);
|
|
5055
|
+
};
|
|
5043
5056
|
win.addEventListener('resize', handleResize);
|
|
5044
|
-
return () =>
|
|
5057
|
+
return () => {
|
|
5058
|
+
win.removeEventListener('resize', handleResize);
|
|
5059
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
5060
|
+
};
|
|
5045
5061
|
}, [win]);
|
|
5046
5062
|
return /*#__PURE__*/React.createElement(WindowSizeContext.Provider, {
|
|
5047
5063
|
value: size
|
|
@@ -5074,12 +5090,13 @@ function useActive() {
|
|
|
5074
5090
|
return [ref, active];
|
|
5075
5091
|
}
|
|
5076
5092
|
|
|
5093
|
+
const DEFAULT_CLICK_OUTSIDE_OPTIONS = {};
|
|
5077
5094
|
function useClickOutside(options) {
|
|
5078
5095
|
const [clickedOutside, setClickedOutside] = useState(false);
|
|
5079
5096
|
const ref = useRef(null);
|
|
5080
5097
|
const {
|
|
5081
5098
|
targetWindow
|
|
5082
|
-
} = options ||
|
|
5099
|
+
} = options || DEFAULT_CLICK_OUTSIDE_OPTIONS;
|
|
5083
5100
|
useEffect(() => {
|
|
5084
5101
|
const win = targetWindow || (typeof window !== 'undefined' ? window : null);
|
|
5085
5102
|
if (!win) return;
|
|
@@ -5099,13 +5116,14 @@ function useClickOutside(options) {
|
|
|
5099
5116
|
return [ref, clickedOutside];
|
|
5100
5117
|
}
|
|
5101
5118
|
|
|
5119
|
+
const DEFAULT_ELEMENT_POSITION_OPTIONS = {};
|
|
5102
5120
|
/**
|
|
5103
5121
|
* A React hook to determine an element's relative position within the viewport
|
|
5104
5122
|
* and where the most available space is around it within the viewport.
|
|
5105
5123
|
*/
|
|
5106
5124
|
function useElementPosition(options) {
|
|
5107
5125
|
if (options === void 0) {
|
|
5108
|
-
options =
|
|
5126
|
+
options = DEFAULT_ELEMENT_POSITION_OPTIONS;
|
|
5109
5127
|
}
|
|
5110
5128
|
const {
|
|
5111
5129
|
trackChanges = true,
|
|
@@ -5277,18 +5295,21 @@ function useKeyPress(targetKey) {
|
|
|
5277
5295
|
}
|
|
5278
5296
|
|
|
5279
5297
|
const useMount = callback => {
|
|
5298
|
+
const callbackRef = useRef(callback);
|
|
5299
|
+
callbackRef.current = callback;
|
|
5280
5300
|
useEffect(() => {
|
|
5281
|
-
|
|
5301
|
+
callbackRef.current();
|
|
5282
5302
|
}, []);
|
|
5283
5303
|
};
|
|
5284
5304
|
|
|
5305
|
+
const DEFAULT_ON_SCREEN_OPTIONS = {};
|
|
5285
5306
|
function useOnScreen(options) {
|
|
5286
5307
|
const ref = useRef(null);
|
|
5287
5308
|
const [isOnScreen, setOnScreen] = useState(false);
|
|
5288
5309
|
const {
|
|
5289
5310
|
targetWindow,
|
|
5290
5311
|
...observerOptions
|
|
5291
|
-
} = options ||
|
|
5312
|
+
} = options || DEFAULT_ON_SCREEN_OPTIONS;
|
|
5292
5313
|
useEffect(() => {
|
|
5293
5314
|
const node = ref.current;
|
|
5294
5315
|
if (!node) return;
|
|
@@ -5307,7 +5328,7 @@ function useOnScreen(options) {
|
|
|
5307
5328
|
return () => {
|
|
5308
5329
|
observer.disconnect();
|
|
5309
5330
|
};
|
|
5310
|
-
}, [targetWindow,
|
|
5331
|
+
}, [targetWindow, observerOptions.root, observerOptions.rootMargin, observerOptions.threshold]);
|
|
5311
5332
|
return [ref, isOnScreen];
|
|
5312
5333
|
}
|
|
5313
5334
|
|
|
@@ -5332,14 +5353,14 @@ const useBreakpoint = () => {
|
|
|
5332
5353
|
devices
|
|
5333
5354
|
} = context;
|
|
5334
5355
|
// Helper to check if current screen matches a breakpoint or device
|
|
5335
|
-
const on = s => devices[s] ? devices[s].includes(screen) : s === screen;
|
|
5336
|
-
return {
|
|
5356
|
+
const on = useCallback(s => devices[s] ? devices[s].includes(screen) : s === screen, [devices, screen]);
|
|
5357
|
+
return useMemo(() => ({
|
|
5337
5358
|
...context,
|
|
5338
5359
|
screen,
|
|
5339
5360
|
orientation,
|
|
5340
5361
|
on,
|
|
5341
5362
|
is: on
|
|
5342
|
-
};
|
|
5363
|
+
}), [context, screen, orientation, on]);
|
|
5343
5364
|
};
|
|
5344
5365
|
/**
|
|
5345
5366
|
* Hook for components that need exact window dimensions.
|
|
@@ -5370,17 +5391,21 @@ const useResponsive = () => {
|
|
|
5370
5391
|
orientation,
|
|
5371
5392
|
devices
|
|
5372
5393
|
} = context;
|
|
5373
|
-
const on = s => devices[s] ? devices[s].includes(screen) : s === screen;
|
|
5374
|
-
|
|
5394
|
+
const on = useCallback(s => devices[s] ? devices[s].includes(screen) : s === screen, [devices, screen]);
|
|
5395
|
+
return useMemo(() => ({
|
|
5375
5396
|
...context,
|
|
5376
5397
|
screen,
|
|
5377
5398
|
orientation,
|
|
5378
5399
|
on,
|
|
5379
5400
|
is: on
|
|
5380
|
-
};
|
|
5381
|
-
return result;
|
|
5401
|
+
}), [context, screen, orientation, on]);
|
|
5382
5402
|
};
|
|
5383
5403
|
|
|
5404
|
+
// Stable default references to prevent unnecessary re-renders
|
|
5405
|
+
const DEFAULT_SCROLL_OFFSET = [0, 0];
|
|
5406
|
+
const DEFAULT_SCROLL_OPTIONS = {};
|
|
5407
|
+
const DEFAULT_SCROLL_ANIMATION_OPTIONS = {};
|
|
5408
|
+
const DEFAULT_INFINITE_SCROLL_OPTIONS = {};
|
|
5384
5409
|
// Helper to check if element is a Window object (works across iframes)
|
|
5385
5410
|
const isWindow = obj => {
|
|
5386
5411
|
return obj && obj.window === obj;
|
|
@@ -5414,10 +5439,10 @@ const getScrollDimensions = element => {
|
|
|
5414
5439
|
const useScroll = function (_temp) {
|
|
5415
5440
|
let {
|
|
5416
5441
|
container,
|
|
5417
|
-
offset =
|
|
5442
|
+
offset = DEFAULT_SCROLL_OFFSET,
|
|
5418
5443
|
throttleMs = 100,
|
|
5419
5444
|
disabled = false
|
|
5420
|
-
} = _temp === void 0 ?
|
|
5445
|
+
} = _temp === void 0 ? DEFAULT_SCROLL_OPTIONS : _temp;
|
|
5421
5446
|
const [scrollPosition, setScrollPosition] = useState({
|
|
5422
5447
|
x: 0,
|
|
5423
5448
|
y: 0,
|
|
@@ -5556,7 +5581,7 @@ const useScroll = function (_temp) {
|
|
|
5556
5581
|
// Enhanced useScrollAnimation with callback support and iframe support
|
|
5557
5582
|
const useScrollAnimation = function (ref, options) {
|
|
5558
5583
|
if (options === void 0) {
|
|
5559
|
-
options =
|
|
5584
|
+
options = DEFAULT_SCROLL_ANIMATION_OPTIONS;
|
|
5560
5585
|
}
|
|
5561
5586
|
const [isInView, setIsInView] = useState(false);
|
|
5562
5587
|
const [progress, setProgress] = useState(0);
|
|
@@ -5624,7 +5649,7 @@ const useSmoothScroll = targetWindow => {
|
|
|
5624
5649
|
// Enhanced useInfiniteScroll with debouncing
|
|
5625
5650
|
const useInfiniteScroll = function (callback, options) {
|
|
5626
5651
|
if (options === void 0) {
|
|
5627
|
-
options =
|
|
5652
|
+
options = DEFAULT_INFINITE_SCROLL_OPTIONS;
|
|
5628
5653
|
}
|
|
5629
5654
|
const [sentinel, setSentinel] = useState(null);
|
|
5630
5655
|
const callbackRef = useRef(callback);
|
|
@@ -5719,12 +5744,13 @@ const useScrollDirection = function (threshold, targetWindow) {
|
|
|
5719
5744
|
|
|
5720
5745
|
const useWindowSize = () => useContext(WindowSizeContext);
|
|
5721
5746
|
|
|
5747
|
+
const DEFAULT_IN_VIEW_OPTIONS = {};
|
|
5722
5748
|
function useInView(options) {
|
|
5723
5749
|
const {
|
|
5724
5750
|
triggerOnce = false,
|
|
5725
5751
|
targetWindow,
|
|
5726
5752
|
...observerOptions
|
|
5727
|
-
} = options ||
|
|
5753
|
+
} = options || DEFAULT_IN_VIEW_OPTIONS;
|
|
5728
5754
|
const ref = useRef(null);
|
|
5729
5755
|
const [inView, setInView] = useState(false);
|
|
5730
5756
|
useEffect(() => {
|
|
@@ -5754,7 +5780,7 @@ function useInView(options) {
|
|
|
5754
5780
|
return () => {
|
|
5755
5781
|
observer.disconnect();
|
|
5756
5782
|
};
|
|
5757
|
-
}, [triggerOnce, targetWindow,
|
|
5783
|
+
}, [triggerOnce, targetWindow, observerOptions.root, observerOptions.rootMargin, observerOptions.threshold]);
|
|
5758
5784
|
return {
|
|
5759
5785
|
ref,
|
|
5760
5786
|
inView
|
|
@@ -5839,7 +5865,7 @@ function useIframe(iframeRef) {
|
|
|
5839
5865
|
if (!iframe) return;
|
|
5840
5866
|
const updateState = () => {
|
|
5841
5867
|
const win = iframe.contentWindow;
|
|
5842
|
-
const doc = iframe.contentDocument
|
|
5868
|
+
const doc = win?.document || iframe.contentDocument;
|
|
5843
5869
|
if (win && doc) {
|
|
5844
5870
|
setIframeWindow(win);
|
|
5845
5871
|
setIframeDocument(doc);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-studio.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-studio.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|