@prorobotech/openapi-k8s-toolkit 1.4.0-alpha.33 → 1.4.0-alpha.35

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.
@@ -1,2 +1,2 @@
1
- export { af as BackToDefaultIcon, aM as BlackholeForm, aL as BlackholeFormProvider, aH as ClusterListTable, ac as ConfirmModal, aq as ContentCard, aw as CursorDefaultDiv, au as CursorPointerTag, av as CursorPointerTagMinContent, at as CustomSelect, D as DeleteIcon, l as DeleteModal, n as DeleteModalMany, ae as DownIcon, aZ as DynamicComponents, aY as DynamicRenderer, a_ as DynamicRendererWithProviders, ap as EarthIcon, h as EditIcon, aG as EnrichedTable, E as EnrichedTableProvider, ay as ErrorBoundary, az as ErrorBoundaryWithDataReset, aX as Events, ar as FlexGrow, ak as LockedIcon, ao as LookingGlassIcon, aC as ManageableBreadcrumbs, aA as ManageableBreadcrumbsProvider, aF as ManageableSidebar, aD as ManageableSidebarProvider, aO as MarketPlace, aP as MarketplaceCard, aj as MinusIcon, aS as NodeTerminal, i as PaddingContainer, am as PauseCircleIcon, ai as PlusIcon, aT as PodLogs, aU as PodLogsMonaco, aR as PodTerminal, aQ as ProjectInfoCard, ax as ResourceLink, an as ResumeCircleIcon, aW as Search, aa as Spacer, ag as SuccessIcon, ab as TreeWithSearch, as as UncontrolledSelect, al as UnlockedIcon, ad as UpIcon, aV as VMVNC, aK as YamlEditorSingleton, M as checkIfApiInstanceNamespaceScoped, N as checkIfBuiltInInstanceNamespaceScoped, I as checkPermission, bu as convertBytes, bC as convertCompute, bz as convertCores, bx as convertStorage, bd as createContextFactory, q as createNewEntry, bf as deepMerge, t as deleteEntry, ah as feedbackIcons, K as filterIfApiInstanceNamespaceScoped, L as filterIfBuiltInInstanceNamespaceScoped, b1 as filterSelectOptions, b3 as floorToDecimal, bv as formatBytesAuto, bA as formatCoresAuto, bE as formatDateAuto, b8 as getAllPathsFromObj, w as getApiResourceSingle, B as getApiResourceTypes, C as getApiResourceTypesByApiGroup, v as getApiResources, y as getBuiltinResourceSingle, F as getBuiltinResourceTypes, x as getBuiltinResources, bb as getBuiltinTreeData, o as getClusterList, G as getCrdData, A as getCrdResourceSingle, z as getCrdResources, H as getDirectUnknownResource, aI as getEnrichedColumns, aJ as getEnrichedColumnsWithControls, bc as getGroupsByCategory, O as getKinds, bo as getLinkToApiForm, bn as getLinkToBuiltinForm, k as getLinkToForm, bt as getNamespaceLink, aN as getObjectFormItemsDraft, b9 as getPrefixSubarrays, bs as getResourceLink, bg as getSortedKinds, bh as getSortedKindsAll, b2 as getStringByName, J as getSwagger, bj as getUppercase, ba as groupsToTreeData, bi as hslFromString, br as includesArray, b0 as isFlatObject, bq as isMultilineFromYaml, bp as isMultilineString, bF as isValidRFC3339, bk as kindByGvr, bm as namespacedByGvr, b7 as normalizeValuesForQuotasToNumber, bD as parseCoresWithUnit, b4 as parseQuotaValue, b5 as parseQuotaValueCpu, b6 as parseQuotaValueMemoryAndStorage, by as parseValueWithUnit, bl as pluralByKind, aB as prepareDataForManageableBreadcrumbs, aE as prepareDataForManageableSidebar, a$ as prepareTemplate, be as prepareUrlsToFetchForDynamicRenderer, bw as toBytes, bB as toCores, r as updateEntry, T as useApiResourceSingle, Z as useApiResourceTypesByGroup, S as useApiResources, Y as useApisResourceTypes, V as useBuiltinResourceSingle, $ as useBuiltinResourceTypes, U as useBuiltinResources, Q as useClusterList, a0 as useCrdData, X as useCrdResourceSingle, W as useCrdResources, e as useDirectUnknownResource, a2 as useInfiniteSentinel, f as useK8sSmartResource, a3 as useK8sVerbs, a7 as useKinds, a8 as useKindsRaw, a1 as useListWatch, a4 as useManyK8sSmartResource, d as usePermissions, a9 as usePluginManifest, a6 as useResourceScope, a5 as useSmartResourceParams } from './index-DstjN_y0.mjs';
1
+ export { af as BackToDefaultIcon, aM as BlackholeForm, aL as BlackholeFormProvider, aH as ClusterListTable, ac as ConfirmModal, aq as ContentCard, aw as CursorDefaultDiv, au as CursorPointerTag, av as CursorPointerTagMinContent, at as CustomSelect, D as DeleteIcon, l as DeleteModal, n as DeleteModalMany, ae as DownIcon, aZ as DynamicComponents, aY as DynamicRenderer, a_ as DynamicRendererWithProviders, ap as EarthIcon, h as EditIcon, aG as EnrichedTable, E as EnrichedTableProvider, ay as ErrorBoundary, az as ErrorBoundaryWithDataReset, aX as Events, ar as FlexGrow, ak as LockedIcon, ao as LookingGlassIcon, aC as ManageableBreadcrumbs, aA as ManageableBreadcrumbsProvider, aF as ManageableSidebar, aD as ManageableSidebarProvider, aO as MarketPlace, aP as MarketplaceCard, aj as MinusIcon, aS as NodeTerminal, i as PaddingContainer, am as PauseCircleIcon, ai as PlusIcon, aT as PodLogs, aU as PodLogsMonaco, aR as PodTerminal, aQ as ProjectInfoCard, ax as ResourceLink, an as ResumeCircleIcon, aW as Search, aa as Spacer, ag as SuccessIcon, ab as TreeWithSearch, as as UncontrolledSelect, al as UnlockedIcon, ad as UpIcon, aV as VMVNC, aK as YamlEditorSingleton, M as checkIfApiInstanceNamespaceScoped, N as checkIfBuiltInInstanceNamespaceScoped, I as checkPermission, bu as convertBytes, bC as convertCompute, bz as convertCores, bx as convertStorage, bd as createContextFactory, q as createNewEntry, bf as deepMerge, t as deleteEntry, ah as feedbackIcons, K as filterIfApiInstanceNamespaceScoped, L as filterIfBuiltInInstanceNamespaceScoped, b1 as filterSelectOptions, b3 as floorToDecimal, bv as formatBytesAuto, bA as formatCoresAuto, bE as formatDateAuto, b8 as getAllPathsFromObj, w as getApiResourceSingle, B as getApiResourceTypes, C as getApiResourceTypesByApiGroup, v as getApiResources, y as getBuiltinResourceSingle, F as getBuiltinResourceTypes, x as getBuiltinResources, bb as getBuiltinTreeData, o as getClusterList, G as getCrdData, A as getCrdResourceSingle, z as getCrdResources, H as getDirectUnknownResource, aI as getEnrichedColumns, aJ as getEnrichedColumnsWithControls, bc as getGroupsByCategory, O as getKinds, bo as getLinkToApiForm, bn as getLinkToBuiltinForm, k as getLinkToForm, bt as getNamespaceLink, aN as getObjectFormItemsDraft, b9 as getPrefixSubarrays, bs as getResourceLink, bg as getSortedKinds, bh as getSortedKindsAll, b2 as getStringByName, J as getSwagger, bj as getUppercase, ba as groupsToTreeData, bi as hslFromString, br as includesArray, b0 as isFlatObject, bq as isMultilineFromYaml, bp as isMultilineString, bF as isValidRFC3339, bk as kindByGvr, bm as namespacedByGvr, b7 as normalizeValuesForQuotasToNumber, bD as parseCoresWithUnit, b4 as parseQuotaValue, b5 as parseQuotaValueCpu, b6 as parseQuotaValueMemoryAndStorage, by as parseValueWithUnit, bl as pluralByKind, aB as prepareDataForManageableBreadcrumbs, aE as prepareDataForManageableSidebar, a$ as prepareTemplate, be as prepareUrlsToFetchForDynamicRenderer, bw as toBytes, bB as toCores, r as updateEntry, T as useApiResourceSingle, Z as useApiResourceTypesByGroup, S as useApiResources, Y as useApisResourceTypes, V as useBuiltinResourceSingle, $ as useBuiltinResourceTypes, U as useBuiltinResources, Q as useClusterList, a0 as useCrdData, X as useCrdResourceSingle, W as useCrdResources, e as useDirectUnknownResource, a2 as useInfiniteSentinel, f as useK8sSmartResource, a3 as useK8sVerbs, a7 as useKinds, a8 as useKindsRaw, a1 as useListWatch, a4 as useManyK8sSmartResource, d as usePermissions, a9 as usePluginManifest, a6 as useResourceScope, a5 as useSmartResourceParams } from './index-DZxEKtGA.mjs';
2
2
  //# sourceMappingURL=openapi-k8s-toolkit.es.js.map
