You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by dh...@apache.org on 2026/07/17 09:20:02 UTC

(ranger) 01/04: RANGER-5444 : Policy Form Improvements – Label Corrections & Layout Updates

This is an automated email from the ASF dual-hosted git repository.

dhavaljrajpara pushed a commit to branch RANGER-5444
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit deee9bf09d1202dd5fc89b578d4d848ff70ff9a9
Author: Dhaval Rajpara <dh...@gmail.com>
AuthorDate: Fri Jul 17 07:05:42 2026 +0530

    RANGER-5444 : Policy Form Improvements – Label Corrections & Layout Updates
---
 .../react-webapp/src/components/Editable.jsx       |  9 ++---
 .../main/webapp/react-webapp/src/styles/style.css  | 20 +++++++++++
 .../webapp/react-webapp/src/utils/XAMessages.js    |  4 +--
 .../Admin/AdminLogs/PolicyViewDetails.jsx          | 18 +++++-----
 .../views/GovernedData/Dataset/AccessGrantForm.jsx |  1 +
 .../views/PolicyListing/AddUpdatePolicyForm.jsx    | 18 ++++++----
 .../views/PolicyListing/PolicyPermissionItem.jsx   | 41 ++++++++++++++--------
 .../src/views/Reports/SearchPolicyTable.jsx        | 26 ++++++--------
 .../views/ServiceManager/ServiceAuditFilter.jsx    |  1 +
 9 files changed, 86 insertions(+), 52 deletions(-)

diff --git a/security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx b/security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx
index 639b25314..f69d0240c 100644
--- a/security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/components/Editable.jsx
@@ -485,6 +485,7 @@ const Editable = (props) => {
     conditionDefVal,
     servicedefName,
     isGDS,
+    popOverheader,
     actionFilterContext
   } = props;
 
