app-studio 0.6.54 → 0.6.55
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 +116 -1
- 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 +116 -1
- package/dist/app-studio.esm.js.map +1 -1
- package/dist/app-studio.umd.development.js +116 -1
- package/dist/app-studio.umd.development.js.map +1 -1
- package/dist/app-studio.umd.production.min.js +1 -1
- package/dist/providers/Theme.d.ts +1 -0
- package/package.json +1 -1
|
@@ -898,6 +898,7 @@ const defaultDarkColorConfig = {
|
|
|
898
898
|
// --- Create Theme Context ---
|
|
899
899
|
const ThemeContext = /*#__PURE__*/React.createContext({
|
|
900
900
|
getColor: () => '',
|
|
901
|
+
getColorHex: () => '',
|
|
901
902
|
theme: {},
|
|
902
903
|
colors: {
|
|
903
904
|
main: defaultLightColors,
|
|
@@ -952,6 +953,51 @@ const convertToRgba = (color, alpha) => {
|
|
|
952
953
|
console.warn(`Unable to convert color "${color}" to rgba format`);
|
|
953
954
|
return color;
|
|
954
955
|
};
|
|
956
|
+
const clamp255 = value => Math.max(0, Math.min(255, value));
|
|
957
|
+
const toTwoHex = value => clamp255(Math.round(value)).toString(16).padStart(2, '0');
|
|
958
|
+
const normalizeToHex = color => {
|
|
959
|
+
if (!color || typeof color !== 'string') return String(color);
|
|
960
|
+
const trimmed = color.trim();
|
|
961
|
+
if (trimmed === TRANSPARENT) return '#00000000';
|
|
962
|
+
if (trimmed.startsWith('#')) {
|
|
963
|
+
const hex = trimmed.slice(1);
|
|
964
|
+
if (hex.length === 3) {
|
|
965
|
+
const r = hex[0] + hex[0];
|
|
966
|
+
const g = hex[1] + hex[1];
|
|
967
|
+
const b = hex[2] + hex[2];
|
|
968
|
+
return `#${r}${g}${b}`.toLowerCase();
|
|
969
|
+
}
|
|
970
|
+
if (hex.length === 4) {
|
|
971
|
+
const r = hex[0] + hex[0];
|
|
972
|
+
const g = hex[1] + hex[1];
|
|
973
|
+
const b = hex[2] + hex[2];
|
|
974
|
+
const a = hex[3] + hex[3];
|
|
975
|
+
return `#${r}${g}${b}${a}`.toLowerCase();
|
|
976
|
+
}
|
|
977
|
+
if (hex.length === 6 || hex.length === 8) {
|
|
978
|
+
return `#${hex}`.toLowerCase();
|
|
979
|
+
}
|
|
980
|
+
return trimmed;
|
|
981
|
+
}
|
|
982
|
+
if (trimmed.startsWith('rgb')) {
|
|
983
|
+
const match = trimmed.match(/rgba?\(([^)]+)\)/i);
|
|
984
|
+
if (!match) return trimmed;
|
|
985
|
+
const parts = match[1].split(',').map(p => p.trim()).filter(Boolean);
|
|
986
|
+
const r = Number(parts[0]);
|
|
987
|
+
const g = Number(parts[1]);
|
|
988
|
+
const b = Number(parts[2]);
|
|
989
|
+
const a = parts.length >= 4 ? Number(parts[3]) : 1;
|
|
990
|
+
if ([r, g, b].some(v => Number.isNaN(v)) || Number.isNaN(a)) return trimmed;
|
|
991
|
+
const rr = toTwoHex(r);
|
|
992
|
+
const gg = toTwoHex(g);
|
|
993
|
+
const bb = toTwoHex(b);
|
|
994
|
+
const alpha = Math.max(0, Math.min(1, a));
|
|
995
|
+
if (alpha >= 1) return `#${rr}${gg}${bb}`.toLowerCase();
|
|
996
|
+
const aa = toTwoHex(alpha * 255);
|
|
997
|
+
return `#${rr}${gg}${bb}${aa}`.toLowerCase();
|
|
998
|
+
}
|
|
999
|
+
return trimmed;
|
|
1000
|
+
};
|
|
955
1001
|
// --- Deep Merge Function (remains the same, assuming it works as intended) ---
|
|
956
1002
|
// Consider using a library like `lodash.merge` or `deepmerge` if complexity grows
|
|
957
1003
|
// or edge cases (like merging arrays) need different handling.
|
|
@@ -1006,6 +1052,60 @@ const ThemeProvider = _ref => {
|
|
|
1006
1052
|
dark: deepMerge(defaultDarkColorConfig, darkOverride)
|
|
1007
1053
|
}), [lightOverride, darkOverride]);
|
|
1008
1054
|
const currentColors = React.useMemo(() => themeColors[themeMode], [themeColors, themeMode]);
|
|
1055
|
+
const resolveColorTokenForMode = React.useCallback(function (token, mode, override, depth) {
|
|
1056
|
+
if (depth === void 0) {
|
|
1057
|
+
depth = 0;
|
|
1058
|
+
}
|
|
1059
|
+
if (!token || typeof token !== 'string') return String(token);
|
|
1060
|
+
if (token === TRANSPARENT) return token;
|
|
1061
|
+
if (depth > 25) return token;
|
|
1062
|
+
const effectiveTheme = override?.theme ? deepMerge(mergedTheme, override.theme) : mergedTheme;
|
|
1063
|
+
// Resolve theme.* tokens recursively
|
|
1064
|
+
if (token.startsWith(THEME_PREFIX)) {
|
|
1065
|
+
const themeKey = token.substring(THEME_PREFIX.length);
|
|
1066
|
+
const themeValue = effectiveTheme[themeKey];
|
|
1067
|
+
if (typeof themeValue === 'string') {
|
|
1068
|
+
return resolveColorTokenForMode(themeValue, mode, override, depth + 1);
|
|
1069
|
+
}
|
|
1070
|
+
return token;
|
|
1071
|
+
}
|
|
1072
|
+
// Resolve explicit mode paths like "light.blue.500" / "dark.blue.500"
|
|
1073
|
+
if (token.startsWith('light.') || token.startsWith('dark.')) {
|
|
1074
|
+
const explicitMode = token.startsWith('light.') ? 'light' : 'dark';
|
|
1075
|
+
const prefixLength = token.startsWith('light.') ? 6 : 5;
|
|
1076
|
+
const modifiedName = `${COLOR_PREFIX}${token.substring(prefixLength)}`;
|
|
1077
|
+
return resolveColorTokenForMode(modifiedName, explicitMode, override, depth + 1);
|
|
1078
|
+
}
|
|
1079
|
+
// Resolve color.* tokens
|
|
1080
|
+
if (token.startsWith(COLOR_PREFIX)) {
|
|
1081
|
+
const keys = token.substring(COLOR_PREFIX.length).split('.');
|
|
1082
|
+
const colorsToUse = themeColors[mode];
|
|
1083
|
+
const palette = deepMerge(colorsToUse.palette, override?.colors?.palette || {});
|
|
1084
|
+
const main = deepMerge(colorsToUse.main, override?.colors?.main || {});
|
|
1085
|
+
if (keys.length === 3) {
|
|
1086
|
+
// e.g. color.blue.500.200 (alpha)
|
|
1087
|
+
const [colorName, variant, alphaStr] = keys;
|
|
1088
|
+
const base = palette?.[colorName]?.[variant];
|
|
1089
|
+
const alpha = parseInt(alphaStr, 10);
|
|
1090
|
+
if (typeof base === 'string' && !isNaN(alpha)) {
|
|
1091
|
+
return convertToRgba(base, alpha);
|
|
1092
|
+
}
|
|
1093
|
+
return token;
|
|
1094
|
+
}
|
|
1095
|
+
if (keys.length === 2) {
|
|
1096
|
+
const [colorName, variant] = keys;
|
|
1097
|
+
const value = palette?.[colorName]?.[variant];
|
|
1098
|
+
return typeof value === 'string' ? value : token;
|
|
1099
|
+
}
|
|
1100
|
+
if (keys.length === 1) {
|
|
1101
|
+
const [colorName] = keys;
|
|
1102
|
+
const value = main?.[colorName];
|
|
1103
|
+
return typeof value === 'string' ? value : token;
|
|
1104
|
+
}
|
|
1105
|
+
return token;
|
|
1106
|
+
}
|
|
1107
|
+
return token;
|
|
1108
|
+
}, [mergedTheme, themeColors]);
|
|
1009
1109
|
// --- Helper function to resolve color tokens to actual values ---
|
|
1010
1110
|
const resolveColorToken = React.useCallback(token => {
|
|
1011
1111
|
if (!token || typeof token !== 'string') return String(token);
|
|
@@ -1125,14 +1225,29 @@ const ThemeProvider = _ref => {
|
|
|
1125
1225
|
if (needCache) colorCache.set(cacheKey, resolvedColor);
|
|
1126
1226
|
return resolvedColor;
|
|
1127
1227
|
}, [mergedTheme, themeColors, themeMode, colorCache, strict]);
|
|
1228
|
+
const getColorHex = React.useCallback((name, override) => {
|
|
1229
|
+
if (!name || typeof name !== 'string') return String(name);
|
|
1230
|
+
if (name === TRANSPARENT) return '#00000000';
|
|
1231
|
+
const effectiveMode = override?.themeMode ?? themeMode;
|
|
1232
|
+
const cacheKey = `${name}-${effectiveMode}-hex`;
|
|
1233
|
+
// Cache only when no override object is provided
|
|
1234
|
+
if (!override && colorCache.has(cacheKey)) {
|
|
1235
|
+
return colorCache.get(cacheKey);
|
|
1236
|
+
}
|
|
1237
|
+
const resolved = resolveColorTokenForMode(name, effectiveMode, override);
|
|
1238
|
+
const hex = normalizeToHex(resolved);
|
|
1239
|
+
if (!override) colorCache.set(cacheKey, hex);
|
|
1240
|
+
return hex;
|
|
1241
|
+
}, [themeMode, colorCache, resolveColorTokenForMode]);
|
|
1128
1242
|
// --- Memoize Context Value ---
|
|
1129
1243
|
const contextValue = React.useMemo(() => ({
|
|
1130
1244
|
getColor,
|
|
1245
|
+
getColorHex,
|
|
1131
1246
|
theme: mergedTheme,
|
|
1132
1247
|
colors: currentColors,
|
|
1133
1248
|
themeMode,
|
|
1134
1249
|
setThemeMode
|
|
1135
|
-
}), [getColor, mergedTheme, currentColors, themeMode]);
|
|
1250
|
+
}), [getColor, getColorHex, mergedTheme, currentColors, themeMode]);
|
|
1136
1251
|
return /*#__PURE__*/React__default.createElement(ThemeContext.Provider, {
|
|
1137
1252
|
value: contextValue
|
|
1138
1253
|
}, /*#__PURE__*/React__default.createElement("style", null, generateCSSVariables(mergedTheme, themeColors.light, themeColors.dark)), /*#__PURE__*/React__default.createElement("div", {
|
|
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|