app-studio 0.7.7 → 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.
@@ -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 of current props
2982
- const currentHash = useMemo(() => {
2983
- // Include theme in hash to bust cache on theme changes
2984
- const themeHash = theme ? JSON.stringify(theme) : '';
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
- const propsToProcess = useMemo(() => {
3079
- const processed = {
3080
- ...rest,
3081
- blend
3082
- };
3083
- // Apply view() timeline ONLY if animateOn='View' (not Both or Mount)
3084
- if (animateOn === 'View' && processed.animate) {
3085
- const animations = Array.isArray(processed.animate) ? processed.animate : [processed.animate];
3086
- processed.animate = animations.map(anim => {
3087
- // Only add timeline if not already specified
3088
- if (!anim.timeline) {
3089
- return {
3090
- ...anim,
3091
- timeline: 'view()',
3092
- range: anim.range || 'entry',
3093
- fillMode: anim.fillMode || 'both'
3094
- };
3095
- }
3096
- return anim;
3097
- });
3098
- }
3099
- // Apply scroll() timeline if animateOn='Scroll'
3100
- if (animateOn === 'Scroll' && processed.animate) {
3101
- const animations = Array.isArray(processed.animate) ? processed.animate : [processed.animate];
3102
- processed.animate = animations.map(anim => {
3103
- // Only add timeline if not already specified
3104
- if (!anim.timeline) {
3105
- return {
3106
- ...anim,
3107
- timeline: 'scroll()',
3108
- fillMode: anim.fillMode || 'both'
3109
- };
3110
- }
3111
- return anim;
3112
- });
3113
- }
3114
- return processed;
3115
- }, [rest, blend, animateOn]);
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 = () => setSize({
5040
- width: win.innerWidth,
5041
- height: win.innerHeight
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 () => win.removeEventListener('resize', handleResize);
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
- callback();
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, options]);
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
- const result = {
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,18 +5439,21 @@ const getScrollDimensions = element => {
5414
5439
  const useScroll = function (_temp) {
5415
5440
  let {
5416
5441
  container,
5417
- offset = [0, 0],
5442
+ offset = DEFAULT_SCROLL_OFFSET,
5418
5443
  throttleMs = 100,
5419
5444
  disabled = false
5420
- } = _temp === void 0 ? {} : _temp;
5445
+ } = _temp === void 0 ? DEFAULT_SCROLL_OPTIONS : _temp;
5421
5446
  const [scrollPosition, setScrollPosition] = useState({
5422
5447
  x: 0,
5423
5448
  y: 0,
5424
5449
  xProgress: 0,
5425
- yProgress: 0
5450
+ yProgress: 0,
5451
+ elementY: 0,
5452
+ elementProgress: 0
5426
5453
  });
5427
5454
  const lastUpdateRef = useRef(0);
5428
5455
  const frameRef = useRef();
5456
+ const ticking = useRef(false);
5429
5457
  // Resolve the window/document context. If the container is an iframe element, use its contentWindow.
5430
5458
  const getContext = useCallback(() => {
5431
5459
  const targetEl = container?.current ?? null;
@@ -5446,18 +5474,21 @@ const useScroll = function (_temp) {
5446
5474
  targetDocument
5447
5475
  };
5448
5476
  }, [container]);
5449
- const handleScroll = useCallback(() => {
5450
- if (disabled) return;
5477
+ const updateScrollPosition = useCallback(() => {
5451
5478
  const {
5452
5479
  targetEl,
5453
5480
  targetWindow
5454
5481
  } = getContext();
5455
5482
  const hasScrollableElement = targetEl && isElementScrollable(targetEl);
5456
5483
  const scrollTarget = hasScrollableElement ? targetEl : targetWindow || targetEl;
5457
- if (!scrollTarget) return;
5484
+ if (!scrollTarget) {
5485
+ ticking.current = false;
5486
+ return;
5487
+ }
5458
5488
  const now = Date.now();
5489
+ // Verify throttle constraints inside the RAF to skip frame if needed
5459
5490
  if (throttleMs > 0 && now - lastUpdateRef.current < throttleMs) {
5460
- frameRef.current = requestAnimationFrame(handleScroll);
5491
+ ticking.current = false;
5461
5492
  return;
5462
5493
  }
5463
5494
  const dimensions = getScrollDimensions(scrollTarget);
@@ -5467,19 +5498,47 @@ const useScroll = function (_temp) {
5467
5498
  const maxScrollY = dimensions.scrollHeight - dimensions.clientHeight;
5468
5499
  const xProgress = maxScrollX <= 0 ? 1 : Math.min(Math.max(x / maxScrollX, 0), 1);
5469
5500
  const yProgress = maxScrollY <= 0 ? 1 : Math.min(Math.max(y / maxScrollY, 0), 1);
5501
+ // Calculate element-specific stats if we are tracking a specific element container
5502
+ // that is NOT the main scroller itself.
5503
+ let elementY = 0;
5504
+ let elementProgress = 0;
5505
+ if (targetEl && targetEl !== scrollTarget) {
5506
+ const rect = targetEl.getBoundingClientRect();
5507
+ elementY = rect.top;
5508
+ const viewportHeight = dimensions.clientHeight;
5509
+ const scrollDistance = rect.height - viewportHeight;
5510
+ if (scrollDistance > 0) {
5511
+ // Calculate progress consistent with sticky scrolling behavior
5512
+ // 0 when hitting top, 1 when finished scrolling
5513
+ const scrolled = -rect.top;
5514
+ elementProgress = Math.max(0, Math.min(1, scrolled / scrollDistance));
5515
+ } else {
5516
+ elementProgress = 0;
5517
+ }
5518
+ }
5470
5519
  setScrollPosition(prev => {
5471
- if (prev.x !== x || prev.y !== y || prev.xProgress !== xProgress || prev.yProgress !== yProgress) {
5520
+ if (prev.elementProgress !== elementProgress || prev.y !== y || prev.x !== x || prev.yProgress !== yProgress) {
5472
5521
  lastUpdateRef.current = now;
5473
5522
  return {
5474
5523
  x,
5475
5524
  y,
5476
5525
  xProgress,
5477
- yProgress
5526
+ yProgress,
5527
+ elementY,
5528
+ elementProgress
5478
5529
  };
5479
5530
  }
5480
5531
  return prev;
5481
5532
  });
5482
- }, [offset, throttleMs, disabled, getContext]);
5533
+ ticking.current = false;
5534
+ }, [offset, throttleMs, getContext]);
5535
+ const handleScroll = useCallback(() => {
5536
+ if (disabled) return;
5537
+ if (!ticking.current) {
5538
+ frameRef.current = requestAnimationFrame(updateScrollPosition);
5539
+ ticking.current = true;
5540
+ }
5541
+ }, [disabled, updateScrollPosition]);
5483
5542
  useEffect(() => {
5484
5543
  if (disabled) return;
5485
5544
  const {
@@ -5491,7 +5550,7 @@ const useScroll = function (_temp) {
5491
5550
  const scrollTarget = hasScrollableElement ? targetEl : targetWindow || targetEl;
5492
5551
  if (!scrollTarget) return;
5493
5552
  // Initial scroll position
5494
- handleScroll();
5553
+ updateScrollPosition();
5495
5554
  const options = {
5496
5555
  passive: true
5497
5556
  };
@@ -5514,14 +5573,15 @@ const useScroll = function (_temp) {
5514
5573
  if (frameRef.current) {
5515
5574
  cancelAnimationFrame(frameRef.current);
5516
5575
  }
5576
+ ticking.current = false;
5517
5577
  };
5518
- }, [handleScroll, disabled, getContext]);
5578
+ }, [handleScroll, disabled, getContext, updateScrollPosition]);
5519
5579
  return scrollPosition;
5520
5580
  };
5521
5581
  // Enhanced useScrollAnimation with callback support and iframe support
5522
5582
  const useScrollAnimation = function (ref, options) {
5523
5583
  if (options === void 0) {
5524
- options = {};
5584
+ options = DEFAULT_SCROLL_ANIMATION_OPTIONS;
5525
5585
  }
5526
5586
  const [isInView, setIsInView] = useState(false);
5527
5587
  const [progress, setProgress] = useState(0);
@@ -5589,7 +5649,7 @@ const useSmoothScroll = targetWindow => {
5589
5649
  // Enhanced useInfiniteScroll with debouncing
5590
5650
  const useInfiniteScroll = function (callback, options) {
5591
5651
  if (options === void 0) {
5592
- options = {};
5652
+ options = DEFAULT_INFINITE_SCROLL_OPTIONS;
5593
5653
  }
5594
5654
  const [sentinel, setSentinel] = useState(null);
5595
5655
  const callbackRef = useRef(callback);
@@ -5684,12 +5744,13 @@ const useScrollDirection = function (threshold, targetWindow) {
5684
5744
 
5685
5745
  const useWindowSize = () => useContext(WindowSizeContext);
5686
5746
 
5747
+ const DEFAULT_IN_VIEW_OPTIONS = {};
5687
5748
  function useInView(options) {
5688
5749
  const {
5689
5750
  triggerOnce = false,
5690
5751
  targetWindow,
5691
5752
  ...observerOptions
5692
- } = options || {};
5753
+ } = options || DEFAULT_IN_VIEW_OPTIONS;
5693
5754
  const ref = useRef(null);
5694
5755
  const [inView, setInView] = useState(false);
5695
5756
  useEffect(() => {
@@ -5719,7 +5780,7 @@ function useInView(options) {
5719
5780
  return () => {
5720
5781
  observer.disconnect();
5721
5782
  };
5722
- }, [triggerOnce, targetWindow, ...Object.values(observerOptions || {})]);
5783
+ }, [triggerOnce, targetWindow, observerOptions.root, observerOptions.rootMargin, observerOptions.threshold]);
5723
5784
  return {
5724
5785
  ref,
5725
5786
  inView
@@ -5804,7 +5865,7 @@ function useIframe(iframeRef) {
5804
5865
  if (!iframe) return;
5805
5866
  const updateState = () => {
5806
5867
  const win = iframe.contentWindow;
5807
- const doc = iframe.contentDocument || win?.document;
5868
+ const doc = win?.document || iframe.contentDocument;
5808
5869
  if (win && doc) {
5809
5870
  setIframeWindow(win);
5810
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}