@@ -555,7 +556,9 @@ const Editable = (props) => {
             <div
               key={property}
               className={`${
-                uiHintVal?.isMultiline ? "editable-label" : "badge bg-dark"
+                uiHintVal?.isMultiline
+                  ? "editable-label rule-condition-wrapper"
+                  : "badge bg-dark"
               }`}
             >
               {`${conditionObj.label}: ${
@@ -855,9 +858,7 @@ const Editable = (props) => {
         type === TYPE_CHECKBOX && "popover-maxHeight popover-minHeight"
       }`}
     >
-      <Popover.Header>
-        {type === TYPE_CHECKBOX ? "Select" : "Enter"}
-      </Popover.Header>
+      <Popover.Header>{popOverheader}</Popover.Header>
       <Popover.Body>
         {type === TYPE_CHECKBOX ? (
           <CheckboxComp
diff --git a/security-admin/src/main/webapp/react-webapp/src/styles/style.css b/security-admin/src/main/webapp/react-webapp/src/styles/style.css
index 3002fac88..a5c9cff2d 100644
--- a/security-admin/src/main/webapp/react-webapp/src/styles/style.css
+++ b/security-admin/src/main/webapp/react-webapp/src/styles/style.css
@@ -579,6 +579,11 @@ h3.wrap-header {
   padding: 3px;
 }
 
+.rule-condition-wrapper {
+  white-space: normal;
+  word-break: break-all;
+}
+
 /* Service Manager */
 .select-zone-name {
   cursor: not-allowed;
@@ -676,6 +681,16 @@ table.no-bg-color thead tr th:first-child {
   padding: 8px;
 }
 
+.table-fixed table {
+  width: 100%;
+  table-layout: fixed;
+}
+
+.table-fixed .table thead th {
+  font-size: 13px;
+  padding: 8px;
+}
+
 .bt-1 {
   border-top: 1px solid #ddd;
 }
@@ -1666,6 +1681,11 @@ header {
   overflow-y: auto;
 }
 
+.permission-item {
+  max-height: 256px;
+  overflow-y: auto;
+}
+
 /* Form control */
 .form-control:disabled {
   cursor: not-allowed;
diff --git a/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js b/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js
index 75b064758..a9cf53944 100644
--- a/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js
+++ b/security-admin/src/main/webapp/react-webapp/src/utils/XAMessages.js
@@ -51,9 +51,9 @@ export const RegexMessage = {
       </>
     ),
     policyConditionInfoIcon:
-      "1. JavaScript Condition Examples :\
+      "1. Boolean expression Examples :\
                       country_code == 'USA', time_range >= 900 time_range <= 1800 etc.\
-                      2. Dragging bottom-right corner of javascript condition editor(Textarea) can resizable",
+                      2. Dragging bottom-right corner of condition editor(Textarea) can resizable",
     firstNameValidationMsg: (
       <>
         <p className="pd-10 mb-0" style={{ fontSize: "small" }}>
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/Admin/AdminLogs/PolicyViewDetails.jsx b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/Admin/AdminLogs/PolicyViewDetails.jsx
index 2c96e1559..6e13cd94e 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/Admin/AdminLogs/PolicyViewDetails.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/AuditEvent/Admin/AdminLogs/PolicyViewDetails.jsx
@@ -377,7 +377,7 @@ export function PolicyViewDetails(props) {
             <th className="text-center text-nowrap">Select User</th>
             {!isEmpty(
               filterServiceDef && filterServiceDef.policyConditions
-            ) && <th className="text-center text-nowrap">Policy Conditions</th>}
+            ) && <th className="text-center text-nowrap">Rule Conditions</th>}
             <th className="text-center text-nowrap">
               {policyType == RangerPolicyType.RANGER_ACCESS_POLICY_TYPE.value
                 ? "Permissions"
@@ -682,14 +682,14 @@ export function PolicyViewDetails(props) {
       {getPolicyConditions(conditions, serviceDef)}
       {policyType == RangerPolicyType.RANGER_ACCESS_POLICY_TYPE.value && (
         <>
-          <p className="form-header">Allow Conditions :</p>
+          <p className="form-header">Allow Rules :</p>
           <div className="overflow-auto">
             <Table bordered size="sm" className="table-audit-filter-ready-only">
               {getFilterPolicy(
                 policyItems,
                 serviceDef,
                 serviceType,
-                ` No policy items of "Allow Conditions" are present`
+                ` No policy items of "Allow Rules" are present`
               )}
             </Table>
           </div>
@@ -700,7 +700,7 @@ export function PolicyViewDetails(props) {
       {policyType == RangerPolicyType.RANGER_ACCESS_POLICY_TYPE.value &&
         serviceDef?.options?.enableDenyAndExceptionsInPolicies == "true" && (
           <>
-            <p className="form-header">Exclude from Allow Conditions :</p>
+            <p className="form-header">Exclude from Allow Rules :</p>
             <div className="overflow-auto">
               <Table
                 bordered
@@ -711,7 +711,7 @@ export function PolicyViewDetails(props) {
                   allowExceptions,
                   serviceDef,
                   serviceType,
-                  `No policy items of "Exclude from Allow Conditions" are present`
+                  `No policy items of "Exclude from Allow Rules" are present`
                 )}
               </Table>
             </div>
@@ -742,7 +742,7 @@ export function PolicyViewDetails(props) {
         policyType == RangerPolicyType.RANGER_ACCESS_POLICY_TYPE.value &&
         serviceDef?.options?.enableDenyAndExceptionsInPolicies == "true" && (
           <>
-            <p className="form-header">Deny Conditions :</p>
+            <p className="form-header">Deny Rules :</p>
             <div className="overflow-auto">
               <Table
                 bordered
@@ -753,7 +753,7 @@ export function PolicyViewDetails(props) {
                   denyPolicyItems,
                   serviceDef,
                   serviceType,
-                  ` No policy items of "Deny Conditions" are present`
+                  ` No policy items of "Deny Rules" are present`
                 )}
               </Table>
             </div>
@@ -764,7 +764,7 @@ export function PolicyViewDetails(props) {
         policyType == RangerPolicyType.RANGER_ACCESS_POLICY_TYPE.value &&
         serviceDef?.options?.enableDenyAndExceptionsInPolicies == "true" && (
           <>
-            <p className="form-header">Exclude from Deny Conditions :</p>
+            <p className="form-header">Exclude from Deny Rules :</p>
             <div className="overflow-auto">
               <Table
                 bordered
@@ -775,7 +775,7 @@ export function PolicyViewDetails(props) {
                   denyExceptions,
                   serviceDef,
                   serviceType,
-                  `No policy items of "Exclude from Deny Conditions" are present`
+                  `No policy items of "Exclude from Deny Rules" are present`
                 )}
               </Table>
             </div>
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/AccessGrantForm.jsx b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/AccessGrantForm.jsx
index 34dfae608..7051d32eb 100755
--- a/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/AccessGrantForm.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/GovernedData/Dataset/AccessGrantForm.jsx
@@ -609,6 +609,7 @@ function AccessGrantForm({
                                                       isMulti: true
                                                     }}
                                                     isGDS={true}
+                                                    popOverheader="Policy Conditions"
                                                   />
                                                 </div>
                                               )}
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx
index 48797a5c0..434c4831f 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/AddUpdatePolicyForm.jsx
@@ -1593,7 +1593,11 @@ export default function AddUpdatePolicyForm() {
                     {isMultiResources && (
                       <>
                         <fieldset>
-                          <p className="formHeader">Resources :</p>
+                          <p className="formHeader">
+                            {serviceCompDetails.name == "tag"
+                              ? "Tags :"
+                              : "Resources :"}
+                          </p>
                         </fieldset>
                         <>
                           <FieldArray name="additionalResources">
@@ -1660,7 +1664,7 @@ export default function AddUpdatePolicyForm() {
                           <Accordion defaultActiveKey="0">
                             <>
                               <p className="formHeader">
-                                Allow Conditions:{" "}
+                                Allow Rules:{" "}
                                 <CustomToggle eventKey="0"></CustomToggle>
                               </p>
                               <Accordion.Collapse eventKey="0">
@@ -1688,7 +1692,7 @@ export default function AddUpdatePolicyForm() {
                                       <fieldset>
                                         <p className="wrap-header search-header">
                                           <i className="fa-fw fa fa-exclamation-triangle fa-fw fa fa-1 text-color-red"></i>
-                                          Exclude from Allow Conditions:
+                                          Exclude from Allow Rules:
                                         </p>
                                       </fieldset>
                                       <div className="wrap">
@@ -1754,7 +1758,7 @@ export default function AddUpdatePolicyForm() {
                                 <Accordion defaultActiveKey="0">
                                   <>
                                     <p className="formHeader">
-                                      Deny Conditions:
+                                      Deny Rules:
                                       <CustomToggle eventKey="0"></CustomToggle>
                                     </p>
                                     <Accordion.Collapse eventKey="0">
@@ -1780,7 +1784,7 @@ export default function AddUpdatePolicyForm() {
                                         <fieldset>
                                           <p className="wrap-header search-header">
                                             <i className="fa-fw fa fa-exclamation-triangle fa-fw fa fa-1 text-color-red"></i>
-                                            Exclude from Deny Conditions:
+                                            Exclude from Deny Rules:
                                           </p>
                                         </fieldset>
                                         <div className="wrap">
@@ -1815,7 +1819,7 @@ export default function AddUpdatePolicyForm() {
                         <Accordion defaultActiveKey="0">
                           <>
                             <p className="formHeader">
-                              Mask Conditions:
+                              Mask Rules:
                               <CustomToggle eventKey="0"></CustomToggle>
                             </p>
                             <Accordion.Collapse eventKey="0">
@@ -1847,7 +1851,7 @@ export default function AddUpdatePolicyForm() {
                           <Accordion defaultActiveKey="0">
                             <>
                               <p className="wrap-header search-header">
-                                Row Filter Conditions:
+                                Row Filter Rules:
                                 <CustomToggle eventKey="0"></CustomToggle>
                               </p>
                               <Accordion.Collapse eventKey="0">
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyPermissionItem.jsx b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyPermissionItem.jsx
index 942cdd674..0e44e46a7 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyPermissionItem.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/PolicyListing/PolicyPermissionItem.jsx
@@ -78,7 +78,7 @@ export default function PolicyPermissionItem(props) {
   const permList = ["Select Roles", "Select Groups", "Select Users"];
 
   if (serviceCompDetails?.policyConditions?.length > 0) {
-    permList.push("Policy Conditions");
+    permList.push("Rule Conditions");
   }
   permList.push("Permissions");
   if (
@@ -102,7 +102,14 @@ export default function PolicyPermissionItem(props) {
 
   const tableHeader = () => {
     return permList.map((data) => {
-      return <th key={data}>{data}</th>;
+      return (
+        <th
+          key={data}
+          style={data === "Delegate Admin" ? { width: "100px" } : {}}
+        >
+          {data}
+        </th>
+      );
     });
   };
 
@@ -295,10 +302,10 @@ export default function PolicyPermissionItem(props) {
       if ((users || grps || roles) && !accTypes) {
         if (delegateAdmin !== undefined && delegateAdmin === false) {
           error =
-            "Please select permision item for selected users/groups/roles";
+            "Please select permission item for selected users/groups/roles";
         } else if (delegateAdmin == undefined) {
           error =
-            "Please select permision item for selected users/groups/roles";
+            "Please select permission item for selected users/groups/roles";
         }
       }
       if (accTypes && !users && !grps && !roles) {
@@ -322,7 +329,7 @@ export default function PolicyPermissionItem(props) {
           !roles
         ) {
           error =
-            "Please select user/group/role for the entered policy condition";
+            "Please select user/group/role for the entered Rule Condition";
         }
       }
       return error;
@@ -333,7 +340,6 @@ export default function PolicyPermissionItem(props) {
     ...selectInputCustomStyles,
     control: (base) => ({
       ...base,
-      width: 200,
       whiteSpace: "nowrap"
     })
   };
@@ -365,7 +371,7 @@ export default function PolicyPermissionItem(props) {
   return (
     <div>
       <Col sm="12">
-        <div className="table-responsive">
+        <div className="table-fixed">
           <Table
             bordered
             className="policy-permission-table"
@@ -374,7 +380,7 @@ export default function PolicyPermissionItem(props) {
             <thead className="thead-light">
               <tr>
                 {tableHeader()}
-                <th></th>
+                <th width="64px"></th>
               </tr>
             </thead>
             <tbody className="drag-drop-wrap">
@@ -398,7 +404,7 @@ export default function PolicyPermissionItem(props) {
                                 className="form-control"
                                 name={`${name}.roles`}
                                 render={({ input }) => (
-                                  <div className="d-flex">
+                                  <div className="permission-item">
                                     <AsyncSelect
                                       {...input}
                                       menuPortalTarget={document.body}
@@ -431,7 +437,7 @@ export default function PolicyPermissionItem(props) {
                                 className="form-control"
                                 name={`${name}.groups`}
                                 render={({ input }) => (
-                                  <div>
+                                  <div className="permission-item">
                                     <AsyncSelect
                                       {...input}
                                       menuPortalTarget={document.body}
@@ -464,7 +470,7 @@ export default function PolicyPermissionItem(props) {
                                 className="form-control"
                                 name={`${name}.users`}
                                 render={({ input }) => (
-                                  <div>
+                                  <div className="permission-item">
                                     <AsyncSelect
                                       {...input}
                                       menuPortalTarget={document.body}
@@ -490,7 +496,7 @@ export default function PolicyPermissionItem(props) {
                             </td>
                           );
                         }
-                        if (colName == "Policy Conditions") {
+                        if (colName == "Rule Conditions") {
                           return (
                             serviceCompDetails?.policyConditions?.length >
                               0 && (
@@ -506,10 +512,9 @@ export default function PolicyPermissionItem(props) {
                                     )
                                   }
                                   render={({ input }) => (
-                                    <div className="table-editable">
+                                    <div className="table-editable permission-item">
                                       <Editable
                                         {...input}
-                                        placement="auto"
                                         type="custom"
                                         conditionDefVal={conditionDefVal}
                                         servicedefName={serviceCompDetails?.name}
@@ -525,6 +530,7 @@ export default function PolicyPermissionItem(props) {
                                           // Portal menus to body (see Editable CONDITION_POPOVER_SELECT_PROPS)
                                           // so a long Action list with ALL permission does not jump the page.
                                         }}
+                                        popOverheader="Rule Conditions"
                                       />
                                     </div>
                                   )}
@@ -603,6 +609,7 @@ export default function PolicyPermissionItem(props) {
                                           options={accessTypeOptions}
                                           showSelectAll={true}
                                           selectAllLabel="Select All"
+                                          popOverheader="Add/Edit Permissions"
                                         />
                                       </div>
                                     );
@@ -638,6 +645,7 @@ export default function PolicyPermissionItem(props) {
                                             fields?.value[index]?.accesses
                                               ?.tableList
                                           }
+                                          popOverheader="Select Masking Option"
                                         />
                                         {fields?.value[index]?.dataMaskInfo
                                           ?.label == "Custom" && (
@@ -705,6 +713,7 @@ export default function PolicyPermissionItem(props) {
                                         options={getMaskingAccessTypeOptions()}
                                         showSelectAll={false}
                                         selectAllLabel="Select All"
+                                        popOverheader="Select Masking Option"
                                       />
                                       {fields?.value[index]?.dataMaskInfo
                                         ?.label == "Custom" && (
@@ -749,6 +758,7 @@ export default function PolicyPermissionItem(props) {
                                       {...input}
                                       placement="auto"
                                       type="input"
+                                      popOverheader="Enter Filter Expression"
                                     />
                                     {meta.touched && meta.error && (
                                       <span>{meta.error}</span>
@@ -767,6 +777,7 @@ export default function PolicyPermissionItem(props) {
                             <td
                               key={`${name}-${index}`}
                               className="text-center align-middle"
+                              width="64px"
                             >
                               <div key={`${name}-${index}`}>
                                 <Field
@@ -794,7 +805,7 @@ export default function PolicyPermissionItem(props) {
                         }
                         return <td key={colName}>{colName}</td>;
                       })}
-                      <td className="align-middle">
+                      <td className="align-middle" width="64px">
                         <Button
                           variant="danger"
                           size="sm"
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/Reports/SearchPolicyTable.jsx b/security-admin/src/main/webapp/react-webapp/src/views/Reports/SearchPolicyTable.jsx
index a09d516dc..c1728f04d 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/Reports/SearchPolicyTable.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/Reports/SearchPolicyTable.jsx
@@ -515,7 +515,7 @@ function PolicyConditionData(props) {
     <React.Fragment>
       {props.policyData.policyType == 0 && (
         <>
-          <p className="form-header">Allow Conditions</p>
+          <p className="form-header">Allow Rules</p>
           <div className="overflow-x-auto">
             <Table
               bordered
@@ -528,9 +528,7 @@ function PolicyConditionData(props) {
                   <th>Groups</th>
                   <th>Users</th>
                   {!isEmpty(props?.serviceDef?.policyConditions) && (
-                    <th className="text-center text-nowrap">
-                      Policy Conditions
-                    </th>
+                    <th className="text-center text-nowrap">Rule Conditions</th>
                   )}
                   <th>Accesses</th>
                 </tr>
@@ -541,7 +539,7 @@ function PolicyConditionData(props) {
           {props.serviceDef?.options?.enableDenyAndExceptionsInPolicies ==
             "true" && (
             <>
-              <p className="form-header">Allow Exclude</p>
+              <p className="form-header">Allow Exclude Rules</p>
               <div className="overflow-x-auto">
                 <Table
                   bordered
@@ -555,7 +553,7 @@ function PolicyConditionData(props) {
                       <th>Users</th>
                       {!isEmpty(props?.serviceDef?.policyConditions) && (
                         <th className="text-center text-nowrap">
-                          Policy Conditions
+                          Rule Conditions
                         </th>
                       )}
                       <th>Accesses</th>
@@ -566,7 +564,7 @@ function PolicyConditionData(props) {
                   </tbody>
                 </Table>
               </div>
-              <p className="form-header">Deny Conditions</p>
+              <p className="form-header">Deny Rules</p>
               <div className="overflow-x-auto">
                 <Table
                   bordered
@@ -580,7 +578,7 @@ function PolicyConditionData(props) {
                       <th>Users</th>
                       {!isEmpty(props?.serviceDef?.policyConditions) && (
                         <th className="text-center text-nowrap">
-                          Policy Conditions
+                          Rule Conditions
                         </th>
                       )}
                       <th>Accesses</th>
@@ -591,7 +589,7 @@ function PolicyConditionData(props) {
                   </tbody>
                 </Table>
               </div>
-              <p className="form-header">Deny Exclude</p>
+              <p className="form-header">Deny Exclude Rules</p>
               <div className="overflow-x-auto">
                 <Table
                   bordered
@@ -605,7 +603,7 @@ function PolicyConditionData(props) {
                       <th>Users</th>
                       {!isEmpty(props?.serviceDef?.policyConditions) && (
                         <th className="text-center text-nowrap">
-                          Policy Conditions
+                          Rule Conditions
                         </th>
                       )}
                       <th>Accesses</th>
@@ -623,7 +621,7 @@ function PolicyConditionData(props) {
 
       {props.policyData.policyType == 1 && (
         <>
-          <p className="form-header ">Masking Conditions</p>
+          <p className="form-header ">Mask Rules</p>
           <div className="overflow-x-auto">
             <Table
               bordered
@@ -636,9 +634,7 @@ function PolicyConditionData(props) {
                   <th>Groups</th>
                   <th>Users</th>
                   {!isEmpty(props?.serviceDef?.policyConditions) && (
-                    <th className="text-center text-nowrap">
-                      Policy Conditions
-                    </th>
+                    <th className="text-center text-nowrap">Rule Conditions</th>
                   )}
                   <th>Accesses</th>
                   <th>Masking Condition</th>
@@ -654,7 +650,7 @@ function PolicyConditionData(props) {
 
       {props.policyData.policyType == 2 && (
         <>
-          <p className="form-header">Row Level Conditions</p>
+          <p className="form-header">Row Filter Rules</p>
           <div className="overflow-x-auto">
             <Table
               bordered
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceAuditFilter.jsx b/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceAuditFilter.jsx
index 9468bef96..23c2e8a13 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceAuditFilter.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/ServiceManager/ServiceAuditFilter.jsx
@@ -388,6 +388,7 @@ export default function ServiceAuditFilter(props) {
                                     options={getAccessTypeOptions()}
                                     showSelectAll={true}
                                     selectAllLabel="Select All"
+                                    popOverheader="Add/Edit Permissions"
                                   />
                                 </div>
                               )}