@@ -35722,6 +35722,50 @@
35722
35722
  const value = getValueByPath(reqData, path);
35723
35723
  return Array.isArray(value) && value.length === 0;
35724
35724
  };
35725
+ const STATUS_SEVERITY = {
35726
+ "500": 3,
35727
+ "403": 2,
35728
+ "404": 1,
35729
+ error: 0
35730
+ };
35731
+ const httpStatusToResultStatus = (statusCode) => {
35732
+ if (statusCode === 403) return "403";
35733
+ if (statusCode === 404) return "404";
35734
+ if (statusCode && statusCode >= 500) return "500";
35735
+ return "error";
35736
+ };
35737
+ const getDefaultTitle = (status) => {
35738
+ if (status === "403") return "Access Denied";
35739
+ if (status === "404") return "Not Found";
35740
+ if (status === "500") return "Server Error";
35741
+ return "Error";
35742
+ };
35743
+ const resolveItemsPath = (itemsPath, index) => {
35744
+ if (Array.isArray(itemsPath)) return itemsPath[index] ?? ".items";
35745
+ return itemsPath ?? ".items";
35746
+ };
35747
+ const checkReqIndex = (reqIndex, multiQueryData, getErrorForReq, shouldCheckEmpty, itemsPath) => {
35748
+ const error = getErrorForReq(reqIndex);
35749
+ const emptyListDetected = !error && shouldCheckEmpty && isEmptyAtPath(multiQueryData, reqIndex, itemsPath);
35750
+ if (!error && !emptyListDetected) return null;
35751
+ const httpStatus = emptyListDetected ? 404 : extractHttpStatus(error);
35752
+ const resultStatus = httpStatusToResultStatus(httpStatus);
35753
+ const severity = STATUS_SEVERITY[resultStatus] ?? 0;
35754
+ const message = emptyListDetected ? "The requested resource was not found" : extractErrorMessage(error);
35755
+ return { resultStatus, severity, message };
35756
+ };
35757
+ const findWorstError = (reqIndexes, multiQueryData, getErrorForReq, shouldCheckEmpty, itemsPath) => reqIndexes.reduce(
35758
+ (worst, reqIndex, index) => {
35759
+ const resolved = resolveItemsPath(itemsPath, index);
35760
+ const result = checkReqIndex(reqIndex, multiQueryData, getErrorForReq, shouldCheckEmpty, resolved);
35761
+ if (!result) return worst;
35762
+ if (!worst || result.severity > worst.severity) {
35763
+ return { resultStatus: result.resultStatus, message: result.message, severity: result.severity };
35764
+ }
35765
+ return worst;
35766
+ },
35767
+ null
35768
+ );
35725
35769
 
