diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..77eeb37
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,42 @@
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+.env
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..d28243b
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..9f48f22
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..e9a0f78
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,25 @@
+plugins {
+ id("java")
+ id("application")
+}
+group = "dev.ksan"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ mavenCentral();
+ maven("https://jitpack.io")
+ }
+application{
+
+ mainClass.set("dev.ksan.Main")
+}
+dependencies {
+ implementation("org.simplejavamail:simple-java-mail:8.7.0")
+ implementation("net.sourceforge.htmlunit:htmlunit:2.53.0")
+ testImplementation(platform("org.junit:junit-bom:5.10.0"))
+ testImplementation("org.junit.jupiter:junit-jupiter")
+}
+
+tasks.test {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..249e583
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..fef54b1
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jun 16 16:20:31 CEST 2025
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..1b6c787
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..ac1b06f
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..113fe8a
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,2 @@
+rootProject.name = "etfOglasi"
+
diff --git a/src/main/java/dev/ksan/DataStore.java b/src/main/java/dev/ksan/DataStore.java
new file mode 100644
index 0000000..8aeeb0a
--- /dev/null
+++ b/src/main/java/dev/ksan/DataStore.java
@@ -0,0 +1,49 @@
+package dev.ksan;
+
+import java.io.*;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class DataStore {
+
+ public static Map subjectSubscriptions = new ConcurrentHashMap<>();
+ private static final String DATA_FILE = "subjects_data.ser";
+ static{
+ loadSubjectsFromFile();
+ }
+
+ public static void notifySubject(Subject subject, SubjectEntry entry){
+ subjectSubscriptions.get(subject).notifyUsers(entry);
+ }
+ public static synchronized void subscribeUserToSubject(User user, Subject subject) {
+ if (user != null && subject != null && subjectSubscriptions.containsKey(subject)) {
+ subjectSubscriptions.get(subject).subscribe(user);
+ user.addSubject(subject);
+ }
+ }
+
+ public synchronized void unsubscribeUserFromSubject(User user, Subject subject) {
+ if (user != null && subject != null && subjectSubscriptions.containsKey(subject)) {
+ Subscription subscription = subjectSubscriptions.get(subject);
+ if (subscription != null) {
+ subscription.unsubscribe(user);
+ }
+ }
+ }
+ private static void loadSubjectsFromFile() {
+ try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(DATA_FILE))) {
+ subjectSubscriptions = (Map) in.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ System.out.println("Error loading subjects data: " + e.getMessage());
+ }
+ }
+
+ private static void saveSubjectsToFile() {
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(DATA_FILE))) {
+ out.writeObject(subjectSubscriptions);
+ } catch (IOException e) {
+ System.out.println("Error saving subjects data: " + e.getMessage());
+ }
+ }
+
+}
diff --git a/src/main/java/dev/ksan/DataThread.java b/src/main/java/dev/ksan/DataThread.java
new file mode 100644
index 0000000..1aaf8e2
--- /dev/null
+++ b/src/main/java/dev/ksan/DataThread.java
@@ -0,0 +1,35 @@
+package dev.ksan;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class DataThread implements Runnable {
+ private List allEntries = new ArrayList<>();
+ private boolean running;
+ Set subjects = Subject.generateSubjects();
+ @Override
+ public void run() {
+ while(running){
+
+ }
+ }
+ public void compare(List subjectEntries) {
+ for(SubjectEntry subjectEntry : subjectEntries){
+ if(!allEntries.contains(subjectEntry)){
+
+ for(Subject subject : subjects){
+ if(subject.matchesTitle(subjectEntry.getTitle())){
+ DataStore.notifySubject(subject, subjectEntry);
+ allEntries.add(subjectEntry);
+ }
+ }
+
+ }
+ }
+ }
+
+ public void stop(){
+ running = false;
+ }
+}
diff --git a/src/main/java/dev/ksan/ETFScraper.java b/src/main/java/dev/ksan/ETFScraper.java
new file mode 100644
index 0000000..3ec39ab
--- /dev/null
+++ b/src/main/java/dev/ksan/ETFScraper.java
@@ -0,0 +1,98 @@
+package dev.ksan;
+
+import com.gargoylesoftware.htmlunit.BrowserVersion;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.html.DomElement;
+import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ETFScraper implements Runnable {
+ private List entries = new ArrayList<>();
+
+ private volatile boolean running = true;
+
+ public ETFScraper() {
+ }
+ private static String getTextOrEmpty(HtmlElement parent, String xPath) {
+ HtmlElement element = parent.getFirstByXPath(xPath);
+ return element == null ? "" : element.asNormalizedText();
+ }
+ List getAllEntries() {
+ return entries;
+ }
+
+ @Override
+ public void run() {
+ while(running) {
+ try (final WebClient webClient = new WebClient(BrowserVersion.FIREFOX)) {
+
+ webClient.getOptions().setJavaScriptEnabled(true);
+ webClient.getOptions().setCssEnabled(false);
+ webClient.getOptions().setThrowExceptionOnScriptError(false);
+
+ HtmlPage mainPage = webClient.getPage("https://efee.etf.unibl.org/oglasi/");
+ webClient.waitForBackgroundJavaScript(1000);
+
+ List rawToggles = mainPage.getByXPath("//a[@href='#']");
+ List toggles = new ArrayList<>();
+ for (DomElement el : rawToggles) {
+ if (el instanceof HtmlAnchor) {
+ toggles.add((HtmlAnchor) el);
+ }
+ }
+ int ul_idSelection = 1;
+ for (HtmlAnchor anchor : toggles) {
+ String groupName = anchor.asNormalizedText().split("\n")[0].trim();
+ System.out.println("Group name: " + groupName);
+ HtmlPage updatedPage = anchor.click();
+ webClient.waitForBackgroundJavaScript(1000);
+
+ String ul_id = "ul_id_" + Integer.toString(ul_idSelection);
+
+ DomElement rawElement = updatedPage.getElementById(ul_id);
+ HtmlElement listElement = rawElement instanceof HtmlElement ? (HtmlElement) rawElement : null;
+
+ if (listElement == null) {
+ System.out.println("An element with id " + ul_id + " was not found");
+ ul_idSelection++;
+ continue;
+ }
+
+ List items = listElement.getElementsByTagName("li");
+ for (HtmlElement item : items) {
+ String title = getTextOrEmpty(item, ".//h1");
+ String date = getTextOrEmpty(item, ".//h2[1]");
+ String info = getTextOrEmpty(item, ".//h2[2]");
+ List paragraphs = new ArrayList<>();
+ List pTags = item.getByXPath(".//p");
+ for (HtmlElement pTag : pTags) {
+ paragraphs.add(pTag.asNormalizedText());
+ }
+ SubjectEntry entry = new SubjectEntry(title, date, info, paragraphs);
+
+ entries.add(entry);
+
+
+ }
+
+ ul_idSelection++;
+ }
+
+ Thread.sleep(20000);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("ERROR: " + e.getMessage());
+ }
+ }
+ System.out.println("WebScraper thread stopped");
+ }
+ public void stop(){
+ running = false;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/dev/ksan/MailService.java b/src/main/java/dev/ksan/MailService.java
new file mode 100644
index 0000000..1cd68f5
--- /dev/null
+++ b/src/main/java/dev/ksan/MailService.java
@@ -0,0 +1,42 @@
+package dev.ksan;
+
+import org.simplejavamail.api.email.Email;
+import org.simplejavamail.api.mailer.Mailer;
+import org.simplejavamail.api.mailer.config.TransportStrategy;
+import org.simplejavamail.email.EmailBuilder;
+import org.simplejavamail.mailer.MailerBuilder;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+
+public class MailService {
+
+ String address;
+ String passwd;
+ Mailer mailer;
+
+ public MailService(String filename) {
+ try(BufferedReader br = new BufferedReader((new FileReader(filename)))) {
+ address = br.readLine();
+ System.out.println(address);
+ passwd = br.readLine();
+ }catch(IOException e) {
+ e.printStackTrace();
+ }
+ this.mailer = MailerBuilder
+ .withSMTPServer("smtp.gmail.com",587,address,passwd)
+ .withTransportStrategy(TransportStrategy.SMTP)
+ .withSessionTimeout(10_000).buildMailer();
+ }
+
+ public void sendEmail(String to, String subject, String body) {
+ Email email = EmailBuilder.startingBlank()
+ .from(address).to(to)
+ .withSubject(subject)
+ .withPlainText(body).buildEmail();
+
+ mailer.sendMail(email);
+ }
+}
diff --git a/src/main/java/dev/ksan/Main.java b/src/main/java/dev/ksan/Main.java
new file mode 100644
index 0000000..38e0332
--- /dev/null
+++ b/src/main/java/dev/ksan/Main.java
@@ -0,0 +1,88 @@
+package dev.ksan;
+
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.BrowserVersion;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.*;
+
+import java.io.IOException;
+import java.util.*;
+
+public class Main {
+
+ public static void main(String[] args) {
+ boolean running = true;
+ User user = new User("djordje@ksan.dev","123");
+ boolean istrue = user.addSubject("Filozofija");
+ user.addSubject("Programiranje 2");
+ System.out.println(istrue);
+ System.out.println(user.getEmail() + user.getId());
+
+ Set subjectSet = user.getSubjectSet();
+
+ List entries = new ArrayList<>();
+ List newEntries = new ArrayList<>();
+
+
+
+ ETFScraper task = new ETFScraper();
+
+
+ Thread webClientThread = new Thread(task, "WebClientThread");
+ webClientThread.start();
+
+ Scanner scanner = new Scanner(System.in);
+
+ try {
+ while (running) {
+
+ String command = scanner.nextLine();
+
+ switch (command) {
+ case "stop":
+ task.stop();
+ running = false;
+ System.out.println("Stopping...");
+ break;
+ case "list":
+ System.out.println();
+
+ }
+
+
+ }
+ }catch (Exception e) {
+ scanner.close();
+ e.printStackTrace();
+ }
+ scanner.close();
+ //temp
+ SubjectEntry mail = new SubjectEntry("TAAAA","asd", "Test", Arrays.asList("Testing mail broj 2", "ne znam zas je u spamu"));
+ try {
+ //user.sendEmail(mail);
+ System.out.println("AAAAAAAAAAAAAAAAAAAA");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ entries=task.getAllEntries();
+ System.out.println("BBBBBBBBBBBBb");
+ System.out.println(entries.size());
+
+ for(SubjectEntry e : task.getAllEntries()) {
+ //System.out.println(e);
+ }
+ for(Subject subject : user.getSubjectSet()) {
+
+ for(SubjectEntry entry : entries){
+ if(subject.isSubject(entry.getTitle())){
+ //user.sendEmail(entry);
+ System.out.println("Subject " + subject.getTitle() + " was found");
+ }
+ }
+
+ }
+ //temp
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/ksan/NotificationMethod.java b/src/main/java/dev/ksan/NotificationMethod.java
new file mode 100644
index 0000000..e61df19
--- /dev/null
+++ b/src/main/java/dev/ksan/NotificationMethod.java
@@ -0,0 +1,6 @@
+package dev.ksan;
+
+public enum NotificationMethod{
+ EMAIL,
+ PUSH_NOTIFICATION;
+}
diff --git a/src/main/java/dev/ksan/Subject.java b/src/main/java/dev/ksan/Subject.java
new file mode 100644
index 0000000..7f7bdd7
--- /dev/null
+++ b/src/main/java/dev/ksan/Subject.java
@@ -0,0 +1,234 @@
+package dev.ksan;
+
+import java.io.Serializable;
+import java.text.Normalizer;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+public class Subject implements Serializable {
+ public String title;
+ public Set alternatives = new HashSet<>();
+
+ public Subject(String title){
+ this.title = title;
+ alternatives.add(title);
+ }
+ public Subject(String title, Set alternatives) {
+ this.title = title;
+ this.alternatives = alternatives;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Subject)) return false;
+ Subject subject = (Subject) o;
+ if(Objects.equals(title, subject.title)){
+ return true;
+ }
+ if(alternatives.equals(subject.alternatives)){
+ return true;
+ }
+ for(String alt:subject.alternatives){
+ if(this.alternatives.contains(alt)){
+ return true;
+ }
+ }
+ return false;
+ }
+ private String normalizeText(String text) {
+ return Normalizer.normalize(text.toLowerCase(), Normalizer.Form.NFD).replaceAll("\\p{M}", "");
+ }
+ public boolean matchesTitle(String title) {
+ String normalizedTitle = normalizeText(title);
+ // Check direct match with subject title
+ if (normalizedTitle.contains(normalizeText(this.title))) {
+ return true;
+ }
+ // Check alternatives
+ for (String alt : alternatives) {
+ if (normalizedTitle.contains(normalizeText(alt))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ @Override
+ public int hashCode() {
+ return Objects.hash(title);
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+ public String getTitle() {
+ return title;
+ }
+ public void setTitle(String title) {
+ this.title = title;
+ alternatives.add(title);
+ }
+
+ public boolean isSubject(String name) {
+ for(String alt : alternatives){
+ if(name.contains(alt)){
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // TODO works for now but change to check website and get the list of subjects from there and add function to
+ // generate alternative versions of that subject name
+ // "https://etf.unibl.org/studiranje/1-ciklus/pl-n-i-r-sp-r-d-n-s-v.html" does not have the full list of subjects?? dodati prebmete sa smjerova rucno do tad mozda??
+ public static Set generateSubjects(){
+ Set subjects = new HashSet<>();
+
+ subjects.add(new Subject("Savremene telekomunikacije", Set.of("Савремене телекомуникације", "савремене телекомуникације", "Savremene telekomunikacije", "САВРЕМЕНЕ ТЕЛЕКОМУНИКАЦИЈЕ", "SAVREMENE TELEKOMUNIKACIJE", "savremene telekomunikacije")));
+ subjects.add(new Subject("Mrežno i distribuirano programiranje", Set.of("Мрежно и дистрибуирано програмирање", "MREZNO I DISTRIBUIRANO PROGRAMIRANJE", "mrezno i distribuirano programiranje", "mrežno i distribuirano programiranje", "мрежно и дистрибуирано програмирање", "Mrezno i distribuirano programiranje", "МРЕЖНО И ДИСТРИБУИРАНО ПРОГРАМИРАЊЕ", "MREŽNO I DISTRIBUIRANO PROGRAMIRANJE", "Mrežno i distribuirano programiranje")));
+ subjects.add(new Subject("Osnovi sistema automatskog upravljanja", Set.of("основи система аутоматског управљања", "Основи система аутоматског управљања", "ОСНОВИ СИСТЕМА АУТОМАТСКОГ УПРАВЉАЊА", "Osnovi sistema automatskog upravljanja", "osnovi sistema automatskog upravljanja", "OSNOVI SISTEMA AUTOMATSKOG UPRAVLJANJA")));
+ subjects.add(new Subject("Tehnika visokog napona", Set.of("TEHNIKA VISOKOG NAPONA", "Техника високог напона", "ТЕХНИКА ВИСОКОГ НАПОНА", "tehnika visokog napona", "техника високог напона", "Tehnika visokog napona")));
+ subjects.add(new Subject("Sinteza sistema automatskog upravljanja", Set.of("Синтеза система аутоматског управљања", "sinteza sistema automatskog upravljanja", "SINTEZA SISTEMA AUTOMATSKOG UPRAVLJANJA", "синтеза система аутоматског управљања", "Sinteza sistema automatskog upravljanja", "СИНТЕЗА СИСТЕМА АУТОМАТСКОГ УПРАВЉАЊА")));
+ subjects.add(new Subject("Telekomunikacione mreže", Set.of("Telekomunikacione mreže", "telekomunikacione mreže", "ТЕЛЕКОМУНИКАЦИОНЕ МРЕЖЕ", "telekomunikacione mreze", "телекомуникационе мреже", "TELEKOMUNIKACIONE MREŽE", "Телекомуникационе мреже", "Telekomunikacione mreze", "TELEKOMUNIKACIONE MREZE")));
+ subjects.add(new Subject("Multimedijalni signali i sistemi", Set.of("мултимедијални сигнали и системи", "multimedijalni signali i sistemi", "МУЛТИМЕДИЈАЛНИ СИГНАЛИ И СИСТЕМИ", "Мултимедијални сигнали и системи", "MULTIMEDIJALNI SIGNALI I SISTEMI", "Multimedijalni signali i sistemi")));
+ subjects.add(new Subject("Osnovi softverskog inženjerstva", Set.of("Osnovi softverskog inženjerstva", "ОСНОВИ СОФТВЕРСКОГ ИНЖЕЊЕРСТВА", "Osnovi softverskog inzenjerstva", "osnovi softverskog inženjerstva", "osnovi softverskog inzenjerstva", "OSNOVI SOFTVERSKOG INZENJERSTVA", "OSNOVI SOFTVERSKOG INŽENJERSTVA", "Основи софтверског инжењерства", "основи софтверског инжењерства")));
+ subjects.add(new Subject("Kriptografija i računarska zaštita", Set.of("KRIPTOGRAFIJA I RAČUNARSKA ZAŠTITA", "Kriptografija i racunarska zastita", "kriptografija i računarska zaštita", "KRIPTOGRAFIJA I RACUNARSKA ZASTITA", "Kriptografija i računarska zaštita", "КРИПТОГРАФИЈА И РАЧУНАРСКА ЗАШТИТА", "kriptografija i racunarska zastita", "Криптографија и рачунарска заштита", "криптографија и рачунарска заштита")));
+ subjects.add(new Subject("Operativni sistemi i programiranje u realnom vremenu", Set.of("Оперативни системи и програмирање у реалном времену", "operativni sistemi i programiranje u realnom vremenu", "ОПЕРАТИВНИ СИСТЕМИ И ПРОГРАМИРАЊЕ У РЕАЛНОМ ВРЕМЕНУ", "Operativni sistemi i programiranje u realnom vremenu", "OPERATIVNI SISTEMI I PROGRAMIRANJE U REALNOM VREMENU", "оперативни системи и програмирање у реалном времену")));
+ subjects.add(new Subject("Vještine komuniciranja", Set.of("Vještine komuniciranja", "Вјештине комуницирања", "vještine komuniciranja", "vjestine komuniciranja", "VJEŠTINE KOMUNICIRANJA", "ВЈЕШТИНЕ КОМУНИЦИРАЊА", "вјештине комуницирања", "Vjestine komuniciranja", "VJESTINE KOMUNICIRANJA")));
+ subjects.add(new Subject("Uvod u teoriju sistema", Set.of("uvod u teoriju sistema", "UVOD U TEORIJU SISTEMA", "увод у теорију система", "УВОД У ТЕОРИЈУ СИСТЕМА", "Uvod u teoriju sistema", "Увод у теорију система")));
+ subjects.add(new Subject("Električne mašine 2", Set.of("Elektricne masine 2", "Електричне машине 2", "električne mašine 2", "ELEKTRICNE MASINE 2", "ЕЛЕКТРИЧНЕ МАШИНЕ 2", "ELEKTRIČNE MAŠINE 2", "електричне машине 2", "elektricne masine 2", "Električne mašine 2")));
+ subjects.add(new Subject("Mikroprocesori", Set.of("mikroprocesori", "Микропроцесори", "микропроцесори", "Mikroprocesori", "MIKROPROCESORI", "МИКРОПРОЦЕСОРИ")));
+ subjects.add(new Subject("Elektromotorni pogoni", Set.of("Електромоторни погони", "ELEKTROMOTORNI POGONI", "електромоторни погони", "Elektromotorni pogoni", "ЕЛЕКТРОМОТОРНИ ПОГОНИ", "elektromotorni pogoni")));
+ subjects.add(new Subject("Digitalna obrada signala", Set.of("Digitalna obrada signala", "digitalna obrada signala", "Дигитална обрада сигнала", "DIGITALNA OBRADA SIGNALA", "дигитална обрада сигнала", "ДИГИТАЛНА ОБРАДА СИГНАЛА")));
+ subjects.add(new Subject("Digitalna televizija", Set.of("Digitalna televizija", "Дигитална телевизија", "digitalna televizija", "дигитална телевизија", "DIGITALNA TELEVIZIJA", "ДИГИТАЛНА ТЕЛЕВИЗИЈА")));
+ subjects.add(new Subject("Projekat iz elektroenergetike", Set.of("ПРОЈЕКАТ ИЗ ЕЛЕКТРОЕНЕРГЕТИКЕ", "projekat iz elektroenergetike", "Projekat iz elektroenergetike", "Пројекат из електроенергетике", "пројекат из електроенергетике", "PROJEKAT IZ ELEKTROENERGETIKE")));
+ subjects.add(new Subject("Kućna automatizacija", Set.of("КУЋНА АУТОМАТИЗАЦИЈА", "KUCNA AUTOMATIZACIJA", "Kućna automatizacija", "кућна аутоматизација", "kućna automatizacija", "Кућна аутоматизација", "Kucna automatizacija", "kucna automatizacija", "KUĆNA AUTOMATIZACIJA")));
+ subjects.add(new Subject("Razvodna postrojenja i aparati", Set.of("razvodna postrojenja i aparati", "RAZVODNA POSTROJENJA I APARATI", "разводна постројења и апарати", "Razvodna postrojenja i aparati", "РАЗВОДНА ПОСТРОЈЕЊА И АПАРАТИ", "Разводна постројења и апарати")));
+ subjects.add(new Subject("Performanse računarskih sistema", Set.of("Performanse racunarskih sistema", "performanse racunarskih sistema", "Перформансе рачунарских система", "performanse računarskih sistema", "Performanse računarskih sistema", "перформансе рачунарских система", "PERFORMANSE RACUNARSKIH SISTEMA", "ПЕРФОРМАНСЕ РАЧУНАРСКИХ СИСТЕМА", "PERFORMANSE RAČUNARSKIH SISTEMA")));
+ subjects.add(new Subject("Mobilni radio sistemi", Set.of("мобилни радио системи", "MOBILNI RADIO SISTEMI", "Мобилни радио системи", "mobilni radio sistemi", "МОБИЛНИ РАДИО СИСТЕМИ", "Mobilni radio sistemi")));
+ subjects.add(new Subject("Programiranje u realnom vremenu", Set.of("PROGRAMIRANJE U REALNOM VREMENU", "програмирање у реалном времену", "Програмирање у реалном времену", "programiranje u realnom vremenu", "ПРОГРАМИРАЊЕ У РЕАЛНОМ ВРЕМЕНУ", "Programiranje u realnom vremenu")));
+ subjects.add(new Subject("Računarske mreže", Set.of("RAČUNARSKE MREŽE", "рачунарске мреже", "Racunarske mreze", "RACUNARSKE MREZE", "Рачунарске мреже", "racunarske mreze", "računarske mreže", "Računarske mreže", "РАЧУНАРСКЕ МРЕЖЕ")));
+ subjects.add(new Subject("Telekomunikacioni sistemi", Set.of("Телекомуникациони системи", "TELEKOMUNIKACIONI SISTEMI", "телекомуникациони системи", "Telekomunikacioni sistemi", "ТЕЛЕКОМУНИКАЦИОНИ СИСТЕМИ", "telekomunikacioni sistemi")));
+ subjects.add(new Subject("Strukture podataka i algoritmi", Set.of("СТРУКТУРЕ ПОДАТАКА И АЛГОРИТМИ", "структуре података и алгоритми", "Strukture podataka i algoritmi", "strukture podataka i algoritmi", "STRUKTURE PODATAKA I ALGORITMI", "Структуре података и алгоритми")));
+ subjects.add(new Subject("Operaciona istraživanja", Set.of("operaciona istrazivanja", "operaciona istraživanja", "операциона истраживања", "Operaciona istrazivanja", "ОПЕРАЦИОНА ИСТРАЖИВАЊА", "OPERACIONA ISTRAŽIVANJA", "Operaciona istraživanja", "Операциона истраживања", "OPERACIONA ISTRAZIVANJA")));
+ subjects.add(new Subject("Stručna praksa", Set.of("Стручна пракса", "Strucna praksa", "Stručna praksa", "СТРУЧНА ПРАКСА", "STRUČNA PRAKSA", "stručna praksa", "стручна пракса", "strucna praksa", "STRUCNA PRAKSA")));
+ subjects.add(new Subject("Odabrana poglavlja operativnih sistema", Set.of("Одабрана поглавља оперативних система", "ODABRANA POGLAVLJA OPERATIVNIH SISTEMA", "одабрана поглавља оперативних система", "Odabrana poglavlja operativnih sistema", "ОДАБРАНА ПОГЛАВЉА ОПЕРАТИВНИХ СИСТЕМА", "odabrana poglavlja operativnih sistema")));
+ subjects.add(new Subject("Senzori i aktuatori", Set.of("Сензори и актуатори", "senzori i aktuatori", "СЕНЗОРИ И АКТУАТОРИ", "SENZORI I AKTUATORI", "Senzori i aktuatori", "сензори и актуатори")));
+ subjects.add(new Subject("Projektovanje elektronskih uređaja", Set.of("PROJEKTOVANJE ELEKTRONSKIH UREĐAJA", "Пројектовање електронских уређаја", "ПРОЈЕКТОВАЊЕ ЕЛЕКТРОНСКИХ УРЕЂАЈА", "projektovanje elektronskih uređaja", "пројектовање електронских уређаја", "Projektovanje elektronskih uređaja", "PROJEKTOVANJE ELEKTRONSKIH UREDJAJA", "Projektovanje elektronskih uredjaja", "projektovanje elektronskih uredjaja")));
+ subjects.add(new Subject("Projektovanje namjenskih računarskih sistema", Set.of("PROJEKTOVANJE NAMJENSKIH RAČUNARSKIH SISTEMA", "PROJEKTOVANJE NAMJENSKIH RACUNARSKIH SISTEMA", "Пројектовање намјенских рачунарских система", "ПРОЈЕКТОВАЊЕ НАМЈЕНСКИХ РАЧУНАРСКИХ СИСТЕМА", "Projektovanje namjenskih računarskih sistema", "projektovanje namjenskih racunarskih sistema", "projektovanje namjenskih računarskih sistema", "пројектовање намјенских рачунарских система", "Projektovanje namjenskih racunarskih sistema")));
+ subjects.add(new Subject("Digitalna obrada slike", Set.of("дигитална обрада слике", "DIGITALNA OBRADA SLIKE", "Дигитална обрада слике", "ДИГИТАЛНА ОБРАДА СЛИКЕ", "digitalna obrada slike", "Digitalna obrada slike")));
+ subjects.add(new Subject("Arhitektura interneta", Set.of("Arhitektura interneta", "Архитектура интернета", "архитектура интернета", "arhitektura interneta", "АРХИТЕКТУРА ИНТЕРНЕТА", "ARHITEKTURA INTERNETA")));
+ subjects.add(new Subject("Akustika i audio tehnika", Set.of("Akustika i audio tehnika", "AKUSTIKA I AUDIO TEHNIKA", "АКУСТИКА И АУДИО ТЕХНИКА", "Акустика и аудио техника", "акустика и аудио техника", "akustika i audio tehnika")));
+ subjects.add(new Subject("Matematika 3", Set.of("MATEMATIKA 3", "matematika 3", "математика 3", "Математика 3", "МАТЕМАТИКА 3", "Matematika 3")));
+ subjects.add(new Subject("Signali i sistemi", Set.of("сигнали и системи", "СИГНАЛИ И СИСТЕМИ", "signali i sistemi", "SIGNALI I SISTEMI", "Сигнали и системи", "Signali i sistemi")));
+ subjects.add(new Subject("Robotika", Set.of("ROBOTIKA", "РОБОТИКА", "Robotika", "роботика", "Роботика", "robotika")));
+ subjects.add(new Subject("Osnovi elektronike i digitalne tehnike", Set.of("основи електронике и дигиталне технике", "osnovi elektronike i digitalne tehnike", "ОСНОВИ ЕЛЕКТРОНИКЕ И ДИГИТАЛНЕ ТЕХНИКЕ", "OSNOVI ELEKTRONIKE I DIGITALNE TEHNIKE", "Osnovi elektronike i digitalne tehnike", "Основи електронике и дигиталне технике")));
+ subjects.add(new Subject("Upravljanje u realnom vremenu", Set.of("УПРАВЉАЊЕ У РЕАЛНОМ ВРЕМЕНУ", "upravljanje u realnom vremenu", "Upravljanje u realnom vremenu", "UPRAVLJANJE U REALNOM VREMENU", "управљање у реалном времену", "Управљање у реалном времену")));
+ subjects.add(new Subject("Funkcionalna verifikacija hardvera", Set.of("функционална верификација хардвера", "Funkcionalna verifikacija hardvera", "Функционална верификација хардвера", "ФУНКЦИОНАЛНА ВЕРИФИКАЦИЈА ХАРДВЕРА", "funkcionalna verifikacija hardvera", "FUNKCIONALNA VERIFIKACIJA HARDVERA")));
+ subjects.add(new Subject("Nelinearni sistemi", Set.of("НЕЛИНЕАРНИ СИСТЕМИ", "Nelinearni sistemi", "Нелинеарни системи", "NELINEARNI SISTEMI", "nelinearni sistemi", "нелинеарни системи")));
+ subjects.add(new Subject("Matematika 2", Set.of("МАТЕМАТИКА 2", "matematika 2", "математика 2", "MATEMATIKA 2", "Математика 2", "Matematika 2")));
+ subjects.add(new Subject("Programiranje 1", Set.of("Programiranje 1", "Програмирање 1", "програмирање 1", "PROGRAMIRANJE 1", "ПРОГРАМИРАЊЕ 1", "programiranje 1")));
+ subjects.add(new Subject("Uvod u elektroniku", Set.of("увод у електронику", "Uvod u elektroniku", "uvod u elektroniku", "УВОД У ЕЛЕКТРОНИКУ", "Увод у електронику", "UVOD U ELEKTRONIKU")));
+ subjects.add(new Subject("Osnovi komunikacija i teorija informacija", Set.of("OSNOVI KOMUNIKACIJA I TEORIJA INFORMACIJA", "Osnovi komunikacija i teorija informacija", "основи комуникација и теорија информација", "ОСНОВИ КОМУНИКАЦИЈА И ТЕОРИЈА ИНФОРМАЦИЈА", "Основи комуникација и теорија информација", "osnovi komunikacija i teorija informacija")));
+ subjects.add(new Subject("Engleski jezik 1", Set.of("engleski jezik 1", "ENGLESKI JEZIK 1", "енглески језик 1", "ЕНГЛЕСКИ ЈЕЗИК 1", "Engleski jezik 1", "Енглески језик 1")));
+ subjects.add(new Subject("Multimedijalne telekomunikacije", Set.of("Мултимедијалне телекомуникације", "мултимедијалне телекомуникације", "multimedijalne telekomunikacije", "Multimedijalne telekomunikacije", "MULTIMEDIJALNE TELEKOMUNIKACIJE", "МУЛТИМЕДИЈАЛНЕ ТЕЛЕКОМУНИКАЦИЈЕ")));
+ subjects.add(new Subject("Internet programiranje", Set.of("internet programiranje", "INTERNET PROGRAMIRANJE", "интернет програмирање", "Интернет програмирање", "ИНТЕРНЕТ ПРОГРАМИРАЊЕ", "Internet programiranje")));
+ subjects.add(new Subject("Upravljanje projektima", Set.of("управљање пројектима", "upravljanje projektima", "УПРАВЉАЊЕ ПРОЈЕКТИМА", "Управљање пројектима", "Upravljanje projektima", "UPRAVLJANJE PROJEKTIMA")));
+ subjects.add(new Subject("Internet tehnologije", Set.of("ИНТЕРНЕТ ТЕХНОЛОГИЈЕ", "internet tehnologije", "Internet tehnologije", "Интернет технологије", "INTERNET TEHNOLOGIJE", "интернет технологије")));
+ subjects.add(new Subject("Fizika", Set.of("ФИЗИКА", "физика", "fizika", "Физика", "FIZIKA", "Fizika")));
+ subjects.add(new Subject("Bežične senzorske mreže", Set.of("BEZICNE SENZORSKE MREZE", "BEŽIČNE SENZORSKE MREŽE", "bežične senzorske mreže", "Bežične senzorske mreže", "бежичне сензорске мреже", "Бежичне сензорске мреже", "Bezicne senzorske mreze", "БЕЖИЧНЕ СЕНЗОРСКЕ МРЕЖЕ", "bezicne senzorske mreze")));
+ subjects.add(new Subject("Radio-relejne komunikacije", Set.of("радио-релејне комуникације", "RADIO-RELEJNE KOMUNIKACIJE", "radio-relejne komunikacije", "Радио-релејне комуникације", "РАДИО-РЕЛЕЈНЕ КОМУНИКАЦИЈЕ", "Radio-relejne komunikacije")));
+ subjects.add(new Subject("Osnovi elektrotehnike 2", Set.of("основи електротехнике 2", "Основи електротехнике 2", "osnovi elektrotehnike 2", "OSNOVI ELEKTROTEHNIKE 2", "ОСНОВИ ЕЛЕКТРОТЕХНИКЕ 2", "Osnovi elektrotehnike 2")));
+ subjects.add(new Subject("Sociologija", Set.of("sociologija", "социологија", "СОЦИОЛОГИЈА", "SOCIOLOGIJA", "Sociologija", "Социологија")));
+ subjects.add(new Subject("Metodi vještačke inteligencije", Set.of("Методи вјештачке интелигенције", "METODI VJEŠTAČKE INTELIGENCIJE", "Metodi vjestacke inteligencije", "МЕТОДИ ВЈЕШТАЧКЕ ИНТЕЛИГЕНЦИЈЕ", "методи вјештачке интелигенције", "metodi vjestacke inteligencije", "metodi vještačke inteligencije", "METODI VJESTACKE INTELIGENCIJE", "Metodi vještačke inteligencije")));
+ subjects.add(new Subject("Baze podataka", Set.of("БАЗЕ ПОДАТАКА", "Базе података", "Baze podataka", "BAZE PODATAKA", "baze podataka", "базе података")));
+ subjects.add(new Subject("Optičke telekomunikacije", Set.of("Оптичке телекомуникације", "Opticke telekomunikacije", "оптичке телекомуникације", "Optičke telekomunikacije", "OPTIČKE TELEKOMUNIKACIJE", "ОПТИЧКЕ ТЕЛЕКОМУНИКАЦИЈЕ", "optičke telekomunikacije", "opticke telekomunikacije", "OPTICKE TELEKOMUNIKACIJE")));
+ subjects.add(new Subject("Stohastički sistemi i estimacija", Set.of("стохастички системи и естимација", "Stohasticki sistemi i estimacija", "Stohastički sistemi i estimacija", "Стохастички системи и естимација", "stohasticki sistemi i estimacija", "stohastički sistemi i estimacija", "STOHASTICKI SISTEMI I ESTIMACIJA", "СТОХАСТИЧКИ СИСТЕМИ И ЕСТИМАЦИЈА", "STOHASTIČKI SISTEMI I ESTIMACIJA")));
+ subjects.add(new Subject("Projektovanje softvera", Set.of("projektovanje softvera", "ПРОЈЕКТОВАЊЕ СОФТВЕРА", "Пројектовање софтвера", "пројектовање софтвера", "PROJEKTOVANJE SOFTVERA", "Projektovanje softvera")));
+ subjects.add(new Subject("Ugrađeni računarski sistemi", Set.of("Ugrađeni računarski sistemi", "Уграђени рачунарски системи", "ugradjeni racunarski sistemi", "Ugradjeni racunarski sistemi", "UGRADJENI RACUNARSKI SISTEMI", "уграђени рачунарски системи", "UGRAĐENI RAČUNARSKI SISTEMI", "ugrađeni računarski sistemi", "УГРАЂЕНИ РАЧУНАРСКИ СИСТЕМИ")));
+ subjects.add(new Subject("Filozofija", Set.of("FILOZOFIJA", "Filozofija", "филозофија", "filozofija", "Филозофија", "ФИЛОЗОФИЈА")));
+ subjects.add(new Subject("Programiranje 2", Set.of("ПРОГРАМИРАЊЕ 2", "programiranje 2", "PROGRAMIRANJE 2", "Programiranje 2", "Програмирање 2", "програмирање 2")));
+ subjects.add(new Subject("Linearna elektronika", Set.of("ЛИНЕАРНА ЕЛЕКТРОНИКА", "linearna elektronika", "Линеарна електроника", "Linearna elektronika", "LINEARNA ELEKTRONIKA", "линеарна електроника")));
+ subjects.add(new Subject("Analiza elektroenergetskih sistema 2", Set.of("analiza elektroenergetskih sistema 2", "АНАЛИЗА ЕЛЕКТРОЕНЕРГЕТСКИХ СИСТЕМА 2", "анализа електроенергетских система 2", "ANALIZA ELEKTROENERGETSKIH SISTEMA 2", "Анализа електроенергетских система 2", "Analiza elektroenergetskih sistema 2")));
+ subjects.add(new Subject("Elektrane", Set.of("Elektrane", "elektrane", "ELEKTRANE", "електране", "ЕЛЕКТРАНЕ", "Електране")));
+ subjects.add(new Subject("Računarska grafika", Set.of("Računarska grafika", "Рачунарска графика", "Racunarska grafika", "racunarska grafika", "RAČUNARSKA GRAFIKA", "рачунарска графика", "RACUNARSKA GRAFIKA", "РАЧУНАРСКА ГРАФИКА", "računarska grafika")));
+ subjects.add(new Subject("Energetska elektronika", Set.of("Energetska elektronika", "energetska elektronika", "Енергетска електроника", "ENERGETSKA ELEKTRONIKA", "ЕНЕРГЕТСКА ЕЛЕКТРОНИКА", "енергетска електроника")));
+ subjects.add(new Subject("Sistemi za digitalnu obradu signala", Set.of("Sistemi za digitalnu obradu signala", "sistemi za digitalnu obradu signala", "Системи за дигиталну обраду сигнала", "СИСТЕМИ ЗА ДИГИТАЛНУ ОБРАДУ СИГНАЛА", "SISTEMI ZA DIGITALNU OBRADU SIGNALA", "системи за дигиталну обраду сигнала")));
+ subjects.add(new Subject("Projektovanje izvora napajanja", Set.of("projektovanje izvora napajanja", "Projektovanje izvora napajanja", "пројектовање извора напајања", "Пројектовање извора напајања", "PROJEKTOVANJE IZVORA NAPAJANJA", "ПРОЈЕКТОВАЊЕ ИЗВОРА НАПАЈАЊА")));
+ subjects.add(new Subject("Digitalne telekomunikacije", Set.of("Digitalne telekomunikacije", "ДИГИТАЛНЕ ТЕЛЕКОМУНИКАЦИЈЕ", "дигиталне телекомуникације", "DIGITALNE TELEKOMUNIKACIJE", "Дигиталне телекомуникације", "digitalne telekomunikacije")));
+ subjects.add(new Subject("Osnovi operativnih sistema", Set.of("OSNOVI OPERATIVNIH SISTEMA", "ОСНОВИ ОПЕРАТИВНИХ СИСТЕМА", "osnovi operativnih sistema", "Osnovi operativnih sistema", "Основи оперативних система", "основи оперативних система")));
+ subjects.add(new Subject("Informacioni sistemi", Set.of("informacioni sistemi", "информациони системи", "ИНФОРМАЦИОНИ СИСТЕМИ", "Информациони системи", "INFORMACIONI SISTEMI", "Informacioni sistemi")));
+ subjects.add(new Subject("Računarski integrisana proizvodnja", Set.of("рачунарски интегрисана производња", "Računarski integrisana proizvodnja", "RAČUNARSKI INTEGRISANA PROIZVODNJA", "računarski integrisana proizvodnja", "racunarski integrisana proizvodnja", "RACUNARSKI INTEGRISANA PROIZVODNJA", "Racunarski integrisana proizvodnja", "Рачунарски интегрисана производња", "РАЧУНАРСКИ ИНТЕГРИСАНА ПРОИЗВОДЊА")));
+ subjects.add(new Subject("Industrijske komunikacione mreže", Set.of("Industrijske komunikacione mreze", "ИНДУСТРИЈСКЕ КОМУНИКАЦИОНЕ МРЕЖЕ", "INDUSTRIJSKE KOMUNIKACIONE MREŽE", "industrijske komunikacione mreze", "INDUSTRIJSKE KOMUNIKACIONE MREZE", "Industrijske komunikacione mreže", "industrijske komunikacione mreže", "индустријске комуникационе мреже", "Индустријске комуникационе мреже")));
+ subjects.add(new Subject("Osnovi elektrotehnike 1", Set.of("osnovi elektrotehnike 1", "Основи електротехнике 1", "основи електротехнике 1", "ОСНОВИ ЕЛЕКТРОТЕХНИКЕ 1", "OSNOVI ELEKTROTEHNIKE 1", "Osnovi elektrotehnike 1")));
+ subjects.add(new Subject("Inženjering softverskih zahtjeva", Set.of("Инжењеринг софтверских захтјева", "Inženjering softverskih zahtjeva", "ИНЖЕЊЕРИНГ СОФТВЕРСКИХ ЗАХТЈЕВА", "инжењеринг софтверских захтјева", "INZENJERING SOFTVERSKIH ZAHTJEVA", "INŽENJERING SOFTVERSKIH ZAHTJEVA", "inženjering softverskih zahtjeva", "inzenjering softverskih zahtjeva", "Inzenjering softverskih zahtjeva")));
+ subjects.add(new Subject("Interakcija čovjek – računar", Set.of("interakcija covjek – racunar", "ИНТЕРАКЦИЈА ЧОВЈЕК – РАЧУНАР", "Интеракција човјек – рачунар", "Interakcija čovjek – računar", "интеракција човјек – рачунар", "INTERAKCIJA ČOVJEK – RAČUNAR", "Interakcija covjek – racunar", "INTERAKCIJA COVJEK – RACUNAR", "interakcija čovjek – računar")));
+ subjects.add(new Subject("Umreženi sistemi upravljanja", Set.of("Umrezeni sistemi upravljanja", "Умрежени системи управљања", "Umreženi sistemi upravljanja", "umreženi sistemi upravljanja", "умрежени системи управљања", "umrezeni sistemi upravljanja", "УМРЕЖЕНИ СИСТЕМИ УПРАВЉАЊА", "UMREZENI SISTEMI UPRAVLJANJA", "UMREŽENI SISTEMI UPRAVLJANJA")));
+ subjects.add(new Subject("Regulacija elektromotornih pogona", Set.of("регулација електромоторних погона", "Регулација електромоторних погона", "regulacija elektromotornih pogona", "РЕГУЛАЦИЈА ЕЛЕКТРОМОТОРНИХ ПОГОНА", "REGULACIJA ELEKTROMOTORNIH POGONA", "Regulacija elektromotornih pogona")));
+ subjects.add(new Subject("Sistemi sa bazama podataka", Set.of("SISTEMI SA BAZAMA PODATAKA", "sistemi sa bazama podataka", "Системи са базама података", "системи са базама података", "СИСТЕМИ СА БАЗАМА ПОДАТАКА", "Sistemi sa bazama podataka")));
+ subjects.add(new Subject("Digitalni sistemi upravljanja", Set.of("DIGITALNI SISTEMI UPRAVLJANJA", "ДИГИТАЛНИ СИСТЕМИ УПРАВЉАЊА", "дигитални системи управљања", "digitalni sistemi upravljanja", "Дигитални системи управљања", "Digitalni sistemi upravljanja")));
+ subjects.add(new Subject("Prepoznavanje uzoraka", Set.of("ПРЕПОЗНАВАЊЕ УЗОРАКА", "препознавање узорака", "prepoznavanje uzoraka", "Prepoznavanje uzoraka", "Препознавање узорака", "PREPOZNAVANJE UZORAKA")));
+ subjects.add(new Subject("Matematika 1", Set.of("matematika 1", "математика 1", "МАТЕМАТИКА 1", "MATEMATIKA 1", "Математика 1", "Matematika 1")));
+ subjects.add(new Subject("Mikrokontrolerski sistemi", Set.of("Mikrokontrolerski sistemi", "МИКРОКОНТРОЛЕРСКИ СИСТЕМИ", "mikrokontrolerski sistemi", "MIKROKONTROLERSKI SISTEMI", "Микроконтролерски системи", "микроконтролерски системи")));
+ subjects.add(new Subject("Testiranje i kvalitet softvera", Set.of("testiranje i kvalitet softvera", "TESTIRANJE I KVALITET SOFTVERA", "тестирање и квалитет софтвера", "Testiranje i kvalitet softvera", "Тестирање и квалитет софтвера", "ТЕСТИРАЊЕ И КВАЛИТЕТ СОФТВЕРА")));
+ subjects.add(new Subject("Programski jezici 1", Set.of("програмски језици 1", "programski jezici 1", "Programski jezici 1", "PROGRAMSKI JEZICI 1", "ПРОГРАМСКИ ЈЕЗИЦИ 1", "Програмски језици 1")));
+ subjects.add(new Subject("Osnovi radarskih sistema", Set.of("Основи радарских система", "основи радарских система", "osnovi radarskih sistema", "OSNOVI RADARSKIH SISTEMA", "Osnovi radarskih sistema", "ОСНОВИ РАДАРСКИХ СИСТЕМА")));
+ subjects.add(new Subject("Impulsna elektronika", Set.of("Импулсна електроника", "ИМПУЛСНА ЕЛЕКТРОНИКА", "импулсна електроника", "Impulsna elektronika", "impulsna elektronika", "IMPULSNA ELEKTRONIKA")));
+ subjects.add(new Subject("Analogna integrisana kola", Set.of("аналогна интегрисана кола", "АНАЛОГНА ИНТЕГРИСАНА КОЛА", "analogna integrisana kola", "Аналогна интегрисана кола", "Analogna integrisana kola", "ANALOGNA INTEGRISANA KOLA")));
+ subjects.add(new Subject("Obnovljivi izvori energije", Set.of("ОБНОВЉИВИ ИЗВОРИ ЕНЕРГИЈЕ", "obnovljivi izvori energije", "обновљиви извори енергије", "OBNOVLJIVI IZVORI ENERGIJE", "Obnovljivi izvori energije", "Обновљиви извори енергије")));
+ subjects.add(new Subject("Arhitektura računara", Set.of("arhitektura računara", "Архитектура рачунара", "АРХИТЕКТУРА РАЧУНАРА", "Arhitektura računara", "ARHITEKTURA RACUNARA", "ARHITEKTURA RAČUNARA", "Arhitektura racunara", "arhitektura racunara", "архитектура рачунара")));
+ subjects.add(new Subject("Sistemi za upravljanje i nadzor", Set.of("системи за управљање и надзор", "Sistemi za upravljanje i nadzor", "Системи за управљање и надзор", "sistemi za upravljanje i nadzor", "СИСТЕМИ ЗА УПРАВЉАЊЕ И НАДЗОР", "SISTEMI ZA UPRAVLJANJE I NADZOR")));
+ subjects.add(new Subject("Osnovi telekomunikacija 1", Set.of("ОСНОВИ ТЕЛЕКОМУНИКАЦИЈА 1", "Основи телекомуникација 1", "основи телекомуникација 1", "Osnovi telekomunikacija 1", "OSNOVI TELEKOMUNIKACIJA 1", "osnovi telekomunikacija 1")));
+ subjects.add(new Subject("Osnovi računarske tehnike", Set.of("Osnovi racunarske tehnike", "OSNOVI RAČUNARSKE TEHNIKE", "Основи рачунарске технике", "osnovi racunarske tehnike", "osnovi računarske tehnike", "основи рачунарске технике", "Osnovi računarske tehnike", "OSNOVI RACUNARSKE TEHNIKE", "ОСНОВИ РАЧУНАРСКЕ ТЕХНИКЕ")));
+ subjects.add(new Subject("Kola i signali", Set.of("Kola i signali", "Кола и сигнали", "КОЛА И СИГНАЛИ", "KOLA I SIGNALI", "кола и сигнали", "kola i signali")));
+ subjects.add(new Subject("Osnovi sistemskog inženjerstva", Set.of("osnovi sistemskog inženjerstva", "osnovi sistemskog inzenjerstva", "OSNOVI SISTEMSKOG INZENJERSTVA", "ОСНОВИ СИСТЕМСКОГ ИНЖЕЊЕРСТВА", "основи системског инжењерства", "Osnovi sistemskog inzenjerstva", "Основи системског инжењерства", "Osnovi sistemskog inženjerstva", "OSNOVI SISTEMSKOG INŽENJERSTVA")));
+ subjects.add(new Subject("Biomedicinska elektronika", Set.of("biomedicinska elektronika", "биомедицинска електроника", "BIOMEDICINSKA ELEKTRONIKA", "Biomedicinska elektronika", "Биомедицинска електроника", "БИОМЕДИЦИНСКА ЕЛЕКТРОНИКА")));
+ subjects.add(new Subject("Električna mjerenja", Set.of("ELEKTRIČNA MJERENJA", "ELEKTRICNA MJERENJA", "elektricna mjerenja", "ЕЛЕКТРИЧНА МЈЕРЕЊА", "električna mjerenja", "Електрична мјерења", "Elektricna mjerenja", "електрична мјерења", "Električna mjerenja")));
+ subjects.add(new Subject("Sistemi automatskog upravljanja", Set.of("sistemi automatskog upravljanja", "Sistemi automatskog upravljanja", "Системи аутоматског управљања", "системи аутоматског управљања", "СИСТЕМИ АУТОМАТСКОГ УПРАВЉАЊА", "SISTEMI AUTOMATSKOG UPRAVLJANJA")));
+ subjects.add(new Subject("Eksploatacija elektroenergetskih sistema", Set.of("eksploatacija elektroenergetskih sistema", "EKSPLOATACIJA ELEKTROENERGETSKIH SISTEMA", "Eksploatacija elektroenergetskih sistema", "експлоатација електроенергетских система", "Експлоатација електроенергетских система", "ЕКСПЛОАТАЦИЈА ЕЛЕКТРОЕНЕРГЕТСКИХ СИСТЕМА")));
+ subjects.add(new Subject("Formalne metode u softverskom inženjerstvu", Set.of("FORMALNE METODE U SOFTVERSKOM INŽENJERSTVU", "formalne metode u softverskom inženjerstvu", "Formalne metode u softverskom inženjerstvu", "Formalne metode u softverskom inzenjerstvu", "formalne metode u softverskom inzenjerstvu", "формалне методе у софтверском инжењерству", "ФОРМАЛНЕ МЕТОДЕ У СОФТВЕРСКОМ ИНЖЕЊЕРСТВУ", "FORMALNE METODE U SOFTVERSKOM INZENJERSTVU", "Формалне методе у софтверском инжењерству")));
+ subjects.add(new Subject("Osnovi elektronike", Set.of("ОСНОВИ ЕЛЕКТРОНИКЕ", "Основи електронике", "osnovi elektronike", "Osnovi elektronike", "OSNOVI ELEKTRONIKE", "основи електронике")));
+ subjects.add(new Subject("Osnovi elektroenergetike", Set.of("Основи електроенергетике", "osnovi elektroenergetike", "OSNOVI ELEKTROENERGETIKE", "ОСНОВИ ЕЛЕКТРОЕНЕРГЕТИКЕ", "Osnovi elektroenergetike", "основи електроенергетике")));
+ subjects.add(new Subject("Programski jezici 2", Set.of("Programski jezici 2", "PROGRAMSKI JEZICI 2", "програмски језици 2", "Програмски језици 2", "programski jezici 2", "ПРОГРАМСКИ ЈЕЗИЦИ 2")));
+ subjects.add(new Subject("Operativni sistemi za rad u realnom vremenu", Set.of("Operativni sistemi za rad u realnom vremenu", "operativni sistemi za rad u realnom vremenu", "OPERATIVNI SISTEMI ZA RAD U REALNOM VREMENU", "Оперативни системи за рад у реалном времену", "оперативни системи за рад у реалном времену", "ОПЕРАТИВНИ СИСТЕМИ ЗА РАД У РЕАЛНОМ ВРЕМЕНУ")));
+ subjects.add(new Subject("Ispitivanje električnih mašina", Set.of("ispitivanje električnih mašina", "ispitivanje elektricnih masina", "Ispitivanje električnih mašina", "испитивање електричних машина", "ISPITIVANJE ELEKTRIČNIH MAŠINA", "ИСПИТИВАЊЕ ЕЛЕКТРИЧНИХ МАШИНА", "Испитивање електричних машина", "ISPITIVANJE ELEKTRICNIH MASINA", "Ispitivanje elektricnih masina")));
+ subjects.add(new Subject("Projekat iz automatike", Set.of("projekat iz automatike", "Projekat iz automatike", "Пројекат из аутоматике", "ПРОЈЕКАТ ИЗ АУТОМАТИКЕ", "пројекат из аутоматике", "PROJEKAT IZ AUTOMATIKE")));
+ subjects.add(new Subject("Zaštita u elektroenergetskim sistemima", Set.of("zaštita u elektroenergetskim sistemima", "Заштита у електроенергетским системима", "Zastita u elektroenergetskim sistemima", "заштита у електроенергетским системима", "ZAŠTITA U ELEKTROENERGETSKIM SISTEMIMA", "ZASTITA U ELEKTROENERGETSKIM SISTEMIMA", "Zaštita u elektroenergetskim sistemima", "zastita u elektroenergetskim sistemima", "ЗАШТИТА У ЕЛЕКТРОЕНЕРГЕТСКИМ СИСТЕМИМА")));
+ subjects.add(new Subject("Inženjersko preduzetništvo", Set.of("inzenjersko preduzetnistvo", "INŽENJERSKO PREDUZETNIŠTVO", "INZENJERSKO PREDUZETNISTVO", "Inzenjersko preduzetnistvo", "Инжењерско предузетништво", "ИНЖЕЊЕРСКО ПРЕДУЗЕТНИШТВО", "инжењерско предузетништво", "Inženjersko preduzetništvo", "inženjersko preduzetništvo")));
+ subjects.add(new Subject("Teorija električnih kola", Set.of("TEORIJA ELEKTRIČNIH KOLA", "Teorija električnih kola", "Теорија електричних кола", "Teorija elektricnih kola", "TEORIJA ELEKTRICNIH KOLA", "ТЕОРИЈА ЕЛЕКТРИЧНИХ КОЛА", "теорија електричних кола", "teorija električnih kola", "teorija elektricnih kola")));
+ subjects.add(new Subject("Multimedijalni sistemi", Set.of("мултимедијални системи", "Мултимедијални системи", "multimedijalni sistemi", "Multimedijalni sistemi", "MULTIMEDIJALNI SISTEMI", "МУЛТИМЕДИЈАЛНИ СИСТЕМИ")));
+ subjects.add(new Subject("Osnovi digitalne obrade signala", Set.of("ОСНОВИ ДИГИТАЛНЕ ОБРАДЕ СИГНАЛА", "osnovi digitalne obrade signala", "основи дигиталне обраде сигнала", "Основи дигиталне обраде сигнала", "Osnovi digitalne obrade signala", "OSNOVI DIGITALNE OBRADE SIGNALA")));
+ subjects.add(new Subject("Teorija informacija sa kodovanjem", Set.of("TEORIJA INFORMACIJA SA KODOVANJEM", "теорија информација са кодовањем", "Теорија информација са кодовањем", "ТЕОРИЈА ИНФОРМАЦИЈА СА КОДОВАЊЕМ", "teorija informacija sa kodovanjem", "Teorija informacija sa kodovanjem")));
+ subjects.add(new Subject("Osnovi telekomunikacija 2", Set.of("Osnovi telekomunikacija 2", "osnovi telekomunikacija 2", "Основи телекомуникација 2", "ОСНОВИ ТЕЛЕКОМУНИКАЦИЈА 2", "основи телекомуникација 2", "OSNOVI TELEKOMUNIKACIJA 2")));
+ subjects.add(new Subject("Električne instalacije i osvjetljenje", Set.of("електричне инсталације и освјетљење", "električne instalacije i osvjetljenje", "Električne instalacije i osvjetljenje", "ELEKTRICNE INSTALACIJE I OSVJETLJENJE", "ELEKTRIČNE INSTALACIJE I OSVJETLJENJE", "Електричне инсталације и освјетљење", "Elektricne instalacije i osvjetljenje", "elektricne instalacije i osvjetljenje", "ЕЛЕКТРИЧНЕ ИНСТАЛАЦИЈЕ И ОСВЈЕТЉЕЊЕ")));
+ subjects.add(new Subject("Računarska elektronika", Set.of("RACUNARSKA ELEKTRONIKA", "Računarska elektronika", "Racunarska elektronika", "рачунарска електроника", "РАЧУНАРСКА ЕЛЕКТРОНИКА", "računarska elektronika", "Рачунарска електроника", "RAČUNARSKA ELEKTRONIKA", "racunarska elektronika")));
+ subjects.add(new Subject("Matematika 4", Set.of("Matematika 4", "matematika 4", "МАТЕМАТИКА 4", "математика 4", "MATEMATIKA 4", "Математика 4")));
+ subjects.add(new Subject("Radio komunikacije", Set.of("Радио комуникације", "RADIO KOMUNIKACIJE", "radio komunikacije", "РАДИО КОМУНИКАЦИЈЕ", "радио комуникације", "Radio komunikacije")));
+ subjects.add(new Subject("Električne mašine 1", Set.of("električne mašine 1", "Електричне машине 1", "електричне машине 1", "ELEKTRIČNE MAŠINE 1", "Elektricne masine 1", "elektricne masine 1", "ELEKTRICNE MASINE 1", "Električne mašine 1", "ЕЛЕКТРИЧНЕ МАШИНЕ 1")));
+ subjects.add(new Subject("Identifikacija sistema", Set.of("Идентификација система", "identifikacija sistema", "Identifikacija sistema", "идентификација система", "IDENTIFIKACIJA SISTEMA", "ИДЕНТИФИКАЦИЈА СИСТЕМА")));
+ subjects.add(new Subject("Antene i prostiranje radio-talasa", Set.of("Antene i prostiranje radio-talasa", "antene i prostiranje radio-talasa", "Антене и простирање радио-таласа", "ANTENE I PROSTIRANJE RADIO-TALASA", "антене и простирање радио-таласа", "АНТЕНЕ И ПРОСТИРАЊЕ РАДИО-ТАЛАСА")));
+ subjects.add(new Subject("Mobilno računarstvo", Set.of("mobilno računarstvo", "МОБИЛНО РАЧУНАРСТВО", "MOBILNO RAČUNARSTVO", "Мобилно рачунарство", "Mobilno računarstvo", "Mobilno racunarstvo", "mobilno racunarstvo", "MOBILNO RACUNARSTVO", "мобилно рачунарство")));
+ subjects.add(new Subject("Projektovanje informacionih sistema u internet okruženju", Set.of("PROJEKTOVANJE INFORMACIONIH SISTEMA U INTERNET OKRUŽENJU", "projektovanje informacionih sistema u internet okruženju", "ПРОЈЕКТОВАЊЕ ИНФОРМАЦИОНИХ СИСТЕМА У ИНТЕРНЕТ ОКРУЖЕЊУ", "Пројектовање информационих система у интернет окружењу", "Projektovanje informacionih sistema u internet okruzenju", "Projektovanje informacionih sistema u internet okruženju", "пројектовање информационих система у интернет окружењу", "PROJEKTOVANJE INFORMACIONIH SISTEMA U INTERNET OKRUZENJU", "projektovanje informacionih sistema u internet okruzenju")));
+ subjects.add(new Subject("Digitalna obrada slučajnih signala", Set.of("дигитална обрада случајних сигнала", "Digitalna obrada slučajnih signala", "Digitalna obrada slucajnih signala", "Дигитална обрада случајних сигнала", "ДИГИТАЛНА ОБРАДА СЛУЧАЈНИХ СИГНАЛА", "DIGITALNA OBRADA SLUČAJNIH SIGNALA", "DIGITALNA OBRADA SLUCAJNIH SIGNALA", "digitalna obrada slucajnih signala", "digitalna obrada slučajnih signala")));
+ subjects.add(new Subject("Engleski jezik 2", Set.of("енглески језик 2", "Engleski jezik 2", "ENGLESKI JEZIK 2", "Енглески језик 2", "engleski jezik 2", "ЕНГЛЕСКИ ЈЕЗИК 2")));
+ subjects.add(new Subject("Projektovanje integrisanih kola", Set.of("пројектовање интегрисаних кола", "PROJEKTOVANJE INTEGRISANIH KOLA", "ПРОЈЕКТОВАЊЕ ИНТЕГРИСАНИХ КОЛА", "projektovanje integrisanih kola", "Projektovanje integrisanih kola", "Пројектовање интегрисаних кола")));
+ subjects.add(new Subject("Diskretna matematika", Set.of("дискретна математика", "DISKRETNA MATEMATIKA", "ДИСКРЕТНА МАТЕМАТИКА", "diskretna matematika", "Diskretna matematika", "Дискретна математика")));
+ subjects.add(new Subject("Upravljanje u realnom vremenu i ugrađeni računarski sistemi", Set.of("upravljanje u realnom vremenu i ugrađeni računarski sistemi", "УПРАВЉАЊЕ У РЕАЛНОМ ВРЕМЕНУ И УГРАЂЕНИ РАЧУНАРСКИ СИСТЕМИ", "управљање у реалном времену и уграђени рачунарски системи", "upravljanje u realnom vremenu i ugradjeni racunarski sistemi", "UPRAVLJANJE U REALNOM VREMENU I UGRAĐENI RAČUNARSKI SISTEMI", "Upravljanje u realnom vremenu i ugradjeni racunarski sistemi", "Upravljanje u realnom vremenu i ugrađeni računarski sistemi", "UPRAVLJANJE U REALNOM VREMENU I UGRADJENI RACUNARSKI SISTEMI", "Управљање у реалном времену и уграђени рачунарски системи")));
+ subjects.add(new Subject("Akvizicija podataka", Set.of("Аквизиција података", "AKVIZICIJA PODATAKA", "akvizicija podataka", "Akvizicija podataka", "аквизиција података", "АКВИЗИЦИЈА ПОДАТАКА")));
+ subjects.add(new Subject("Sigurnost na internetu", Set.of("Сигурност на интернету", "Sigurnost na internetu", "СИГУРНОСТ НА ИНТЕРНЕТУ", "sigurnost na internetu", "SIGURNOST NA INTERNETU", "сигурност на интернету")));
+ subjects.add(new Subject("Digitalna elektronika", Set.of("DIGITALNA ELEKTRONIKA", "Дигитална електроника", "дигитална електроника", "ДИГИТАЛНА ЕЛЕКТРОНИКА", "digitalna elektronika", "Digitalna elektronika")));
+ subjects.add(new Subject("Analogni i digitalni filtri", Set.of("Аналогни и дигитални филтри", "Analogni i digitalni filtri", "АНАЛОГНИ И ДИГИТАЛНИ ФИЛТРИ", "аналогни и дигитални филтри", "analogni i digitalni filtri", "ANALOGNI I DIGITALNI FILTRI")));
+ subjects.add(new Subject("Elektromagnetika", Set.of("ELEKTROMAGNETIKA", "Електромагнетика", "Elektromagnetika", "електромагнетика", "elektromagnetika", "ЕЛЕКТРОМАГНЕТИКА")));
+ subjects.add(new Subject("RF i mikrotalasna elektronika", Set.of("РФ и микроталасна електроника", "RF i mikrotalasna elektronika", "RF I MIKROTALASNA ELEKTRONIKA", "РФ И МИКРОТАЛАСНА ЕЛЕКТРОНИКА", "рф и микроталасна електроника", "rf i mikrotalasna elektronika")));
+ subjects.add(new Subject("Mikrotalasna tehnika", Set.of("микроталасна техника", "Микроталасна техника", "MIKROTALASNA TEHNIKA", "МИКРОТАЛАСНА ТЕХНИКА", "mikrotalasna tehnika", "Mikrotalasna tehnika")));
+ subjects.add(new Subject("Projektovanje digitalnih sistema", Set.of("ПРОЈЕКТОВАЊЕ ДИГИТАЛНИХ СИСТЕМА", "пројектовање дигиталних система", "Projektovanje digitalnih sistema", "Пројектовање дигиталних система", "projektovanje digitalnih sistema", "PROJEKTOVANJE DIGITALNIH SISTEMA")));
+ subjects.add(new Subject("Programska podrška u digitalnoj televiziji", Set.of("ПРОГРАМСКА ПОДРШКА У ДИГИТАЛНОЈ ТЕЛЕВИЗИЈИ", "Programska podrška u digitalnoj televiziji", "Програмска подршка у дигиталној телевизији", "програмска подршка у дигиталној телевизији", "PROGRAMSKA PODRSKA U DIGITALNOJ TELEVIZIJI", "PROGRAMSKA PODRŠKA U DIGITALNOJ TELEVIZIJI", "Programska podrska u digitalnoj televiziji", "programska podrska u digitalnoj televiziji", "programska podrška u digitalnoj televiziji")));
+ subjects.add(new Subject("Distributivne i industrijske mreže", Set.of("дистрибутивне и индустријске мреже", "Дистрибутивне и индустријске мреже", "distributivne i industrijske mreže", "ДИСТРИБУТИВНЕ И ИНДУСТРИЈСКЕ МРЕЖЕ", "distributivne i industrijske mreze", "DISTRIBUTIVNE I INDUSTRIJSKE MREZE", "Distributivne i industrijske mreže", "DISTRIBUTIVNE I INDUSTRIJSKE MREŽE", "Distributivne i industrijske mreze")));
+ subjects.add(new Subject("Automatizacija i upravljanje u zgradama", Set.of("AUTOMATIZACIJA I UPRAVLJANJE U ZGRADAMA", "Аутоматизација и управљање у зградама", "automatizacija i upravljanje u zgradama", "АУТОМАТИЗАЦИЈА И УПРАВЉАЊЕ У ЗГРАДАМА", "Automatizacija i upravljanje u zgradama", "аутоматизација и управљање у зградама")));
+ subjects.add(new Subject("Elektronsko poslovanje", Set.of("ELEKTRONSKO POSLOVANJE", "elektronsko poslovanje", "електронско пословање", "Електронско пословање", "ЕЛЕКТРОНСКО ПОСЛОВАЊЕ", "Elektronsko poslovanje")));
+ subjects.add(new Subject("Analiza elektroenergetskih sistema 1", Set.of("analiza elektroenergetskih sistema 1", "ANALIZA ELEKTROENERGETSKIH SISTEMA 1", "анализа електроенергетских система 1", "АНАЛИЗА ЕЛЕКТРОЕНЕРГЕТСКИХ СИСТЕМА 1", "Analiza elektroenergetskih sistema 1", "Анализа електроенергетских система 1")));
+ return subjects;
+ }
+}
diff --git a/src/main/java/dev/ksan/SubjectEntry.java b/src/main/java/dev/ksan/SubjectEntry.java
new file mode 100644
index 0000000..c342322
--- /dev/null
+++ b/src/main/java/dev/ksan/SubjectEntry.java
@@ -0,0 +1,44 @@
+package dev.ksan;
+
+import java.util.List;
+
+public class SubjectEntry {
+ private String title;
+ private String date;
+ private String info;
+ private List paragraphs;
+
+ public SubjectEntry(String title, String date, String info, List paragraphs) {
+ this.title = title;
+ this.date = date;
+ this.info = info;
+ this.paragraphs = paragraphs;
+ }
+ public String getTitle() {
+ return title;
+ }
+ public String getDate() {
+ return date;
+ }
+ public String getInfo() {
+ return info;
+ }
+ public List getParagraphs() {
+ return paragraphs;
+ }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if(o ==null) return false;
+ SubjectEntry subject = (SubjectEntry) o;
+ if(title.equals(subject.getTitle()) && date.equals(subject.getDate()) && info.equals(subject.getInfo())) {
+ return true;
+ }
+ return false;
+ }
+ @Override
+ public String toString() {
+ return title + " " + date + " " + info + "\n\t" + paragraphs + "\n";
+ }
+
+}
diff --git a/src/main/java/dev/ksan/Subscription.java b/src/main/java/dev/ksan/Subscription.java
new file mode 100644
index 0000000..f6fa6e0
--- /dev/null
+++ b/src/main/java/dev/ksan/Subscription.java
@@ -0,0 +1,28 @@
+package dev.ksan;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Subscription {
+ private Subject subject;
+ private List users = new ArrayList<>();
+
+ public Subscription(Subject subject){
+ this.subject = subject;
+ }
+ public synchronized void subscribe(User user){
+ if(!users.contains(user)){
+ users.add(user);
+ }
+ }
+ public synchronized void unsubscribe(User user){
+ if(users.contains(user)){
+ users.remove(user);
+ }
+ }
+ public synchronized void notifyUsers(SubjectEntry entry){
+ for(User user : users){
+ user.sendNotification(entry);
+ }
+ }
+}
diff --git a/src/main/java/dev/ksan/User.java b/src/main/java/dev/ksan/User.java
new file mode 100644
index 0000000..3f586cb
--- /dev/null
+++ b/src/main/java/dev/ksan/User.java
@@ -0,0 +1,118 @@
+package dev.ksan;
+
+import com.gargoylesoftware.htmlunit.html.HtmlEmailInput;
+import org.simplejavamail.api.email.Email;
+import org.simplejavamail.api.mailer.Mailer;
+import org.simplejavamail.api.mailer.config.TransportStrategy;
+import org.simplejavamail.email.EmailBuilder;
+import org.simplejavamail.mailer.MailerBuilder;
+import java.io.*;
+import java.util.*;
+
+public class User implements Serializable {
+ private static Set usedIds = new HashSet<>();
+
+ private String id;
+ private String email;
+ private String password;
+ private NotificationMethod notificationMethod;
+ private Set subjectSet = new HashSet<>();
+
+ public User(String email, String password) {
+ this.id = generateId();
+ this.email = email;
+ this.password = password;
+ this.notificationMethod = NotificationMethod.EMAIL;
+ }
+
+ public void setNotificationMethod(NotificationMethod notificationMethod) {
+ this.notificationMethod = notificationMethod;
+ }
+ public void serializeToFile(String filename) throws IOException {
+ try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {
+ oos.writeObject(this);
+ }
+ }
+
+ public static User deserializeFromFile(String filename) throws IOException, ClassNotFoundException {
+ try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {
+ return (User) ois.readObject();
+ }
+ }
+ public static void saveUsedIds(String filename) throws IOException {
+ try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {
+ oos.writeObject(usedIds);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void loadUsedIds(String filename) throws IOException, ClassNotFoundException {
+ try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {
+ usedIds = (Set) ois.readObject();
+ }
+ }
+
+
+ public void sendNotification(SubjectEntry entry){
+
+ if(notificationMethod == NotificationMethod.EMAIL){
+ sendEmail(entry);
+ } else if (notificationMethod == NotificationMethod.PUSH_NOTIFICATION) {
+ pushNotification(entry);
+ }
+ }
+ private void pushNotification(SubjectEntry entry){
+ //TODO
+ }
+ private void sendEmail(SubjectEntry entry) {
+ MailService mail = new MailService(".env");
+ mail.sendEmail(this.email,entry.getTitle(),entry.getParagraphs().toString());
+
+ }
+
+ public Set getSubjectSet() {
+ return subjectSet;
+ }
+
+ public void addSubject(Subject subject) {
+ subjectSet.add(subject);
+ }
+ public void addSubjects(Set subjects) {
+ this.subjectSet.addAll(subjects);
+ }
+ public boolean addSubject(String subject) {
+ Set subjects = new HashSet<>();
+ subjects = Subject.generateSubjects();
+
+ System.out.println(subject);
+ for(Subject s : subjects){
+ if(s.equals(new Subject(subject))){
+ this.subjectSet.add(s);
+ return true;
+ //break;
+ }
+ }
+ return false;
+ }
+ public String getId() {
+ return id;
+ }
+ public String getEmail() {
+ return email;
+ }
+ public void setEmail(String email) {
+ this.email = email;
+ }
+ public void setPassword(String password) {
+ this.password = password;
+ }
+ private String generateId() {
+ String id;
+ do{
+ id = UUID.randomUUID().toString();
+ }while(usedIds.contains(id));
+ usedIds.add(id);
+ return id;
+ }
+
+}