app-studio 0.6.7 → 0.6.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 +172 -44
- 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 +172 -44
- package/dist/app-studio.esm.js.map +1 -1
- package/dist/app-studio.umd.development.js +172 -44
- package/dist/app-studio.umd.development.js.map +1 -1
- package/dist/app-studio.umd.production.min.js +1 -1
- package/dist/utils/vendorPrefixes.d.ts +9 -0
- package/package.json +1 -1
|
@@ -1069,25 +1069,34 @@ const vendorPrefixToKebabCase = property => {
|
|
|
1069
1069
|
if (property.startsWith('--')) {
|
|
1070
1070
|
return property;
|
|
1071
1071
|
}
|
|
1072
|
-
//
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
if (
|
|
1080
|
-
|
|
1081
|
-
const
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1072
|
+
// Comprehensive regex to match all vendor prefix patterns
|
|
1073
|
+
// This handles:
|
|
1074
|
+
// 1. Uppercase vendor prefixes (WebkitTransform)
|
|
1075
|
+
// 2. Lowercase vendor prefixes (webkitTransform)
|
|
1076
|
+
// 3. Mixed case vendor prefixes (webkitbackgroundClip)
|
|
1077
|
+
// 4. All lowercase vendor prefixes (webkitbackgroundclip)
|
|
1078
|
+
const vendorPrefixRegex = /^(webkit|moz|ms|o|Webkit|Moz|Ms|O)([A-Za-z])/;
|
|
1079
|
+
if (vendorPrefixRegex.test(property)) {
|
|
1080
|
+
// Extract the prefix and normalize it to lowercase
|
|
1081
|
+
const prefixMatch = property.match(/^(webkit|moz|ms|o|Webkit|Moz|Ms|O)/i);
|
|
1082
|
+
if (prefixMatch) {
|
|
1083
|
+
const prefix = prefixMatch[0].toLowerCase();
|
|
1084
|
+
const restOfProperty = property.slice(prefix.length);
|
|
1085
|
+
// Convert the rest of the property to kebab case
|
|
1086
|
+
let kebabRestOfProperty = restOfProperty;
|
|
1087
|
+
// If the rest starts with an uppercase letter or has uppercase letters, convert to kebab case
|
|
1088
|
+
if (/[A-Z]/.test(restOfProperty)) {
|
|
1089
|
+
kebabRestOfProperty = restOfProperty.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
1090
|
+
} else if (restOfProperty && restOfProperty[0] === restOfProperty[0].toLowerCase()) {
|
|
1091
|
+
// If the rest starts with a lowercase letter, ensure proper kebab case
|
|
1092
|
+
// This handles cases like webkitbackgroundclip
|
|
1093
|
+
kebabRestOfProperty = restOfProperty.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
1094
|
+
}
|
|
1095
|
+
// Ensure we don't have double hyphens
|
|
1096
|
+
kebabRestOfProperty = kebabRestOfProperty.replace(/^-/, '');
|
|
1097
|
+
// Return the properly formatted vendor-prefixed property
|
|
1098
|
+
return `-${prefix}-${kebabRestOfProperty}`;
|
|
1099
|
+
}
|
|
1091
1100
|
}
|
|
1092
1101
|
// Regular camelCase to kebab-case
|
|
1093
1102
|
return property.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
@@ -1329,6 +1338,95 @@ const generateKeyframes = animation => {
|
|
|
1329
1338
|
};
|
|
1330
1339
|
};
|
|
1331
1340
|
|
|
1341
|
+
/**
|
|
1342
|
+
* Mapping of standard CSS properties to their vendor-prefixed equivalents.
|
|
1343
|
+
* This helps ensure cross-browser compatibility by automatically applying
|
|
1344
|
+
* the appropriate vendor prefixes when needed.
|
|
1345
|
+
*/
|
|
1346
|
+
// Properties that commonly need vendor prefixes across browsers
|
|
1347
|
+
const vendorPrefixedProperties = {
|
|
1348
|
+
// Animation properties
|
|
1349
|
+
animation: ['-webkit-animation', '-moz-animation', '-o-animation'],
|
|
1350
|
+
animationDelay: ['-webkit-animation-delay', '-moz-animation-delay', '-o-animation-delay'],
|
|
1351
|
+
animationDirection: ['-webkit-animation-direction', '-moz-animation-direction', '-o-animation-direction'],
|
|
1352
|
+
animationDuration: ['-webkit-animation-duration', '-moz-animation-duration', '-o-animation-duration'],
|
|
1353
|
+
animationFillMode: ['-webkit-animation-fill-mode', '-moz-animation-fill-mode', '-o-animation-fill-mode'],
|
|
1354
|
+
animationIterationCount: ['-webkit-animation-iteration-count', '-moz-animation-iteration-count', '-o-animation-iteration-count'],
|
|
1355
|
+
animationName: ['-webkit-animation-name', '-moz-animation-name', '-o-animation-name'],
|
|
1356
|
+
animationPlayState: ['-webkit-animation-play-state', '-moz-animation-play-state', '-o-animation-play-state'],
|
|
1357
|
+
animationTimingFunction: ['-webkit-animation-timing-function', '-moz-animation-timing-function', '-o-animation-timing-function'],
|
|
1358
|
+
// Transform properties
|
|
1359
|
+
transform: ['-webkit-transform', '-moz-transform', '-ms-transform', '-o-transform'],
|
|
1360
|
+
transformOrigin: ['-webkit-transform-origin', '-moz-transform-origin', '-ms-transform-origin', '-o-transform-origin'],
|
|
1361
|
+
transformStyle: ['-webkit-transform-style', '-moz-transform-style', '-ms-transform-style'],
|
|
1362
|
+
// Transition properties
|
|
1363
|
+
transition: ['-webkit-transition', '-moz-transition', '-ms-transition', '-o-transition'],
|
|
1364
|
+
transitionDelay: ['-webkit-transition-delay', '-moz-transition-delay', '-ms-transition-delay', '-o-transition-delay'],
|
|
1365
|
+
transitionDuration: ['-webkit-transition-duration', '-moz-transition-duration', '-ms-transition-duration', '-o-transition-duration'],
|
|
1366
|
+
transitionProperty: ['-webkit-transition-property', '-moz-transition-property', '-ms-transition-property', '-o-transition-property'],
|
|
1367
|
+
transitionTimingFunction: ['-webkit-transition-timing-function', '-moz-transition-timing-function', '-ms-transition-timing-function', '-o-transition-timing-function'],
|
|
1368
|
+
// Flexbox properties
|
|
1369
|
+
flex: ['-webkit-flex', '-ms-flex'],
|
|
1370
|
+
flexBasis: ['-webkit-flex-basis', '-ms-flex-basis'],
|
|
1371
|
+
flexDirection: ['-webkit-flex-direction', '-ms-flex-direction'],
|
|
1372
|
+
flexFlow: ['-webkit-flex-flow', '-ms-flex-flow'],
|
|
1373
|
+
flexGrow: ['-webkit-flex-grow', '-ms-flex-positive'],
|
|
1374
|
+
flexShrink: ['-webkit-flex-shrink', '-ms-flex-negative'],
|
|
1375
|
+
flexWrap: ['-webkit-flex-wrap', '-ms-flex-wrap'],
|
|
1376
|
+
justifyContent: ['-webkit-justify-content', '-ms-flex-pack'],
|
|
1377
|
+
alignItems: ['-webkit-align-items', '-ms-flex-align'],
|
|
1378
|
+
alignContent: ['-webkit-align-content', '-ms-flex-line-pack'],
|
|
1379
|
+
alignSelf: ['-webkit-align-self', '-ms-flex-item-align'],
|
|
1380
|
+
order: ['-webkit-order', '-ms-flex-order'],
|
|
1381
|
+
// Other commonly prefixed properties
|
|
1382
|
+
appearance: ['-webkit-appearance', '-moz-appearance', '-ms-appearance'],
|
|
1383
|
+
backfaceVisibility: ['-webkit-backface-visibility', '-moz-backface-visibility'],
|
|
1384
|
+
backgroundClip: ['-webkit-background-clip', '-moz-background-clip'],
|
|
1385
|
+
backgroundOrigin: ['-webkit-background-origin', '-moz-background-origin'],
|
|
1386
|
+
backgroundSize: ['-webkit-background-size', '-moz-background-size', '-o-background-size'],
|
|
1387
|
+
borderImage: ['-webkit-border-image', '-moz-border-image', '-o-border-image'],
|
|
1388
|
+
boxShadow: ['-webkit-box-shadow', '-moz-box-shadow'],
|
|
1389
|
+
boxSizing: ['-webkit-box-sizing', '-moz-box-sizing'],
|
|
1390
|
+
columns: ['-webkit-columns', '-moz-columns'],
|
|
1391
|
+
columnCount: ['-webkit-column-count', '-moz-column-count'],
|
|
1392
|
+
columnGap: ['-webkit-column-gap', '-moz-column-gap'],
|
|
1393
|
+
columnRule: ['-webkit-column-rule', '-moz-column-rule'],
|
|
1394
|
+
columnWidth: ['-webkit-column-width', '-moz-column-width'],
|
|
1395
|
+
filter: ['-webkit-filter'],
|
|
1396
|
+
fontSmoothing: ['-webkit-font-smoothing', '-moz-osx-font-smoothing'],
|
|
1397
|
+
hyphens: ['-webkit-hyphens', '-moz-hyphens', '-ms-hyphens'],
|
|
1398
|
+
maskImage: ['-webkit-mask-image'],
|
|
1399
|
+
perspective: ['-webkit-perspective', '-moz-perspective'],
|
|
1400
|
+
perspectiveOrigin: ['-webkit-perspective-origin', '-moz-perspective-origin'],
|
|
1401
|
+
textSizeAdjust: ['-webkit-text-size-adjust', '-moz-text-size-adjust', '-ms-text-size-adjust'],
|
|
1402
|
+
userSelect: ['-webkit-user-select', '-moz-user-select', '-ms-user-select'],
|
|
1403
|
+
// Special webkit-only properties
|
|
1404
|
+
textFillColor: ['-webkit-text-fill-color'],
|
|
1405
|
+
textStroke: ['-webkit-text-stroke'],
|
|
1406
|
+
textStrokeColor: ['-webkit-text-stroke-color'],
|
|
1407
|
+
textStrokeWidth: ['-webkit-text-stroke-width'],
|
|
1408
|
+
tapHighlightColor: ['-webkit-tap-highlight-color'],
|
|
1409
|
+
touchCallout: ['-webkit-touch-callout'],
|
|
1410
|
+
userDrag: ['-webkit-user-drag'],
|
|
1411
|
+
lineClamp: ['-webkit-line-clamp'],
|
|
1412
|
+
overflowScrolling: ['-webkit-overflow-scrolling']
|
|
1413
|
+
};
|
|
1414
|
+
// Convert camelCase property names to kebab-case
|
|
1415
|
+
const camelToKebabCase = property => {
|
|
1416
|
+
return property.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
1417
|
+
};
|
|
1418
|
+
// Get all vendor prefixed versions of a property in kebab-case
|
|
1419
|
+
const getVendorPrefixedProperties = property => {
|
|
1420
|
+
const kebabProperty = camelToKebabCase(property);
|
|
1421
|
+
const prefixedProperties = vendorPrefixedProperties[property] || [];
|
|
1422
|
+
// Return the standard property along with all vendor-prefixed versions
|
|
1423
|
+
return [kebabProperty, ...prefixedProperties];
|
|
1424
|
+
};
|
|
1425
|
+
// Check if a property needs vendor prefixes
|
|
1426
|
+
const needsVendorPrefix = property => {
|
|
1427
|
+
return property in vendorPrefixedProperties;
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1332
1430
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
1333
1431
|
// Implement a simple LRU cache for classCache
|
|
1334
1432
|
class LRUCache {
|
|
@@ -1503,20 +1601,42 @@ const ValueUtils = {
|
|
|
1503
1601
|
if (property.toLowerCase().includes('color')) {
|
|
1504
1602
|
processedValue = getColor(value);
|
|
1505
1603
|
}
|
|
1506
|
-
// Handle
|
|
1604
|
+
// Handle properties that might contain color values (borders, gradients, etc.)
|
|
1507
1605
|
if (typeof value === 'string' && value.length > 3) {
|
|
1508
|
-
//
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1606
|
+
// Check if the value contains any color tokens
|
|
1607
|
+
if (value.includes('color.') || value.includes('theme.')) {
|
|
1608
|
+
// For gradients and complex values, we need to process color tokens within the string
|
|
1609
|
+
// This handles cases like: "linear-gradient(135deg, color.blue.500, color.red.500)"
|
|
1610
|
+
let processedString = value;
|
|
1611
|
+
// Find all color tokens in the string
|
|
1612
|
+
const colorTokenRegex = /(color\.[a-zA-Z0-9.]+|theme\.[a-zA-Z0-9.]+)/g;
|
|
1613
|
+
const colorTokens = value.match(colorTokenRegex);
|
|
1614
|
+
if (colorTokens) {
|
|
1615
|
+
// Replace each color token with its processed value
|
|
1616
|
+
colorTokens.forEach(token => {
|
|
1617
|
+
const processedColor = getColor(token);
|
|
1618
|
+
// Use a global replace to catch all instances of this token
|
|
1619
|
+
// Escape all special regex characters in the token
|
|
1620
|
+
const escapedToken = token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1621
|
+
processedString = processedString.replace(new RegExp(escapedToken, 'g'), processedColor);
|
|
1622
|
+
});
|
|
1623
|
+
processedValue = processedString;
|
|
1624
|
+
} else {
|
|
1625
|
+
// Fallback to the old method for simpler cases (like borders)
|
|
1626
|
+
// Parse property to extract color
|
|
1627
|
+
const parts = value.split(' ');
|
|
1628
|
+
// Check each part to see if it starts with 'color.' or 'theme.'
|
|
1629
|
+
const processedParts = parts.map(part => {
|
|
1630
|
+
if (part.startsWith('color.') || part.startsWith('theme.')) {
|
|
1631
|
+
// Process the color part through getColor
|
|
1632
|
+
return getColor(part);
|
|
1633
|
+
}
|
|
1634
|
+
return part;
|
|
1635
|
+
});
|
|
1636
|
+
// Reconstruct the value with processed parts
|
|
1637
|
+
processedValue = processedParts.join(' ');
|
|
1515
1638
|
}
|
|
1516
|
-
|
|
1517
|
-
});
|
|
1518
|
-
// Reconstruct the value with processed parts
|
|
1519
|
-
processedValue = processedParts.join(' ');
|
|
1639
|
+
}
|
|
1520
1640
|
}
|
|
1521
1641
|
// Handle numeric values
|
|
1522
1642
|
if (typeof processedValue === 'number') {
|
|
@@ -1702,39 +1822,47 @@ class UtilityClassManager {
|
|
|
1702
1822
|
let rules = [];
|
|
1703
1823
|
// Format CSS property name with proper vendor prefix handling
|
|
1704
1824
|
const cssProperty = propertyToKebabCase(property);
|
|
1705
|
-
// Format CSS property name
|
|
1706
|
-
// const cssProperty = property.startsWith('--')
|
|
1707
|
-
// ? property
|
|
1708
|
-
// : toKebabCase(property);
|
|
1709
1825
|
let valueForCss = processedValue;
|
|
1710
1826
|
// Handle numeric values for CSS
|
|
1711
1827
|
if (typeof valueForCss === 'number' && numericCssProperties.has(cssProperty)) {
|
|
1712
1828
|
valueForCss = `${valueForCss}px`;
|
|
1713
1829
|
}
|
|
1830
|
+
// Check if this property needs vendor prefixes
|
|
1831
|
+
const needsPrefixes = needsVendorPrefix(property);
|
|
1832
|
+
const cssProperties = needsPrefixes ? getVendorPrefixedProperties(property) : [cssProperty];
|
|
1714
1833
|
// Generate CSS rules based on context
|
|
1715
1834
|
if (context === 'pseudo' && modifier) {
|
|
1716
1835
|
const pseudoClassName = `${baseClassName}--${modifier}`;
|
|
1717
1836
|
classNames = [pseudoClassName];
|
|
1718
1837
|
const escapedClassName = this.escapeClassName(pseudoClassName);
|
|
1719
|
-
rules
|
|
1720
|
-
|
|
1721
|
-
|
|
1838
|
+
// Add rules for all necessary vendor prefixes
|
|
1839
|
+
cssProperties.forEach(prefixedProperty => {
|
|
1840
|
+
rules.push({
|
|
1841
|
+
rule: `.${escapedClassName}:${modifier} { ${prefixedProperty}: ${valueForCss}; }`,
|
|
1842
|
+
context: 'pseudo'
|
|
1843
|
+
});
|
|
1722
1844
|
});
|
|
1723
1845
|
} else if (context === 'media' && modifier) {
|
|
1724
1846
|
const mediaClassName = `${modifier}--${baseClassName}`;
|
|
1725
1847
|
classNames = [mediaClassName];
|
|
1726
1848
|
const escapedClassName = this.escapeClassName(mediaClassName);
|
|
1727
1849
|
mediaQueries.forEach(mq => {
|
|
1728
|
-
rules
|
|
1729
|
-
|
|
1730
|
-
|
|
1850
|
+
// Add media query rules for all necessary vendor prefixes
|
|
1851
|
+
cssProperties.forEach(prefixedProperty => {
|
|
1852
|
+
rules.push({
|
|
1853
|
+
rule: `@media ${mq} { .${escapedClassName} { ${prefixedProperty}: ${valueForCss}; } }`,
|
|
1854
|
+
context: 'media'
|
|
1855
|
+
});
|
|
1731
1856
|
});
|
|
1732
1857
|
});
|
|
1733
1858
|
} else {
|
|
1734
1859
|
const escapedClassName = this.escapeClassName(baseClassName);
|
|
1735
|
-
rules
|
|
1736
|
-
|
|
1737
|
-
|
|
1860
|
+
// Add rules for all necessary vendor prefixes
|
|
1861
|
+
cssProperties.forEach(prefixedProperty => {
|
|
1862
|
+
rules.push({
|
|
1863
|
+
rule: `.${escapedClassName} { ${prefixedProperty}: ${valueForCss}; }`,
|
|
1864
|
+
context: 'base'
|
|
1865
|
+
});
|
|
1738
1866
|
});
|
|
1739
1867
|
}
|
|
1740
1868
|
// Inject all rules
|
|
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|