35726
35770
  const isValidLabelSelectorObject = (input) => {
35727
35771
  if (typeof input !== "object" || input === null || Array.isArray(input) || Object.getPrototypeOf(input) !== Object.prototype) {
@@ -81701,7 +81745,7 @@ Take a look at the reducer(s) handling this action type: ${action.type}.
81701
81745
  }
81702
81746
  }
81703
81747
  });
81704
- const isLinkableVolumeTypeKey = (typeKey) => typeKey === "configMap" || typeKey === "secret";
81748
+ const isLinkableVolumeTypeKey = (typeKey) => typeKey === "configMap" || typeKey === "secret" || typeKey === "persistentVolumeClaim";
81705
81749
  const isPendingLinkSegment = (value) => !value || value.includes("...") || value.includes("{") || value.includes("}");
81706
81750
  const getVolumeFactoryKey = ({
81707
81751
  apiGroup,
@@ -81881,59 +81925,41 @@ Take a look at the reducer(s) handling this action type: ${action.type}.
81881
81925
  ]);
81882
81926
  const hasLinkableVolumeTypes = dataSourceWithoutHref.some(({ typeKey }) => isLinkableVolumeTypeKey(typeKey));
81883
81927
  const linkableNamespace = dataSourceWithoutHref.find(({ typeKey }) => isLinkableVolumeTypeKey(typeKey))?.namespace;
