diff --git a/src/Components/Columns/ColumnsImage.tsx b/src/Components/Columns/ColumnsImage.tsx index 7dc1e80..95b7638 100644 --- a/src/Components/Columns/ColumnsImage.tsx +++ b/src/Components/Columns/ColumnsImage.tsx @@ -1,43 +1,33 @@ import { - DownloadOutlined, RotateLeftOutlined, RotateRightOutlined, SwapOutlined, ZoomInOutlined, ZoomOutOutlined, } from "@ant-design/icons"; -import React from "react"; +import React, { useState } from "react"; import { Image, Space } from "antd"; -import useImageError from "../../Hooks/useImageError"; -import { ErrorImage } from "../../Layout/app/Const"; +import { CiImageOff } from "react-icons/ci"; // Assuming you're using this icon from react-icons const ColumnsImage = ({ src }: any) => { - const imageUrl = src || ErrorImage; + const [hasError, setHasError] = useState(false); // Track if the image has an error - const handleError = useImageError; - // or you can download flipped and rotated image - // https://codesandbox.io/s/zi-ding-yi-gong-ju-lan-antd-5-7-0-forked-c9jvmp - const onDownload = () => { - fetch(src) - .then((response) => response.blob()) - .then((blob) => { - const url = URL.createObjectURL(new Blob([blob])); - const link = document.createElement("a"); - link.href = url; - link.download = "image.png"; - document.body.appendChild(link); - link.click(); - URL.revokeObjectURL(url); - link.remove(); - }); - }; + const imageUrl = src; + if (hasError) { + // If there is an error, display the fallback icon + return ; + } + if(!imageUrl){ + return ; + } return ( setHasError(true)} // Triggered when image fails to load preview={{ toolbarRender: ( _, @@ -54,7 +44,6 @@ const ColumnsImage = ({ src }: any) => { }, ) => ( - {/* */} @@ -64,19 +53,8 @@ const ColumnsImage = ({ src }: any) => { ), }} - onError={handleError} /> ); }; export default ColumnsImage; - -// { -// name: t("image"), -// center: "true", -// cell: (row: any) => { -// return ( -// -// ) -// } -// }, diff --git a/src/Components/DataTable/SearchField.tsx b/src/Components/DataTable/SearchField.tsx index 20d89e3..280a778 100644 --- a/src/Components/DataTable/SearchField.tsx +++ b/src/Components/DataTable/SearchField.tsx @@ -1,7 +1,5 @@ import React, { useState, useEffect, useRef } from "react"; import { useTranslation } from "react-i18next"; -import { IoSearch } from "react-icons/io5"; -import { useLocation, useNavigate } from "react-router-dom"; import { useFilterStateState } from "../../zustand/Filter"; import { useDebounce } from "../../utils/useDebounce"; @@ -15,15 +13,16 @@ const SearchField: React.FC = ({ placeholder, searchBy }) => { const [searchQuery, setSearchQuery] = useState(""); const inputRef = useRef(null); - const { setFilter } = useFilterStateState(); + const { setFilter,Filter } = useFilterStateState(); const handleInputChange = (value: string) => { setSearchQuery(value); }; - + console.log(searchBy,"searchBy"); + const handleInputChangeWithDebounce = useDebounce((value: string) => { setFilter({ - name: value, + [searchBy]: value, }); }); diff --git a/src/Components/ValidationField/utils/ValidationField.scss b/src/Components/ValidationField/utils/ValidationField.scss index d158b96..909abd9 100644 --- a/src/Components/ValidationField/utils/ValidationField.scss +++ b/src/Components/ValidationField/utils/ValidationField.scss @@ -7,7 +7,7 @@ margin-bottom: 10px; position: relative; min-height: 80px; - padding-inline: 20px; + // padding-inline: 20px; > * { width: 100% !important; min-width: 150px; diff --git a/src/Layout/Dashboard/FilterLayout.tsx b/src/Layout/Dashboard/FilterLayout.tsx index 045febf..fc3733d 100644 --- a/src/Layout/Dashboard/FilterLayout.tsx +++ b/src/Layout/Dashboard/FilterLayout.tsx @@ -14,9 +14,15 @@ import useFilter from "../../Components/Utils/Filter/useFilter"; const FilterLayout = ({ filterTitle, sub_children, + search_by = "name", + width = "500px", + haveFilter=true }: { filterTitle: string; sub_children: any; + search_by?:string + width?:string + haveFilter?:boolean }) => { const { t } = useTranslation(); const translateArray = translateOptions(search_array, t); @@ -37,17 +43,23 @@ const FilterLayout = ({ ModelClassName="filter_model_direction" isOpen={isOpen} setIsOpen={setIsOpen} + width={width} >
{sub_children}
-
setIsOpen(true)}> + {haveFilter && + +
setIsOpen(true)}> {t("header.filter")} -
+
+ + } + @@ -66,7 +78,7 @@ const FilterLayout = ({
- +
diff --git a/src/Layout/Dashboard/FormikFormModel.tsx b/src/Layout/Dashboard/FormikFormModel.tsx index c12a9cc..3f99817 100644 --- a/src/Layout/Dashboard/FormikFormModel.tsx +++ b/src/Layout/Dashboard/FormikFormModel.tsx @@ -35,9 +35,6 @@ const FormikFormModel: React.FC = ({ useEffect(() => { if (isOpen === "") { formik.setErrors({}); - } - if (isOpen === "isSuccess") { - formik.setErrors({}); formik.resetForm(); } }, [isOpen]); diff --git a/src/Layout/Dashboard/PageHeader.tsx b/src/Layout/Dashboard/PageHeader.tsx index 79773e4..153822a 100644 --- a/src/Layout/Dashboard/PageHeader.tsx +++ b/src/Layout/Dashboard/PageHeader.tsx @@ -27,12 +27,6 @@ const PageHeader = ({ const { t } = useTranslation(); const PrevPath = getPrevPathRoute(location.pathname); - const handelNavigate = () => { - if (PrevPath === 0) { - return; - } - navigate(deletePathSegments(location.pathname, PrevPath)); - }; const handleNavigateToPage = (location: string) => { navigate(location); }; @@ -41,7 +35,7 @@ const PageHeader = ({ return (
- +

{t(`PageTitle.${pageTitle}`)}

diff --git a/src/Pages/Admin/Grade/useTableColumns.tsx b/src/Pages/Admin/Grade/useTableColumns.tsx index c48ccef..43f29f3 100644 --- a/src/Pages/Admin/Grade/useTableColumns.tsx +++ b/src/Pages/Admin/Grade/useTableColumns.tsx @@ -15,6 +15,8 @@ import { import ActionButtons from "../../../Components/Table/ActionButtons"; import ColumnsImage from "../../../Components/Columns/ColumnsImage"; import { Grade } from "../../../types/Grade"; +import { CiImageOff } from "react-icons/ci"; +import { isValidImage } from "../../../utils/isValidImage"; export const useColumns = () => { const { handel_open_model } = useModalHandler(); @@ -59,20 +61,11 @@ export const useColumns = () => { align: "center", render: (_text: any, record: Grade) => { let str = record?.icon; - return ; + + return ; }, }, { - // canAddGrade ? ( - // - // ) : ( - // "" - // ), title: t("columns.procedure"), key: "actions", diff --git a/src/Pages/Admin/QuestionBank/Model/AddModel.tsx b/src/Pages/Admin/QuestionBank/Model/AddModel.tsx deleted file mode 100644 index 348426b..0000000 --- a/src/Pages/Admin/QuestionBank/Model/AddModel.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react"; -import { getInitialValues, getValidationSchema } from "./formUtil"; -import { ModalEnum } from "../../../../enums/Model"; -import LayoutModel from "../../../../Layout/Dashboard/LayoutModel"; -import { QueryStatusEnum } from "../../../../enums/QueryStatus"; -import ModelForm from "./ModelForm"; -import { useAddGrade } from "../../../../api/grade"; - -const AddModel: React.FC = () => { - const { mutate, status } = useAddGrade(); - - const handleSubmit = (values: any) => { - mutate({ - ...values, - }); - }; - return ( - <> - - - - - ); -}; - -export default AddModel; diff --git a/src/Pages/Admin/QuestionBank/Model/EditModel.tsx b/src/Pages/Admin/QuestionBank/Model/EditModel.tsx deleted file mode 100644 index a2e1fdb..0000000 --- a/src/Pages/Admin/QuestionBank/Model/EditModel.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from "react"; -import { getInitialValues, getValidationSchema } from "./formUtil"; -import { ModalEnum } from "../../../../enums/Model"; -import LayoutModel from "../../../../Layout/Dashboard/LayoutModel"; -import ModelForm from "./ModelForm"; -import { QueryStatusEnum } from "../../../../enums/QueryStatus"; -import { useObjectToEdit } from "../../../../zustand/ObjectToEditState"; -import { useUpdateQuestion } from "../../../../api/Question"; -import { handelImageState } from "../../../../utils/DataToSendImageState"; - -const EditModel: React.FC = () => { - const { mutate, status } = useUpdateQuestion(); - const { objectToEdit } = useObjectToEdit((state) => state); - - const handleSubmit = (values: any) => { - const Data_to_send = { ...values }; - const handelImage = handelImageState(Data_to_send, "icon"); - mutate(handelImage); - }; - - return ( - <> - - - - - ); -}; - -export default EditModel; diff --git a/src/Pages/Admin/QuestionBank/Model/FilterForm.tsx b/src/Pages/Admin/QuestionBank/Model/FilterForm.tsx index c870850..3571691 100644 --- a/src/Pages/Admin/QuestionBank/Model/FilterForm.tsx +++ b/src/Pages/Admin/QuestionBank/Model/FilterForm.tsx @@ -2,15 +2,141 @@ import React from "react"; import ValidationField from "../../../../Components/ValidationField/ValidationField"; import { Col, Row } from "reactstrap"; import { useFormikContext } from "formik"; +import { useGetAllGrade } from "../../../../api/grade"; +import { useValidationValidationParamState } from "../../../../Components/ValidationField/state/ValidationValidationParamState"; +import { useGetAllUnit } from "../../../../api/unit"; +import { useGetAllSubject } from "../../../../api/subject"; +import { useGetAllLesson } from "../../../../api/lesson"; const FilterForm = () => { - const formik = useFormikContext(); + + const { ValidationParamState } = useValidationValidationParamState(); + const { + GradeName, GradeCurrentPage, + SubjectName, SubjectCurrentPage, + UnitName, UnitCurrentPage, + LessonName, LessonCurrentPage + + + } = ValidationParamState; + + + + const { data: Grade, isLoading: isLoadingGrade } = useGetAllGrade({ + name: GradeName, + page: GradeCurrentPage + }); + const GradeOption = Grade?.data ?? [] + const canChangeGradePage = !!Grade?.links?.next; + const GradePage = Grade?.meta?.currentPage; + + + /// subject_id + const { data: Subject, isLoading: isLoadingSubject } = useGetAllSubject({ + name: SubjectName, + page: SubjectCurrentPage + }); + const SubjectOption = Subject?.data ?? [] + const canChangeSubjectPage = !!Subject?.links?.next; + const SubjectPage = Subject?.meta?.currentPage; + + /// unit_id + const { data: Unit, isLoading: isLoadingUnit } = useGetAllUnit({ + name: UnitName, + page: UnitCurrentPage + }); + const UnitOption = Unit?.data ?? [] + const canChangeUnitPage = !!Unit?.links?.next; + const UnitPage = Unit?.meta?.currentPage; + + /// lessonsIds + const { data: Lesson, isLoading: isLoadingLesson } = useGetAllLesson({ + name: LessonName, + page: LessonCurrentPage + }); + const LessonOption = Lesson?.data ?? [] + const canChangeLessonPage = !!Lesson?.links?.next; + const LessonPage = Lesson?.meta?.currentPage; return (
- + {/* + grade_id + */} + + + + {/* + subject_id + */} + + + + + + + + + + {/* + unit_id + */} + + + + + {/* + lessonsIds + */} + +
diff --git a/src/Pages/Admin/QuestionBank/Model/formUtil.ts b/src/Pages/Admin/QuestionBank/Model/formUtil.ts deleted file mode 100644 index 77f69bf..0000000 --- a/src/Pages/Admin/QuestionBank/Model/formUtil.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as Yup from "yup"; -import { Grade, GradeInitialValues } from "../../../../types/Grade"; - -export const getInitialValues = ( - objectToEdit: Partial, -): GradeInitialValues => { - return { - id: objectToEdit?.id, - name: objectToEdit?.name ?? "", - icon: objectToEdit?.icon ?? "", - }; -}; - -export const getValidationSchema = () => { - // validate input - return Yup.object().shape({ - name: Yup.string().required("validation.required"), - }); -}; diff --git a/src/Pages/Admin/QuestionBank/Page.tsx b/src/Pages/Admin/QuestionBank/Page.tsx index 91c7f43..6243a34 100644 --- a/src/Pages/Admin/QuestionBank/Page.tsx +++ b/src/Pages/Admin/QuestionBank/Page.tsx @@ -10,8 +10,6 @@ import FilterForm from "./Model/FilterForm"; import { canAddQuestionBank } from "../../../utils/hasAbilityFn"; const Table = lazy(() => import("./Table")); -const AddModalForm = lazy(() => import("./Model/AddModel")); -const EditModalForm = lazy(() => import("./Model/EditModel")); const DeleteModalForm = lazy( () => import("../../../Layout/Dashboard/DeleteModels"), ); @@ -33,10 +31,8 @@ const TableHeader = () => { ModelAbility={ModalEnum?.QUESTION_BANK_ADD} canAdd={canAddQuestionBank} /> - } filterTitle="table.QuestionBank" /> + } filterTitle="table.QuestionBank" /> - - { const { filterState } = useFilterState(); + const { setFilter,Filter } = useFilterStateState(); + console.log(filterState,"filterState"); + const response = useGetAllQuestion({ pagination: true, ...filterState, + content:Filter?.content + }); return ; diff --git a/src/Pages/Admin/QuestionBank/useTableColumns.tsx b/src/Pages/Admin/QuestionBank/useTableColumns.tsx index 632669b..def1863 100644 --- a/src/Pages/Admin/QuestionBank/useTableColumns.tsx +++ b/src/Pages/Admin/QuestionBank/useTableColumns.tsx @@ -1,6 +1,5 @@ import { TableColumnsType } from "antd"; import { Question } from "../../../types/Item"; -import { FaPlus } from "react-icons/fa"; import { ModalEnum } from "../../../enums/Model"; import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; import { useTranslation } from "react-i18next"; @@ -8,7 +7,6 @@ import { ABILITIES_ENUM } from "../../../enums/abilities"; import { useNavigate } from "react-router-dom"; import { useModalState } from "../../../zustand/Modal"; import { - canAddQuestion, canDeleteQuestion, canEditQuestion, } from "../../../utils/hasAbilityFn"; @@ -19,19 +17,18 @@ export const useColumns = () => { const navigate = useNavigate(); const { setIsOpen } = useModalState((state) => state); - const handelAdd = () => { - setObjectToEdit({}); - navigate(`${ABILITIES_ENUM?.QUESTION}/add`); - }; - const handelDelete = (data: any) => { setObjectToEdit(data); setIsOpen(ModalEnum?.QUESTION_DELETE); }; const handleEdit = (record: any) => { - setObjectToEdit(record); - navigate(`${ABILITIES_ENUM?.QUESTION}/${record?.id}`); + console.log(record,"record"); + const lesson = record?.lessons?.[0] ; + const unit = lesson?.unit; + const subject = unit?.subject; + const grade = subject?.grade; + navigate(`/${ABILITIES_ENUM?.GRADE}/${grade?.id}/${ABILITIES_ENUM?.SUBJECT}/${subject?.id}/${ABILITIES_ENUM?.UNIT}/${unit?.id}/${ABILITIES_ENUM?.LESSON}/${lesson?.id}/${ABILITIES_ENUM?.QUESTION}/${record?.id}`); }; const [t] = useTranslation(); @@ -51,6 +48,24 @@ export const useColumns = () => { render: (text, record) => record?.content, ellipsis: true, }, + { + title: `${t("columns.course")}`, + dataIndex: "lessons", + key: "lessons", + align: "center", + render: (text, record) => { + const lesson = record?.lessons?.[0] ; + const unit = lesson?.unit; + const subject = unit?.subject; + const grade = subject?.grade; + + return ( + <> {grade?.name} + ) + }, + ellipsis: true, + }, + { title: `${t("columns.hint")}`, dataIndex: "hint", diff --git a/src/Pages/Admin/question/FilterForm.tsx b/src/Pages/Admin/question/FilterForm.tsx index 7aae982..48f546e 100644 --- a/src/Pages/Admin/question/FilterForm.tsx +++ b/src/Pages/Admin/question/FilterForm.tsx @@ -1,27 +1,143 @@ import React from "react"; import ValidationField from "../../../Components/ValidationField/ValidationField"; import { Col, Row } from "reactstrap"; -import useFormatDataToSelect from "../../../utils/useFormatDataToSelect"; +import { useFormikContext } from "formik"; +import { useGetAllGrade } from "../../../api/grade"; +import { useValidationValidationParamState } from "../../../Components/ValidationField/state/ValidationValidationParamState"; +import { useGetAllUnit } from "../../../api/unit"; +import { useGetAllSubject } from "../../../api/subject"; +import { useGetAllLesson } from "../../../api/lesson"; const FilterForm = () => { - const yesNoArray = [ - { id: "لا", name: "لا" }, - { id: "نعم", name: "نعم" }, - ]; + + const { ValidationParamState } = useValidationValidationParamState(); + const { + GradeName, GradeCurrentPage, + SubjectName, SubjectCurrentPage, + UnitName, UnitCurrentPage, + LessonName, LessonCurrentPage + + + } = ValidationParamState; + + + + const { data: Grade, isLoading: isLoadingGrade } = useGetAllGrade({ + name: GradeName, + page: GradeCurrentPage + }); + const GradeOption = Grade?.data ?? [] + const canChangeGradePage = !!Grade?.links?.next; + const GradePage = Grade?.meta?.currentPage; + + + /// subject_id + const { data: Subject, isLoading: isLoadingSubject } = useGetAllSubject({ + name: SubjectName, + page: SubjectCurrentPage + }); + const SubjectOption = Subject?.data ?? [] + const canChangeSubjectPage = !!Subject?.links?.next; + const SubjectPage = Subject?.meta?.currentPage; + + /// unit_id + const { data: Unit, isLoading: isLoadingUnit } = useGetAllUnit({ + name: UnitName, + page: UnitCurrentPage + }); + const UnitOption = Unit?.data ?? [] + const canChangeUnitPage = !!Unit?.links?.next; + const UnitPage = Unit?.meta?.currentPage; + + /// lessonsIds + const { data: Lesson, isLoading: isLoadingLesson } = useGetAllLesson({ + name: LessonName, + page: LessonCurrentPage + }); + const LessonOption = Lesson?.data ?? [] + const canChangeLessonPage = !!Lesson?.links?.next; + const LessonPage = Lesson?.meta?.currentPage; + return (
- - {/* */} + {/* + grade_id + */} + + + + {/* + subject_id + */} + + + + + + + + + + {/* + unit_id + */} + + + + + {/* + lessonsIds + */} + + - {/* - - */} ); diff --git a/src/Pages/Admin/question/Page.tsx b/src/Pages/Admin/question/Page.tsx index 6584a49..31537df 100644 --- a/src/Pages/Admin/question/Page.tsx +++ b/src/Pages/Admin/question/Page.tsx @@ -65,6 +65,8 @@ const TableHeader = () => { } filterTitle={` ${unitName} (${LessonName}) `} + search_by="content" + haveFilter={false} />
diff --git a/src/Pages/Admin/question/Table.tsx b/src/Pages/Admin/question/Table.tsx index 491377b..d0917ce 100644 --- a/src/Pages/Admin/question/Table.tsx +++ b/src/Pages/Admin/question/Table.tsx @@ -5,15 +5,18 @@ import { useGetAllQuestion } from "../../../api/Question"; import { useParams } from "react-router-dom"; import { ParamsEnum } from "../../../enums/params"; import { useFilterState } from "../../../Components/Utils/Filter/FilterState"; +import { useFilterStateState } from "../../../zustand/Filter"; const App: React.FC = () => { const { lesson_id } = useParams(); const { filterState } = useFilterState(); + const { setFilter,Filter } = useFilterStateState(); const response = useGetAllQuestion({ lessonsIds: [lesson_id], pagination: true, ...filterState, + content:Filter?.content }); return ; }; diff --git a/src/Pages/Admin/subject/Table/useTableColumns.tsx b/src/Pages/Admin/subject/Table/useTableColumns.tsx index d8e26d4..2f3315b 100644 --- a/src/Pages/Admin/subject/Table/useTableColumns.tsx +++ b/src/Pages/Admin/subject/Table/useTableColumns.tsx @@ -14,6 +14,7 @@ import { } from "../../../../utils/hasAbilityFn"; import { ABILITIES_ENUM } from "../../../../enums/abilities"; import { Subject } from "../../../../types/Subject"; +import { CiImageOff } from "react-icons/ci"; export const useColumns = () => { const navigate = useNavigate(); @@ -54,7 +55,7 @@ export const useColumns = () => { align: "center", render: (row: Subject, record) => { let str = record.icon; - return ; + return ; }, }, diff --git a/src/Styles/Layout/DataTable.scss b/src/Styles/Layout/DataTable.scss index 51540fd..acd9b62 100644 --- a/src/Styles/Layout/DataTable.scss +++ b/src/Styles/Layout/DataTable.scss @@ -61,6 +61,9 @@ border-radius: var(--border-radius); transition: 1s ease-in-out; animation: fadeInRight 1s ease-in-out; + max-height: 90vh; + overflow-y: scroll; + @include Scrollbar; > header { display: flex; diff --git a/src/Styles/Layout/FilterLayout.scss b/src/Styles/Layout/FilterLayout.scss index c86cda1..7e6f38c 100644 --- a/src/Styles/Layout/FilterLayout.scss +++ b/src/Styles/Layout/FilterLayout.scss @@ -85,3 +85,8 @@ font-size: 8px !important; } } + + +.model_sub_children{ + padding-bottom: 30px; +} \ No newline at end of file diff --git a/src/Styles/Pages/exercise.scss b/src/Styles/Pages/exercise.scss index 6a2078e..12f1087 100644 --- a/src/Styles/Pages/exercise.scss +++ b/src/Styles/Pages/exercise.scss @@ -209,12 +209,12 @@ } .SelectTag { - padding-inline: 20px; + // padding-inline: 20px; } .exercise_add { .add_new_button { - padding-inline: 20px !important; + // padding-inline: 20px !important; } } @@ -229,12 +229,12 @@ display: flex; align-items: center; justify-content: center; - >{ - flex: 1; - min-height: auto; - min-width: 30px; + // >{ + // flex: 1; + // min-height: auto; + // min-width: 30px; - } + // } .ant-btn{ min-height: 30px !important; max-height: 30px !important; diff --git a/src/translate/ar.json b/src/translate/ar.json index ba4c07b..fd7002c 100644 --- a/src/translate/ar.json +++ b/src/translate/ar.json @@ -196,6 +196,7 @@ "normal_question": " تمرين عادي", "hint":"شرح ", "tags":"كلمات مفتاحية", + "course":" الصفوف", "student_full_name":"اسم الطالب الثلاثي", "amount_paid":"المبلغ المدفوع", "sale_date":"تاريخ البيع", @@ -450,6 +451,10 @@ "city": "المحافظة", "personal_image": "صورة شخصية", "id_image": "صورة الهوية", + "grade":"الصفوف", + "subject":"المادة", + "unit":"الوحدة", + "lesson":"الدرس", "date_of_receipt":"تاريخ الاستلام", "amount_value":"قيمة المبلغ" }, diff --git a/src/types/Item.ts b/src/types/Item.ts index 8c97e8d..fec4221 100644 --- a/src/types/Item.ts +++ b/src/types/Item.ts @@ -315,7 +315,8 @@ export interface Question { question_options_count?: any; answers: QuestionOption[]; hint?: string; - tags: tags[]; // Assuming tags are strings, adjust as per actual data type + tags: tags[]; + lessons:any } export type report = { diff --git a/src/utils/isValidImage.ts b/src/utils/isValidImage.ts new file mode 100644 index 0000000..bc45a00 --- /dev/null +++ b/src/utils/isValidImage.ts @@ -0,0 +1,9 @@ +export const isValidImage = (url: string): Promise => { + return new Promise((resolve) => { + const img = new Image(); + img.src = url; + + img.onload = () => resolve(true); // Image loaded successfully + img.onerror = () => resolve(false); // Error loading image + }); + }; \ No newline at end of file