diff --git a/.idea/artifacts/java_quiz_management_jar.xml b/.idea/artifacts/java_quiz_management_jar.xml
new file mode 100644
index 0000000..a5666e8
--- /dev/null
+++ b/.idea/artifacts/java_quiz_management_jar.xml
@@ -0,0 +1,43 @@
+
+
+ $PROJECT_DIR$/out/artifacts/java_quiz_management_jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml
new file mode 100644
index 0000000..e6a0e19
--- /dev/null
+++ b/.idea/dbnavigator.xml
@@ -0,0 +1,556 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..dc7e61a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+# Java quiz application
+
+This is an quiz management application that provides quiz management functionality.
+
+# Functionalities
+
+1. Student
+ 1. Take test
+ 2. View own report
+2. Teacher
+ 1. Manage accounts
+ 2. Manage questions
+ 3. View full report
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 7ea5206..099ac01 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,6 @@
-
4.0.0
@@ -106,6 +106,11 @@
${junit.version}
test
+
+ mysql
+ mysql-connector-java
+ 5.1.36
+
diff --git a/src/main/img/undraw_online_test_re_kyfx.svg b/src/main/img/undraw_online_test_re_kyfx.svg
new file mode 100644
index 0000000..4761a27
--- /dev/null
+++ b/src/main/img/undraw_online_test_re_kyfx.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/main/java/com/example/quizmanagement/AccountController.java b/src/main/java/com/example/quizmanagement/AccountController.java
new file mode 100644
index 0000000..59a210e
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/AccountController.java
@@ -0,0 +1,87 @@
+package com.example.quizmanagement;
+
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.geometry.Pos;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.PasswordField;
+import javafx.scene.control.TextField;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.Statement;
+import java.util.regex.Pattern;
+
+public class AccountController {
+ @FXML
+ private TextField username, email;
+ @FXML
+ private PasswordField pass;
+ @FXML
+ private Label error;
+
+ @FXML
+ private VBox container;
+ @FXML
+ private Button back;
+
+ @FXML
+ private void onCreate() {
+ try {
+ if (username.getText().equals("") || pass.getText().equals("") || email.getText().equals("")) {
+ error.setText("Please fill all fields");
+ } else {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] bytes = md.digest(pass.getText().getBytes());
+ BigInteger no = new BigInteger(1, bytes);
+ String hashedPass = no.toString(16);
+ while (hashedPass.length() < 32) {
+ hashedPass = "0" + hashedPass;
+ }
+ if (Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE).matcher(email.getText()).find()) {
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/quiz", "root", "");
+ Statement st = con.createStatement();
+ int rs = st.executeUpdate("INSERT INTO `users`(`username`, `email`, `password`, `admin`) VALUES ('" + username.getText() + "','" + email.getText() + "','" + hashedPass + "','0')");
+ if (rs == 1) {
+ container.getChildren().clear();
+ container.getChildren().add(new Label("Account added successfully"));
+ container.getChildren().add(back);
+ container.setAlignment(Pos.CENTER);
+ }
+ } else {
+ error.setText("Invalid email address");
+ }
+ }
+
+ } catch (Exception e) {
+ error.setText("Error connecting to database");
+ }
+ }
+
+ @FXML
+ private void onCancel() throws Exception {
+ Stage primaryStage = (Stage) back.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("teacher-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Online Quiz Management");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @FXML
+ private void setOnKeyPressed(KeyEvent k) {
+ if (k.getCode().equals(KeyCode.ENTER)) {
+ onCreate();
+ }
+ }
+}
diff --git a/src/main/java/com/example/quizmanagement/AddQuestionController.java b/src/main/java/com/example/quizmanagement/AddQuestionController.java
new file mode 100644
index 0000000..5555272
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/AddQuestionController.java
@@ -0,0 +1,60 @@
+package com.example.quizmanagement;
+
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextArea;
+import javafx.scene.control.TextField;
+import javafx.stage.Stage;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.Statement;
+
+public class AddQuestionController {
+ @FXML
+ private Button goBack;
+ @FXML
+ private Label error;
+ @FXML
+ private TextArea question;
+ @FXML
+ private TextField op1, op2, op3, op4, cro;
+
+ @FXML
+ private void onClickGoBack() throws Exception {
+ Stage primaryStage = (Stage) goBack.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("manage-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Manage questions");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @FXML
+ private void onClickSubmit() throws Exception {
+ if (op1.getText().equals("") || op2.getText().equals("") || op3.getText().equals("") || op4.getText().equals("") || cro.getText().equals("") || question.getText().equals("")) {
+ error.setText("Please fill all the fields");
+ } else if (!cro.getText().equals(op1.getText()) && !cro.getText().equals(op2.getText()) && !cro.getText().equals(op3.getText()) && !cro.getText().equals(op4.getText())) {
+ error.setText("Correct ans doesn't match any of the above options");
+ } else if (op1.getText().equals(op2.getText()) || op1.getText().equals(op3.getText()) || op1.getText().equals(op4.getText()) || op2.getText().equals(op3.getText()) || op2.getText().equals(op4.getText()) || op3.getText().equals(op4.getText())) {
+ error.setText("Multiple options match each other");
+ } else {
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/quiz", "root", "");
+ Statement st = con.createStatement();
+ if (st.executeUpdate("INSERT INTO `quiz_list` (`Question`, `option1`, `option2`, `option3`, `option4`, `correct`) VALUES ('" + question.getText() + "', '" + op1.getText() + "', '" + op2.getText() + "', '" + op3.getText() + "', '" + op4.getText() + "', '" + cro.getText() + "');") == 1) {
+ Stage primaryStage = (Stage) goBack.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("manage-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Manage questions");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/quizmanagement/Credentials.java b/src/main/java/com/example/quizmanagement/Credentials.java
new file mode 100644
index 0000000..ca32e20
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/Credentials.java
@@ -0,0 +1,22 @@
+package com.example.quizmanagement;
+
+public class Credentials {
+ private static String username;
+ private static String email;
+
+ public static String getUsername() {
+ return username;
+ }
+
+ public static void setUsername(String name) {
+ username = name;
+ }
+
+ public static String getEmail() {
+ return email;
+ }
+
+ public static void setEmail(String mail) {
+ email = mail;
+ }
+}
diff --git a/src/main/java/com/example/quizmanagement/LoginController.java b/src/main/java/com/example/quizmanagement/LoginController.java
new file mode 100644
index 0000000..ce4e3e6
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/LoginController.java
@@ -0,0 +1,75 @@
+package com.example.quizmanagement;
+
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyEvent;
+import javafx.stage.Stage;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+public class LoginController {
+ @FXML
+ private TextField email, pass;
+ @FXML
+ private Label error;
+
+ @FXML
+ private Button cancel, login;
+
+ @FXML
+ private void onLogin() {
+ try {
+ if (email.getText().equals("") || pass.getText().equals("")) {
+ error.setText("Please fill all fields");
+ } else {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] bytes = md.digest(pass.getText().getBytes());
+ BigInteger no = new BigInteger(1, bytes);
+ String hashedPass = no.toString(16);
+ while (hashedPass.length() < 32) {
+ hashedPass = "0" + hashedPass;
+ }
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/quiz", "root", "");
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery("select * from `users` where `email` = '" + email.getText() + "' and " +
+ "`password` = " + "'" + hashedPass + "'");
+ if (rs != null && rs.next()) {
+ Credentials.setUsername(rs.getString("username"));
+ Credentials.setEmail(rs.getString("email"));
+ Stage primaryStage = (Stage) login.getScene().getWindow();
+ Parent root = rs.getString("admin").equals("1") ? FXMLLoader.load(getClass().getResource("teacher-view.fxml")) :
+ FXMLLoader.load(getClass().getResource("student-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle(rs.getString("admin").equals("1") ? "Online Quiz Management" : "Online Quiz");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ } else {
+ error.setText("Incorrect username or password");
+ }
+ }
+
+ } catch (Exception e) {
+ error.setText("Error connecting to database");
+ }
+ }
+
+
+ @FXML
+ private void setOnKeyPressed(KeyEvent k) {
+ if (k.getCode().equals(KeyCode.ENTER)) {
+ onLogin();
+ }
+ }
+}
diff --git a/src/main/java/com/example/quizmanagement/MainApplication.java b/src/main/java/com/example/quizmanagement/MainApplication.java
index 4d22226..4b2a14c 100644
--- a/src/main/java/com/example/quizmanagement/MainApplication.java
+++ b/src/main/java/com/example/quizmanagement/MainApplication.java
@@ -8,16 +8,17 @@
import java.io.IOException;
public class MainApplication extends Application {
+ public static void main(String[] args) {
+ launch();
+ }
+
@Override
public void start(Stage stage) throws IOException {
- FXMLLoader fxmlLoader = new FXMLLoader(MainApplication.class.getResource("hello-view.fxml"));
- Scene scene = new Scene(fxmlLoader.load(), 820, 640);
- stage.setTitle("Online java quiz management system");
+ FXMLLoader fxmlLoader = new FXMLLoader(MainApplication.class.getResource("login-view.fxml"));
+ Scene scene = new Scene(fxmlLoader.load(), 400, 600);
+ scene.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ stage.setTitle("Online Java Quiz Management System");
stage.setScene(scene);
stage.show();
}
-
- public static void main(String[] args) {
- launch();
- }
}
\ No newline at end of file
diff --git a/src/main/java/com/example/quizmanagement/MainController.java b/src/main/java/com/example/quizmanagement/MainController.java
index 790a41d..0d9aed7 100644
--- a/src/main/java/com/example/quizmanagement/MainController.java
+++ b/src/main/java/com/example/quizmanagement/MainController.java
@@ -1,14 +1,89 @@
package com.example.quizmanagement;
import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
import javafx.scene.control.Label;
+import javafx.stage.Stage;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class MainController implements Initializable {
+ @FXML
+ private Button testButton, addButton;
+ @FXML
+ private Label wcLbl;
+
+ @FXML
+ private void onClickAccButton() throws Exception {
+ Stage primaryStage = (Stage) addButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("add-acc-view.fxml"));
+ primaryStage.setTitle("Add new accounts");
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @FXML
+ private void onClickAddButton() throws Exception {
+ Stage primaryStage = (Stage) addButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("manage-view.fxml"));
+ primaryStage.setTitle("Manage questions");
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @FXML
+ private void onClickReportButton() throws Exception {
+ Stage primaryStage = (Stage) testButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("student-report-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Student's report");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+
+ }
-public class MainController {
@FXML
- private Label welcomeText;
-
+ private void onClickFullReportButton() throws Exception {
+ Stage primaryStage = (Stage) testButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("teacher-report-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("All student's report");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+
+ }
+
@FXML
- protected void onHelloButtonClick() {
- welcomeText.setText("Welcome to JavaFX Application!");
+ private void onClickTestButton() throws Exception {
+ Stage primaryStage = (Stage) testButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("quiz-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Quiz");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @FXML
+ private void onLogout() throws Exception {
+ Credentials.setUsername("");
+ Credentials.setEmail("");
+ Stage primaryStage = (Stage) testButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("login-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Login");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ wcLbl.setText("Welcome, " + Credentials.getUsername());
}
}
\ No newline at end of file
diff --git a/src/main/java/com/example/quizmanagement/ManageController.java b/src/main/java/com/example/quizmanagement/ManageController.java
new file mode 100644
index 0000000..fa409d1
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/ManageController.java
@@ -0,0 +1,83 @@
+package com.example.quizmanagement;
+
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ResourceBundle;
+
+public class ManageController implements Initializable {
+ TableView table = new TableView();
+ TableColumn qsCol = new TableColumn("Question");
+ TableColumn crCol = new TableColumn("Answer");
+ @FXML
+ private Button addButton;
+ @FXML
+ private VBox tableCon;
+
+ @FXML
+ private void onAdd() throws Exception {
+ Stage primaryStage = (Stage) addButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("add-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Add new question");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @FXML
+ private void onExit() throws Exception {
+ Stage primaryStage = (Stage) addButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("teacher-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Online Quiz Management");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @FXML
+ private void deleteQs() throws Exception {
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/quiz", "root", "");
+ Statement st = con.createStatement();
+ int rs = st.executeUpdate("DELETE from quiz_list");
+ if (rs == 1)
+ table.getItems().clear();
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ qsCol.setCellValueFactory(new PropertyValueFactory("Question"));
+ crCol.setCellValueFactory(new PropertyValueFactory("Answer"));
+ crCol.setStyle("-fx-alignment:CENTER");
+ table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+ table.getColumns().clear();
+ table.getColumns().add(qsCol);
+ table.getColumns().add(crCol);
+ tableCon.getChildren().add(table);
+ try {
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/quiz", "root", "");
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery("Select * from quiz_list");
+ while (rs.next()) {
+ Button del = new Button("Delete");
+ table.getItems().add(new QuestionTable(rs.getString("Question"), rs.getString("correct")));
+ }
+ } catch (Exception e) {
+ }
+ }
+}
diff --git a/src/main/java/com/example/quizmanagement/QuestionTable.java b/src/main/java/com/example/quizmanagement/QuestionTable.java
new file mode 100644
index 0000000..ae99484
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/QuestionTable.java
@@ -0,0 +1,32 @@
+package com.example.quizmanagement;
+
+public class QuestionTable {
+ private String question;
+ private String answer;
+
+ public QuestionTable() {
+ this.question = "";
+ this.answer = "";
+ }
+
+ public QuestionTable(String question, String answer) {
+ this.question = question;
+ this.answer = answer;
+ }
+
+ public String getQuestion() {
+ return question;
+ }
+
+ public void setQuestion(String question) {
+ this.question = question;
+ }
+
+ public String getAnswer() {
+ return answer;
+ }
+
+ public void setAnswer(String answer) {
+ this.answer = answer;
+ }
+}
diff --git a/src/main/java/com/example/quizmanagement/QuizController.java b/src/main/java/com/example/quizmanagement/QuizController.java
new file mode 100644
index 0000000..d39aeca
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/QuizController.java
@@ -0,0 +1,167 @@
+package com.example.quizmanagement;
+
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.chart.PieChart;
+import javafx.scene.control.*;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.ResourceBundle;
+
+public class QuizController implements Initializable {
+
+ ResultSet rs;
+ Statement st;
+ float qsSize, progress = 0;
+ String ans;
+ float result = 0;
+ @FXML
+ private VBox quizBox;
+ @FXML
+ private Button goBack, nextButton;
+ @FXML
+ private Label question, report;
+ @FXML
+ private HBox btnContainer;
+ @FXML
+ private GridPane opBox;
+ @FXML
+ private ProgressBar pb;
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ try {
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/quiz", "root", "");
+ st = con.createStatement();
+ rs = st.executeQuery("Select * from quiz_list");
+ if (rs != null) {
+ rs.last();
+ qsSize = rs.getRow();
+ rs.beforeFirst();
+ }
+ if (rs.next()) {
+ updateQuestion();
+ }
+ } catch (Exception e) {
+ report.setText("No question in found. Please try adding questions");
+ }
+ }
+
+ private void updateQuestion() throws Exception {
+ quizBox.getChildren().clear();
+ question.setText(rs.getString("question"));
+ quizBox.getChildren().add(question);
+ question.wrapTextProperty().set(true);
+ opBox.getChildren().clear();
+ RadioButton o1 = new RadioButton(rs.getString("option1"));
+ o1.wrapTextProperty().set(true);
+ RadioButton o2 = new RadioButton(rs.getString("option2"));
+ o2.wrapTextProperty().set(true);
+ RadioButton o3 = new RadioButton(rs.getString("option3"));
+ o3.wrapTextProperty().set(true);
+ RadioButton o4 = new RadioButton(rs.getString("option4"));
+ o4.wrapTextProperty().set(true);
+ ToggleGroup optionGroup = new ToggleGroup();
+ optionGroup.selectedToggleProperty().addListener(new ChangeListener() {
+ @Override
+ public void changed(ObservableValue extends Toggle> observableValue, Toggle toggle, Toggle t1) {
+ RadioButton rb = (RadioButton) optionGroup.getSelectedToggle();
+ ans = rb.getText();
+ }
+ });
+ o1.setToggleGroup(optionGroup);
+ o2.setToggleGroup(optionGroup);
+ o3.setToggleGroup(optionGroup);
+ o4.setToggleGroup(optionGroup);
+ opBox.add(o1, 0, 0);
+ opBox.add(o2, 1, 0);
+ opBox.add(o3, 0, 1);
+ opBox.add(o4, 1, 1);
+ quizBox.getChildren().add(opBox);
+
+ }
+
+ @FXML
+ private void onClickGoBack() throws Exception {
+ Stage primaryStage = (Stage) goBack.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("student-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Online Quiz");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @FXML
+ private void onClickStart() throws Exception {
+ if (ans != null) {
+ pb.setProgress(progress += (1 / qsSize));
+ report.setText("");
+ if (rs.getString("correct").equals(ans)) {
+ result++;
+ }
+ if (rs.next()) {
+ updateQuestion();
+ } else {
+ quizBox.getChildren().clear();
+ btnContainer.getChildren().remove(nextButton);
+ Button reportButton = new Button("Show report");
+ reportButton.setId("purple-button");
+ reportButton.setOnAction(new EventHandler() {
+ @Override
+ public void handle(ActionEvent actionEvent) {
+ try {
+ Stage primaryStage = (Stage) goBack.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("student-report-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Online Quiz");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+ });
+ btnContainer.getChildren().add(reportButton);
+ ObservableList pieChartData =
+ FXCollections.observableArrayList(
+ new PieChart.Data("Correct " + String.valueOf(Math.round((result / qsSize) * 100) + "% (" + Math.round(result) +
+ ")"),
+ ((result / qsSize) * 100)),
+ new PieChart.Data("Wrong " + String.valueOf(Math.round(((qsSize - result) / qsSize) * 100) +
+ "% (" + Math.round(qsSize - result) + ")"),
+ (((qsSize - result) / qsSize) * 100)));
+ final PieChart chart = new PieChart(pieChartData);
+ st.executeUpdate("INSERT INTO `result`(`name`, `email`, `date`, `mark`) VALUES ('" + Credentials.getUsername() + "','" + Credentials.getEmail() + "'," +
+ "'" + new SimpleDateFormat("dd-MMM hh:mm aa").format(new Date()) + "','" + Math.round(result) + "/" + Math.round(qsSize) + "')");
+ chart.setAnimated(true);
+ chart.setLabelsVisible(false);
+ chart.setTitle("Quiz result");
+ quizBox.getChildren().add(chart);
+ }
+ ans = null;
+ } else {
+ report.setText("Please select an option");
+ }
+ }
+
+}
diff --git a/src/main/java/com/example/quizmanagement/ResultTable.java b/src/main/java/com/example/quizmanagement/ResultTable.java
new file mode 100644
index 0000000..b14672c
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/ResultTable.java
@@ -0,0 +1,45 @@
+package com.example.quizmanagement;
+
+import javafx.beans.property.SimpleStringProperty;
+
+public class ResultTable {
+ public SimpleStringProperty name;
+ public SimpleStringProperty date;
+ public SimpleStringProperty mark;
+
+ public ResultTable() {
+ this.name = new SimpleStringProperty("");
+ this.date = new SimpleStringProperty("");
+ this.mark = new SimpleStringProperty("");
+ }
+
+ public ResultTable(String name, String date, String mark) {
+ this.name = new SimpleStringProperty(name);
+ this.date = new SimpleStringProperty(date);
+ this.mark = new SimpleStringProperty(mark);
+ }
+
+ public String getName() {
+ return name.get();
+ }
+
+ public void setName(String name) {
+ this.name = new SimpleStringProperty(name);
+ }
+
+ public String getDate() {
+ return date.get();
+ }
+
+ public void setDate(String date) {
+ this.date = new SimpleStringProperty(date);
+ }
+
+ public String getMark() {
+ return mark.get();
+ }
+
+ public void setMark(String mark) {
+ this.mark = new SimpleStringProperty(mark);
+ }
+}
diff --git a/src/main/java/com/example/quizmanagement/StudentReportController.java b/src/main/java/com/example/quizmanagement/StudentReportController.java
new file mode 100644
index 0000000..60b9661
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/StudentReportController.java
@@ -0,0 +1,69 @@
+package com.example.quizmanagement;
+
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ResourceBundle;
+
+public class StudentReportController implements Initializable {
+ @FXML
+ private Button exitButton;
+ @FXML
+ private Label wcLbl;
+ @FXML
+ private VBox tableCon;
+
+ @FXML
+ private void onExit() throws Exception {
+ Stage primaryStage = (Stage) exitButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("student-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Online Quiz");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ wcLbl.setText(Credentials.getUsername() + "'s result");
+ TableView table = new TableView();
+ TableColumn nmCol = new TableColumn("Name");
+ TableColumn dtCol = new TableColumn("Date");
+ TableColumn mkCol = new TableColumn("Mark");
+ nmCol.setCellValueFactory(new PropertyValueFactory("Name"));
+ dtCol.setCellValueFactory(new PropertyValueFactory("Date"));
+ mkCol.setCellValueFactory(new PropertyValueFactory("Mark"));
+ mkCol.setStyle("-fx-alignment:CENTER");
+ table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+ table.getColumns().clear();
+ table.getColumns().add(nmCol);
+ table.getColumns().add(dtCol);
+ table.getColumns().add(mkCol);
+ tableCon.getChildren().add(table);
+ try {
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/quiz", "root", "");
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery("Select * from `result` where result.email = '" + Credentials.getEmail() + "'");
+ while (rs.next()) {
+ table.getItems().add(new ResultTable(rs.getString("name"), rs.getString("date"), rs.getString("mark")));
+ }
+ } catch (Exception e) {
+ }
+ }
+}
diff --git a/src/main/java/com/example/quizmanagement/TeacherReportController.java b/src/main/java/com/example/quizmanagement/TeacherReportController.java
new file mode 100644
index 0000000..2f9a266
--- /dev/null
+++ b/src/main/java/com/example/quizmanagement/TeacherReportController.java
@@ -0,0 +1,65 @@
+package com.example.quizmanagement;
+
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
+
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ResourceBundle;
+
+public class TeacherReportController implements Initializable {
+ @FXML
+ private Button exitButton;
+ @FXML
+ private VBox tableCon;
+
+ @FXML
+ private void onExit() throws Exception {
+ Stage primaryStage = (Stage) exitButton.getScene().getWindow();
+ Parent root = FXMLLoader.load(getClass().getResource("teacher-view.fxml"));
+ root.getStylesheets().add(getClass().getResource("/com/example/quizmanagement/styles.css").toExternalForm());
+ primaryStage.setTitle("Online Quiz Management");
+ primaryStage.setScene(new Scene(root, 400, 600));
+ primaryStage.show();
+ }
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ TableView table = new TableView();
+ TableColumn nmCol = new TableColumn("Name");
+ TableColumn dtCol = new TableColumn("Date");
+ TableColumn mkCol = new TableColumn("Mark");
+ nmCol.setCellValueFactory(new PropertyValueFactory("Name"));
+ dtCol.setCellValueFactory(new PropertyValueFactory("Date"));
+ mkCol.setCellValueFactory(new PropertyValueFactory("Mark"));
+ mkCol.setStyle("-fx-alignment:CENTER");
+ table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
+ table.getColumns().clear();
+ table.getColumns().add(nmCol);
+ table.getColumns().add(dtCol);
+ table.getColumns().add(mkCol);
+ tableCon.getChildren().add(table);
+ try {
+ Class.forName("com.mysql.jdbc.Driver");
+ Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/quiz", "root", "");
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery("Select * from `result`");
+ while (rs.next()) {
+ table.getItems().add(new ResultTable(rs.getString("name"), rs.getString("date"), rs.getString("mark")));
+ }
+ } catch (Exception e) {
+ }
+ }
+}
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 2658c8c..10dbd0d 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -3,6 +3,8 @@
requires javafx.fxml;
requires javafx.web;
+ requires mysql.connector.java;
+ requires java.sql;
requires org.controlsfx.controls;
requires com.dlsc.formsfx;
requires validatorfx;
diff --git a/src/main/resources/com/example/quizmanagement/add-acc-view.fxml b/src/main/resources/com/example/quizmanagement/add-acc-view.fxml
new file mode 100644
index 0000000..c17ab44
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/add-acc-view.fxml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/add-view.fxml b/src/main/resources/com/example/quizmanagement/add-view.fxml
new file mode 100644
index 0000000..2fb6919
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/add-view.fxml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/hello-view.fxml b/src/main/resources/com/example/quizmanagement/hello-view.fxml
deleted file mode 100644
index aa58f1b..0000000
--- a/src/main/resources/com/example/quizmanagement/hello-view.fxml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/com/example/quizmanagement/login-view.fxml b/src/main/resources/com/example/quizmanagement/login-view.fxml
new file mode 100644
index 0000000..391efc6
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/login-view.fxml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/manage-view.fxml b/src/main/resources/com/example/quizmanagement/manage-view.fxml
new file mode 100644
index 0000000..8e5c526
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/manage-view.fxml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/quiz-view.fxml b/src/main/resources/com/example/quizmanagement/quiz-view.fxml
new file mode 100644
index 0000000..d4e3eca
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/quiz-view.fxml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/result-view.fxml b/src/main/resources/com/example/quizmanagement/result-view.fxml
new file mode 100644
index 0000000..8036021
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/result-view.fxml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/student-report-view.fxml b/src/main/resources/com/example/quizmanagement/student-report-view.fxml
new file mode 100644
index 0000000..2c44134
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/student-report-view.fxml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/student-view.fxml b/src/main/resources/com/example/quizmanagement/student-view.fxml
new file mode 100644
index 0000000..c2090ba
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/student-view.fxml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/styles.css b/src/main/resources/com/example/quizmanagement/styles.css
new file mode 100644
index 0000000..0deb5f7
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/styles.css
@@ -0,0 +1,103 @@
+#blue-button{
+ -fx-border-width: 5px;
+ -fx-background-color: #6c63ff;
+ -fx-background-radius: 10px;
+ -fx-padding: 8px;
+ -fx-text-fill: white;
+}
+#purple-button{
+ -fx-border-width: 0px;
+ -fx-background-color: #fa6f66;
+ -fx-background-radius: 10px;
+ -fx-padding: 8px;
+ -fx-text-fill: white;
+}
+
+.button {
+ -fx-pref-width: 100px;
+ -fx-pref-height: 20px;
+}
+
+#green-button{
+ -fx-border-width: 0px;
+ -fx-background-color: #66b266;
+ -fx-background-radius: 10px;
+ -fx-padding: 8px;
+ -fx-text-fill: white;
+}
+#red-button{
+ -fx-border-width: 0px;
+ -fx-background-color: red;
+ -fx-background-radius: 10px;
+ -fx-padding: 8px;
+ -fx-text-fill: white;
+}
+.question-label {
+ -fx-font-family: Poppins, sans-serif;
+ -fx-font-size: 20px;
+}
+.data0.chart-pie { -fx-pie-color: green; }
+.data1.chart-pie { -fx-pie-color: red; }
+
+.table-view {
+ -fx-background-color: transparent;
+}
+.table-view .column-header-background .filler {
+ -fx-background-color: transparent;
+}
+.table-view .column-header-background{
+ -fx-background-color: linear-gradient(to bottom, #6c63ff22, #fa6f6622);
+ -fx-background-radius: 7px 7px 0px 0px;
+ -fx-background-insets: 0 0 0 0;
+ -fx-padding: 0 0 0 0;
+}
+.table-view .scroll-bar * {
+ -fx-min-width: 0;
+ -fx-pref-width: 0;
+ -fx-max-width: 0;
+
+ -fx-min-height: 0;
+ -fx-pref-height: 0;
+ -fx-max-height: 0;
+}
+.table-view .column-header {
+ -fx-background-color: transparent;
+}
+.table-view .corner {
+ -fx-background-color: transparent;
+}
+.table-view .table-cell{
+ -fx-border-color: transparent;
+ -fx-padding: 2 0 2 10px;
+}
+.table-row-cell: hover {
+ -fx-background-color: #93f9b922;
+ -fx-text-background-color: red;
+}
+.table-row-cell: odd{
+ -fx-background-color: #fa6f6622;
+ -fx-background-insets: 0, 0 0 1 0;
+ -fx-padding: 0.0em;
+}
+.table-row-cell: even{
+ -fx-background-color: #6c63ff11;
+ -fx-background-insets: 0, 0 0 1 0;
+ -fx-padding: 0.0em;
+}
+.table-row-cell: highlighted {
+ -fx-background-color: #81c483;
+ -fx-background-radius: 15px;
+}
+.table-view .virtual-flow .scroll-bar .increment-button,
+.table-view .virtual-flow .scroll-bar .decrement-button {
+ -fx-opacity: 0;
+ -fx-padding: 2;
+}
+.table-view .virtual-flow .scroll-bar:vertical,
+.table-view .virtual-flow .scroll-bar:vertical .track,
+.table-view .virtual-flow .scroll-bar:vertical .track-background,
+.table-view .virtual-flow .scroll-bar:horizontal,
+.table-view .virtual-flow .scroll-bar:horizontal .track,
+.table-view .virtual-flow .scroll-bar:horizontal .track-background {
+ -fx-background-color: transparent;
+}
diff --git a/src/main/resources/com/example/quizmanagement/teacher-report-view.fxml b/src/main/resources/com/example/quizmanagement/teacher-report-view.fxml
new file mode 100644
index 0000000..04a039a
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/teacher-report-view.fxml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/com/example/quizmanagement/teacher-view.fxml b/src/main/resources/com/example/quizmanagement/teacher-view.fxml
new file mode 100644
index 0000000..cd6b542
--- /dev/null
+++ b/src/main/resources/com/example/quizmanagement/teacher-view.fxml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/img/quiz.png b/src/main/resources/img/quiz.png
new file mode 100644
index 0000000..f3443ab
Binary files /dev/null and b/src/main/resources/img/quiz.png differ