81884
- const configMapFactoryKey = hasLinkableVolumeTypes && !isNavigationLoading && !isNavigationError ? getVolumeFactoryKey({
81885
- apiGroup: void 0,
81886
- apiVersion: "v1",
81887
- resource: "configmaps",
81888
- namespace: linkableNamespace,
81889
- baseFactoriesMapping,
81890
- baseFactoryNamespacedAPIKey,
81891
- baseFactoryClusterSceopedAPIKey,
81892
- baseFactoryNamespacedBuiltinKey,
81893
- baseFactoryClusterSceopedBuiltinKey
81894
- }) : void 0;
81895
- const secretFactoryKey = hasLinkableVolumeTypes && !isNavigationLoading && !isNavigationError ? getVolumeFactoryKey({
81928
+ const baseFactoryKeyParams = {
81896
81929
  apiGroup: void 0,
81897
81930
  apiVersion: "v1",
81898
- resource: "secrets",
81899
81931
  namespace: linkableNamespace,
81900
81932
  baseFactoriesMapping,
81901
81933
  baseFactoryNamespacedAPIKey,
81902
81934
  baseFactoryClusterSceopedAPIKey,
81903
81935
  baseFactoryNamespacedBuiltinKey,
81904
81936
  baseFactoryClusterSceopedBuiltinKey
81905
- }) : void 0;
81906
- const hasPendingLinkPrefixInputs = hasLinkableVolumeTypes && (isPendingLinkSegment(clusterPrepared) || isPendingLinkSegment(linkableNamespace) || isPendingLinkSegment(configMapFactoryKey) || isPendingLinkSegment(secretFactoryKey));
81937
+ };
81938
+ const canResolveLinkableKeys = hasLinkableVolumeTypes && !isNavigationLoading && !isNavigationError;
81939
+ const configMapFactoryKey = canResolveLinkableKeys ? getVolumeFactoryKey({ ...baseFactoryKeyParams, resource: "configmaps" }) : void 0;
81940
+ const secretFactoryKey = canResolveLinkableKeys ? getVolumeFactoryKey({ ...baseFactoryKeyParams, resource: "secrets" }) : void 0;
81941
+ const pvcFactoryKey = canResolveLinkableKeys ? getVolumeFactoryKey({ ...baseFactoryKeyParams, resource: "persistentvolumeclaims" }) : void 0;
81942
+ const hasPendingLinkPrefixInputs = hasLinkableVolumeTypes && (isPendingLinkSegment(clusterPrepared) || isPendingLinkSegment(linkableNamespace) || isPendingLinkSegment(configMapFactoryKey) || isPendingLinkSegment(secretFactoryKey) || isPendingLinkSegment(pvcFactoryKey));
81907
81943
  const isLinkPrefixLoading = hasLinkableVolumeTypes && !ownReqFailed && !isNavigationError && (isNavigationLoading || hasPendingLinkPrefixInputs);
