diff --git a/frontend/.gitignore b/.gitignore
similarity index 85%
rename from frontend/.gitignore
rename to .gitignore
index 0563835d..106a295f 100644
--- a/frontend/.gitignore
+++ b/.gitignore
@@ -1,8 +1,8 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
-/node_modules
-/.pnp
+node_modules
+.pnp
.pnp.js
.yarn/install-state.gz
@@ -10,11 +10,11 @@
/coverage
# next.js
-/.next/
-/out/
+.next/
+out/
# production
-/build
+build
# misc
.DS_Store
@@ -33,4 +33,7 @@ yarn-error.log*
# typescript
*.tsbuildinfo
-next-env.d.ts
\ No newline at end of file
+next-env.d.ts
+
+env
+venv
\ No newline at end of file
diff --git a/frontend/.env b/frontend/.env
new file mode 100644
index 00000000..e2fa391f
--- /dev/null
+++ b/frontend/.env
@@ -0,0 +1,2 @@
+REACT_APP_BASE_URL=http://127.0.0.1:8000
+
diff --git a/frontend/src/App.js b/frontend/src/App.js
index 12636704..b44623c1 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -1,51 +1,79 @@
import './App.css';
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Navbar from "./components/Navbar";
-import Home from "./pages/Home";
-import Search from './pages/Search';
+import React, { Suspense, useEffect, useState } from 'react';
import { DataProvider } from './context/DataContext';
-import ImageTree from './pages/3DTree';
-import React, { useEffect, useState } from 'react';
-import axios from 'axios';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
+import { gql } from '@apollo/client';
+import { useQuery } from '@apollo/client';
+
+// Lazy load components
+const Home = React.lazy(() => import('./pages/Home'));
+const Search = React.lazy(() => import('./pages/Search'));
+const ImageTree = React.lazy(() => import('./pages/3DTree'));
+
+function generateQuery(depth) {
+ if (depth === 0) {
+ return `
+ rollNo
+ name
+ parentId
+ picture
+ `;
+ }
+ return `
+ rollNo
+ name
+ parentId
+ picture
+ children {
+ ${generateQuery(depth - 1)}
+ }
+ `;
+}
+
+const GET_Query = gql`
+ query GetNestedTree {
+ studentTree {
+ ${generateQuery(10)}
+ }
+ }
+`;
function App() {
const [data, setData] = useState([]);
- const [error,seterror]=useState(false)
- useEffect(() => {
- const fetchData = async () => {
- try {
- const response = await axios.get(`https://devluplabs.iitj.ac.in/ftadmin/tree/`);
- setData(response.data);
- } catch (error) {
- seterror(true)
- }
- };
- fetchData();
- }, []);
-
- if(error){
- toast.error("server error",{
- autoClose:20000
- })
- }
-// console.log(window.location.pathname)
+ const [error, setError] = useState(false);
+ const { error: queryError, data: treeData } = useQuery(GET_Query);
+
+ useEffect(() => {
+ if (treeData && treeData.studentTree) {
+ setData(treeData.studentTree);
+ }
+ if (queryError) {
+ setError(true);
+ toast.error("GraphQL query error", {
+ autoClose: 20000
+ });
+ }
+ }, [treeData, queryError]);
+
+ // if (loading) return
Loading...
;
+
return (
-
-
-
-
-
-
- } />
- } />
- } />
-
-
-
+
+
+
+
+ Loading...}>
+
+ } />
+ } />
+ } />
+
+
+
+
);
}
diff --git a/frontend/src/assets/Style/team.css b/frontend/src/assets/Style/team.css
index b447c86c..a387e084 100644
--- a/frontend/src/assets/Style/team.css
+++ b/frontend/src/assets/Style/team.css
@@ -1,4 +1,4 @@
-.modalme{
+.modalme {
position: fixed;
top: 0;
left: 0;
@@ -8,108 +8,127 @@
display: flex;
justify-content: center;
align-items: center;
+ z-index: 1000;
}
-.modal-contentme{
- padding: 20px;
- border-radius: 5px;
+
+.modal-contentme {
+ padding: 30px;
+ border-radius: 10px;
color: aliceblue;
- font-weight: 900;
- justify-content: center;
+ background: rgba(20, 94, 135, 0.85);
+ box-shadow: 0 8px 32px 0 rgba(243, 243, 243, 0.37);
+ max-width: 800px;
+ width: 90%;
+}
+
+.team-header {
+ display: flex;
+ justify-content: space-between;
align-items: center;
- background: rgba(20, 94, 135, 0.75);
-box-shadow: 0 8px 32px 0 rgba(243, 243, 243, 0.37);
-border-radius: 10px;
+ margin-bottom: 20px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+ padding-bottom: 15px;
+}
+
+.team-header h2 {
+ margin: 0;
+ font-size: 1.8rem;
+}
+
+.team-members-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+ gap: 25px;
+}
+
+.team-member-card {
+ background: rgba(255, 255, 255, 0.1);
+ border-radius: 8px;
+ padding: 20px;
+ text-align: center;
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
+}
+
+.team-member-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
+}
+
+.team-member-card h3 {
+ margin: 0 0 5px 0;
+ font-size: 1.2rem;
}
-.iconsocialmedia{
+
+.member-id {
+ color: rgba(255, 255, 255, 0.8);
+ margin-bottom: 15px;
+ font-size: 0.9rem;
+}
+
+.iconsocialmedia {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
- color:aliceblue;
- }
- .closeshomepro{
- position: relative;
- top: 0px;
- right:0px !important;
- cursor: pointer;
- color:aliceblue;
- }
+ margin-top: 15px;
+}
+
+.iconsocialmedia a {
+ transition: transform 0.2s ease;
+}
+.iconsocialmedia a:hover {
+ transform: scale(1.2);
+}
+.closeshomepro {
+ cursor: pointer;
+ color: aliceblue;
+ transition: transform 0.2s ease;
+}
-/* Popup.css */
-.modalhelp {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- backdrop-filter: blur(3px);
- display: flex;
- justify-content: center;
- align-items: center;
+.closeshomepro:hover {
+ transform: scale(1.1);
+ color: #a3a3a3;
}
.visible {
- animation: movedown 1s forwards;
+ animation: movedown 0.5s forwards;
}
.notvisible {
- animation: moveup 1s forwards;
+ animation: moveup 0.5s forwards;
}
@keyframes movedown {
- 0% {
- transform: translateY(-400px);
- /* Start position: move up by 100px */
- }
-
- 60% {
- transform: translateY(100px);
- /* End position: move down to original position */
- }
-
- 100% {
- transform: translateY(0);
- /* End position: move down to original position */
- }
+ 0% {
+ transform: translateY(-400px);
+ opacity: 0;
+ }
+ 100% {
+ transform: translateY(0);
+ opacity: 1;
+ }
}
@keyframes moveup {
- 100% {
- transform: translateY(-400px);
- /* Start position: move up by 100px */
- }
-
- 0% {
- transform: translateY(0);
- /* End position: move down to original position */
- }
-}
-
-.modal-contenthelp {
- /* background-color: rgba(255, 255, 255, 0.338); */
- padding: 20px;
- width: 400px;
- border-radius: 5px;
- box-shadow: 0 0 10px rgba(20, 20, 20, 0.3);
- color: aliceblue;
- font-weight: 900;
-
- background: rgba(14, 14, 14, 0.4);
- box-shadow: 0 8px 32px 0 rgba(243, 243, 243, 0.37);
- border-radius: 10px;
-}
-
-.closes {
- position: relative;
- top: 0px;
- right: 0px !important;
- cursor: pointer;
-}
-
-@media screen and (max-width: 600px) {
- .modal-contenthelp {
- width: 250px;
- }
-}
\ No newline at end of file
+ 0% {
+ transform: translateY(0);
+ opacity: 1;
+ }
+ 100% {
+ transform: translateY(-400px);
+ opacity: 0;
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .team-members-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .modal-contentme {
+ width: 85%;
+ padding: 20px;
+ }
+}
diff --git a/frontend/src/assets/Style/tree.css b/frontend/src/assets/Style/tree.css
index 62136dad..f1d78f1d 100644
--- a/frontend/src/assets/Style/tree.css
+++ b/frontend/src/assets/Style/tree.css
@@ -12,23 +12,7 @@
position: relative;
display: block;
}
-.container_JYOTIN{
- border: 3px solid #ffffff;
- box-shadow: 2px 2px 5px black;
- /* padding: 10px 10px; */
- color: #ffffff;
- font-family: arial, verdana, tahoma;
- font-size: 20px;
- display: inline-block;
- border-radius: 20px;
- transition: all 0.5s;
- -webkit-transition: all 0.5s;
- -moz-transition: all 0.5s;
- cursor: pointer;
- width: 100px;
- height: 120px;
- background-color: #3574b4;
-}
+
.tree_ li {
float: left;
text-align: center;
diff --git a/frontend/src/components/2DTree.jsx b/frontend/src/components/2DTree.jsx
index 5ea4dd9b..e4eb901f 100644
--- a/frontend/src/components/2DTree.jsx
+++ b/frontend/src/components/2DTree.jsx
@@ -1,52 +1,115 @@
-import React, { useState } from 'react';
-import Tree from 'react-d3-tree';
-import '../assets/Style/home.css'
-import { CircularProgressbar } from 'react-circular-progressbar';
-import 'react-circular-progressbar/dist/styles.css';
-import Profile from './Profile';
+import React, { useState, useRef, useEffect } from "react";
+import Tree from "react-d3-tree";
+import "../assets/Style/home.css";
+import { CircularProgressbar } from "react-circular-progressbar";
+import "react-circular-progressbar/dist/styles.css";
+// import Profile from "./Profile";
+import { useData } from "../context/DataContext";
+import { useNavigate } from "react-router-dom";
const TwoDTree = ({ data }) => {
- const [roll, setroll] = useState()
- const [showModal, setShowModal] = useState(false);
+ // const [roll, setroll] = useState();
+ // const [showModal, setShowModal] = useState(false);
+ const [dimensions, setDimensions] = useState({ width: 800, height: 600 });
+ const treeContainerRef = useRef(null);
const value = 0.5;
+ const { search } = useData();
+ const searchNode = useRef();
+ const navigate = useNavigate();
- if (!data) return
+ useEffect(() => {
+ const setInitialDimensions = () => {
+ if (treeContainerRef.current) {
+ const { width, height } =
+ treeContainerRef.current.getBoundingClientRect();
+ setDimensions({ width, height });
+ }
+ };
- const new_data = []
+ setInitialDimensions();
+ window.addEventListener("resize", setInitialDimensions);
+ return () => window.removeEventListener("resize", setInitialDimensions);
+ }, []);
+
+ useEffect(() => {
+ searchNode.current = document.getElementById(search);
+ // console.log(searchNode);
+ if (searchNode.current) {
+ // Trigger programmatic click
+ const clickEvent = new MouseEvent("click", {
+ bubbles: true,
+ cancelable: true,
+ view: window,
+ });
+ searchNode.current.dispatchEvent(clickEvent);
+ }
+ },[search])
+
+ if (!data)
+ return (
+
+
+
+ );
+
+ const new_data = [];
const all_parent = {
- name: 'All',
- children: []
- }
- data.forEach(item => {
+ name: "All",
+ children: [],
+ };
+ data.forEach((item) => {
all_parent.children.push(item);
});
- new_data.push(all_parent)
+ new_data.push(all_parent);
+
+ // const handleNodeMouseOver = (nodeDatum) => {
+ // // console.log(search);
+ // if (nodeDatum.name !== "All") {
+ // setroll(nodeDatum);
+ // setShowModal(true);
+ // }
+ // };
+
+ // const handleNodeMouseOut = (nodeData) => {
+ // if (nodeData.name !== "All") {
+ // setShowModal(false);
+ // }
+ // };
+
+ const renderCustom = ({ nodeDatum, toggleNode }) => {
+ const str = nodeDatum.name;
+ const name = str.slice(0, 19) + "";
- const renderCustom = ({ nodeDatum, toggleNode, links }) => {
- const str = nodeDatum.name
- const name = str.slice(0, 19) + ''
return (
handleNodeMouseOut(nodeDatum)}
- onMouseOver={() => handleNodeMouseOver(nodeDatum)}
+ onClick={toggleNode}
+ // onMouseOut={() => handleNodeMouseOut(nodeDatum)}
+ // onMouseOver={() => handleNodeMouseOver(nodeDatum)}
+ id={nodeDatum.rollNo}
>
-
-
- {name}
+ {
+ console.log(nodeDatum.rollNo);
+ navigate(`/search?q=${window.btoa(nodeDatum.rollNo)}`);
+ }
+ }/>
+
+ {name}
+
+ );
+ };
- )
- }
const getLinkColor = (link) => {
- if (link.source.name.includes('root')) {
- return 'white';
+ if (link.source.name.includes("root")) {
+ return "white";
}
- return 'white';
+ return "white";
};
const getLinkProps = (link) => ({
@@ -54,54 +117,36 @@ const TwoDTree = ({ data }) => {
strokeWidth: 10,
});
- const handleNodeMouseOver = (nodeDatum, event) => {
- if (nodeDatum.name !== 'All') {
- setroll(nodeDatum)
- setShowModal(true)
-
- }
- };
- const handleNodeMouseOut = (nodeData, event) => {
- if (nodeData.name !== 'All') {
- setShowModal(false)
- }
- };
- const dimensions = {
- width: 800,
- height: 600
- };
return (
<>
- {showModal && (
-
- )}
- 'custom-link'}
- renderCustomNodeElement={renderCustom}
- transitionDuration={500}
- shouldCollapseNeighborNodes={true}
- separation={{ siblings: 2, nonSiblings: 2 }}
- // renderCustomLinkElement={renderCustomLink}
-
- />
+ {/* {showModal && } */}
+
+
+ renderCustom({
+ ...rd3tProps,
+ toggleNode: () => {
+ rd3tProps.toggleNode();
+ },
+ })
+ }
+ transitionDuration={500}
+ shouldCollapseNeighborNodes={true}
+ separation={{ siblings: 2, nonSiblings: 2 }}
+ />
+
>
- )
-}
+ );
+};
-export default TwoDTree
+export default TwoDTree;
diff --git a/frontend/src/components/Family.jsx b/frontend/src/components/Family.jsx
index d677a15c..385b3a06 100644
--- a/frontend/src/components/Family.jsx
+++ b/frontend/src/components/Family.jsx
@@ -60,12 +60,12 @@ const IitjTree = ({ data }) => {
{treeDatas.map((item, index) =>
-
-
toggleModal(item.rollNo)}>{item.name.slice(0,15) + ''}
diff --git a/frontend/src/components/Navbar.jsx b/frontend/src/components/Navbar.jsx
index 19b9f1b8..60dc8e1d 100644
--- a/frontend/src/components/Navbar.jsx
+++ b/frontend/src/components/Navbar.jsx
@@ -1,116 +1,198 @@
+import React, { useState,useEffect } from "react";
+import { Link, NavLink } from "react-router-dom";
+import { useQuery, gql } from "@apollo/client";
import "../assets/Style/navbar.css";
-import { Link } from "react-router-dom";
import logo from "../assets/image/logo.png";
-import React, { useState } from "react";
-import { useQuery, gql } from "@apollo/client";
-import { useNavigate } from 'react-router-dom';
import { FiAlignLeft } from "react-icons/fi";
import { IoClose } from "react-icons/io5";
+import { useData } from "../context/DataContext";
-function Navbar({ error }) {
- const navigate = useNavigate();
- const [parentId, setParentId] = useState('');
- const [close, setclose] = useState(true)
+const SEARCH_QUERY = gql`
+ query Query($searchText: String!) {
+ studentSearch(searchQuery: $searchText) {
+ name
+ rollNo
+ }
+ }
+`;
- const FILMS_QUERY = gql`
- query Query($parentId: String!) {
- studentSearch(searchQuery: $parentId) {
- name
- rollNo
+const threshold = 600;
+
+const Navbar = ({ error }) => {
+ const { updateSearch } = useData();
+ const [searchText, setSearchText] = useState("");
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
+ const [ isMobile, setIsMobile ] = useState(false);
+
+ useEffect(() => {
+ const handleResize = () => {
+ const currentWidth = window.innerWidth;
+
+ if (currentWidth <= threshold ) {
+ setIsMobile(true);
+ } else if (currentWidth > threshold ) {
+ setIsMobile(false);
}
- }
- `;
- const { data, loading } = useQuery(FILMS_QUERY, {
- variables: { parentId },
+
+ };
+ handleResize();
+
+ window.addEventListener("resize", handleResize);
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ const { data, loading } = useQuery(SEARCH_QUERY, {
+ variables: { searchText },
+ skip: !searchText,
});
- const handleinput = (e) => {
- setclose(true)
+
+ const handleSearchInput = (e) => {
if (!error) {
- setParentId(e.target.value)
+ setSearchText(e.target.value);
}
- }
- const toggleModal = (Id) => {
- let encoded = window.btoa(Id);
- // let decoded = window.atob(encoded);
- navigate(`/search/${encoded}`);
- setParentId('')
- }
+ };
+
+ const handleStudentSelect = (rollNo) => {
+ updateSearch(rollNo);
+ setSearchText("");
+ if(isMobile)toggleMenu();
+ };
+
+ const toggleMenu = () => {
+ setIsMenuOpen(!isMenuOpen);
+ };
+
return (
- {close ?
-
setclose(!close)} />
- :
- setclose(!close)} />
+ {isMenuOpen ? (
+
+ ) : (
+
+ )}
- }
- {
- close ? null :
-
-
-
- Home
-
-
- ImageTree
-
+ {isMenuOpen && (
+
+
+
(isActive ? "active" : "")}
+ >
+ Home
+
+
(isActive ? "active" : "")}
+ >
+ ImageTree
+
+
+
+
+ {searchText && (
+
+
+
+ {loading ? (
+
Loading...
+ ) : data?.studentSearch?.length > 0 ? (
+ data.studentSearch.slice(0, 7).map((student, index) => (
+
handleStudentSelect(student.rollNo)}
+ >
+ {student.name} ({student.rollNo})
+
+ ))
+ ) : (
+ "No match with your name or roll number"
+ )}
+
- }
+ )}
+
+
+ )}
+
-
+
-
Indian Institute Of Technology Jodhpur
+
Indian Institute Of Technology Jodhpur
भारतीय प्रौद्योगिकी संस्थान जोधपुर
+
-
+ (isActive ? "active" : "")}
+ >
Home
-
+
-
+ (isActive ? "active" : "")}
+ >
ImageTree
-
+
-
+
+ {!isMobile && <>
handleinput(e)}
+ value={searchText}
+ onChange={handleSearchInput}
/>
- {parentId ?
-
+
+ {searchText && (
+
-
- {
- loading ?
Loading...
:
- data.studentSearch.length > 0 ?
- data.studentSearch.slice(0, 7).map((student, index) => (
-
toggleModal(student.rollNo)}
- >
- {student.name} ({student.rollNo})
-
- )) : 'No match with your name or roll number'
- }
+
+ {loading ? (
+
Loading...
+ ) : data?.studentSearch?.length > 0 ? (
+ data.studentSearch.slice(0, 7).map((student, index) => (
+
handleStudentSelect(student.rollNo)}
+ >
+ {student.name} ({student.rollNo})
+
+ ))
+ ) : (
+ "No match with your name or roll number"
+ )}
- : null
+ )} >
}
+
-
);
-}
+};
export default Navbar;
diff --git a/frontend/src/components/Profile.jsx b/frontend/src/components/Profile.jsx
index 048d6176..2248eccb 100644
--- a/frontend/src/components/Profile.jsx
+++ b/frontend/src/components/Profile.jsx
@@ -1,11 +1,24 @@
-import React from 'react'
-import '../assets/Style/profile.css'
+import React, { useRef, useEffect } from 'react';
import { Link } from "react-router-dom";
-import { FaLinkedin } from 'react-icons/fa';
+import { FaLinkedin, FaChevronRight } from 'react-icons/fa';
import { useQuery, gql } from "@apollo/client";
-import { FaChevronRight } from 'react-icons/fa';
-import demo from '../assets/image/download.jpeg'
+import demo from '../assets/image/download.jpeg';
+
function Profile({ toggleModal, rollNo }) {
+ const modalRef = useRef();
+ const docRef = useRef();
+
+ useEffect(() => {
+ const handleOutsideClick = (e) => {
+ if (modalRef.current && !modalRef.current.contains(e.target)) {
+ toggleModal();
+ }
+ };
+
+ docRef.current.addEventListener('mousedown', handleOutsideClick);
+
+ }, [toggleModal]);
+
const FILMS_QUERY = gql`
query Query($rollNo: String!) {
studentSearch(searchQuery: $rollNo) {
@@ -14,46 +27,62 @@ function Profile({ toggleModal, rollNo }) {
picture
linkedIn
}
- }
- `;
+ }
+ `;
+
var { loading, data } = useQuery(FILMS_QUERY, {
variables: { rollNo },
});
+
if (!loading) {
- data = data.studentSearch[0]
+ data = data.studentSearch[0];
+ console.log(data.picture.replace('open', 'thumbnail') );
}
+
return (
-
-
- {!loading ?
+
+
+ {!loading ? (
<>
- {
- window.location.pathname === 'https://devluplabs.iitj.ac.in/familytree/' ?
-
-

-
{data.name}
-
{data.rollNo}
-
- :
- <>
- {/*
*/}
-

-
{data.name}
-
{data.rollNo}
-
+ {window.location.pathname === `${process.env.REACT_APP_BASE_URL}/familytree/` ? (
+
+

+
{data.name}
+
{data.rollNo}
+
+ ) : (
+ <>
+
+

+
{data.name}
+
{data.rollNo}
+
- >
- }
+
+
+ >
+ )}
>
- :
- "loading"}
+ ) : (
+
Loading...
+ )}
- )
+ );
}
-export default Profile
+export default Profile;
diff --git a/frontend/src/components/Team.jsx b/frontend/src/components/Team.jsx
index 63795524..03a2bc06 100644
--- a/frontend/src/components/Team.jsx
+++ b/frontend/src/components/Team.jsx
@@ -1,29 +1,82 @@
-import React, { useEffect } from 'react'
+import React, { useEffect,useRef } from 'react'
import '../assets/Style/team.css'
import { FaLinkedin, FaGithub} from 'react-icons/fa';
import { AiOutlineCloseCircle } from 'react-icons/ai';
const Team = ({ team, teamshow }) => {
+
+ const modalRef = useRef();
+ const docRef = useRef();
+
+
+ // Team members data
+ const teamMembers = [
+ {
+ name: "Ashutosh Kumar",
+ id: "B22CS015",
+ linkedin: "https://www.linkedin.com/in/ashutosh-kumar-5aa3b3259/",
+ github: "https://github.com/a19hu/"
+ },
+ {
+ name: "Harshit Saini",
+ id: "B24CS1031",
+ linkedin: "https://www.linkedin.com/in/harshitsaini18/",
+ github: "https://github.com/harshitsaini17"
+ },
+ {
+ name: "Anshika Jha",
+ id: "B24CS1010",
+ linkedin: "https://www.linkedin.com/in/anshika-jha-2b2207326/",
+ github: "https://github.com/dkstlzk"
+ }
+ ];
+
+ useEffect(() => {
+ const handleOutsideClick = (e) => {
+ if (modalRef.current && !modalRef.current.contains(e.target)) {
+ team();
+ }
+ };
+
+ docRef.current.addEventListener('mousedown', handleOutsideClick);
+
+ }, [teamshow,team]);
+
useEffect(() => {
const timerId = setTimeout(() => {
}, 3000);
return () => clearTimeout(timerId);
}, []);
+
return (
-
-
-
-
Ashutosh kumar (B22CS015)
-
-
-
-
-
-
-
+
+
+
+
+
+ {teamMembers.map((member, index) => (
+
+
{member.name}
+
{member.id}
+
+
+ ))}
-
)
diff --git a/frontend/src/context/DataContext.jsx b/frontend/src/context/DataContext.jsx
index 1b56f40c..2718052f 100644
--- a/frontend/src/context/DataContext.jsx
+++ b/frontend/src/context/DataContext.jsx
@@ -1,25 +1,37 @@
-import React, { createContext, useContext, useState } from 'react';
+import React, { createContext, useContext, useState } from "react";
const DataContext = createContext();
export const useData = () => useContext(DataContext);
export const DataProvider = ({ children }) => {
- const [searchtext, setsearchtext] = useState('');
- const [searchtexts, setsearchId] = useState('');
-
+ const [searchtext, setsearchtext] = useState("");
+ const [searchtexts, setsearchId] = useState("");
+ const [search, setSearch] = useState(""); // New search state
const updateData = (newData) => {
setsearchtext(newData);
};
+
const updateDataId = (newData) => {
setsearchId(newData);
};
- const updatesearch = (newData) => {
- setsearchId(newData);
+
+ const updateSearch = (newData) => {
+ setSearch(newData); // Update search state
};
+
return (
-
+
{children}
);
diff --git a/frontend/src/index.js b/frontend/src/index.js
index 8c18035a..dc9c73fb 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -7,7 +7,7 @@ import { ApolloProvider, ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
- uri: `https://devluplabs.iitj.ac.in/ftadmin/graphql/`,
+ uri: `${process.env.REACT_APP_BASE_URL}/ftadmin/graphql/`,
cache: new InMemoryCache()
});
const root = ReactDOM.createRoot(document.getElementById('root'));
diff --git a/frontend/src/pages/3DTree.jsx b/frontend/src/pages/3DTree.jsx
index d9da92a1..515209b2 100644
--- a/frontend/src/pages/3DTree.jsx
+++ b/frontend/src/pages/3DTree.jsx
@@ -5,6 +5,13 @@ import defaultimage from '../assets/image/download.jpeg'
import logo from '../assets/image/logo.png'
import background from '../assets/image/b1.jpg'
+function convertGoogleDriveUrl(url, size = 80) {
+ const fileId = url.match(/id=([^&]+)/)?.[1];
+ if (!fileId) return url;
+
+ return `https://lh3.googleusercontent.com/d/${fileId}=s${size}`;
+}
+
const ImageTree = ({ data }) => {
const nodes = [{
id: 'All',
@@ -24,7 +31,7 @@ const ImageTree = ({ data }) => {
id: node.rollNo,
user: node.name,
description: node.rollNo,
- img: node.picture ? node.picture : defaultimage
+ img: node.picture ? convertGoogleDriveUrl(node.picture) : defaultimage
};
nodes.push(nodeData);
if (node.parentId) {
@@ -44,7 +51,7 @@ const ImageTree = ({ data }) => {
id: element.rollNo,
user: element.name,
description: element.rollNo,
- img: element.picture ? element.picture : defaultimage
+ img: element.picture ? convertGoogleDriveUrl(element.picture) : defaultimage
};
nodes.push(nodeData);
links.push({ source: 'All', target: element.rollNo });
diff --git a/frontend/src/pages/Search.jsx b/frontend/src/pages/Search.jsx
index cf5e2ecc..ad97b345 100644
--- a/frontend/src/pages/Search.jsx
+++ b/frontend/src/pages/Search.jsx
@@ -1,14 +1,16 @@
import React from 'react';
import { useQuery, gql, } from "@apollo/client";
import IitjTree from '../components/Family';
-import { useNavigate,useParams } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import background from '../assets/image/b1.jpg'
+import { useSearchParams } from 'react-router-dom';
const Search = () => {
const navigate = useNavigate();
- var { id } = useParams();
+ const [searchParams] = useSearchParams();
+ const id= searchParams.get('q');
const searchtexts=window.atob(id);
const FILMS_QUERYS = gql`
query Query($searchtexts: String!) {
diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js
index f79884a8..7b5ec26f 100644
--- a/frontend/tailwind.config.js
+++ b/frontend/tailwind.config.js
@@ -3,7 +3,23 @@
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
- extend: {},
+ extend: {
+ keyframes: {
+ movedown: {
+ '0%': { transform: 'translateY(-400px)' },
+ '60%': { transform: 'translateY(100px)' },
+ '100%': { transform: 'translateY(0)' }
+ },
+ moveup: {
+ '0%': { transform: 'translateY(0)' },
+ '100%': { transform: 'translateY(-400px)' }
+ }
+ },
+ animation: {
+ 'movedown': 'movedown 1s forwards',
+ 'moveup': 'moveup 1s forwards'
+ }
+ },
},
plugins: [],
};
\ No newline at end of file
diff --git a/server/.env b/server/.env
new file mode 100644
index 00000000..8f5a96e6
--- /dev/null
+++ b/server/.env
@@ -0,0 +1,12 @@
+DB_NAME=familytree
+DB_USER=postgres
+DB_PASSWORD=dev@iitj
+DB_HOST=10.6.0.63
+DB_PORT=5432
+
+SECRET_KEY=django-insecure-w72ih+f^$g$lmg$#60w*3!-i*t+jl8cfc-nsfaas=zfdwq6ckv
+DJANGO_ENV=development
+DEBUG=True
+CORS_ALLOWED_ORIGINS=http://localhost:3001,http://localhost:3000,http://localhost:3006
+CORS_ORIGIN_WHITELIST=http://localhost:3000,http://localhost:3001,http://127.0.0.1:3000
+ALLOWED_HOSTS=*
diff --git a/server/api/__pycache__/__init__.cpython-312.pyc b/server/api/__pycache__/__init__.cpython-312.pyc
index f5bfb727..b5526255 100644
Binary files a/server/api/__pycache__/__init__.cpython-312.pyc and b/server/api/__pycache__/__init__.cpython-312.pyc differ
diff --git a/server/api/__pycache__/admin.cpython-312.pyc b/server/api/__pycache__/admin.cpython-312.pyc
index 4d4984ae..3e625679 100644
Binary files a/server/api/__pycache__/admin.cpython-312.pyc and b/server/api/__pycache__/admin.cpython-312.pyc differ
diff --git a/server/api/__pycache__/apps.cpython-312.pyc b/server/api/__pycache__/apps.cpython-312.pyc
index bed0e39e..73f1c617 100644
Binary files a/server/api/__pycache__/apps.cpython-312.pyc and b/server/api/__pycache__/apps.cpython-312.pyc differ
diff --git a/server/api/__pycache__/models.cpython-312.pyc b/server/api/__pycache__/models.cpython-312.pyc
index 9812fb4c..f02add05 100644
Binary files a/server/api/__pycache__/models.cpython-312.pyc and b/server/api/__pycache__/models.cpython-312.pyc differ
diff --git a/server/api/__pycache__/resource.cpython-312.pyc b/server/api/__pycache__/resource.cpython-312.pyc
index ebf5ca2c..34a959a7 100644
Binary files a/server/api/__pycache__/resource.cpython-312.pyc and b/server/api/__pycache__/resource.cpython-312.pyc differ
diff --git a/server/api/__pycache__/schema.cpython-312.pyc b/server/api/__pycache__/schema.cpython-312.pyc
new file mode 100644
index 00000000..813abf97
Binary files /dev/null and b/server/api/__pycache__/schema.cpython-312.pyc differ
diff --git a/server/api/__pycache__/urls.cpython-312.pyc b/server/api/__pycache__/urls.cpython-312.pyc
index 664f5570..d7ffdc88 100644
Binary files a/server/api/__pycache__/urls.cpython-312.pyc and b/server/api/__pycache__/urls.cpython-312.pyc differ
diff --git a/server/api/__pycache__/views.cpython-312.pyc b/server/api/__pycache__/views.cpython-312.pyc
index e03dc1fd..22e6a86b 100644
Binary files a/server/api/__pycache__/views.cpython-312.pyc and b/server/api/__pycache__/views.cpython-312.pyc differ
diff --git a/server/api/migrations/__pycache__/0001_initial.cpython-312.pyc b/server/api/migrations/__pycache__/0001_initial.cpython-312.pyc
index 09f8c94c..9e9bb43d 100644
Binary files a/server/api/migrations/__pycache__/0001_initial.cpython-312.pyc and b/server/api/migrations/__pycache__/0001_initial.cpython-312.pyc differ
diff --git a/server/api/migrations/__pycache__/__init__.cpython-312.pyc b/server/api/migrations/__pycache__/__init__.cpython-312.pyc
index bc09d93a..e844c537 100644
Binary files a/server/api/migrations/__pycache__/__init__.cpython-312.pyc and b/server/api/migrations/__pycache__/__init__.cpython-312.pyc differ
diff --git a/server/api/schema.py b/server/api/schema.py
index 562b6e99..21e42b9e 100644
--- a/server/api/schema.py
+++ b/server/api/schema.py
@@ -2,58 +2,143 @@
from graphene_django import DjangoObjectType
from api.models import Student
from django.db.models import Q
-
+from django.core.cache import cache
class StudentType(DjangoObjectType):
class Meta:
- model= Student
+ model = Student
fields = "__all__"
+class StudentTreeType(graphene.ObjectType):
+ roll_no = graphene.String()
+ name = graphene.String()
+ parent_id = graphene.String(required=False)
+ picture = graphene.String()
+ children = graphene.List(lambda: StudentTreeType)
+
class Query(graphene.ObjectType):
- students=graphene.List(StudentType)
- student_search= graphene.List(StudentType, search_query=graphene.String())
+ students = graphene.List(StudentType)
+ student_search = graphene.List(StudentType, search_query=graphene.String(), limit=graphene.Int(default_value=8))
student = graphene.Field(StudentType, roll_number=graphene.String())
parent = graphene.Field(StudentType, roll_number=graphene.String())
sibling = graphene.List(StudentType, roll_number=graphene.String())
children = graphene.List(StudentType, roll_number=graphene.String())
-
- def resolve_students(root,info):
- return Student.objects.all()
+ student_tree = graphene.List(StudentTreeType)
+
+ def resolve_students(root, info):
+ cache_key = "all_students"
+ students = cache.get(cache_key)
+ if not students:
+ students = Student.objects.all()
+ cache.set(cache_key, students, timeout=600) # Cache for 10 minutes
+ return students
def resolve_student(self, info, roll_number):
- student = Student.objects.get(roll_no=roll_number)
-
+ cache_key = f"student_{roll_number}"
+ student = cache.get(cache_key)
+ if not student:
+ try:
+ student = Student.objects.get(roll_no=roll_number)
+ cache.set(cache_key, student, timeout=300) # Cache for 5 minutes
+ except Student.DoesNotExist:
+ return None
return student
def resolve_parent(self, info, roll_number):
- student = Student.objects.get(roll_no=roll_number)
- parent = None
-
- if student.parentId:
- parent = Student.objects.get(roll_no=student.parentId)
-
+ cache_key = f"parent_{roll_number}"
+ parent = cache.get(cache_key)
+ if parent is None:
+ try:
+ student = Student.objects.get(roll_no=roll_number)
+ if student.parentId:
+ parent_roll_no = student.parentId
+ parent_cache_key = f"student_{parent_roll_no}"
+ parent = cache.get(parent_cache_key)
+ if not parent:
+ parent = Student.objects.get(roll_no=parent_roll_no)
+ cache.set(parent_cache_key, parent, timeout=300)
+ else:
+ parent = None
+ cache.set(cache_key, parent, timeout=300)
+ except Student.DoesNotExist:
+ return None
return parent
+
def resolve_children(self, info, roll_number):
- student = Student.objects.get(roll_no=roll_number)
- print(student)
- # children = None
- children = list(Student.objects.filter(parentId=student.roll_no))
-
- return children
+ cache_key = f"children_{roll_number}"
+ children = cache.get(cache_key)
+ if children is None:
+ try:
+ student = Student.objects.get(roll_no=roll_number)
+ children = list(Student.objects.filter(parentId=student.roll_no))
+ cache.set(cache_key, children, timeout=300)
+ except Student.DoesNotExist:
+ return []
+ return children
+
def resolve_sibling(self, info, roll_number):
- student = Student.objects.get(roll_no=roll_number)
- siblings = None
+ cache_key = f"siblings_{roll_number}"
+ siblings = cache.get(cache_key)
+ if siblings is None:
+ try:
+ student = Student.objects.get(roll_no=roll_number)
+ if student.parentId:
+ siblings = list(Student.objects.filter(parentId=student.parentId).exclude(roll_no=student.roll_no))
+ cache.set(cache_key, siblings, timeout=300)
+ else:
+ siblings = []
+ cache.set(cache_key, siblings, timeout=300)
+ except Student.DoesNotExist:
+ return []
+ return siblings
- if student.parentId:
- siblings = list(Student.objects.filter(parentId=student.parentId).exclude(roll_no=student.roll_no))
+ def resolve_student_tree(self, info):
+ cache_key = "student_tree"
+ student_tree = cache.get(cache_key)
+ if not student_tree:
+ students = Student.objects.all()
+ student_dict = {}
+ root_nodes = []
-
- return siblings
-
-
+ for student in students:
+ student_dict[student.roll_no] = {
+ 'name': student.name,
+ 'roll_no': student.roll_no,
+ 'picture': student.picture,
+ 'parent_id': student.parentId,
+ 'children': []
+ }
+
+ for student_data in student_dict.values():
+ if student_data['parent_id']:
+ parent_id = student_data['parent_id']
+ if student_dict.get(parent_id):
+ student_dict[parent_id]['children'].append(student_data)
+ else:
+ root_nodes.append(student_data)
+ else:
+ root_nodes.append(student_data)
+
+ def build_tree(node):
+ return StudentTreeType(
+ roll_no=node['roll_no'],
+ name=node['name'],
+ parent_id=node['parent_id'],
+ picture=node['picture'],
+ children=[build_tree(child) for child in node['children']]
+ )
+
+ student_tree = [build_tree(node) for node in root_nodes]
+ cache.set(cache_key, student_tree, timeout=3600) # Cache for 1 hour
+ return student_tree
- def resolve_student_search(root,info, search_query):
- return Student.objects.filter(Q(name__icontains=search_query) | Q(roll_no__icontains= search_query))[0:8]
+ def resolve_student_search(root, info, search_query, limit):
+ cache_key = f"student_search_{search_query}_{limit}"
+ results = cache.get(cache_key)
+ if not results:
+ results = Student.objects.filter(Q(name__icontains=search_query) | Q(roll_no__icontains=search_query))[:limit]
+ cache.set(cache_key, results, timeout=300) # Cache for 5 minutes
+ return results
-schema=graphene.Schema(query=Query)
\ No newline at end of file
+schema = graphene.Schema(query=Query)
diff --git a/server/backend/__pycache__/__init__.cpython-312.pyc b/server/backend/__pycache__/__init__.cpython-312.pyc
index 5f9fa42a..4b0dbf48 100644
Binary files a/server/backend/__pycache__/__init__.cpython-312.pyc and b/server/backend/__pycache__/__init__.cpython-312.pyc differ
diff --git a/server/backend/__pycache__/settings.cpython-312.pyc b/server/backend/__pycache__/settings.cpython-312.pyc
index dd7e254d..e9285ffa 100644
Binary files a/server/backend/__pycache__/settings.cpython-312.pyc and b/server/backend/__pycache__/settings.cpython-312.pyc differ
diff --git a/server/backend/__pycache__/urls.cpython-312.pyc b/server/backend/__pycache__/urls.cpython-312.pyc
index 46f8a170..2110d180 100644
Binary files a/server/backend/__pycache__/urls.cpython-312.pyc and b/server/backend/__pycache__/urls.cpython-312.pyc differ
diff --git a/server/backend/__pycache__/wsgi.cpython-312.pyc b/server/backend/__pycache__/wsgi.cpython-312.pyc
index 9bd88ab8..29d5450e 100644
Binary files a/server/backend/__pycache__/wsgi.cpython-312.pyc and b/server/backend/__pycache__/wsgi.cpython-312.pyc differ
diff --git a/server/backend/settings.py b/server/backend/settings.py
index 95cf7c4c..b895911b 100644
--- a/server/backend/settings.py
+++ b/server/backend/settings.py
@@ -14,7 +14,9 @@
from pathlib import Path
import psycopg2
import environ
+from dotenv import load_dotenv
+load_dotenv()
env = environ.Env()
environ.Env.read_env()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
@@ -28,9 +30,19 @@
SECRET_KEY = 'django-insecure-w72ih+f^$g$lmg$#60w*3!-i*t+jl8cfc-nsfaas=zfdwq6ckv'
# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
+DEBUG = os.getenv('DEBUG', 'True') == 'True'
+CACHES = {
+ "default": {
+ "BACKEND": "django_redis.cache.RedisCache",
+ "LOCATION": "redis://127.0.0.1:6379/1",
+ "OPTIONS": {
+ "CLIENT_CLASS": "django_redis.client.DefaultClient"
+ },
+ "KEY_PREFIX": "example"
+ }
+}
# Application definition
@@ -96,10 +108,10 @@
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.getenv('DB_NAME', 'familytree'),
- 'USER': os.getenv('DB_USER', 'postgres'),
- 'PASSWORD': os.getenv('DB_PASSWORD', 'dev@iitj'),
- 'HOST': os.getenv('DB_HOST', '10.6.0.63'),
- 'PORT': os.getenv('DB_PORT', '5432'),
+ 'USER': os.getenv('DB_USER', ' '),
+ 'PASSWORD': os.getenv('DB_PASSWORD', ' '),
+ 'HOST': os.getenv('DB_HOST', ' '),
+ 'PORT': os.getenv('DB_PORT', ' '),
}
}
@@ -148,23 +160,14 @@
# CORS_ALLOW_ALL_ORIGINS = True
-CORS_ALLOWED_ORIGINS = [
- 'http://localhost:3001',
- 'http://localhost:3000',
- 'http://localhost:3006',
-
+CORS_ALLOWED_ORIGINS = os.getenv('CORS_ALLOWED_ORIGINS', '').split(',')
+CORS_ORIGIN_WHITELIST = os.getenv('CORS_ORIGIN_WHITELIST', '').split(',')
-]
-CORS_ORIGIN_WHITELIST = [
- 'http://localhost:3000',
- 'http://localhost:3001',
- 'http://127.0.0.1:3000'
-]
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
-ALLOWED_HOSTS = ['*']
+ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',')
GRAPHENE = {
diff --git a/server/enva/bin/Activate.ps1 b/server/enva/bin/Activate.ps1
deleted file mode 100644
index b49d77ba..00000000
--- a/server/enva/bin/Activate.ps1
+++ /dev/null
@@ -1,247 +0,0 @@
-<#
-.Synopsis
-Activate a Python virtual environment for the current PowerShell session.
-
-.Description
-Pushes the python executable for a virtual environment to the front of the
-$Env:PATH environment variable and sets the prompt to signify that you are
-in a Python virtual environment. Makes use of the command line switches as
-well as the `pyvenv.cfg` file values present in the virtual environment.
-
-.Parameter VenvDir
-Path to the directory that contains the virtual environment to activate. The
-default value for this is the parent of the directory that the Activate.ps1
-script is located within.
-
-.Parameter Prompt
-The prompt prefix to display when this virtual environment is activated. By
-default, this prompt is the name of the virtual environment folder (VenvDir)
-surrounded by parentheses and followed by a single space (ie. '(.venv) ').
-
-.Example
-Activate.ps1
-Activates the Python virtual environment that contains the Activate.ps1 script.
-
-.Example
-Activate.ps1 -Verbose
-Activates the Python virtual environment that contains the Activate.ps1 script,
-and shows extra information about the activation as it executes.
-
-.Example
-Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
-Activates the Python virtual environment located in the specified location.
-
-.Example
-Activate.ps1 -Prompt "MyPython"
-Activates the Python virtual environment that contains the Activate.ps1 script,
-and prefixes the current prompt with the specified string (surrounded in
-parentheses) while the virtual environment is active.
-
-.Notes
-On Windows, it may be required to enable this Activate.ps1 script by setting the
-execution policy for the user. You can do this by issuing the following PowerShell
-command:
-
-PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
-
-For more information on Execution Policies:
-https://go.microsoft.com/fwlink/?LinkID=135170
-
-#>
-Param(
- [Parameter(Mandatory = $false)]
- [String]
- $VenvDir,
- [Parameter(Mandatory = $false)]
- [String]
- $Prompt
-)
-
-<# Function declarations --------------------------------------------------- #>
-
-<#
-.Synopsis
-Remove all shell session elements added by the Activate script, including the
-addition of the virtual environment's Python executable from the beginning of
-the PATH variable.
-
-.Parameter NonDestructive
-If present, do not remove this function from the global namespace for the
-session.
-
-#>
-function global:deactivate ([switch]$NonDestructive) {
- # Revert to original values
-
- # The prior prompt:
- if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
- Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
- Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
- }
-
- # The prior PYTHONHOME:
- if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
- Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
- Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
- }
-
- # The prior PATH:
- if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
- Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
- Remove-Item -Path Env:_OLD_VIRTUAL_PATH
- }
-
- # Just remove the VIRTUAL_ENV altogether:
- if (Test-Path -Path Env:VIRTUAL_ENV) {
- Remove-Item -Path env:VIRTUAL_ENV
- }
-
- # Just remove VIRTUAL_ENV_PROMPT altogether.
- if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
- Remove-Item -Path env:VIRTUAL_ENV_PROMPT
- }
-
- # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
- if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
- Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
- }
-
- # Leave deactivate function in the global namespace if requested:
- if (-not $NonDestructive) {
- Remove-Item -Path function:deactivate
- }
-}
-
-<#
-.Description
-Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
-given folder, and returns them in a map.
-
-For each line in the pyvenv.cfg file, if that line can be parsed into exactly
-two strings separated by `=` (with any amount of whitespace surrounding the =)
-then it is considered a `key = value` line. The left hand string is the key,
-the right hand is the value.
-
-If the value starts with a `'` or a `"` then the first and last character is
-stripped from the value before being captured.
-
-.Parameter ConfigDir
-Path to the directory that contains the `pyvenv.cfg` file.
-#>
-function Get-PyVenvConfig(
- [String]
- $ConfigDir
-) {
- Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
-
- # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
- $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
-
- # An empty map will be returned if no config file is found.
- $pyvenvConfig = @{ }
-
- if ($pyvenvConfigPath) {
-
- Write-Verbose "File exists, parse `key = value` lines"
- $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
-
- $pyvenvConfigContent | ForEach-Object {
- $keyval = $PSItem -split "\s*=\s*", 2
- if ($keyval[0] -and $keyval[1]) {
- $val = $keyval[1]
-
- # Remove extraneous quotations around a string value.
- if ("'""".Contains($val.Substring(0, 1))) {
- $val = $val.Substring(1, $val.Length - 2)
- }
-
- $pyvenvConfig[$keyval[0]] = $val
- Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
- }
- }
- }
- return $pyvenvConfig
-}
-
-
-<# Begin Activate script --------------------------------------------------- #>
-
-# Determine the containing directory of this script
-$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
-$VenvExecDir = Get-Item -Path $VenvExecPath
-
-Write-Verbose "Activation script is located in path: '$VenvExecPath'"
-Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
-Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
-
-# Set values required in priority: CmdLine, ConfigFile, Default
-# First, get the location of the virtual environment, it might not be
-# VenvExecDir if specified on the command line.
-if ($VenvDir) {
- Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
-}
-else {
- Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
- $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
- Write-Verbose "VenvDir=$VenvDir"
-}
-
-# Next, read the `pyvenv.cfg` file to determine any required value such
-# as `prompt`.
-$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
-
-# Next, set the prompt from the command line, or the config file, or
-# just use the name of the virtual environment folder.
-if ($Prompt) {
- Write-Verbose "Prompt specified as argument, using '$Prompt'"
-}
-else {
- Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
- if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
- Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
- $Prompt = $pyvenvCfg['prompt'];
- }
- else {
- Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
- Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
- $Prompt = Split-Path -Path $venvDir -Leaf
- }
-}
-
-Write-Verbose "Prompt = '$Prompt'"
-Write-Verbose "VenvDir='$VenvDir'"
-
-# Deactivate any currently active virtual environment, but leave the
-# deactivate function in place.
-deactivate -nondestructive
-
-# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
-# that there is an activated venv.
-$env:VIRTUAL_ENV = $VenvDir
-
-if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
-
- Write-Verbose "Setting prompt to '$Prompt'"
-
- # Set the prompt to include the env name
- # Make sure _OLD_VIRTUAL_PROMPT is global
- function global:_OLD_VIRTUAL_PROMPT { "" }
- Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
- New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
-
- function global:prompt {
- Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
- _OLD_VIRTUAL_PROMPT
- }
- $env:VIRTUAL_ENV_PROMPT = $Prompt
-}
-
-# Clear PYTHONHOME
-if (Test-Path -Path Env:PYTHONHOME) {
- Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
- Remove-Item -Path Env:PYTHONHOME
-}
-
-# Add the venv to the PATH
-Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
-$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
diff --git a/server/enva/bin/activate b/server/enva/bin/activate
deleted file mode 100644
index ffd8e10c..00000000
--- a/server/enva/bin/activate
+++ /dev/null
@@ -1,70 +0,0 @@
-# This file must be used with "source bin/activate" *from bash*
-# You cannot run it directly
-
-deactivate () {
- # reset old environment variables
- if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
- PATH="${_OLD_VIRTUAL_PATH:-}"
- export PATH
- unset _OLD_VIRTUAL_PATH
- fi
- if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
- PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
- export PYTHONHOME
- unset _OLD_VIRTUAL_PYTHONHOME
- fi
-
- # Call hash to forget past commands. Without forgetting
- # past commands the $PATH changes we made may not be respected
- hash -r 2> /dev/null
-
- if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
- PS1="${_OLD_VIRTUAL_PS1:-}"
- export PS1
- unset _OLD_VIRTUAL_PS1
- fi
-
- unset VIRTUAL_ENV
- unset VIRTUAL_ENV_PROMPT
- if [ ! "${1:-}" = "nondestructive" ] ; then
- # Self destruct!
- unset -f deactivate
- fi
-}
-
-# unset irrelevant variables
-deactivate nondestructive
-
-# on Windows, a path can contain colons and backslashes and has to be converted:
-if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
- # transform D:\path\to\venv to /d/path/to/venv on MSYS
- # and to /cygdrive/d/path/to/venv on Cygwin
- export VIRTUAL_ENV=$(cygpath "/home/a19hu/course/iitj_family_tree/server/enva")
-else
- # use the path as-is
- export VIRTUAL_ENV="/home/a19hu/course/iitj_family_tree/server/enva"
-fi
-
-_OLD_VIRTUAL_PATH="$PATH"
-PATH="$VIRTUAL_ENV/bin:$PATH"
-export PATH
-
-# unset PYTHONHOME if set
-# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
-# could use `if (set -u; : $PYTHONHOME) ;` in bash
-if [ -n "${PYTHONHOME:-}" ] ; then
- _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
- unset PYTHONHOME
-fi
-
-if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
- _OLD_VIRTUAL_PS1="${PS1:-}"
- PS1="(enva) ${PS1:-}"
- export PS1
- VIRTUAL_ENV_PROMPT="(enva) "
- export VIRTUAL_ENV_PROMPT
-fi
-
-# Call hash to forget past commands. Without forgetting
-# past commands the $PATH changes we made may not be respected
-hash -r 2> /dev/null
diff --git a/server/enva/bin/activate.csh b/server/enva/bin/activate.csh
deleted file mode 100644
index 44d35b8b..00000000
--- a/server/enva/bin/activate.csh
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file must be used with "source bin/activate.csh" *from csh*.
-# You cannot run it directly.
-
-# Created by Davide Di Blasi .
-# Ported to Python 3.3 venv by Andrew Svetlov
-
-alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
-
-# Unset irrelevant variables.
-deactivate nondestructive
-
-setenv VIRTUAL_ENV "/home/a19hu/course/iitj_family_tree/server/enva"
-
-set _OLD_VIRTUAL_PATH="$PATH"
-setenv PATH "$VIRTUAL_ENV/bin:$PATH"
-
-
-set _OLD_VIRTUAL_PROMPT="$prompt"
-
-if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
- set prompt = "(enva) $prompt"
- setenv VIRTUAL_ENV_PROMPT "(enva) "
-endif
-
-alias pydoc python -m pydoc
-
-rehash
diff --git a/server/enva/bin/activate.fish b/server/enva/bin/activate.fish
deleted file mode 100644
index 24a19228..00000000
--- a/server/enva/bin/activate.fish
+++ /dev/null
@@ -1,69 +0,0 @@
-# This file must be used with "source /bin/activate.fish" *from fish*
-# (https://fishshell.com/). You cannot run it directly.
-
-function deactivate -d "Exit virtual environment and return to normal shell environment"
- # reset old environment variables
- if test -n "$_OLD_VIRTUAL_PATH"
- set -gx PATH $_OLD_VIRTUAL_PATH
- set -e _OLD_VIRTUAL_PATH
- end
- if test -n "$_OLD_VIRTUAL_PYTHONHOME"
- set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
- set -e _OLD_VIRTUAL_PYTHONHOME
- end
-
- if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
- set -e _OLD_FISH_PROMPT_OVERRIDE
- # prevents error when using nested fish instances (Issue #93858)
- if functions -q _old_fish_prompt
- functions -e fish_prompt
- functions -c _old_fish_prompt fish_prompt
- functions -e _old_fish_prompt
- end
- end
-
- set -e VIRTUAL_ENV
- set -e VIRTUAL_ENV_PROMPT
- if test "$argv[1]" != "nondestructive"
- # Self-destruct!
- functions -e deactivate
- end
-end
-
-# Unset irrelevant variables.
-deactivate nondestructive
-
-set -gx VIRTUAL_ENV "/home/a19hu/course/iitj_family_tree/server/enva"
-
-set -gx _OLD_VIRTUAL_PATH $PATH
-set -gx PATH "$VIRTUAL_ENV/bin" $PATH
-
-# Unset PYTHONHOME if set.
-if set -q PYTHONHOME
- set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
- set -e PYTHONHOME
-end
-
-if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
- # fish uses a function instead of an env var to generate the prompt.
-
- # Save the current fish_prompt function as the function _old_fish_prompt.
- functions -c fish_prompt _old_fish_prompt
-
- # With the original prompt function renamed, we can override with our own.
- function fish_prompt
- # Save the return status of the last command.
- set -l old_status $status
-
- # Output the venv prompt; color taken from the blue of the Python logo.
- printf "%s%s%s" (set_color 4B8BBE) "(enva) " (set_color normal)
-
- # Restore the return status of the previous command.
- echo "exit $old_status" | .
- # Output the original/"old" prompt.
- _old_fish_prompt
- end
-
- set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
- set -gx VIRTUAL_ENV_PROMPT "(enva) "
-end
diff --git a/server/enva/bin/django-admin b/server/enva/bin/django-admin
deleted file mode 100755
index 145577c1..00000000
--- a/server/enva/bin/django-admin
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/a19hu/course/iitj_family_tree/server/enva/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from django.core.management import execute_from_command_line
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(execute_from_command_line())
diff --git a/server/enva/bin/pip b/server/enva/bin/pip
deleted file mode 100755
index 1da09431..00000000
--- a/server/enva/bin/pip
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/a19hu/course/iitj_family_tree/server/enva/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from pip._internal.cli.main import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/server/enva/bin/pip3 b/server/enva/bin/pip3
deleted file mode 100755
index 1da09431..00000000
--- a/server/enva/bin/pip3
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/a19hu/course/iitj_family_tree/server/enva/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from pip._internal.cli.main import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/server/enva/bin/pip3.12 b/server/enva/bin/pip3.12
deleted file mode 100755
index 1da09431..00000000
--- a/server/enva/bin/pip3.12
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/a19hu/course/iitj_family_tree/server/enva/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from pip._internal.cli.main import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/server/enva/bin/python b/server/enva/bin/python
deleted file mode 120000
index b8a0adbb..00000000
--- a/server/enva/bin/python
+++ /dev/null
@@ -1 +0,0 @@
-python3
\ No newline at end of file
diff --git a/server/enva/bin/python3 b/server/enva/bin/python3
deleted file mode 120000
index ae65fdaa..00000000
--- a/server/enva/bin/python3
+++ /dev/null
@@ -1 +0,0 @@
-/usr/bin/python3
\ No newline at end of file
diff --git a/server/enva/bin/python3.12 b/server/enva/bin/python3.12
deleted file mode 120000
index b8a0adbb..00000000
--- a/server/enva/bin/python3.12
+++ /dev/null
@@ -1 +0,0 @@
-python3
\ No newline at end of file
diff --git a/server/enva/bin/sqlformat b/server/enva/bin/sqlformat
deleted file mode 100755
index 140e9fbd..00000000
--- a/server/enva/bin/sqlformat
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/a19hu/course/iitj_family_tree/server/enva/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from sqlparse.__main__ import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/server/enva/bin/wheel b/server/enva/bin/wheel
deleted file mode 100755
index c028c665..00000000
--- a/server/enva/bin/wheel
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/a19hu/course/iitj_family_tree/server/enva/bin/python3
-# -*- coding: utf-8 -*-
-import re
-import sys
-from wheel.cli import main
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(main())
diff --git a/server/enva/lib/python3.12/site-packages/Django-5.0.7.dist-info/AUTHORS b/server/enva/lib/python3.12/site-packages/Django-5.0.7.dist-info/AUTHORS
deleted file mode 100644
index 2f342a83..00000000
--- a/server/enva/lib/python3.12/site-packages/Django-5.0.7.dist-info/AUTHORS
+++ /dev/null
@@ -1,1090 +0,0 @@
-Django was originally created in late 2003 at World Online, the web division
-of the Lawrence Journal-World newspaper in Lawrence, Kansas.
-
-Here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --
-people who have submitted patches, reported bugs, added translations, helped
-answer newbie questions, and generally made Django that much better:
-
- Aaron Cannon
- Aaron Swartz
- Aaron T. Myers
- Abeer Upadhyay
- Abhijeet Viswa
- Abhinav Patil
- Abhinav Yadav
- Abhishek Gautam
- Abhyudai
- Adam Allred
- Adam Bogdał
- Adam Donaghy
- Adam Johnson
- Adam Malinowski
- Adam Vandenberg
- Ade Lee
- Adiyat Mubarak
- Adnan Umer
- Arslan Noor
- Adrian Holovaty
- Adrian Torres
- Adrien Lemaire
- Afonso Fernández Nogueira
- AgarFu
- Ahmad Alhashemi
- Ahmad Al-Ibrahim
- Ahmed Eltawela
- ajs
- Akash Agrawal
- Akash Kumar Sen
- Akis Kesoglou
- Aksel Ethem
- Akshesh Doshi
- alang@bright-green.com
- Alasdair Nicol
- Albert Defler
- Albert Wang
- Alcides Fonseca
- Aldian Fazrihady
- Aleksander Milinkevich
- Aleksandra Sendecka
- Aleksi Häkli
- Alex Dutton
- Alexander Myodov
- Alexandr Tatarinov
- Alex Aktsipetrov
- Alex Becker
- Alex Couper
- Alex Dedul
- Alex Gaynor
- Alex Hill
- Alex Ogier
- Alex Robbins
- Alexey Boriskin
- Alexey Tsivunin
- Ali Vakilzade
- Aljaž Košir
- Aljosa Mohorovic
- Alokik Vijay
- Amir Karimi
- Amit Chakradeo
- Amit Ramon
- Amit Upadhyay
- A. Murat Eren
- Ana Belen Sarabia
- Ana Krivokapic
- Andi Albrecht
- André Ericson
- Andrei Kulakov
- Andreas
- Andreas Mock
- Andreas Pelme
- Andrés Torres Marroquín
- Andrew Brehaut
- Andrew Clark
- Andrew Durdin
- Andrew Godwin
- Andrew Miller
- Andrew Pinkham
- Andrews Medina
- Andrew Northall
- Andriy Sokolovskiy
- Andy Chosak
- Andy Dustman
- Andy Gayton
- andy@jadedplanet.net
- Anssi Kääriäinen
- ant9000@netwise.it
- Anthony Briggs
- Anthony Wright
- Anton Samarchyan
- Antoni Aloy
- Antonio Cavedoni
- Antonis Christofides
- Antti Haapala
- Antti Kaihola
- Anubhav Joshi
- Anvesh Mishra
- Aram Dulyan
- arien
- Armin Ronacher
- Aron Podrigal
- Arsalan Ghassemi
- Artem Gnilov
- Arthur
- Arthur Jovart
- Arthur Koziel
- Arthur Moreira
- Arthur Rio
- Arvis Bickovskis
- Arya Khaligh
- Aryeh Leib Taurog
- A S Alam
- Asif Saif Uddin
- atlithorn
- Audrey Roy
- av0000@mail.ru
- Axel Haustant
- Aymeric Augustin
- Bahadır Kandemir
- Baishampayan Ghose
- Baptiste Mispelon
- Barry Pederson
- Bartolome Sanchez Salado
- Barton Ip
- Bartosz Grabski
- Bashar Al-Abdulhadi
- Bastian Kleineidam
- Batiste Bieler
- Batman
- Batuhan Taskaya
- Baurzhan Ismagulov
- Ben Dean Kawamura
- Ben Firshman
- Ben Godfrey
- Benjamin Wohlwend
- Ben Khoo
- Ben Lomax
- Ben Slavin
- Ben Sturmfels
- Berker Peksag
- Bernd Schlapsi
- Bernhard Essl
- berto
- Bhuvnesh Sharma
- Bill Fenner
- Bjørn Stabell
- Bo Marchman
- Bogdan Mateescu
- Bojan Mihelac
- Bouke Haarsma
- Božidar Benko
- Brad Melin
- Brandon Chinn
- Brant Harris
- Brendan Hayward
- Brendan Quinn
- Brenton Simpson
- Brett Cannon
- Brett Hoerner
- Brian Beck
- Brian Fabian Crain
- Brian Harring
- Brian Helba
- Brian Ray
- Brian Rosner
- Bruce Kroeze
- Bruno Alla
- Bruno Renié
- brut.alll@gmail.com
- Bryan Chow
- Bryan Veloso
- bthomas
- btoll@bestweb.net
- C8E
- Caio Ariede
- Calvin Spealman
- Cameron Curry
- Cameron Knight (ckknight)
- Can Burak Çilingir
- Can Sarıgöl
- Carl Meyer
- Carles Pina i Estany
- Carlos Eduardo de Paula
- Carlos Matías de la Torre
- Carlton Gibson
- cedric@terramater.net
- Chad Whitman
- ChaosKCW
- Charlie Leifer
- charly.wilhelm@gmail.com
- Chason Chaffin
- Cheng Zhang
- Chris Adams
- Chris Beaven
- Chris Bennett
- Chris Cahoon
- Chris Chamberlin
- Chris Jerdonek
- Chris Jones
- Chris Lamb
- Chris Streeter
- Christian Barcenas
- Christian Metts
- Christian Oudard
- Christian Tanzer
- Christoffer Sjöbergsson
- Christophe Pettus
- Christopher Adams
- Christopher Babiak
- Christopher Lenz
- Christoph Mędrela
- Chris Wagner
- Chris Wesseling
- Chris Wilson
- Ciaran McCormick
- Claude Paroz
- Clint Ecker
- colin@owlfish.com
- Colin Wood
- Collin Anderson
- Collin Grady
- Colton Hicks
- Craig Blaszczyk
- crankycoder@gmail.com
- Curtis Maloney (FunkyBob)
- dackze+django@gmail.com
- Dagur Páll Ammendrup
- Dane Springmeyer
- Dan Fairs
- Daniel Alves Barbosa de Oliveira Vaz
- Daniel Duan
- Daniele Procida
- Daniel Fairhead
- Daniel Greenfeld
- dAniel hAhler
- Daniel Jilg
- Daniel Lindsley
- Daniel Poelzleithner
- Daniel Pyrathon
- Daniel Roseman
- Daniel Tao
- Daniel Wiesmann
- Danilo Bargen
- Dan Johnson
- Dan Palmer
- Dan Poirier
- Dan Stephenson
- Dan Watson
- dave@thebarproject.com
- David Ascher
- David Avsajanishvili
- David Blewett
- David Brenneman
- David Cramer
- David Danier
- David Eklund
- David Foster
- David Gouldin
- david@kazserve.org
- David Krauth
- David Larlet
- David Reynolds
- David Sanders
- David Schein
- David Tulig
- David Winterbottom
- David Wobrock
- Davide Ceretti
- Deep L. Sukhwani
- Deepak Thukral
- Denis Kuzmichyov
- Dennis Schwertel
- Derek Willis
- Deric Crago
- deric@monowerks.com
- Deryck Hodge
- Dimitris Glezos
- Dirk Datzert
- Dirk Eschler
- Dmitri Fedortchenko
- Dmitry Jemerov
- dne@mayonnaise.net
- Dolan Antenucci
- Donald Harvey
- Donald Stufft
- Don Spaulding
- Doug Beck
- Doug Napoleone
- dready
- Durval Carvalho de Souza
- dusk@woofle.net
- Dustyn Gibson
- Ed Morley
- Egidijus Macijauskas
- eibaan@gmail.com
- elky
- Emmanuelle Delescolle
- Emil Stenström
- enlight
- Enrico
- Eric Boersma
- Eric Brandwein
- Eric Floehr
- Eric Florenzano
- Eric Holscher
- Eric Moritz
- Eric Palakovich Carr
- Erik Karulf
- Erik Romijn
- eriks@win.tue.nl
- Erwin Junge
- Esdras Beleza
- Espen Grindhaug
- Étienne Beaulé
- Eugene Lazutkin