81908
81944
  const resourceLinkPrefixes = React$1.useMemo(() => {
81909
81945
  if (!hasLinkableVolumeTypes || isLinkPrefixLoading) {
81910
81946
  return void 0;
81911
81947
  }
81948
+ const baseLinkPrefixParams = {
81949
+ baseprefix,
81950
+ cluster: clusterPrepared,
81951
+ namespace: linkableNamespace,
81952
+ apiGroupVersion: "v1",
81953
+ baseFactoryNamespacedAPIKey,
81954
+ baseFactoryClusterSceopedAPIKey,
81955
+ baseFactoryNamespacedBuiltinKey,
81956
+ baseFactoryClusterSceopedBuiltinKey,
81957
+ baseFactoriesMapping
81958
+ };
81912
81959
  return {
81913
- configMap: getVolumeResourceLinkPrefix({
81914
- baseprefix,
81915
- cluster: clusterPrepared,
81916
- namespace: linkableNamespace,
81917
- apiGroupVersion: "v1",
81918
- pluralName: "configmaps",
81919
- baseFactoryNamespacedAPIKey,
81920
- baseFactoryClusterSceopedAPIKey,
81921
- baseFactoryNamespacedBuiltinKey,
81922
- baseFactoryClusterSceopedBuiltinKey,
81923
- baseFactoriesMapping
81924
- }) || "",
81925
- secret: getVolumeResourceLinkPrefix({
81926
- baseprefix,
81927
- cluster: clusterPrepared,
81928
- namespace: linkableNamespace,
81929
- apiGroupVersion: "v1",
81930
- pluralName: "secrets",
81931
- baseFactoryNamespacedAPIKey,
81932
- baseFactoryClusterSceopedAPIKey,
81933
- baseFactoryNamespacedBuiltinKey,
81934
- baseFactoryClusterSceopedBuiltinKey,
81935
- baseFactoriesMapping
81936
- }) || ""
81960
+ configMap: getVolumeResourceLinkPrefix({ ...baseLinkPrefixParams, pluralName: "configmaps" }) || "",
81961
+ secret: getVolumeResourceLinkPrefix({ ...baseLinkPrefixParams, pluralName: "secrets" }) || "",
81962
+ persistentVolumeClaim: getVolumeResourceLinkPrefix({ ...baseLinkPrefixParams, pluralName: "persistentvolumeclaims" }) || ""
81937
81963
  };
81938
81964
  }, [
81939
81965
  hasLinkableVolumeTypes,
@@ -81986,18 +82012,6 @@ Take a look at the reducer(s) handling this action type: ${action.type}.
81986
82012
  ] });
81987
82013
  };
81988
82014
 
81989
- const httpStatusToResultStatus = (statusCode) => {
81990
- if (statusCode === 403) return "403";
81991
- if (statusCode === 404) return "404";
81992
- if (statusCode && statusCode >= 500) return "500";
81993
- return "error";
81994
- };
81995
- const getDefaultTitle = (status) => {
81996
- if (status === "403") return "Access Denied";
81997
- if (status === "404") return "Not Found";
81998
- if (status === "500") return "Server Error";
81999
- return "Error";
82000
- };
82001
82015
  const AntdResult = ({ data, children }) => {
82002
82016
  const { data: multiQueryData, isLoading, getErrorForReq } = useMultiQuery();
82003
82017
  const partsOfUrl = usePartsOfUrl();
@@ -82008,20 +82022,26 @@ Take a look at the reducer(s) handling this action type: ${action.type}.
82008
82022
  acc[index.toString()] = value;
82009
82023
  return acc;
82010
82024
  }, {});
82025
+ const shouldCheckEmpty = data.checkEmpty !== false;
82011
82026
  if (typeof data.reqIndex === "number") {
82012
- const error = getErrorForReq(data.reqIndex);
82013
- const shouldCheckEmpty = data.checkEmpty !== false;
82014
- const itemsPath = data.itemsPath ?? ".items";
82015
- const emptyListDetected = !error && shouldCheckEmpty && isEmptyAtPath(multiQueryData, data.reqIndex, itemsPath);
82016
- if (!error && !emptyListDetected) {
82027
+ const itemsPath = resolveItemsPath(data.itemsPath, 0);
82028
+ const result = checkReqIndex(data.reqIndex, multiQueryData, getErrorForReq, shouldCheckEmpty, itemsPath);
82029
+ if (!result) {
82017
82030
  return children ?? null;
82018
82031
  }
82019
- const httpStatus = emptyListDetected ? 404 : extractHttpStatus(error);
82020
- const autoStatus = httpStatusToResultStatus(httpStatus);
82021
- const autoMessage = emptyListDetected ? "The requested resource was not found" : extractErrorMessage(error);
82022
- const status = data.status ?? autoStatus;
82032
+ const status = data.status ?? result.resultStatus;
82023
82033
  const title = data.title ? parseAll({ text: data.title, replaceValues, multiQueryData }) : getDefaultTitle(status);
82024
- const subTitle = data.subTitle ? parseAll({ text: data.subTitle, replaceValues, multiQueryData }) : autoMessage;
82034
+ const subTitle = data.subTitle ? parseAll({ text: data.subTitle, replaceValues, multiQueryData }) : result.message;
82035
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(antd.Result, { status, title, subTitle, style: data.style });
82036
+ }
82037
+ if (Array.isArray(data.reqIndex)) {
82038
+ const worst = findWorstError(data.reqIndex, multiQueryData, getErrorForReq, shouldCheckEmpty, data.itemsPath);
82039
+ if (!worst) {
82040
+ return children ?? null;
82041
+ }
82042
+ const status = data.status ?? worst.resultStatus;
82043
+ const title = data.title ? parseAll({ text: data.title, replaceValues, multiQueryData }) : getDefaultTitle(status);
82044
+ const subTitle = data.subTitle ? parseAll({ text: data.subTitle, replaceValues, multiQueryData }) : worst.message;
82025
82045
  return /* @__PURE__ */ jsxRuntimeExports.jsx(antd.Result, { status, title, subTitle, style: data.style });
82026
82046
  }
82027
82047
  const parsedTitle = data.title ? parseAll({ text: data.title, replaceValues, multiQueryData }) : void 0;
@@ -82105,6 +82125,12 @@ Take a look at the reducer(s) handling this action type: ${action.type}.
82105
82125
  const FactoryConfigContextProvider = factoryConfigContext.Provider;
82106
82126
  factoryConfigContext.useTypedContext;
82107
82127
 
82128
+ const EffectiveAntdResultWrapper = ({
82129
+ effectiveReqIndexes,
82130
+ itemsPath,
82131
+ children
82132
+ }) => /* @__PURE__ */ jsxRuntimeExports.jsx(AntdResult, { data: { id: "effective-antd-result", reqIndex: effectiveReqIndexes, itemsPath }, children });
82133
+
82108
82134
  const STRING_KEYS = [
82109
82135
  "cluster",
82110
82136
  "apiGroup",
@@ -82116,7 +82142,15 @@ Take a look at the reducer(s) handling this action type: ${action.type}.
82116
82142
  ];
82117
82143
  const DynamicRendererWithProviders = (props) => {
82118
82144
  const location = reactRouterDom.useLocation();
82119
- const { urlsToFetch, dataToApplyToContext, theme, nodeTerminalDefaultProfile, disableEventBubbling } = props;
82145
+ const {
82146
+ urlsToFetch,
82147
+ dataToApplyToContext,
82148
+ theme,
82149
+ nodeTerminalDefaultProfile,
82150
+ disableEventBubbling,
82151
+ effectiveReqIndexes,
82152
+ effectiveItemsPath
82153
+ } = props;
82120
82154
  const directUrls = urlsToFetch.filter((el) => typeof el === "string");
82121
82155
  const k8sResourcesUrls = urlsToFetch.filter((el) => typeof el !== "string");
82122
82156
  const preparedUrlsToFetch = prepareUrlsToFetchForDynamicRenderer({
@@ -82151,7 +82185,7 @@ Take a look at the reducer(s) handling this action type: ${action.type}.
82151
82185
  {
82152
82186
  items: [...preparedK8sResoucesUrls, ...preparedUrlsToFetch],
82153
82187
  dataToApplyToContext,
82154
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundaryWithDataReset, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(DynamicRenderer, { ...props }) })
82188
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundaryWithDataReset, { children: effectiveReqIndexes && effectiveReqIndexes.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(EffectiveAntdResultWrapper, { effectiveReqIndexes, itemsPath: effectiveItemsPath, children: /* @__PURE__ */ jsxRuntimeExports.jsx(DynamicRenderer, { ...props }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(DynamicRenderer, { ...props }) })
82155
82189
  }
82156
82190
  ) }) }) })
82157
82191
  }