diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..c1dd12f Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..b74bf7f --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/HELP.md b/HELP.md new file mode 100644 index 0000000..82c63d1 --- /dev/null +++ b/HELP.md @@ -0,0 +1,24 @@ +# Getting Started + +### Reference Documentation + +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.7.5/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.7.5/maven-plugin/reference/html/#build-image) +* [Spring Data JPA](https://docs.spring.io/spring-boot/docs/2.7.5/reference/htmlsingle/#data.sql.jpa-and-spring-data) +* [Thymeleaf](https://docs.spring.io/spring-boot/docs/2.7.5/reference/htmlsingle/#web.servlet.spring-mvc.template-engines) +* [Spring Web](https://docs.spring.io/spring-boot/docs/2.7.5/reference/htmlsingle/#web) + +### Guides + +The following guides illustrate how to use some features concretely: + +* [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/) +* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/) +* [Handling Form Submission](https://spring.io/guides/gs/handling-form-submission/) +* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) +* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) +* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/) + diff --git a/README.md b/README.md index cd41481..d7c9d7c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,66 @@ -# em-spring +## はじめに(演習の⽬的と取り組み⽅) +当演習は、講義で学んだことを⾃⼒で実践できるようになるために実施します。 そのために以下の内容を守って演習に取り組んでください。 + +### 納品物、納期を守りましょう +この演習は、実際の仕事を想定した内容です。 +提出物の内容と提出期限は必ず守ってください。 +作業が間に合わない、提出物に問題が出そうな場合は、**必ずルールにしたがって適切な相⼿に相談してください**。 + +### 適切な⼿順で開発しましょう +プログラムを書き始める前に、**README.md** や**仕様書**(配布されている場合) を必ず読んでください。 +「**何を作るのか**」、「**どこまで作ればよいのか**」を理解してから作業を始めてください。 + +### 知らないことは⾃分で調べましょう +この演習には、**講義で扱っていない内容が⼀部含まれています**。 +その場合は、インターネットなどで⾃分で調べながら進めてください。 +調べることも、エンジニアにとって⼤切なスキルの⼀つです。 + +# 課題に取りかかる前に… + +設計書フォルダにある「start-db-ddl-dml.sql」をA5m2等で実行し +DBの状態をクリアにしてください。 + +# プロジェクト読み込み手順 + +Eclipse > ファイル > ファイルシステムからプロジェクトを開く > +インポート・ソース の右横にある ディレクトリーボタンを押下 > 本ファイル(Readme.md)の上の階層の **01.EM-Spring** フォルダを選択 > +画面下部の完了を押下 + +## モジュールのインストール + +読み込んだプロジェクト(EM-SpringBoot)を右クリックし 実行 > maven clean > maven install を実施 + +## 目的 + +部署テーブルのCRUD機能追加をしなさい。 +※ AOPで実装されているアクセス制御(セッションチェックや管理者権限チェック等)は未実装でかまいません。 + +# 第1段階 + +部署情報検索更新削除機能設計書と既存の実装を参考に部署検索機能を追加してください。 + +検索機能に実装必須な機能 +・メニュー画面から部署検索、新規登録画面に遷移出来ること +・部署IDの完全一致検索 +・部署名の部分一致検索 +・検索ボタン +・クリアボタン +・検索結果表示機能 + +# 第2段階 + +部署情報検索更新削除機能設計書と既存の実装を参考に各検索結果に削除機能を実装してください。 + +# 第3段階(提出可能合格ライン) + +部署情報検索更新削除機能設計書と既存の実装を参考に各検索結果に更新機能を実装してください。 + +# 第4段階(チャレンジ問題) + +部署情報検索更新削除機能設計書と既存の実装を参考に部署新規登録機能を実装してください。 + +# 第5段階(チャレンジ問題その2) + +既存で実装されているアノテーションの機能を解析し、第1段階目〜4段階目のコントローラに実装してください。 + diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..8a8fb22 --- /dev/null +++ b/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + 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 + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..1d8ab01 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. 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, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..24be8c6 --- /dev/null +++ b/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.5 + + + com.example.rhizome + EM-Spring + 0.0.1-SNAPSHOT + war + EM-Spring + Demo project for Spring Boot + + 17 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + com.mysql + mysql-connector-j + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-validation + + + org.projectlombok + lombok + + + com.fasterxml.jackson.core + jackson-databind + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + true + + + + + + diff --git a/src/main/java/com/example/rhizome/EmSpringApplication.java b/src/main/java/com/example/rhizome/EmSpringApplication.java new file mode 100644 index 0000000..0b32d37 --- /dev/null +++ b/src/main/java/com/example/rhizome/EmSpringApplication.java @@ -0,0 +1,15 @@ +package com.example.rhizome; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +@SpringBootApplication +@EnableAspectJAutoProxy(proxyTargetClass = true) +public class EmSpringApplication { + + public static void main(String[] args) { + SpringApplication.run(EmSpringApplication.class, args); + } + +} diff --git a/src/main/java/com/example/rhizome/ServletInitializer.java b/src/main/java/com/example/rhizome/ServletInitializer.java new file mode 100644 index 0000000..992e6d5 --- /dev/null +++ b/src/main/java/com/example/rhizome/ServletInitializer.java @@ -0,0 +1,13 @@ +package com.example.rhizome; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +public class ServletInitializer extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(EmSpringApplication.class); + } + +} diff --git a/src/main/java/com/example/rhizome/aop/Handler/GlobalExceptionHandler.java b/src/main/java/com/example/rhizome/aop/Handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..8e5a8c3 --- /dev/null +++ b/src/main/java/com/example/rhizome/aop/Handler/GlobalExceptionHandler.java @@ -0,0 +1,111 @@ +package com.example.rhizome.aop.Handler; + +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginInfoForm; +import com.example.rhizome.app.presentation.form.MessageForm; +import com.example.rhizome.exception.InsufficientPermissionException; +import com.example.rhizome.exception.NoSessionException; +import org.springframework.http.HttpStatus; +import org.springframework.ui.Model; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword.LOGIN_INFO_FORM; +import static com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword.MESSAGE_ERROR; + +/** + * 例外処理用のコントローラ + */ +@ControllerAdvice +public class GlobalExceptionHandler { + + private final static Logger LOGGER = Logger.getLogger(GlobalExceptionHandler.class.getName()); + + private final String SEVERE_ERROR_MESSAGE_ILLEGAL_TRANSITION = "不正な遷移です。"; + private final String SEVERE_ERROR_MESSAGE_BAD_REQUEST = "不正なリクエストです。"; + + /** + * セッションが切れている場合の例外処理 + * + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @ExceptionHandler(NoSessionException.class) + public String handleNoSessionException(Model model, Exception e) { + + model.addAttribute(MESSAGE_ERROR, new MessageForm(SEVERE_ERROR_MESSAGE_ILLEGAL_TRANSITION)); + model.addAttribute(LOGIN_INFO_FORM, new LoginInfoForm()); + + e.printStackTrace(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE_ILLEGAL_TRANSITION, e); + + return TransitionTargetPageNameKeyword.LOGIN_HTML; + } + + /** + * 権限がない場合の例外処理 + * + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @ExceptionHandler(InsufficientPermissionException.class) + public String handleInsufficientPermissionException(Model model, Exception e) { + + model.addAttribute(MESSAGE_ERROR, new MessageForm(SEVERE_ERROR_MESSAGE_ILLEGAL_TRANSITION)); + model.addAttribute(LOGIN_INFO_FORM, new LoginInfoForm()); + + e.printStackTrace(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE_ILLEGAL_TRANSITION, e); + + return TransitionTargetPageNameKeyword.LOGIN_HTML; + + } + + /** + * リクエストメソッドが不正な場合の例外処理 + * + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public String handleBadRequestException(Model model, Exception e) { + // エラーメッセージやその他の情報をモデルに追加する + model.addAttribute("error", SEVERE_ERROR_MESSAGE_BAD_REQUEST); + model.addAttribute("status", HttpStatus.BAD_REQUEST.value()); + + e.printStackTrace(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE_ILLEGAL_TRANSITION, e); + + // カスタムエラーページにリダイレクト + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + + /** + * その他の例外処理 + * + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @ExceptionHandler(Exception.class) + public String AllException(Model model, Exception e) { + // エラーメッセージやその他の情報をモデルに追加する + model.addAttribute("error", SEVERE_ERROR_MESSAGE_BAD_REQUEST); + + e.printStackTrace(); + + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE_ILLEGAL_TRANSITION, e); + + // カスタムエラーページにリダイレクト + return TransitionTargetPageNameKeyword.ERROR_HTML; + } +} diff --git a/src/main/java/com/example/rhizome/aop/aspect/PermissionCheck.java b/src/main/java/com/example/rhizome/aop/aspect/PermissionCheck.java new file mode 100644 index 0000000..861f94a --- /dev/null +++ b/src/main/java/com/example/rhizome/aop/aspect/PermissionCheck.java @@ -0,0 +1,15 @@ +package com.example.rhizome.aop.aspect; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * SessionCheckアノテーション + * セッションチェックを行うメソッドに付与する + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface PermissionCheck { +} diff --git a/src/main/java/com/example/rhizome/aop/aspect/PermissionCheckAspect.java b/src/main/java/com/example/rhizome/aop/aspect/PermissionCheckAspect.java new file mode 100644 index 0000000..ce416f9 --- /dev/null +++ b/src/main/java/com/example/rhizome/aop/aspect/PermissionCheckAspect.java @@ -0,0 +1,114 @@ +package com.example.rhizome.aop.aspect; + +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import com.example.rhizome.exception.InsufficientPermissionException; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; + +/** + * 権限チェック用のAOP + */ +@Aspect +@Component +public class PermissionCheckAspect { + + HttpServletRequest request; + + @Autowired + public PermissionCheckAspect(HttpServletRequest request) { + this.request = request; + } + + // Aspectのフックを定義(今回はPermissionCheckアノテーションが定義されているメソッドが動作するタイミング) + @Pointcut("@annotation(com.example.rhizome.aop.aspect.PermissionCheck)") + public void permissionCheckMethod() { + } + + /** + * 権限チェック + */ + @Before("permissionCheckMethod()") + public void checkPermission() { + // ログインユーザの取得 + LoginUserForm loginUserForm = (LoginUserForm) request.getSession().getAttribute(SessionKeyword.LOGIN_USER); + + // ログインユーザが取得できない場合、または権限がない場合はエラー画面に遷移 + if (loginUserForm == null || !hasRequiredPermission(request.getRequestURI(), loginUserForm)) { + throw new InsufficientPermissionException("不正な遷移です"); + } + + } + + /** + * 遷移先のURLとログインユーザの権限から、遷移可否を判定する + * + * @param targetURL 遷移したいURL + * @param loginUserForm リクエスト元のユーザ + * @return true:遷移可 false:遷移不可 + */ + private boolean hasRequiredPermission(String targetURL, LoginUserForm loginUserForm) { + + // 管理者権限 + if (isAdminTransition(targetURL, loginUserForm)) { + return true; + } + + // 一般権限 + if (isUserTransition(targetURL, loginUserForm)) { + return true; + } + + // アクセス不許可の場合の処理(不正アクセス画面に遷移) + return false; + + } + + /** + * 管理者用のアカウントで管理者向けのページアクセスか + * + * @param targetURL 遷移したいURL + * @param loginUserForm リクエスト元のユーザ + * @return true:遷移可 false:遷移不可 + */ + private boolean isAdminTransition(String targetURL, LoginUserForm loginUserForm) { + + // 管理者か + if (!loginUserForm.isAdminUser()) { + return false; + } + + // 管理者向けのページ遷移か + if (!TransitionTargetPageNameKeyword.getAdminPageList().contains(targetURL)) { + return false; + } + + return true; + } + + /** + * 一般ユーザ用のアカウントで一般ユーザ向けのページアクセスか + * + * @param targetURL 遷移したいURL + * @param loginUserForm リクエスト元のユーザ + * @return true:遷移可 false:遷移不可 + */ + private boolean isUserTransition(String targetURL, LoginUserForm loginUserForm) { + + // 管理者か + if (loginUserForm.isAdminUser()) { + return false; + } + + // 一般ユーザ向けのページ遷移か + return TransitionTargetPageNameKeyword.getUserPageList().contains(targetURL); + + } +} + diff --git a/src/main/java/com/example/rhizome/aop/aspect/SessionCheck.java b/src/main/java/com/example/rhizome/aop/aspect/SessionCheck.java new file mode 100644 index 0000000..aa2f411 --- /dev/null +++ b/src/main/java/com/example/rhizome/aop/aspect/SessionCheck.java @@ -0,0 +1,15 @@ +package com.example.rhizome.aop.aspect; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * SessionCheckアノテーション + * セッションチェックを行うメソッドに付与する + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface SessionCheck { +} diff --git a/src/main/java/com/example/rhizome/aop/aspect/SessionCheckAspect.java b/src/main/java/com/example/rhizome/aop/aspect/SessionCheckAspect.java new file mode 100644 index 0000000..3bf4ba9 --- /dev/null +++ b/src/main/java/com/example/rhizome/aop/aspect/SessionCheckAspect.java @@ -0,0 +1,47 @@ +package com.example.rhizome.aop.aspect; + +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.exception.NoSessionException; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +/** + * セッションチェック用のAOP + */ +@Aspect +@Component +public class SessionCheckAspect { + + HttpServletRequest request; + + @Autowired + public SessionCheckAspect(HttpServletRequest request) { + this.request = request; + } + + @Pointcut("@annotation(com.example.rhizome.aop.aspect.SessionCheck)") + public void sessionCheckMethod() { + } + + /** + * セッションチェック + */ + @Before("sessionCheckMethod()") + public void checkSession() { + // セッションの取得 + HttpSession session = request.getSession(false); + + // セッションが取得できない場合はエラー画面に遷移 + if (session == null || session.getAttribute(SessionKeyword.LOGIN_USER) == null) { + throw new NoSessionException("不正なログインです"); + } + + } + +} diff --git a/src/main/java/com/example/rhizome/app/domain/model/Department.java b/src/main/java/com/example/rhizome/app/domain/model/Department.java new file mode 100644 index 0000000..360afc8 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/model/Department.java @@ -0,0 +1,21 @@ +package com.example.rhizome.app.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 部署情報の概念を表現するモデルクラスです。 + */ +@Getter +@AllArgsConstructor +public class Department { + /** + * 部署ID + */ + private final Integer idDepartment; + /** + * 部署名 + */ + private final String nmDepartment; + +} diff --git a/src/main/java/com/example/rhizome/app/domain/model/Employee.java b/src/main/java/com/example/rhizome/app/domain/model/Employee.java new file mode 100644 index 0000000..91f20a5 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/model/Employee.java @@ -0,0 +1,41 @@ +package com.example.rhizome.app.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 社員を表現するモデルクラスです + */ +@Getter +@AllArgsConstructor +public class Employee { + /** + * 社員ID + */ + private final Integer idEmployee; + /** + * 社員名 + */ + private final String nmEmployee; + /** + * 社員名カナ + */ + private final String knEmployee; + /** + * メールアドレス + */ + private final String mailAddress; + /** + * パスワード + */ + private final String password; + /** + * 管理者権限 + */ + private final Integer adminAuth; + /** + * 部署ID + */ + private final Integer idDepartment; + +} diff --git a/src/main/java/com/example/rhizome/app/domain/model/EmployeeInfo.java b/src/main/java/com/example/rhizome/app/domain/model/EmployeeInfo.java new file mode 100644 index 0000000..49f137f --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/model/EmployeeInfo.java @@ -0,0 +1,28 @@ +/* + * EmployeeInfo.java + * 作成 IT-College 2016 + *------------------------------------------------------------ + * Copyright(c) Rhizome Inc. All Rights Reserved. + */ +package com.example.rhizome.app.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 社員情報の概念を表現するモデルクラスです。 + */ +@Getter +@AllArgsConstructor +public class EmployeeInfo { + + /** + * 社員情報 + */ + private final Employee employee; + /** + * 部署名 + */ + private final Department department; + +} diff --git a/src/main/java/com/example/rhizome/app/domain/model/LoginInfo.java b/src/main/java/com/example/rhizome/app/domain/model/LoginInfo.java new file mode 100644 index 0000000..f694a54 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/model/LoginInfo.java @@ -0,0 +1,22 @@ +package com.example.rhizome.app.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * ログインを試みる人を表現するモデルクラスです + */ + +@Getter +@AllArgsConstructor +public class LoginInfo { + /** + * メールアドレス + */ + private String mailAddress; + /** + * パスワード + */ + private String password; + +} diff --git a/src/main/java/com/example/rhizome/app/domain/model/LoginUser.java b/src/main/java/com/example/rhizome/app/domain/model/LoginUser.java new file mode 100644 index 0000000..d0bd75c --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/model/LoginUser.java @@ -0,0 +1,51 @@ +package com.example.rhizome.app.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * ログイン者を表現するクラスです + */ +@Getter +@AllArgsConstructor +public class LoginUser { + /** + * 社員ID + */ + private final Integer idEmployee; + /** + * 社員名 + */ + private final String nmEmployee; + /** + * 社員名カナ + */ + private final String knEmployee; + /** + * メールアドレス + */ + private final String mailAddress; + /** + * パスワード + */ + private final String password; + + /** + * 管理者権限 + */ + private final Integer adminAuth; + + /** + * 部署ID + */ + private final Integer idDepartment; + + /** + * ログインユーザが管理者か + * + * @return true:管理者 false:一般権限 + */ + public boolean isAdminUser() { + return getAdminAuth() == 1; + } +} diff --git a/src/main/java/com/example/rhizome/app/domain/model/SearchConditionDepartment.java b/src/main/java/com/example/rhizome/app/domain/model/SearchConditionDepartment.java new file mode 100644 index 0000000..1e365eb --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/model/SearchConditionDepartment.java @@ -0,0 +1,21 @@ +package com.example.rhizome.app.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 部署情報の検索要件を表現するモデルクラスです。 + */ +@Getter +@AllArgsConstructor +public class SearchConditionDepartment { + /** + * 部署ID + */ + private final Integer idDepartment; + /** + * 部署名 + */ + private final String nmDepartment; + +} diff --git a/src/main/java/com/example/rhizome/app/domain/model/SearchConditionEmployee.java b/src/main/java/com/example/rhizome/app/domain/model/SearchConditionEmployee.java new file mode 100644 index 0000000..5ab6f4d --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/model/SearchConditionEmployee.java @@ -0,0 +1,33 @@ +package com.example.rhizome.app.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 社員情報の検索条件という概念を表現するモデルクラスです + */ +@Getter +@AllArgsConstructor +public class SearchConditionEmployee { + /** + * 社員ID + */ + private final Integer idEmployee; + /** + * 社員名 + */ + private final String nmEmployee; + /** + * 社員名カナ + */ + private final String knEmployee; + /** + * メールアドレス + */ + private final String mailAddress; + /** + * 部署ID + */ + private final Integer idDepartment; + +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/DeleteEmployee.java b/src/main/java/com/example/rhizome/app/domain/service/DeleteEmployee.java new file mode 100644 index 0000000..50d102c --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/DeleteEmployee.java @@ -0,0 +1,6 @@ +package com.example.rhizome.app.domain.service; + +public interface DeleteEmployee { + void deleteEmployee(Integer idEmployee); + +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/Login.java b/src/main/java/com/example/rhizome/app/domain/service/Login.java new file mode 100644 index 0000000..7756d83 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/Login.java @@ -0,0 +1,10 @@ +package com.example.rhizome.app.domain.service; + +import com.example.rhizome.app.domain.model.LoginInfo; +import com.example.rhizome.app.domain.model.LoginUser; + +public interface Login { + LoginUser doLogin(LoginInfo loginInfo); + + boolean canLogin(LoginInfo loginInfo); +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/RegisterDepartment.java b/src/main/java/com/example/rhizome/app/domain/service/RegisterDepartment.java new file mode 100644 index 0000000..73eefcb --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/RegisterDepartment.java @@ -0,0 +1,7 @@ +package com.example.rhizome.app.domain.service; + +import com.example.rhizome.app.domain.model.Department; + +public interface RegisterDepartment { + void registerDepartment(Department department); +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/RegisterEmployee.java b/src/main/java/com/example/rhizome/app/domain/service/RegisterEmployee.java new file mode 100644 index 0000000..c4b1297 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/RegisterEmployee.java @@ -0,0 +1,7 @@ +package com.example.rhizome.app.domain.service; + +import com.example.rhizome.app.domain.model.Employee; + +public interface RegisterEmployee { + void registerEmployee(Employee employee); +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/SearchDepartment.java b/src/main/java/com/example/rhizome/app/domain/service/SearchDepartment.java new file mode 100644 index 0000000..572dcee --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/SearchDepartment.java @@ -0,0 +1,14 @@ +package com.example.rhizome.app.domain.service; + +import com.example.rhizome.app.domain.model.Department; +import com.example.rhizome.app.domain.model.SearchConditionDepartment; + +import java.util.List; + +public interface SearchDepartment { + List selectAll(); + + List searchBy(SearchConditionDepartment searchConditionDepartment); + + List searchByWithLike(SearchConditionDepartment searchConditionDepartment); +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/SearchEmployee.java b/src/main/java/com/example/rhizome/app/domain/service/SearchEmployee.java new file mode 100644 index 0000000..318609d --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/SearchEmployee.java @@ -0,0 +1,16 @@ +package com.example.rhizome.app.domain.service; + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.LoginUser; + +import java.util.List; + +public interface SearchEmployee { + List searchEmployee(String mailAddress); + + List searchEmployeeByIdDepartment(Integer idDepartment); + + LoginUser searchLoginUser(String mailAddress); + + Employee searchEmployeeByIdEmployee(Integer idEmployee); +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/SearchEmployeeInfo.java b/src/main/java/com/example/rhizome/app/domain/service/SearchEmployeeInfo.java new file mode 100644 index 0000000..092bf97 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/SearchEmployeeInfo.java @@ -0,0 +1,12 @@ +package com.example.rhizome.app.domain.service; + +import com.example.rhizome.app.domain.model.EmployeeInfo; +import com.example.rhizome.app.domain.model.SearchConditionEmployee; + +import java.util.List; + +public interface SearchEmployeeInfo { + List selectAll(); + + List searchBy(SearchConditionEmployee searchConditionEmployee); +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/UpdateEmployee.java b/src/main/java/com/example/rhizome/app/domain/service/UpdateEmployee.java new file mode 100644 index 0000000..c857d4d --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/UpdateEmployee.java @@ -0,0 +1,8 @@ +package com.example.rhizome.app.domain.service; + +import com.example.rhizome.app.domain.model.Employee; + +public interface UpdateEmployee { + void updateEmployee(Employee beforeEmployee, Employee updateEmployee); + +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/impl/DeleteEmployeeImpl.java b/src/main/java/com/example/rhizome/app/domain/service/impl/DeleteEmployeeImpl.java new file mode 100644 index 0000000..ca5a67a --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/impl/DeleteEmployeeImpl.java @@ -0,0 +1,33 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.service.DeleteEmployee; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * Employee レコード削除関連の機能を持つサービス + */ +@Service +@Transactional +public class DeleteEmployeeImpl implements DeleteEmployee { + + EmployeeRepository employeeRepository; + + @Autowired + public DeleteEmployeeImpl(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + + /** + * idEmployee を元に employee データを削除 + * + * @param idEmployee 削除対象のidEmployee + */ + public void deleteEmployee(Integer idEmployee) { + employeeRepository.deleteById(idEmployee); + } + +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/impl/LoginImpl.java b/src/main/java/com/example/rhizome/app/domain/service/impl/LoginImpl.java new file mode 100644 index 0000000..66c7f02 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/impl/LoginImpl.java @@ -0,0 +1,55 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.LoginInfo; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.service.Login; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * ログイン系の機能を集約させるサービスクラスです。 + */ +@Service +@Transactional +public class LoginImpl implements Login { + + EmployeeRepository employeeRepository; + + @Autowired + public LoginImpl(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + + /** + * メールアドレス、パスワードでログイン判定を行う + * + * @param loginInfo ログインを試みるアカウント + * @return loginUser のインスタンス + */ + public LoginUser doLogin(LoginInfo loginInfo) { + // ログイン情報を元にログインユーザーを取得 + return employeeRepository + .findByMailAddressAndPassword(loginInfo.getMailAddress(), loginInfo.getPassword()) + .orElse(new EmployeeEntity()) + .createLoginUser(); + + } + + /** + * メールアドレス、パスワードでログイン判定を行う + * + * @param loginInfo ログインを試みるアカウント + * @return loginUser のインスタンス + */ + public boolean canLogin(LoginInfo loginInfo) { + // ログイン情報を元にログインユーザーを取得 + return employeeRepository + .findByMailAddressAndPassword(loginInfo.getMailAddress(), loginInfo.getPassword()) + .isPresent(); + + } +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/impl/RegisterEmployeeImpl.java b/src/main/java/com/example/rhizome/app/domain/service/impl/RegisterEmployeeImpl.java new file mode 100644 index 0000000..1683e23 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/impl/RegisterEmployeeImpl.java @@ -0,0 +1,34 @@ +package com.example.rhizome.app.domain.service.impl; + + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.service.RegisterEmployee; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * Employee テーブルの登録系の機能を集約させるサービスクラスです。 + */ +@Service +@Transactional +public class RegisterEmployeeImpl implements RegisterEmployee { + + EmployeeRepository employeeRepository; + + @Autowired + public RegisterEmployeeImpl(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + /** + * employee インスタンスの内容を登録する + * + * @param employee 登録対象のデータ + */ + public void registerEmployee(Employee employee) { + employeeRepository.save(EmployeeEntity.convertFrom(employee)); + } +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/impl/SearchDepartmentImpl.java b/src/main/java/com/example/rhizome/app/domain/service/impl/SearchDepartmentImpl.java new file mode 100644 index 0000000..feb6b37 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/impl/SearchDepartmentImpl.java @@ -0,0 +1,82 @@ +package com.example.rhizome.app.domain.service.impl; + + +import com.example.rhizome.app.domain.model.Department; +import com.example.rhizome.app.domain.model.SearchConditionDepartment; +import com.example.rhizome.app.domain.service.SearchDepartment; +import com.example.rhizome.app.infra.entity.DepartmentEntity; +import com.example.rhizome.app.infra.repository.DepartmentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 部署情報検索系の機能を集約させるサービスクラスです。 + */ +@Service +@Transactional +public class SearchDepartmentImpl implements SearchDepartment { + + DepartmentRepository departmentRepository; + + /** + * コンストラクタ + * + * @param departmentRepository DI対象 + */ + @Autowired + public SearchDepartmentImpl(DepartmentRepository departmentRepository) { + this.departmentRepository = departmentRepository; + } + + /** + * 部署情報を全件取得する + * + * @return 取得した部署情報レコード全件 + */ + public List selectAll() { + return DepartmentEntity.createDepartmentList(departmentRepository.findAll()); + } + + /** + * searchConditionDepartment の情報を元に Department のレコードを取得 + * + * @param searchConditionDepartment 検索条件 + * @return 検索結果のレコード + */ + public List searchBy(SearchConditionDepartment searchConditionDepartment) { + // 動的に検索条件を絞り込む + // Specification は Criteria API の Predicate をラップしたもの + return DepartmentEntity + .createDepartmentList( + departmentRepository.findAll(Specification + .where(DepartmentRepository.idDepartmentEqual(searchConditionDepartment.getIdDepartment())) + .and(DepartmentRepository.nmDepartmentEqual(searchConditionDepartment.getNmDepartment())) + ) + ); + + } + + /** + * searchConditionDepartment の情報を元に Department のレコードを取得 + * 部分一致検索 + * + * @param searchConditionDepartment 検索条件 + * @return 検索結果のレコード + */ + public List searchByWithLike(SearchConditionDepartment searchConditionDepartment) { + // 動的に検索条件を絞り込む + // Specification は Criteria API の Predicate をラップしたもの + return DepartmentEntity + .createDepartmentList( + departmentRepository.findAll(Specification + .where(DepartmentRepository.idDepartmentEqual(searchConditionDepartment.getIdDepartment())) + .and(DepartmentRepository.nmDepartmentLike(searchConditionDepartment.getNmDepartment())) + ) + ); + + } +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeImpl.java b/src/main/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeImpl.java new file mode 100644 index 0000000..002e064 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeImpl.java @@ -0,0 +1,70 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.service.SearchEmployee; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * Employee テーブル検索系の機能を集約させるサービスクラスです。 + */ +@Service +@Transactional +public class SearchEmployeeImpl implements SearchEmployee { + + EmployeeRepository employeeRepository; + + @Autowired + public SearchEmployeeImpl(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + + /** + * mailAddress を元に Employee Table を検索します。 + * + * @param mailAddress 検索対象の mailAddress + * @return Table から取得したレコードの情報 + */ + public List searchEmployee(String mailAddress) { + return EmployeeEntity.createEmployeeList(employeeRepository.findByMailAddress(mailAddress).stream().toList()); + } + + /** + * mailAddress を元に ログイン者の情報 を検索します。 + * + * @param mailAddress 検索対象の mailAddress + * @return login者の情報 + */ + public LoginUser searchLoginUser(String mailAddress) { + return employeeRepository.findByMailAddress(mailAddress).orElse(new EmployeeEntity()).createLoginUser(); + } + + /** + * idEmployee を元に Employee Table を検索します。 + * + * @param idEmployee 検索対象の idEmployee + * @return Table から取得したレコードの情報 + */ + public Employee searchEmployeeByIdEmployee(Integer idEmployee) { + return EmployeeEntity.createEmployee(employeeRepository.findByIdEmployee(idEmployee).orElse(new EmployeeEntity())); + } + + + /** + * idDepartment を元に Employee Table を検索します。 + * + * @param idDepartment 部署ID + * @return Table から取得したレコードの情報 + */ + @Override + public List searchEmployeeByIdDepartment(Integer idDepartment) { + return EmployeeEntity.createEmployeeList(employeeRepository.findByIdDepartment(idDepartment)); + } +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeInfoImpl.java b/src/main/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeInfoImpl.java new file mode 100644 index 0000000..09763c9 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeInfoImpl.java @@ -0,0 +1,62 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.EmployeeInfo; +import com.example.rhizome.app.domain.model.SearchConditionEmployee; +import com.example.rhizome.app.domain.service.SearchEmployeeInfo; +import com.example.rhizome.app.infra.entity.EmployeeDepartmentEntity; +import com.example.rhizome.app.infra.repository.EmployeeInfoRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * SearchEmployeeInfoImpl (employee join department) 検索系の機能を集約させるサービスクラスです + */ +@Service +@Transactional +public class SearchEmployeeInfoImpl implements SearchEmployeeInfo { + + EmployeeInfoRepository employeeInfoRepository; + + @Autowired + public SearchEmployeeInfoImpl(EmployeeInfoRepository employeeInfoRepository) { + this.employeeInfoRepository = employeeInfoRepository; + } + + + /** + * EmployeeInfo (employee join department) のレコードを全件取得 + * + * @return 取得したレコード全件 + */ + public List selectAll() { + + return EmployeeDepartmentEntity.createEmployeeInfoList(employeeInfoRepository.findAll()); + + } + + /** + * SearchConditionEmployee の情報を元に EmployeeInfo (employee join department) のレコードを取得 + * + * @param searchConditionEmployee 検索条件 + * @return 検索結果のレコードリスト + */ + public List searchBy(SearchConditionEmployee searchConditionEmployee) { + // 動的に検索条件を絞り込む + // Specification は Criteria API の Predicate をラップしたもの + return EmployeeDepartmentEntity + .createEmployeeInfoList( + employeeInfoRepository.findAll(Specification + .where(EmployeeInfoRepository.idEmployeeEqual(searchConditionEmployee.getIdEmployee())) + .and(EmployeeInfoRepository.nmEmployeeEqual(searchConditionEmployee.getNmEmployee())) + .and(EmployeeInfoRepository.knEmployeeEqual(searchConditionEmployee.getKnEmployee())) + .and(EmployeeInfoRepository.mailAddressEqual(searchConditionEmployee.getMailAddress())) + .and(EmployeeInfoRepository.idDepartmentEqual(searchConditionEmployee.getIdDepartment())) + ) + ); + + } +} diff --git a/src/main/java/com/example/rhizome/app/domain/service/impl/UpdateEmployeeImpl.java b/src/main/java/com/example/rhizome/app/domain/service/impl/UpdateEmployeeImpl.java new file mode 100644 index 0000000..599a2f9 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/domain/service/impl/UpdateEmployeeImpl.java @@ -0,0 +1,60 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.service.UpdateEmployee; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * employee の更新系の機能を集約させるサービスクラスです。 + */ +@Service +@Transactional +public class UpdateEmployeeImpl implements UpdateEmployee { + + EmployeeRepository employeeRepository; + + @Autowired + public UpdateEmployeeImpl(EmployeeRepository employeeRepository) { + this.employeeRepository = employeeRepository; + } + + /** + * employee の情報を元に employee table のレコードを更新する + * + * @param beforeEmployee 更新前のデータ + * @param updateEmployee 更新後のデータ + */ + public void updateEmployee(Employee beforeEmployee, Employee updateEmployee) { + + employeeRepository.save(EmployeeEntity.convertFrom(mergeEmployee(beforeEmployee, updateEmployee))); + + } + + /** + * 更新前のデータと更新対象のデータをマージする + * + * @param beforeEmployee 更新前のデータ + * @param updateEmployee 更新対象のデータ + * @return マージしたデータ + */ + private Employee mergeEmployee(Employee beforeEmployee, Employee updateEmployee) { + // 更新対象のデータのパスワードが空文字の場合は、更新前のパスワードを使用する + // 更新対象のデータの管理者権限が null の場合は、更新前の管理者権限を使用する + // 更新対象のデータの部署IDが null の場合は、更新前の部署IDを使用する + return new Employee( + updateEmployee.getIdEmployee(), + updateEmployee.getNmEmployee(), + updateEmployee.getKnEmployee(), + updateEmployee.getMailAddress(), + updateEmployee.getPassword().isBlank() ? beforeEmployee.getPassword() : updateEmployee.getPassword(), + updateEmployee.getAdminAuth() == null ? beforeEmployee.getAdminAuth() : updateEmployee.getAdminAuth(), + updateEmployee.getIdDepartment() == null ? beforeEmployee.getIdDepartment() : updateEmployee.getIdDepartment() + ); + + } + +} diff --git a/src/main/java/com/example/rhizome/app/infra/entity/DepartmentEntity.java b/src/main/java/com/example/rhizome/app/infra/entity/DepartmentEntity.java new file mode 100644 index 0000000..fc043e1 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/infra/entity/DepartmentEntity.java @@ -0,0 +1,72 @@ +/* + * Department.java + * 作成 IT-College 2016 + *------------------------------------------------------------ + * Copyright(c) Rhizome Inc. All Rights Reserved. + */ +package com.example.rhizome.app.infra.entity; + + +import com.example.rhizome.app.domain.model.Department; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.List; + +/** + * Department テーブルの Entity + * + * @author IT-College + */ +@Entity +@Table(name = "department") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DepartmentEntity { + + /** + * 部署ID + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id_department", nullable = false) + private Integer idDepartment; + /** + * 部署名 + */ + @Column(name = "nm_department", nullable = false) + private String nmDepartment; + + /** + * DepartmentEntity(DataAccess層依存)から Department(BusinessLogic層依存型)に変換します。 + * + * @param departmentEntityList department Table のリスト + * @return List リスト + */ + public static List createDepartmentList(List departmentEntityList) { + + // Stream API を利用するとこうなります。 + return departmentEntityList + .stream() + .map(departmentEntity -> new Department( + departmentEntity.getIdDepartment(), + departmentEntity.getNmDepartment() + )).toList(); + } + + /** + * Department(BusinessLogic層依存型) から DepartmentEntity(DataAccess層依存)に変換します。 + * + * @param department department モデルの値 + * @return DepartmentEntity に変換したインスタンス + */ + public static DepartmentEntity convertFrom(Department department) { + return new DepartmentEntity( + department.getIdDepartment(), + department.getNmDepartment() + ); + } +} diff --git a/src/main/java/com/example/rhizome/app/infra/entity/EmployeeDepartmentEntity.java b/src/main/java/com/example/rhizome/app/infra/entity/EmployeeDepartmentEntity.java new file mode 100644 index 0000000..989d2cc --- /dev/null +++ b/src/main/java/com/example/rhizome/app/infra/entity/EmployeeDepartmentEntity.java @@ -0,0 +1,118 @@ +package com.example.rhizome.app.infra.entity; + +import com.example.rhizome.app.domain.model.Department; +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.EmployeeInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; + +import javax.persistence.*; +import java.util.List; + +/** + * Employee + Department の Join 情報を保持するEntity + * + * @author IT-College + */ +@Entity +@Table(name = "employee") +@Data +@AllArgsConstructor +@NoArgsConstructor +@NamedEntityGraph( + name = "employee_with_department", + includeAllAttributes = true +) +public class EmployeeDepartmentEntity { + + /** + * 社員ID + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id_employee", nullable = false) + private Integer idEmployee; + + /** + * 社員名 + */ + @Column(name = "nm_employee", nullable = false) + private String nmEmployee; + + /** + * 社員名カナ + */ + @Column(name = "kn_employee", nullable = false) + private String knEmployee; + + /** + * メールアドレス + */ + @Column(name = "mail_address", nullable = false) + private String mailAddress; + + /** + * パスワード + */ + @Column(name = "password", nullable = false) + private String password; + + /** + * 管理者権限 + */ + @Column(name = "admin_auth", nullable = false) + private Integer adminAuth; + + @ManyToOne + @JoinColumn(name = "id_department", referencedColumnName = "id_department", insertable = false, updatable = false) + @Fetch(FetchMode.JOIN) + private DepartmentEntity department; + + /** + * EmployeeDepartmentEntity(DataAccess層依存) を EmployeeInfo(BusinessLogic層依存) に変換します。 + * + * @param employeeDepartmentEntity  EmployeeDepartmentEntity のインスタンス + * @return EmployeeInfo のインスタンス + */ + public static EmployeeInfo createEmployeeInfo(EmployeeDepartmentEntity employeeDepartmentEntity) { + + // コンストラクタを使って書くとSetterを使用するより簡略化出来ます。 + // 混乱してしまう人は落ち着いて EmployeeInfo のフィールドを見に行って、 + // どうしてこの書き方が出来るのかを理解できる様になりましょう。 + return new EmployeeInfo( + new Employee( + employeeDepartmentEntity.getIdEmployee(), + employeeDepartmentEntity.getNmEmployee(), + employeeDepartmentEntity.getKnEmployee(), + employeeDepartmentEntity.getMailAddress(), + employeeDepartmentEntity.getPassword(), + employeeDepartmentEntity.getAdminAuth(), + employeeDepartmentEntity.getDepartment() == null ? null : employeeDepartmentEntity.getDepartment().getIdDepartment() + ), + new Department( + employeeDepartmentEntity.getDepartment() == null ? null : employeeDepartmentEntity.getDepartment().getIdDepartment(), + employeeDepartmentEntity.getDepartment() == null ? null : employeeDepartmentEntity.getDepartment().getNmDepartment() + ) + ); + + } + + /** + * EmployeeDepartmentEntity(DataAccess層依存) を EmployeeInfo(BusinessLogic層依存) に変換します。 + * (リスト版) + * + * @param employeeDepartmentEntityList EmployeeDepartmentEntity インスタンスのリスト + * @return EmployeeInfo インスタンスのリスト + */ + public static List createEmployeeInfoList(List employeeDepartmentEntityList) { + + // StreamAPI を使うとこうなります。 + return employeeDepartmentEntityList.stream().map(EmployeeDepartmentEntity::createEmployeeInfo).toList(); + + } + + +} diff --git a/src/main/java/com/example/rhizome/app/infra/entity/EmployeeEntity.java b/src/main/java/com/example/rhizome/app/infra/entity/EmployeeEntity.java new file mode 100644 index 0000000..17721b5 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/infra/entity/EmployeeEntity.java @@ -0,0 +1,174 @@ +/* + * Employee.java + * 作成 IT-College 2016 + *------------------------------------------------------------ + * Copyright(c) Rhizome Inc. All Rights Reserved. + */ +package com.example.rhizome.app.infra.entity; + + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.model.SearchConditionEmployee; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.List; + +/** + * EmployeeテーブルのEntity + * + * @author IT-College + */ +@Entity +@Table(name = "employee") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class EmployeeEntity { + + /** + * 社員ID + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id_employee", nullable = false) + private Integer idEmployee; + + /** + * 社員名 + */ + @Column(name = "nm_employee", nullable = false) + private String nmEmployee; + + /** + * 社員名カナ + */ + @Column(name = "kn_employee", nullable = false) + private String knEmployee; + + /** + * メールアドレス + */ + @Column(name = "mail_address", nullable = false) + private String mailAddress; + + /** + * パスワード + */ + @Column(name = "password", nullable = false) + private String password; + + /** + * 管理者権限 + */ + @Column(name = "admin_auth", nullable = false) + private Integer adminAuth; + + /** + * 部署ID + */ + @Column(name = "id_department", nullable = false) + private Integer idDepartment; + + + /** + * Employee(BusinessLogic 依存)を EmployeeEntity(DataAccess層依存)に変換します。 + * + * @param employee Employee Table の中身 + * @return EmployeeEntity のインスタンス(1レコード分) + */ + public static EmployeeEntity convertFrom(Employee employee) { + // 値を既に持ったインスタンスの生成に、コンストラクタを使用するとこうなります。 + return new EmployeeEntity( + employee.getIdEmployee(), + employee.getNmEmployee(), + employee.getKnEmployee(), + employee.getMailAddress(), + employee.getPassword(), + employee.getAdminAuth(), + employee.getIdDepartment() + ); + } + + /** + * SearchConditionEmployee(BusinessLogic 依存)を EmployeeEntity(DataAccess層依存)に変換します。 + * (コンストラクタを使用せず、Setterを利用したパターン) + * + * @param searchConditionEmployee 検索条件 + * @return EmployeeEntity のインスタンス(1レコード分) + */ + public static EmployeeEntity convertFrom(SearchConditionEmployee searchConditionEmployee) { + EmployeeEntity employeeEntity = new EmployeeEntity(); + + employeeEntity.setIdEmployee(searchConditionEmployee.getIdEmployee()); + employeeEntity.setNmEmployee(searchConditionEmployee.getNmEmployee()); + employeeEntity.setKnEmployee(searchConditionEmployee.getKnEmployee()); + employeeEntity.setMailAddress(searchConditionEmployee.getMailAddress()); + employeeEntity.setIdDepartment(searchConditionEmployee.getIdDepartment()); + + + return employeeEntity; + + } + + /** + * EmployeeEntity(DataAccess層依存)から Employee (BusinessLogic層依存型)に変換します。 + * + * @param employeeEntity Employee Table のインスタンス + * @return employee インスタンス + */ + public static Employee createEmployee(EmployeeEntity employeeEntity) { + // 値を既に持ったインスタンスの生成に、コンストラクタを使用するとこうなります。 + return new Employee( + employeeEntity.getIdEmployee(), + employeeEntity.getNmEmployee(), + employeeEntity.getKnEmployee(), + employeeEntity.getMailAddress(), + employeeEntity.getPassword(), + employeeEntity.getAdminAuth(), + employeeEntity.getIdDepartment() + ); + } + + /** + * EmployeeEntity(DataAccess層依存) から Employee (BusinessLogic層依存型)に変換します。(リスト版) + * + * @param employeeEntityList EmployeeEntity インスタンスのリスト + * @return Employee インスタンスのリスト + */ + public static List createEmployeeList(List employeeEntityList) { + /* 従来の書き方 + List employeeList = new ArrayList<>(); + for(EmployeeEntity employeeEntity:employeeEntityList){ + Employee employee = EmployeeEntity.createEmployee(employeeEntity); + employeeList.add(employee); + } + return employeeList; + */ + + // Stream APIを使用すると1行で書けます。 + return employeeEntityList.stream().map(EmployeeEntity::createEmployee).toList(); + } + + /** + * EmployeeEntity(DataAccess層依存) から LoginUser (BusinessLogic層依存型)情報を作成します。 + * + * @return loginUser (ログイン者の情報) インスタンス + */ + public LoginUser createLoginUser() { + // 値を既に持ったインスタンスの生成に、コンストラクタを使用するとこうなります。 + return new LoginUser( + getIdEmployee(), + getNmEmployee(), + getKnEmployee(), + getMailAddress(), + getPassword(), + getAdminAuth(), + getIdDepartment() + ); + } + +} diff --git a/src/main/java/com/example/rhizome/app/infra/repository/DepartmentRepository.java b/src/main/java/com/example/rhizome/app/infra/repository/DepartmentRepository.java new file mode 100644 index 0000000..cdb8877 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/infra/repository/DepartmentRepository.java @@ -0,0 +1,50 @@ +package com.example.rhizome.app.infra.repository; + +import com.example.rhizome.app.infra.entity.DepartmentEntity; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + + +/** + * Specification: + * 関数型インターフェースです。 + * JPAの一部として提供されていて、エンティティの情報を元に動的にクエリを生成し、DBからデータを取得します。 + * 使い方: + * toPredicate をOverrideして使います。 + * パラメータ: + * Root:ルートエンティティを指します。に指定したエンティティ(今回はDepartmentEntity)を用いてメンバにアクセスします。 + * CriteriaQuery<\?>:サブクエリを作成する際に使用します。※今回は使用しません + * CriteriaBuilder:条件式(Where句以降の条件)の部分のクエリを作るためのビルダーです。 + * 戻り値はクエリを格納しているPredicateオブジェクトとなります。 + */ +@Repository +public interface DepartmentRepository extends JpaRepository, JpaSpecificationExecutor { + + + static Specification idDepartmentEqual(Integer idDepartment) { + return idDepartment == null ? + null : + // 戻り値の型 Specification にキャスト + (Specification) + // ラムダ式で記載しているが書いてあることは criteriaBuilder を使って Where句の後の "'idDepartment' = idDepartment(変数)" + // を作成している + (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get("idDepartment"), idDepartment); + } + + static Specification nmDepartmentEqual(String nmDepartment) { + return (nmDepartment == null || nmDepartment.isEmpty()) ? + null : + (Specification) + (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("nmDepartment"), nmDepartment); + } + + + static Specification nmDepartmentLike(String nmDepartment) { + return (nmDepartment == null || nmDepartment.isEmpty()) ? + null : + (Specification) + (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("nmDepartment"), "%" + nmDepartment + "%"); + } +} diff --git a/src/main/java/com/example/rhizome/app/infra/repository/EmployeeInfoRepository.java b/src/main/java/com/example/rhizome/app/infra/repository/EmployeeInfoRepository.java new file mode 100644 index 0000000..c2c8c5c --- /dev/null +++ b/src/main/java/com/example/rhizome/app/infra/repository/EmployeeInfoRepository.java @@ -0,0 +1,61 @@ +package com.example.rhizome.app.infra.repository; + +import com.example.rhizome.app.infra.entity.EmployeeDepartmentEntity; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +/** + * ワンポイント情報(ここで登場する関数型インターフェース Specification について解説します) + * Specification: + * 関数型インターフェースです。 + * JPAの一部として提供されていて、エンティティの情報を元に動的にクエリを生成し、DBからデータを取得します。 + * 使い方: + * toPredicate をOverrideして使います。 + * パラメータ: + * Root:ルートエンティティを指します。に指定したエンティティ(今回はDepartmentEntity)を用いてメンバにアクセスします。 + * CriteriaQuery<\?>:サブクエリを作成する際に使用します。※今回は使用しません + * CriteriaBuilder:条件式(Where句以降の条件)の部分のクエリを作るためのビルダーです。 + * 戻り値はクエリを格納しているPredicateオブジェクトとなります。 + */ +@Repository +public interface EmployeeInfoRepository extends JpaRepository, JpaSpecificationExecutor { + + static Specification idEmployeeEqual(Integer idEmployee) { + return idEmployee == null ? + null : + // 戻り値の型 Specification にキャスト + (Specification) + // ラムダ式で記載しているが書いてあることは criteriaBuilder を使って Where句の後の "'idEmployee' = idEmployee(変数)" + // を作成している + (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(root.get("idEmployee"), idEmployee); + } + + static Specification nmEmployeeEqual(String nmEmployee) { + return (nmEmployee == null || nmEmployee.isEmpty()) ? + null : + (Specification) + (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("nmEmployee"), "%" + nmEmployee + "%"); + } + + static Specification knEmployeeEqual(String knEmployee) { + return (knEmployee == null || knEmployee.isEmpty()) ? + null : + (Specification) + (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("knEmployee"), "%" + knEmployee + "%"); + } + + static Specification mailAddressEqual(String mailAddress) { + return (mailAddress == null || mailAddress.isEmpty()) ? + null : + (Specification) + (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("mailAddress"), "%" + mailAddress + "%"); + } + + static Specification idDepartmentEqual(Integer idDepartment) { + return (root, query, criteriaBuilder) -> + idDepartment == null ? null : + criteriaBuilder.equal(root.join("department").get("idDepartment"), idDepartment); + } +} diff --git a/src/main/java/com/example/rhizome/app/infra/repository/EmployeeRepository.java b/src/main/java/com/example/rhizome/app/infra/repository/EmployeeRepository.java new file mode 100644 index 0000000..82d6f8e --- /dev/null +++ b/src/main/java/com/example/rhizome/app/infra/repository/EmployeeRepository.java @@ -0,0 +1,28 @@ +package com.example.rhizome.app.infra.repository; + +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface EmployeeRepository extends JpaRepository { + Optional findByMailAddressAndPassword(String mailAddress, String password); + + /** + * メールアドレスで検索 + **/ + Optional findByMailAddress(String mail); + + /** + * IDで検索 + **/ + Optional findByIdEmployee(Integer idEmployee); + + /** + * IDで検索 + **/ + List findByIdDepartment(Integer idDepartment); +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/DeleteEmployeeController.java b/src/main/java/com/example/rhizome/app/presentation/controller/DeleteEmployeeController.java new file mode 100644 index 0000000..07982f7 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/DeleteEmployeeController.java @@ -0,0 +1,121 @@ +package com.example.rhizome.app.presentation.controller; + + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.service.DeleteEmployee; +import com.example.rhizome.app.domain.service.SearchDepartment; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.DepartmentForm; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import com.example.rhizome.app.presentation.form.MessageForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpSession; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword.DELETE_EMPLOYEE; + +/** + * 削除処理のコントロータ + */ +@Controller +public class DeleteEmployeeController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(DeleteEmployeeController.class.getName()); + + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + DeleteEmployee deleteEmployee; + SearchDepartment searchDepartment; + + @Autowired + public DeleteEmployeeController(DeleteEmployee deleteEmployee, SearchDepartment searchDepartment, HttpSession httpSession) { + this.httpSession = httpSession; + this.deleteEmployee = deleteEmployee; + this.searchDepartment = searchDepartment; + } + + /** + * 削除処理のコントローラ + * + * @param idEmployee 削除対象のemployeeId + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = DELETE_EMPLOYEE, method = RequestMethod.POST) + public String deleteEmployee(@RequestParam("idEmployee") Integer idEmployee, Model model) { + + try { + // 部署一覧を取得し、画面に返す用のクラスに詰め替える + // 作成した部署一覧をセット + model.addAttribute( + PageReturnAttributeKeyword.DEPARTMENT_FORM_LIST, + DepartmentForm.convertFrom(searchDepartment.selectAll()) + ); + + // 削除処理実施 + deleteExec( + model, + idEmployee, + LoginUserForm.convertTo((LoginUserForm) httpSession.getAttribute(SessionKeyword.LOGIN_USER))); + + // 検索画面に遷移 + return "forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY; + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + + e.printStackTrace(); + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + } + + /** + * 削除処理実施 + * + * @param model ビューにデータを渡すためのコンテナ + * @param idEmployee 削除対象のemployeeId + * @param loginUser ログインユーザー情報 + */ + private void deleteExec(Model model, Integer idEmployee, LoginUser loginUser) { + + final String DELETE_TARGET_ID_CAN_NOT_DELETE = "ログイン者自身は削除出来ません。"; + final String DELETE_COMPLETE = "削除しました。"; + + // ログインしている人が、削除対象かチェック + if (Objects.equals(loginUser.getIdEmployee(), idEmployee)) { + // 削除対象だった場合 + // エラーメッセージをセット + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(DELETE_TARGET_ID_CAN_NOT_DELETE)); + // 検索画面に遷移 + return; + } + + // 削除を実施 + deleteEmployee.deleteEmployee(idEmployee); + + // 削除完了したメッセージをセット + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_INFO, new MessageForm(DELETE_COMPLETE)); + + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/IndexController.java b/src/main/java/com/example/rhizome/app/presentation/controller/IndexController.java new file mode 100644 index 0000000..93da70a --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/IndexController.java @@ -0,0 +1,50 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.service.impl.LoginImpl; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpSession; + +import static com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword.*; + +@Controller +public class IndexController { + + HttpSession httpSession; + + @Autowired + public IndexController(HttpSession httpSession, LoginImpl loginImpl) { + this.httpSession = httpSession; + } + + @ModelAttribute + public LoginUserForm loginUserForm() { + return new LoginUserForm(); + } + + /** + * ログイン画面表示処理 + * + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @RequestMapping(value = {INDEX_BLANK, INDEX_SLASH, INDEX_LOGIN}) + public String index(Model model) { + // セッション情報を破棄 + if (httpSession != null) { + httpSession.invalidate(); + } + + // 空のFormをSessionに用意 + model.addAttribute(PageReturnAttributeKeyword.LOGIN_INFO_FORM, loginUserForm()); + + // ログイン画面に遷移 + return LOGIN_HTML; + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeConfirmController.java b/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeConfirmController.java new file mode 100644 index 0000000..4cdf8d1 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeConfirmController.java @@ -0,0 +1,133 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.service.SearchDepartment; +import com.example.rhizome.app.domain.service.SearchEmployee; +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.domain.service.impl.SearchEmployeeImpl; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.DepartmentForm; +import com.example.rhizome.app.presentation.form.InsertEmployeeForm; +import com.example.rhizome.app.presentation.form.MessageForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpSession; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_CONFIRM; + +/** + * 新規登録者情報チェック用のコントローラ + */ +@Controller +public class InsertEmployeeConfirmController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(InsertEmployeeConfirmController.class.getName()); + + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + SearchDepartment searchDepartment; + SearchEmployee searchEmployee; + + @Autowired + public InsertEmployeeConfirmController( + HttpSession httpSession, + SearchDepartmentImpl searchDepartment, + SearchEmployeeImpl searchEmployee + ) { + this.httpSession = httpSession; + this.searchDepartment = searchDepartment; + this.searchEmployee = searchEmployee; + } + + @ModelAttribute + public InsertEmployeeForm insertEmployeeForm() { + return new InsertEmployeeForm(); + } + + /** + * 登録情報のチェックを行う + * + * @param insertEmployeeForm 登録情報 + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = INSERT_EMPLOYEE_CONFIRM, method = RequestMethod.POST) + public String insertEmployeeConfirm(InsertEmployeeForm insertEmployeeForm, Model model) { + + try { + // 部署一覧を取得し、画面に返す用のクラスに詰め替える + // 作成した部署一覧をセット + model.addAttribute( + PageReturnAttributeKeyword.DEPARTMENT_FORM_LIST, + DepartmentForm.convertFrom( + searchDepartment.selectAll() + )); + + // 登録用パラメータチェック + List error = insertEmployeeForm.validateParameter(); + + // 入力内容に誤りがあるか + if (!error.isEmpty()) { + // 誤りがあった場合 + // 誤りがあった箇所のエラーメッセージを表示 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(String.join(", ", error) + "が不正です。")); + // 画面に返す為の登録情報をセット + model.addAttribute(PageReturnAttributeKeyword.INSERT_EMPLOYEE_FORM, insertEmployeeForm); + // 登録画面に遷移 + return TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML; + } + + final String DUPLICATION = "既に登録済みのメールアドレスです。"; + + // 登録対象のメールアドレスを元に検索 + List employeeList = searchEmployee.searchEmployee(insertEmployeeForm.getMailAddress()); + + // 検索結果があるか + if (!employeeList.isEmpty()) { + // 検索した結果0件ではない場合 + // 重複を許さないため、エラー処理 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(DUPLICATION)); + // 画面に返す為の登録情報をセット + model.addAttribute(PageReturnAttributeKeyword.INSERT_EMPLOYEE_FORM, insertEmployeeForm); + // 登録画面に遷移 + return TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML; + } + + // 登録確認ページに遷移 + model.addAttribute(PageReturnAttributeKeyword.INSERT_EMPLOYEE_FORM, insertEmployeeForm); + // 登録確認画面に遷移 + return TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_CONFIRM_HTML; + + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + + e.printStackTrace(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + } +} + + + diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeController.java b/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeController.java new file mode 100644 index 0000000..a532295 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeController.java @@ -0,0 +1,198 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.domain.service.RegisterEmployee; +import com.example.rhizome.app.domain.service.SearchDepartment; +import com.example.rhizome.app.domain.service.impl.RegisterEmployeeImpl; +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.DepartmentForm; +import com.example.rhizome.app.presentation.form.InsertEmployeeForm; +import com.example.rhizome.app.presentation.form.MessageForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpSession; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword.INSERT_EMPLOYEE; + +/** + * 新規登録用のコントローラ + */ +@Controller +public class InsertEmployeeController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(InsertEmployeeController.class.getName()); + + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + RegisterEmployee registerEmployee; + SearchDepartment searchDepartment; + + @Autowired + public InsertEmployeeController(HttpSession httpSession, RegisterEmployeeImpl registerEmployee, SearchDepartmentImpl searchDepartment) { + this.httpSession = httpSession; + this.registerEmployee = registerEmployee; + this.searchDepartment = searchDepartment; + } + + @ModelAttribute + public InsertEmployeeForm insertEmployeeForm() { + return new InsertEmployeeForm(); + } + + /** + * 新規登録画面表示処理 + * + * @param insertEmployeeForm 登録情報 + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = INSERT_EMPLOYEE, method = RequestMethod.POST) + public String insertEmployee(InsertEmployeeForm insertEmployeeForm, Model model) { + + try { + // 部署一覧を取得し、画面に返す用のクラスに詰め替える + // 作成した部署一覧をセット + model.addAttribute( + PageReturnAttributeKeyword.DEPARTMENT_FORM_LIST, + DepartmentForm.convertFrom( + searchDepartment.selectAll() + )); + + // Confirm画面から渡ってきた値をチェック + List error = validateParameter( + insertEmployeeForm.getNmEmployee(), + insertEmployeeForm.getKnEmployee(), + insertEmployeeForm.getMailAddress(), + insertEmployeeForm.getPassword(), + insertEmployeeForm.getAdminAuth(), + insertEmployeeForm.getIdDepartment() + ); + + // エラーが1件以上有る場合 + if (!error.isEmpty()) { + // エラー内容を画面に表示 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(String.join(", ", error) + "が不正です。")); + // 登録画面に遷移 + return TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML; + } + + // 登録処理 + registerEmployee.registerEmployee(InsertEmployeeForm.convertTo(insertEmployeeForm)); + // 登録結果画面に遷移 + return TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_RESULT_HTML; + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + + e.printStackTrace(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + } + + /** + * @param employeeName 登録対象の名前 + * @param employeeKana 登録対象のカナ + * @param mailAddress 登録対象のメールアドレス + * @param password 登録対象のパスワード + * @param management システム権限 + * @param departmentId 部署ID + * @return エラーが有った場合はエラー文言、無ければ空のリストが返る + */ + private List validateParameter( + String employeeName, + String employeeKana, + String mailAddress, + String password, + Integer management, + Integer departmentId + ) { + + final String EMPLOYEE_NAME_NULL_BLANK = "社員名"; + final String EMPLOYEE_KANA_NULL_BLANK = "社員名フリガナ"; + final String MAIL_ADDRESS_NULL_BLANK = "メールアドレス"; + final String PASSWORD_NULL_BLANK = "パスワード"; + final String MANAGEMENT_ERROR = "管理者権限指定"; + final String DEPARTMENT_ID_NULL_BLANK = "所属部署"; + + List error = new ArrayList<>(); + + // null or 空文字判定 + if (isNullOrBlank(employeeName)) { + // エラー内容を追加 + error.add(EMPLOYEE_NAME_NULL_BLANK); + } + + // null or 空文字判定 + if (isNullOrBlank(employeeKana)) { + // エラー内容を追加 + error.add(EMPLOYEE_KANA_NULL_BLANK); + } + + // null or 空文字判定 + if (isNullOrBlank(mailAddress)) { + // エラー内容を追加 + error.add(MAIL_ADDRESS_NULL_BLANK); + } + + // null or 空文字判定 + if (isNullOrBlank(password)) { + // エラー内容を追加 + error.add(PASSWORD_NULL_BLANK); + } + + // 管理者権限の値が不正か + if (management == null) { + // エラー内容を追加 + error.add(MANAGEMENT_ERROR); + } + + // 所属部署の値が不正か + if (departmentId == null) { + // エラー内容を追加 + error.add(DEPARTMENT_ID_NULL_BLANK); + } + + return error; + + } + + /** + * 仮引数を null or 空 判定する + * + * @param str 判定対象の文字列 + * @return true:null or 空 false:null or 空 では無い + */ + private static boolean isNullOrBlank(String str) { + if (null == str) { + return true; + } + + return str.isBlank(); + } + +} + + + diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeInputController.java b/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeInputController.java new file mode 100644 index 0000000..fab6082 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/InsertEmployeeInputController.java @@ -0,0 +1,90 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.domain.service.RegisterEmployee; +import com.example.rhizome.app.domain.service.SearchDepartment; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.DepartmentForm; +import com.example.rhizome.app.presentation.form.InsertEmployeeForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpSession; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT; + +/** + * 登録画面表示用コントローラ + */ +@Controller +public class InsertEmployeeInputController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(InsertEmployeeInputController.class.getName()); + + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + RegisterEmployee registerEmployee; + SearchDepartment searchDepartment; + + @Autowired + public InsertEmployeeInputController(HttpSession httpSession, RegisterEmployee registerEmployee, SearchDepartment searchDepartment) { + this.httpSession = httpSession; + this.registerEmployee = registerEmployee; + this.searchDepartment = searchDepartment; + } + + @ModelAttribute + public InsertEmployeeForm insertEmployeeForm() { + return new InsertEmployeeForm(); + } + + + /** + * 登録画面表示処理 + * + * @param insertEmployeeForm 登録画面のフォーム + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @SessionCheck + @PermissionCheck + @RequestMapping(value = INSERT_EMPLOYEE_INPUT, method = RequestMethod.POST) + public String insertInput(InsertEmployeeForm insertEmployeeForm, Model model) { + + try { + // 部署コードリストを作成し、画面に返す値としてセット + model.addAttribute(PageReturnAttributeKeyword.DEPARTMENT_FORM_LIST, DepartmentForm.convertFrom(searchDepartment.selectAll())); + + // パラメータをセット + model.addAttribute(PageReturnAttributeKeyword.INSERT_EMPLOYEE_FORM, insertEmployeeForm); + + // 登録画面に遷移 + return TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML; + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + + e.printStackTrace(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + } +} + + + diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/LoginController.java b/src/main/java/com/example/rhizome/app/presentation/controller/LoginController.java new file mode 100644 index 0000000..036bee3 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/LoginController.java @@ -0,0 +1,148 @@ +package com.example.rhizome.app.presentation.controller; + + +import com.example.rhizome.app.domain.model.LoginInfo; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.service.Login; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginInfoForm; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import com.example.rhizome.app.presentation.form.MessageForm; +import com.example.rhizome.app.presentation.form.UpdatePersonalUserForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpSession; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword.DO_LOGIN; + +/** + * ログイン関連のコントローラ + */ +@Controller +public class LoginController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(LoginController.class.getName()); + + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + Login login; + + @Autowired + public LoginController(HttpSession httpSession, Login login) { + this.httpSession = httpSession; + this.login = login; + } + + @ModelAttribute + public LoginUserForm loginUserForm() { + return new LoginUserForm(); + } + + /** + * 画面から渡ってきたパラメータのチェックを行う + * + * @param loginInfoForm mailAddress, password を保持したインスタンス + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @RequestMapping(value = DO_LOGIN, method = RequestMethod.POST) + public String doLogin(LoginInfoForm loginInfoForm, Model model) { + + // ログに出力する + final String MAIL_ADDRESS_PASSWORD_ERROR = "メールアドレス、パスワードの入力内容に誤りがあります"; + // 発生しうるErrorに対するメッセージ + final String LOGIN_ERROR = "IDまたはパスワードが間違っています"; + + try { + // mailAddress, password の入力に誤りがあるかチェック + if (!LoginUserForm.checkParameter(loginInfoForm)) { + + // mail,passwordが仕様を満たしていない場合 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(MAIL_ADDRESS_PASSWORD_ERROR)); + + // エラーだった場合に login.html に処理を戻す。mailAddress, password を login.htmlに表示するために + // ここで addAttribute する + model.addAttribute(PageReturnAttributeKeyword.LOGIN_INFO_FORM, loginInfoForm); + // login.html に遷移する様に設定 + return TransitionTargetPageNameKeyword.LOGIN_HTML; + } + + // Login者情報インスタンスを作成 + LoginInfo loginInfo = createLoginInfo(httpSession, loginInfoForm); + + // login 可能かチェック + if (!login.canLogin(loginInfo)) { + // ログイン不可の場合、エラーメッセージをセットして入力された値とともに login.html を再表示 + // 画面に表示するエラーメッセージをセット + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(LOGIN_ERROR)); + // 画面に表示する mailAddress, password をセット + model.addAttribute(PageReturnAttributeKeyword.LOGIN_INFO_FORM, loginInfoForm); + // login.html に遷移 + return TransitionTargetPageNameKeyword.LOGIN_HTML; + } + + // ログイン(インスタンス作成) + LoginUser loginUser = login.doLogin(loginInfo); + + // ログイン者の情報をセッション情報に格納 + // セッションに loginUser 情報を保持し続ける = ログイン中として扱う + httpSession.setAttribute(SessionKeyword.LOGIN_USER, LoginUserForm.convertFrom(loginUser)); + + // 管理者かチェック + if (!loginUser.isAdminUser()) { + // 管理者ではない場合直で自分の情報を更新するページに遷移する + // 編集対象のログイン者の情報を画面に渡す値にセット + model.addAttribute(PageReturnAttributeKeyword.UPDATE_PERSONAL_EMPLOYEE_USER_FORM, UpdatePersonalUserForm.convertFrom(loginUser)); + // 個人の情報更新ページに遷移 + return TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML; + } + + // メニュー画面に遷移 + return TransitionTargetPageNameKeyword.MENU_HTML; + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + e.printStackTrace(); + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面に遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + } + + /** + * ログイン者情報のインスタンスを作成 + * + * @param httpSession セッション情報 + * @param loginInfoForm mailAddress, password を保持したインスタンス + */ + private static LoginInfo createLoginInfo(HttpSession httpSession, LoginInfoForm loginInfoForm) { + // セッションからログイン者情報を取得 + LoginUserForm loginUserForm = (LoginUserForm) httpSession.getAttribute(SessionKeyword.LOGIN_USER); + + // セッションにログイン者情報があるか + if (loginUserForm != null) { + // セッションにログイン者情報がある場合 + return new LoginInfo(loginUserForm.getMailAddress(), loginUserForm.getPassword()); + } + + // セッションにない場合は画面からの input 値 を取得 + return new LoginInfo( + loginInfoForm.getMailAddress(), + loginInfoForm.getPassword() + ); + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/LogoutController.java b/src/main/java/com/example/rhizome/app/presentation/controller/LogoutController.java new file mode 100644 index 0000000..dbc94fc --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/LogoutController.java @@ -0,0 +1,73 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpSession; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword.LOGOUT; + +/** + * ログアウト処理のコントローラ + */ +@Controller +public class LogoutController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(LogoutController.class.getName()); + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + + @Autowired + public LogoutController(HttpSession httpSession) { + this.httpSession = httpSession; + } + + @ModelAttribute + public LoginUserForm loginUserForm() { + return new LoginUserForm(); + } + + /** + * ログアウト処理 + * + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = LOGOUT, method = RequestMethod.POST) + public String doLogout(Model model) { + try { + // セッション情報の破棄 + httpSession.invalidate(); + + // ログイン画面に遷移するための情報を設定 + model.addAttribute(PageReturnAttributeKeyword.LOGIN_INFO_FORM, loginUserForm()); + // login.html に遷移 + return TransitionTargetPageNameKeyword.LOGIN_HTML; + + } catch (Exception e) { + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラーページに遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + + } + +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/MenuController.java b/src/main/java/com/example/rhizome/app/presentation/controller/MenuController.java new file mode 100644 index 0000000..7ba1e9f --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/MenuController.java @@ -0,0 +1,33 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.MessageForm; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * メニュー画面表示用コントローラ + */ +@Controller +public class MenuController { + + @ModelAttribute + public MessageForm messageForm() { + return new MessageForm(); + } + + /** + * メニュー画面に遷移 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = TransitionTargetPageNameKeyword.SHOW_MENU) + public String showMenu() { + // メニュー画面遷移 + return TransitionTargetPageNameKeyword.MENU_HTML; + } + +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/SelectEmployeeController.java b/src/main/java/com/example/rhizome/app/presentation/controller/SelectEmployeeController.java new file mode 100644 index 0000000..fa41f62 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/SelectEmployeeController.java @@ -0,0 +1,121 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.domain.service.SearchDepartment; +import com.example.rhizome.app.domain.service.SearchEmployeeInfo; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.DepartmentForm; +import com.example.rhizome.app.presentation.form.EmployeeInfoForm; +import com.example.rhizome.app.presentation.form.SearchConditionEmployeeForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpSession; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 社員検索画面用コントローラ リスト全件表示、検索表示、更新、削除が可能 + */ +@Controller +public class SelectEmployeeController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(SelectEmployeeController.class.getName()); + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + SearchDepartment searchDepartment; + SearchEmployeeInfo searchEmployeeInfo; + + @Autowired + public SelectEmployeeController(HttpSession httpSession, SearchDepartment searchDepartment, SearchEmployeeInfo searchEmployeeInfo) { + this.httpSession = httpSession; + this.searchDepartment = searchDepartment; + this.searchEmployeeInfo = searchEmployeeInfo; + } + + @ModelAttribute + public SearchConditionEmployeeForm searchConditionEmployeeForm() { + return new SearchConditionEmployeeForm(); + } + + /** + * 社員検索画面表示処理コントローラ + * + * @param searchConditionEmployeeForm 検索画面のフォーム + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO, method = RequestMethod.POST) + public String select(SearchConditionEmployeeForm searchConditionEmployeeForm, Model model) { + + try { + + // 部署一覧を取得し、画面に返す用のクラスに詰め替える + // 作成した部署一覧をセット + model.addAttribute( + PageReturnAttributeKeyword.DEPARTMENT_FORM_LIST, + DepartmentForm.convertFrom(searchDepartment.selectAll()) + ); + + // 検索条件を元に検索を実施 + // 取得した EmployeeInfo( employee + department )の情報を画面に返す用の型に詰め替えてセット + model.addAttribute(PageReturnAttributeKeyword.EMPLOYEE_INFO_FORM_LIST, EmployeeInfoForm.convertFrom(searchEmployeeInfo.searchBy(SearchConditionEmployeeForm.convertTo(searchConditionEmployeeForm)))); + // 検索ページに遷移 + return TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_HTML; + + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + + e.printStackTrace(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + + } + + /** + * 社員検索画面表示処理コントローラ + * 検索条件無しの状態を作るため、空の検索条件で検索した結果を画面に返す + * + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY, method = RequestMethod.POST) + public String select(Model model) { + + // 部署一覧を取得し、画面に返す用のクラスに詰め替える + // 作成した部署一覧をセット + model.addAttribute( + PageReturnAttributeKeyword.DEPARTMENT_FORM_LIST, + DepartmentForm.convertFrom(searchDepartment.selectAll()) + ); + + // 検索条件を元に検索を実施 + model.addAttribute(PageReturnAttributeKeyword.EMPLOYEE_INFO_FORM_LIST, + EmployeeInfoForm.convertFrom( + searchEmployeeInfo.searchBy( + SearchConditionEmployeeForm.convertTo(searchConditionEmployeeForm()) + ))); + + // 検索ページに遷移 + return TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_HTML; + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeController.java b/src/main/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeController.java new file mode 100644 index 0000000..1b43d74 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeController.java @@ -0,0 +1,107 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.domain.model.EmployeeInfo; +import com.example.rhizome.app.domain.model.SearchConditionEmployee; +import com.example.rhizome.app.domain.service.SearchDepartment; +import com.example.rhizome.app.domain.service.SearchEmployeeInfo; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.DepartmentForm; +import com.example.rhizome.app.presentation.form.MessageForm; +import com.example.rhizome.app.presentation.form.SearchConditionEmployeeForm; +import com.example.rhizome.app.presentation.form.UpdateEmployeeInfoForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpSession; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 更新対象の employee が存在するか確認する為のコントローラ + */ +@Controller +public class UpdateEmployeeController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(UpdateEmployeeController.class.getName()); + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + SearchDepartment searchDepartment; + SearchEmployeeInfo searchEmployeeInfo; + + @Autowired + public UpdateEmployeeController(HttpSession httpSession, SearchDepartment searchDepartment, SearchEmployeeInfo searchEmployeeInfo) { + this.httpSession = httpSession; + this.searchDepartment = searchDepartment; + this.searchEmployeeInfo = searchEmployeeInfo; + } + + @ModelAttribute + public SearchConditionEmployeeForm searchConditionEmployeeForm() { + return new SearchConditionEmployeeForm(); + } + + /** + * 更新対象の employee が存在するか確認する為のコントローラ + * + * @param idEmployee 更新対象の employee の id + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = TransitionTargetPageNameKeyword.SHOW_UPDATE_EMPLOYEE, method = RequestMethod.POST) + public String showUpdateEmployee(@RequestParam("idEmployee") Integer idEmployee, Model model) { + final String UPDATE_TARGET_ID_NOT_FOUND = "更新対象のデータが見つかりません。"; + + try { + // 部署一覧を取得し画面に返す値としてセット + model.addAttribute(PageReturnAttributeKeyword.DEPARTMENT_FORM_LIST, DepartmentForm.convertFrom(searchDepartment.selectAll())); + + // id を条件に更新対象のレコードを検索、取得する + List employeeInfoList = searchEmployeeInfo.searchBy( + new SearchConditionEmployee(idEmployee, + null, + null, + null, + null)); + + // DBに更新対象のデータがあるか + if (employeeInfoList.isEmpty()) { + // ない場合はエラーメッセージをセットして検索画面に戻る + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(UPDATE_TARGET_ID_NOT_FOUND)); + return "forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO; + } + + // 更新画面に遷移 + model.addAttribute(PageReturnAttributeKeyword.UPDATE_EMPLOYEE_INFO_FORM, UpdateEmployeeInfoForm.convertFrom(employeeInfoList.get(0))); + + // Update画面に遷移 + return TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML; + + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + + e.printStackTrace(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + + } + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeResultController.java b/src/main/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeResultController.java new file mode 100644 index 0000000..7f0066c --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeResultController.java @@ -0,0 +1,206 @@ +package com.example.rhizome.app.presentation.controller; + + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.service.SearchDepartment; +import com.example.rhizome.app.domain.service.SearchEmployee; +import com.example.rhizome.app.domain.service.UpdateEmployee; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.DepartmentForm; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import com.example.rhizome.app.presentation.form.MessageForm; +import com.example.rhizome.app.presentation.form.UpdateEmployeeInfoForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpSession; +import java.util.List; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * employee を更新して結果を返す為のコントローラ + */ +@Controller +public class UpdateEmployeeResultController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(UpdateEmployeeController.class.getName()); + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + SearchDepartment searchDepartment; + SearchEmployee searchEmployee; + UpdateEmployee updateEmployee; + + @Autowired + public UpdateEmployeeResultController(HttpSession httpSession, SearchDepartment searchDepartment, SearchEmployee searchEmployee, UpdateEmployee updateEmployee) { + this.httpSession = httpSession; + this.searchDepartment = searchDepartment; + this.searchEmployee = searchEmployee; + this.updateEmployee = updateEmployee; + } + + /** + * メールアドレスの重複チェック + * + * @param employeeList 元の employeeList + * @param updateEmployeeInfoForm 更新対象のデータ + * @return true:重複無し false:重複あり + */ + private static boolean checkDuplicateMailAddress(List employeeList, UpdateEmployeeInfoForm updateEmployeeInfoForm) { + // メールアドレスが既に使われていた場合 + if (!employeeList.isEmpty()) { + // 重複が有った場合に、同一人物のものであれば上書きOKとする + return Objects.equals(employeeList.get(0).getIdEmployee(), updateEmployeeInfoForm.getIdEmployee()); + } + return true; + } + + /** + * 更新結果画面表示処理 + * + * @param updateEmployeeInfoForm 更新画面のフォーム + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT, method = RequestMethod.POST) + public String employeeUpdateResult(@ModelAttribute UpdateEmployeeInfoForm updateEmployeeInfoForm, Model model) { + + final String DUPLICATION = "既に登録済みのメールアドレスです。"; + final String NOTHING = "項目が空欄です。"; + final String ADMIN_USER = "更新対象者がログイン者のため、管理者権限を変更できません。"; + final String NO_TARGET = "更新対象のデータが見つかりません。"; + + final String UPDATE_COMPLETE = "更新が完了しました。"; + + + try { + + // 部署一覧取得 + model.addAttribute(PageReturnAttributeKeyword.DEPARTMENT_FORM_LIST, DepartmentForm.convertFrom(searchDepartment.selectAll())); + + // パスワードが仕様を満たしているか確認 + String error = UpdateEmployeeInfoForm.validatePassword( + updateEmployeeInfoForm.getPassword(), + updateEmployeeInfoForm.getPasswordConfirm() + ); + + // エラーが存在するか + if (!error.isBlank()) { + // エラーが存在する場合、更新画面に遷移 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(error)); + model.addAttribute(PageReturnAttributeKeyword.UPDATE_EMPLOYEE_INFO_FORM, updateEmployeeInfoForm); + + return TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML; + } + + // メールアドレスを元に検索 + List employeeList = searchEmployee.searchEmployee(updateEmployeeInfoForm.getMailAddress()); + + // 既に登録済みのメールアドレスが存在するか + if (!checkDuplicateMailAddress(employeeList, updateEmployeeInfoForm)) { + // 存在する場合はエラーメッセージを設定して更新入力画面に遷移 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(DUPLICATION)); + model.addAttribute(PageReturnAttributeKeyword.UPDATE_EMPLOYEE_INFO_FORM, updateEmployeeInfoForm); + + return TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML; + } + + // session 情報からログイン者の情報を取得 + LoginUserForm loginUserForm = (LoginUserForm) httpSession.getAttribute(SessionKeyword.LOGIN_USER); + + // ログイン者が更新対象で、権限を管理者権限から一般権限に変更しようとしているかチェック + if (isUpdateTargetLoginUserAdminToNormal(updateEmployeeInfoForm, loginUserForm)) { + // 存在する場合はエラーメッセージを設定して更新入力画面に遷移 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(ADMIN_USER)); + model.addAttribute(PageReturnAttributeKeyword.UPDATE_EMPLOYEE_INFO_FORM, updateEmployeeInfoForm); + return TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML; + } + + // 画面から渡ってきた値が必須を満たしているか + if (!UpdateEmployeeInfoForm.hasErrorParameter(updateEmployeeInfoForm)) { + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(NOTHING)); + model.addAttribute(PageReturnAttributeKeyword.UPDATE_EMPLOYEE_INFO_FORM, updateEmployeeInfoForm); + + return TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML; + } + + // 更新前のデータを取得 + Employee beforeEmployee = searchEmployee.searchEmployeeByIdEmployee(updateEmployeeInfoForm.getIdEmployee()); + if (beforeEmployee.getIdEmployee() == null) { + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(NO_TARGET)); + model.addAttribute(PageReturnAttributeKeyword.UPDATE_EMPLOYEE_INFO_FORM, updateEmployeeInfoForm); + + return TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML; + } + + // 画面用の型からビジネスロジック用のモデルに変換し、Updateを実行 + updateEmployee.updateEmployee(beforeEmployee, UpdateEmployeeInfoForm.convertTo(updateEmployeeInfoForm)); + + // Update後の情報を再取得 + LoginUser updatedTargetEmployee = searchEmployee.searchLoginUser(updateEmployeeInfoForm.getMailAddress()); + + // ログイン者と更新した対象が同じアカウントだった場合、session情報を更新 + if (Objects.equals(updatedTargetEmployee.getIdEmployee(), loginUserForm.getIdEmployee())) { + // ログイン者の情報をセッション情報に格納 + httpSession.setAttribute(SessionKeyword.LOGIN_USER, LoginUserForm.convertFrom(updatedTargetEmployee)); + } + + // 更新結果のメッセージを画面にセットし一覧画面に遷移 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_INFO, new MessageForm(UPDATE_COMPLETE)); + + // forward 先で不用意な動作をしないために UpdateEmployeeInfoForm をクリア + return "forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY; + + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + + e.printStackTrace(); + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + + } + + /** + * ログイン者がログイン者自身を更新する際 + * 管理者権限から一般権限に変更する内容も含まれているかチェックする + * + * @param updateEmployeeInfoForm 更新対象データ + * @param loginUserForm ログイン者情報 + * @return true:ログイン者自身のデータをUpdate管理者→一般に権限変更しようとしている。 + * false:Update対象者がログイン者自身ではない or 管理者権限 → 一般権限 への更新は含まれていない + */ + private boolean isUpdateTargetLoginUserAdminToNormal(UpdateEmployeeInfoForm updateEmployeeInfoForm, LoginUserForm loginUserForm) { + + // ログイン者が今回の更新対象か + if (!Objects.equals(updateEmployeeInfoForm.getIdEmployee(), loginUserForm.getIdEmployee())) { + // 今回の対象者はログイン者ではない + return false; + } + + // 管理者から一般権限への変更があるか + return updateEmployeeInfoForm.getAdminAuth().equals(0); + + } + + +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/UpdatePersonalEmployeeResultController.java b/src/main/java/com/example/rhizome/app/presentation/controller/UpdatePersonalEmployeeResultController.java new file mode 100644 index 0000000..26b46da --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/UpdatePersonalEmployeeResultController.java @@ -0,0 +1,163 @@ +package com.example.rhizome.app.presentation.controller; + + +import com.example.rhizome.aop.aspect.PermissionCheck; +import com.example.rhizome.aop.aspect.SessionCheck; +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.service.SearchEmployee; +import com.example.rhizome.app.domain.service.UpdateEmployee; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import com.example.rhizome.app.presentation.form.MessageForm; +import com.example.rhizome.app.presentation.form.UpdatePersonalUserForm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpSession; +import java.util.List; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 個人情報更新用コントローラ + */ +@Controller +public class UpdatePersonalEmployeeResultController { + + // ログ出力用インスタンス + private final static Logger LOGGER = Logger.getLogger(UpdatePersonalEmployeeResultController.class.getName()); + + // エラーメッセージ用の定数フィールド + private final static String SEVERE_ERROR_MESSAGE = "エラーが発生しました!"; + + HttpSession httpSession; + SearchEmployee searchEmployee; + UpdateEmployee updateEmployee; + + @Autowired + public UpdatePersonalEmployeeResultController(HttpSession httpSession, SearchEmployee searchEmployee, UpdateEmployee updateEmployee) { + this.httpSession = httpSession; + this.searchEmployee = searchEmployee; + this.updateEmployee = updateEmployee; + } + + /** + * メールアドレスの重複チェック + * + * @param employeeList 元の employeeList + * @param updatePersonalUserForm 更新対象のデータ + * @return true:重複無し false:重複あり + */ + private static boolean checkDuplicateMailAddress(List employeeList, UpdatePersonalUserForm updatePersonalUserForm) { + // メールアドレスが既に使われていた場合 + if (!employeeList.isEmpty()) { + // 更新対象のデータと同じIDの場合は重複していないとみなす + return Objects.equals(employeeList.get(0).getIdEmployee(), updatePersonalUserForm.getIdEmployee()); + } + return true; + } + + @ModelAttribute + public UpdatePersonalUserForm personalUpdateUserForm() { + return new UpdatePersonalUserForm(); + } + + /** + * 個人情報更新結果画面表示処理 + * + * @param updatePersonalUserForm 個人情報更新画面のフォーム + * @param model ビューにデータを渡すためのコンテナ + * @return 遷移先の画面 + */ + @PermissionCheck + @SessionCheck + @RequestMapping(value = TransitionTargetPageNameKeyword.PERSONAL_UPDATE_RESULT, method = RequestMethod.POST) + public String personalEmployeeUpdateResult(UpdatePersonalUserForm updatePersonalUserForm, Model model) { + + final String NOTHING = "項目が空欄です。"; + final String DUPLICATION = "既に登録済みのメールアドレスです。"; + + try { + + // 更新完了画面からの遷移の場合 + if (updatePersonalUserForm.getIdEmployee() == null) { + // ログイン者の情報を取得 + LoginUserForm loginUserForm = (LoginUserForm) httpSession.getAttribute(SessionKeyword.LOGIN_USER); + // ログイン者の情報を元に個人情報更新画面の初期表示用のインスタンスを作成 + model.addAttribute(PageReturnAttributeKeyword.UPDATE_PERSONAL_EMPLOYEE_USER_FORM, UpdatePersonalUserForm.convertFrom(searchEmployee.searchLoginUser(loginUserForm.getMailAddress()))); + + return TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML; + } + + // パスワードが仕様を満たしているかチェック + String error = UpdatePersonalUserForm.validatePassword( + updatePersonalUserForm.getPassword(), + updatePersonalUserForm.getPasswordConfirm() + ); + + // エラーがあるか + if (!error.isBlank()) { + // エラーが有る場合メッセージをセットして個人情報更新入力画面に遷移 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(error)); + model.addAttribute(PageReturnAttributeKeyword.UPDATE_PERSONAL_EMPLOYEE_USER_FORM, updatePersonalUserForm); + + return TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML; + } + + // 入力必須を満たしているか + if (!UpdatePersonalUserForm.hasErrorParameter(updatePersonalUserForm)) { + // 満たしていない場合、メッセージをセットして個人情報更新入力画面に遷移 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(NOTHING)); + model.addAttribute(PageReturnAttributeKeyword.UPDATE_PERSONAL_EMPLOYEE_USER_FORM, updatePersonalUserForm); + + return TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML; + } + + // メールアドレス重複チェック + if (!checkDuplicateMailAddress( + searchEmployee.searchEmployee(updatePersonalUserForm.getMailAddress()), + updatePersonalUserForm) + ) { + // メールアドレスが既に使われていた場合 + // 個人情報更新ページに遷移 + model.addAttribute(PageReturnAttributeKeyword.MESSAGE_ERROR, new MessageForm(DUPLICATION)); + model.addAttribute(PageReturnAttributeKeyword.UPDATE_PERSONAL_EMPLOYEE_USER_FORM, updatePersonalUserForm); + + return TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML; + } + + //更新前のEmployeeの情報を取得 + // 画面用のインスタンスから更新用のインスタンスに変換し、Update実施 + updateEmployee.updateEmployee( + searchEmployee.searchEmployeeByIdEmployee(updatePersonalUserForm.getIdEmployee()), + UpdatePersonalUserForm.convertTo(updatePersonalUserForm) + ); + + // ログイン者の情報をセッション情報に格納 + httpSession.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + searchEmployee.searchLoginUser(updatePersonalUserForm.getMailAddress())) + ); + + // 更新結果画面に遷移 + return TransitionTargetPageNameKeyword.UPDATE_PERSONAL_RESULT_HTML; + + } catch (Exception e) { + // ログイン情報の破棄 + httpSession.invalidate(); + + // エラーログ出力 + LOGGER.log(Level.SEVERE, SEVERE_ERROR_MESSAGE, e); + // エラー画面遷移 + return TransitionTargetPageNameKeyword.ERROR_HTML; + } + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/PageReturnAttributeKeyword.java b/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/PageReturnAttributeKeyword.java new file mode 100644 index 0000000..5e9ec04 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/PageReturnAttributeKeyword.java @@ -0,0 +1,18 @@ +package com.example.rhizome.app.presentation.controller.pageproperty; + +/** + * Servlet から Servlet に返却する際に使用する文字列を管理するクラス + */ +public class PageReturnAttributeKeyword { + + public static final String MESSAGE_ERROR = "messageError"; + public static final String MESSAGE_INFO = "messageInfo"; + + public static final String DEPARTMENT_FORM_LIST = "departmentFormList"; + public static final String UPDATE_EMPLOYEE_INFO_FORM = "updateEmployeeInfoForm"; + public static final String INSERT_EMPLOYEE_FORM = "insertEmployeeForm"; + public static final String LOGIN_INFO_FORM = "loginInfoForm"; + public static final String UPDATE_PERSONAL_EMPLOYEE_USER_FORM = "updatePersonalEmployeeUserForm"; + public static final String EMPLOYEE_INFO_FORM_LIST = "employeeInfoFormList"; + +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/SessionKeyword.java b/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/SessionKeyword.java new file mode 100644 index 0000000..39066c2 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/SessionKeyword.java @@ -0,0 +1,9 @@ +package com.example.rhizome.app.presentation.controller.pageproperty; + +/** + * Sessionキーを管理する + */ +public class SessionKeyword { + // SESSION情報として格納したいログイン者の情報 + public static final String LOGIN_USER = "loginUser"; +} diff --git a/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/TransitionTargetPageNameKeyword.java b/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/TransitionTargetPageNameKeyword.java new file mode 100644 index 0000000..90ded96 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/controller/pageproperty/TransitionTargetPageNameKeyword.java @@ -0,0 +1,93 @@ +package com.example.rhizome.app.presentation.controller.pageproperty; + +import java.util.Set; + +/** + * システムで利用しているJSPのリスト + */ +public class TransitionTargetPageNameKeyword { + + // 共通 + public static final String LOGIN_HTML = "login"; + + // 一般向け + public static final String UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML = "updatePersonalEmployeeInput"; + public static final String UPDATE_PERSONAL_RESULT_HTML = "updatePersonalEmployeeResult"; + + // 管理者向け + public static final String MENU_HTML = "menu"; + public static final String SELECT_EMPLOYEE_HTML = "selectEmployee"; + public static final String INSERT_EMPLOYEE_INPUT_HTML = "insertEmployeeInput"; + public static final String INSERT_EMPLOYEE_CONFIRM_HTML = "insertEmployeeConfirm"; + public static final String INSERT_EMPLOYEE_RESULT_HTML = "insertEmployeeResult"; + public static final String UPDATE_EMPLOYEE_INPUT_HTML = "updateEmployeeInput"; + + public static final String ERROR_HTML = "error"; + + // 共通(Controller) + public static final String INDEX_BLANK = ""; + public static final String INDEX_SLASH = "/"; + public static final String INDEX_LOGIN = "/login"; + public static final String LOGOUT = "/logout"; + public static final String DO_LOGIN = "/doLogin"; + + // 一般向け(Controller) + public static final String PERSONAL_UPDATE_RESULT = "/updatePersonalEmployeeResult"; + + // 管理者向け(Controller) + public static final String DELETE_EMPLOYEE = "/deleteEmployee"; + public static final String INSERT_EMPLOYEE_INPUT = "/insertEmployeeInput"; + public static final String INSERT_EMPLOYEE_CONFIRM = "/insertEmployeeConfirm"; + public static final String INSERT_EMPLOYEE = "/insertEmployee"; + public static final String SHOW_MENU = "/showMenu"; + public static final String SELECT_EMPLOYEE_INFO = "/selectEmployeeInfo"; + public static final String SELECT_EMPLOYEE_INFO_FORM_EMPTY = "/selectAll"; + public static final String SHOW_UPDATE_EMPLOYEE = "/showUpdateEmployee"; + public static final String UPDATE_EMPLOYEE_RESULT = "/updateEmployeeResult"; + + // Department + // HTML + // Controller + + /** + * 管理者向けのページリストを返す + * + * @return 管理者向けのページリスト + */ + public static Set getAdminPageList() { + + return Set.of( + INDEX_BLANK, + INDEX_SLASH, + INDEX_LOGIN, + LOGOUT, + DO_LOGIN, + DELETE_EMPLOYEE, + INSERT_EMPLOYEE_INPUT, + INSERT_EMPLOYEE_CONFIRM, + INSERT_EMPLOYEE, + SHOW_MENU, + SELECT_EMPLOYEE_INFO, + SELECT_EMPLOYEE_INFO_FORM_EMPTY, + SHOW_UPDATE_EMPLOYEE, + UPDATE_EMPLOYEE_RESULT + ); + } + + /** + * 一般向けのページリストを返す + * + * @return 一般向けのページリスト + */ + public static Set getUserPageList() { + return Set.of( + INDEX_BLANK, + INDEX_SLASH, + INDEX_LOGIN, + LOGOUT, + DO_LOGIN, + PERSONAL_UPDATE_RESULT + ); + } + +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/DepartmentForm.java b/src/main/java/com/example/rhizome/app/presentation/form/DepartmentForm.java new file mode 100644 index 0000000..6648423 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/DepartmentForm.java @@ -0,0 +1,47 @@ +package com.example.rhizome.app.presentation.form; + +import com.example.rhizome.app.domain.model.Department; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 画面の表示に使う部署コード管理用のクラス + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DepartmentForm { + /** + * 部署ID + */ + private Integer idDepartment; + /** + * 部署名 + */ + private String nmDepartment; + + /** + * business 層の Department クラスから画面用(presentation 層)の DepartmentForm に + * 変換します。 + * + * @param department business 層の Department インスタンス + * @return 画面用(presentation 層)の DepartmentForm インスタンス + */ + public static DepartmentForm convertFrom(Department department) { + return new DepartmentForm(department.getIdDepartment(), department.getNmDepartment()); + } + + /** + * business 層の Department クラスから画面用(presentation 層)の DepartmentForm に + * 変換します。(リスト版) + * + * @param departmentList business 層の Department インスタンスのリスト + * @return 画面用(presentation 層)の DepartmentForm インスタンスのリスト + */ + public static List convertFrom(List departmentList) { + return departmentList.stream().map(DepartmentForm::convertFrom).toList(); + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/EmployeeInfoForm.java b/src/main/java/com/example/rhizome/app/presentation/form/EmployeeInfoForm.java new file mode 100644 index 0000000..ed8996a --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/EmployeeInfoForm.java @@ -0,0 +1,82 @@ +package com.example.rhizome.app.presentation.form; + + +import com.example.rhizome.app.domain.model.EmployeeInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 画面に表示するために employee と department を Join した構造を扱うクラス + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class EmployeeInfoForm { + + /** + * 社員ID + */ + private Integer idEmployee; + /** + * 社員名 + */ + private String nmEmployee; + /** + * 社員名カナ + */ + private String knEmployee; + /** + * メールアドレス + */ + private String mailAddress; + /** + * パスワード + */ + private String password; + /** + * パスワード + */ + private Integer adminAuth; + /** + * 部署ID + */ + private Integer idDepartment; + /** + * 部署名 + */ + private String nmDepartment; + + /** + * business 層の EmployeeInfo クラスから画面用(presentation 層)の EmployeeInfoForm に + * 変換します。 + * + * @param employeeInfo business 層の EmployeeInfo インスタンス + * @return クラスから画面用(presentation 層)の EmployeeInfoForm インスタンス + */ + public static EmployeeInfoForm convertFrom(EmployeeInfo employeeInfo) { + return new EmployeeInfoForm( + employeeInfo.getEmployee().getIdEmployee(), + employeeInfo.getEmployee().getNmEmployee(), + employeeInfo.getEmployee().getKnEmployee(), + employeeInfo.getEmployee().getMailAddress(), + employeeInfo.getEmployee().getPassword(), + employeeInfo.getEmployee().getAdminAuth(), + employeeInfo.getDepartment().getIdDepartment(), + employeeInfo.getDepartment().getNmDepartment() + ); + } + + /** + * business 層の EmployeeInfo クラスから画面用(presentation 層)の EmployeeInfoForm に + * 変換します。(リスト版) + * + * @param employeeInfoList business 層の EmployeeInfo インスタンスのリスト + * @return クラスから画面用(presentation 層)の EmployeeInfoForm インスタンスのリスト + */ + public static List convertFrom(List employeeInfoList) { + return employeeInfoList.stream().map(EmployeeInfoForm::convertFrom).toList(); + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/InsertEmployeeForm.java b/src/main/java/com/example/rhizome/app/presentation/form/InsertEmployeeForm.java new file mode 100644 index 0000000..5261142 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/InsertEmployeeForm.java @@ -0,0 +1,152 @@ +package com.example.rhizome.app.presentation.form; + +import com.example.rhizome.app.domain.model.Employee; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * 画面から渡ってきた登録内容をまとめ、再度画面に表示する為のクラス + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class InsertEmployeeForm { + + /** + * 社員名 + */ + private String nmEmployee; + + /** + * 社員名カナ + */ + private String knEmployee; + + /** + * メールアドレス + */ + private String mailAddress; + + /** + * パスワード + */ + private String password; + + /** + * 確認用パスワード + */ + private String passwordConfirm; + + /** + * 管理者権限 + */ + private Integer adminAuth; + + /** + * 部署ID + */ + private Integer idDepartment; + + /** + * パスワードのValidation + * チェック対象にエラーが有った場合エラーリストに文言を追加する + * + * @param password 登録対象のパスワード + * @param passwordConfirm 登録対象のパスワード再入力 + * @param error エラーリスト + */ + private static void checkPassword(String password, String passwordConfirm, List error) { + final String PASSWORD_NULL_BLANK = "パスワード が未入力です。"; + final String PASSWORD_CONFIRM_NULL_BLANK = "パスワード確認用 が未入力です。"; + final String PASSWORD_MISMATCH = "パスワード と パスワード確認用 が一致しません。"; + + if (isNullOrBlank(password)) { + error.add(PASSWORD_NULL_BLANK); + return; + } + if (isNullOrBlank(passwordConfirm)) { + error.add(PASSWORD_CONFIRM_NULL_BLANK); + return; + } + + if (!password.equals(passwordConfirm)) { + error.add(PASSWORD_MISMATCH); + } + } + + /** + * 仮引数を null or 空 判定する + * + * @param str 判定対象の文字列 + * @return true:null or 空 false:null or 空 では無い + */ + private static boolean isNullOrBlank(String str) { + if (null == str) { + return true; + } + + return str.isBlank(); + } + + /** + * 画面から渡ってきた登録内容をまとめ、ビジネスモデルに変換 + * + * @param insertEmployeeForm 画面から渡ってきた登録内容 + * @return ビジネスモデルのインスタンス + */ + public static Employee convertTo(InsertEmployeeForm insertEmployeeForm) { + return new Employee( + null, + insertEmployeeForm.getNmEmployee(), + insertEmployeeForm.getKnEmployee(), + insertEmployeeForm.getMailAddress(), + insertEmployeeForm.getPassword(), + insertEmployeeForm.getAdminAuth(), + insertEmployeeForm.getIdDepartment() + ); + } + + /** + * 登録データのValidationを行う + * + * @return エラーが有った場合はエラー文言、無ければ空のリストが返る + */ + public List validateParameter() { + final String EMPLOYEE_NAME_NULL_BLANK = "社員名"; + final String EMPLOYEE_KANA_NULL_BLANK = "社員名フリガナ"; + final String MAIL_ADDRESS_NULL_BLANK = "メールアドレス"; + final String MANAGEMENT_ERROR = "管理者権限指定"; + final String DEPARTMENT_ID_NULL_BLANK = "所属部署"; + + List error = new ArrayList<>(); + + if (isNullOrBlank(nmEmployee)) { + error.add(EMPLOYEE_NAME_NULL_BLANK); + } + if (isNullOrBlank(knEmployee)) { + error.add(EMPLOYEE_KANA_NULL_BLANK); + } + if (isNullOrBlank(mailAddress)) { + error.add(MAIL_ADDRESS_NULL_BLANK); + } + + // パスワードが仕様を満たしているか確認 + checkPassword(password, passwordConfirm, error); + + if (adminAuth == null) { + error.add(MANAGEMENT_ERROR); + } + + if (idDepartment == null) { + error.add(DEPARTMENT_ID_NULL_BLANK); + } + + return error; + + } + +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/LoginInfoForm.java b/src/main/java/com/example/rhizome/app/presentation/form/LoginInfoForm.java new file mode 100644 index 0000000..94104d7 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/LoginInfoForm.java @@ -0,0 +1,23 @@ +package com.example.rhizome.app.presentation.form; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * ログインを試みる人を表現するモデルクラスです + */ + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LoginInfoForm { + /** + * メールアドレス + */ + private String mailAddress; + /** + * パスワード + */ + private String password; +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/LoginUserForm.java b/src/main/java/com/example/rhizome/app/presentation/form/LoginUserForm.java new file mode 100644 index 0000000..00dbab3 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/LoginUserForm.java @@ -0,0 +1,113 @@ +package com.example.rhizome.app.presentation.form; + + +import com.example.rhizome.app.domain.model.LoginUser; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LoginUserForm { + /** + * 社員ID + */ + private Integer idEmployee; + /** + * 社員名 + */ + private String nmEmployee; + /** + * 社員名カナ + */ + private String knEmployee; + /** + * メールアドレス + */ + private String mailAddress; + /** + * パスワード + */ + private String password; + + /** + * 管理者権限 + */ + private Integer adminAuth; + + /** + * 部署ID + */ + private Integer idDepartment; + + /** + * business 層の LoginUser クラスから画面用(presentation 層)の LoginUserForm に + * 変換します。 + * + * @param loginUser business 層の LoginUser インスタンス + * @return クラスから画面用(presentation 層)の LoginUserForm + */ + public static LoginUserForm convertFrom(LoginUser loginUser) { + return new LoginUserForm( + loginUser.getIdEmployee(), + loginUser.getNmEmployee(), + loginUser.getKnEmployee(), + loginUser.getMailAddress(), + loginUser.getPassword(), + loginUser.getAdminAuth(), + loginUser.getIdDepartment() + ); + } + + /** + * 画面用(presentation 層)の LoginUserForm クラスから business 層の LoginUser クラスに + * 変換します。 + * + * @param loginUserForm 画面用(presentation 層)の LoginUserForm インスタンス + * @return business 層の LoginUser インスタンス + */ + public static LoginUser convertTo(LoginUserForm loginUserForm) { + return new LoginUser( + loginUserForm.getIdEmployee(), + loginUserForm.getNmEmployee(), + loginUserForm.getKnEmployee(), + loginUserForm.getMailAddress(), + loginUserForm.getPassword(), + loginUserForm.getAdminAuth(), + loginUserForm.getIdDepartment() + ); + } + + /** + * 画面から渡ってきた必須の値が仕様を満たしているか確認 + * + * @param loginInfoForm 画面から渡ってきた mailAddress, password を格納しているインスタンス + * @return true:仕様を満たしている , false:仕様を満たしていない + */ + public static boolean checkParameter(LoginInfoForm loginInfoForm) { + if (null == loginInfoForm.getMailAddress()) { + return false; + } + + if (loginInfoForm.getMailAddress().isBlank()) { + return false; + } + + if (null == loginInfoForm.getPassword()) { + return false; + } + + return !loginInfoForm.getPassword().isBlank(); + + } + + /** + * 管理者権限を持っているか確認 + * + * @return true:管理者権限を持っている , false:管理者権限を持っていない + */ + public boolean isAdminUser() { + return getAdminAuth() == 1; + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/MessageForm.java b/src/main/java/com/example/rhizome/app/presentation/form/MessageForm.java new file mode 100644 index 0000000..2ea9ca6 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/MessageForm.java @@ -0,0 +1,15 @@ +package com.example.rhizome.app.presentation.form; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 画面に表示するエラーメッセージを管理するクラスです。 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class MessageForm { + private String message; +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/SearchConditionEmployeeForm.java b/src/main/java/com/example/rhizome/app/presentation/form/SearchConditionEmployeeForm.java new file mode 100644 index 0000000..3a03401 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/SearchConditionEmployeeForm.java @@ -0,0 +1,70 @@ +package com.example.rhizome.app.presentation.form; + +import com.example.rhizome.app.domain.model.SearchConditionEmployee; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 画面から渡ってきた検索条件をまとめ、再度画面に表示する為のクラス + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SearchConditionEmployeeForm { + + /** + * 社員ID + */ + private Integer idEmployee; + /** + * 社員名 + */ + private String nmEmployee; + /** + * 社員名カナ + */ + private String knEmployee; + /** + * メールアドレス + */ + private String mailAddress; + /** + * 部署ID + */ + private Integer idDepartment; + + /** + * business 層の SearchConditionEmployee クラスから画面用(presentation 層)の SearchConditionEmployeeForm に + * 変換します。 + * + * @param searchConditionEmployee business 層の SearchConditionEmployee インスタンス + * @return 画面用(presentation 層)の SearchConditionEmployeeForm インスタンス + */ + public static SearchConditionEmployeeForm convertFrom(SearchConditionEmployee searchConditionEmployee) { + return new SearchConditionEmployeeForm( + searchConditionEmployee.getIdEmployee(), + searchConditionEmployee.getNmEmployee(), + searchConditionEmployee.getKnEmployee(), + searchConditionEmployee.getMailAddress(), + searchConditionEmployee.getIdDepartment() + ); + } + + /** + * 画面用(presentation 層)の SearchConditionEmployeeForm クラスから business 層の SearchConditionEmployee クラスに + * 変換します。 + * + * @param searchConditionEmployeeForm 画面用(presentation 層)の SearchConditionEmployeeForm インスタンス + * @return business 層の SearchConditionEmployee インスタンス + */ + public static SearchConditionEmployee convertTo(SearchConditionEmployeeForm searchConditionEmployeeForm) { + return new SearchConditionEmployee( + searchConditionEmployeeForm.getIdEmployee(), + searchConditionEmployeeForm.getNmEmployee(), + searchConditionEmployeeForm.getKnEmployee(), + searchConditionEmployeeForm.getMailAddress(), + searchConditionEmployeeForm.getIdDepartment() + ); + } +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/UpdateEmployeeInfoForm.java b/src/main/java/com/example/rhizome/app/presentation/form/UpdateEmployeeInfoForm.java new file mode 100644 index 0000000..9a42815 --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/UpdateEmployeeInfoForm.java @@ -0,0 +1,192 @@ +package com.example.rhizome.app.presentation.form; + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.EmployeeInfo; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 画面から渡ってきた更新内容をまとめ、再度画面に表示する為のクラス + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UpdateEmployeeInfoForm { + + /** + * 社員ID + */ + private Integer idEmployee; + /** + * 社員名 + */ + private String nmEmployee; + /** + * 社員名カナ + */ + private String knEmployee; + /** + * メールアドレス + */ + private String mailAddress; + /** + * パスワード + */ + private String password; + /** + * パスワード確認用 + */ + private String passwordConfirm; + /** + * 管理者権限 + */ + private Integer adminAuth; + /** + * 部署ID + */ + private Integer idDepartment; + + /** + * business 層の EmployeeInfo クラスから画面用(presentation 層)の UpdateEmployeeInfoForm に + * 変換します。 + * + * @param employeeInfo business 層の EmployeeInfo インスタンス + * @return 画面用(presentation 層)の UpdateEmployeeInfoForm インスタンス + */ + public static UpdateEmployeeInfoForm convertFrom(EmployeeInfo employeeInfo) { + return new UpdateEmployeeInfoForm( + employeeInfo.getEmployee().getIdEmployee(), + employeeInfo.getEmployee().getNmEmployee(), + employeeInfo.getEmployee().getKnEmployee(), + employeeInfo.getEmployee().getMailAddress(), + employeeInfo.getEmployee().getPassword(), + null, + employeeInfo.getEmployee().getAdminAuth(), + employeeInfo.getDepartment().getIdDepartment() + ); + } + + /** + * business 層の EmployeeInfo クラスから画面用(presentation 層)の UpdateEmployeeInfoForm に + * 変換します。(リスト版) + * + * @param employeeInfoList business 層の EmployeeInfo インスタンスのリスト + * @return 画面用(presentation 層)の UpdateEmployeeInfoForm インスタンスのリスト + */ + public static List convertFrom(List employeeInfoList) { + return employeeInfoList.stream().map(UpdateEmployeeInfoForm::convertFrom).toList(); + } + + /** + * 画面用(presentation 層)の UpdateEmployeeInfoForm クラスから business 層の Employee クラスに + * 変換します。 + * + * @param updateEmployeeInfoForm 画面用(presentation 層)の UpdateEmployeeInfoForm インスタンス + * @return business 層の Employee インスタンス + */ + public static Employee convertTo(UpdateEmployeeInfoForm updateEmployeeInfoForm) { + return new Employee( + updateEmployeeInfoForm.getIdEmployee(), + updateEmployeeInfoForm.getNmEmployee(), + updateEmployeeInfoForm.getKnEmployee(), + updateEmployeeInfoForm.getMailAddress(), + updateEmployeeInfoForm.getPassword(), + updateEmployeeInfoForm.getAdminAuth(), + updateEmployeeInfoForm.getIdDepartment() + ); + } + + /** + * 画面から渡ってきたパラメータのチェック + * + * @param updateEmployeeInfoForm 画面から渡ってきたパラメータ + * @return true: エラー無し false:エラーあり(必須を満たしていない) + */ + public static boolean hasErrorParameter(UpdateEmployeeInfoForm updateEmployeeInfoForm) { + + boolean errorFlag = !isNullOrBlank(updateEmployeeInfoForm.getNmEmployee()); + + if (!isNullOrBlank(updateEmployeeInfoForm.getKnEmployee())) { + errorFlag = true; + } + if (!isNullOrBlank(updateEmployeeInfoForm.getMailAddress())) { + errorFlag = true; + } + if (!isNullOrBlank(updateEmployeeInfoForm.getPassword())) { + errorFlag = true; + } + + + return errorFlag; + } + + /** + * パスワードの仕様チェック + * パスワードが仕様を満たしてないか確認 + * + * @param password 更新対象のパスワード + * @param passwordConfirm 更新対象の確認用パスワード + * @return 空文字: エラー無し それ以外:エラー内容 + */ + public static String validatePassword(String password, String passwordConfirm) { + + final String ERROR = "パスワードが一致していません"; + + if (areBothBlank(password, passwordConfirm)) { + // どちらもnullまたは空白の場合はOK + return ""; + } + + // どちらかがnullまたは空白の場合のエラーハンドリング + if (isEitherBlank(password, passwordConfirm)) { + return ERROR; + } + + // 値が異なった場合はエラーハンドリング + if (!password.equals(passwordConfirm)) { + return ERROR; + } + return ""; + + } + + /** + * 仮引数を null or 空 判定する + * + * @param str 判定対象の文字列 + * @return true:null or 空 false:null or 空 では無い + */ + private static boolean isNullOrBlank(String str) { + if (null == str) { + return true; + } + return str.isBlank(); + } + + /** + * パスワードが今回更新対象に含まれているかチェック + * + * @param password 更新対象のパスワード + * @param passwordConfirm 更新対象の確認用パスワード + * @return true:どちらもnullまたは空白の場合 false:それ以外 + */ + private static boolean areBothBlank(String password, String passwordConfirm) { + return (password == null || password.isBlank()) && (passwordConfirm == null || passwordConfirm.isBlank()); + } + + /** + * パスワードが今回更新対象に含まれているかチェック その2 + * + * @param password 更新対象のパスワード + * @param passwordConfirm 更新対象の確認用パスワード + * @return true: 問題なし false:どちらかがnullまたは空白の場合 + */ + // どちらかがnullまたは空白の場合のエラーハンドリング + private static boolean isEitherBlank(String password, String passwordConfirm) { + return password == null || password.isBlank() || passwordConfirm == null || passwordConfirm.isBlank(); + } + +} diff --git a/src/main/java/com/example/rhizome/app/presentation/form/UpdatePersonalUserForm.java b/src/main/java/com/example/rhizome/app/presentation/form/UpdatePersonalUserForm.java new file mode 100644 index 0000000..279e40b --- /dev/null +++ b/src/main/java/com/example/rhizome/app/presentation/form/UpdatePersonalUserForm.java @@ -0,0 +1,185 @@ +package com.example.rhizome.app.presentation.form; + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.LoginUser; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 個人情報更新画面のフォームクラスです。 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UpdatePersonalUserForm { + /** + * 社員ID + */ + private Integer idEmployee; + /** + * 社員名 + */ + private String nmEmployee; + /** + * 社員名カナ + */ + private String knEmployee; + /** + * メールアドレス + */ + private String mailAddress; + /** + * パスワード + */ + private String password; + /** + * パスワード確認用 + */ + private String passwordConfirm; + + + /** + * 画面用(presentation 層)の UpdatePersonalUserForm クラスから business 層の Employee クラスに + * 変換します。 + * + * @param updatePersonalUserForm 画面用(presentation 層)の UpdatePersonalUserForm インスタンス + * @return business 層の Employee インスタンス + */ + public static Employee convertTo(UpdatePersonalUserForm updatePersonalUserForm) { + return new Employee( + updatePersonalUserForm.getIdEmployee(), + updatePersonalUserForm.getNmEmployee(), + updatePersonalUserForm.getKnEmployee(), + updatePersonalUserForm.getMailAddress(), + updatePersonalUserForm.getPassword(), + null, + null + ); + } + + /** + * business 層の Employee クラスから画面用(presentation 層)の UpdatePersonalUserForm に + * 変換します。(リスト版) + * + * @param employee business 層の employee インスタンスのリスト + * @return クラスから画面用(presentation 層)の UpdatePersonalUserForm インスタンスのリスト + */ + public static UpdatePersonalUserForm convertFrom(Employee employee) { + return new UpdatePersonalUserForm( + employee.getIdEmployee(), + employee.getNmEmployee(), + employee.getKnEmployee(), + employee.getMailAddress(), + employee.getPassword(), + null + ); + } + + /** + * business 層の Employee クラスから画面用(presentation 層)の UpdatePersonalUserForm に + * 変換します。(リスト版) + * + * @param loginUser business 層の loginUser インスタンスのリスト + * @return クラスから画面用(presentation 層)の UpdatePersonalUserForm インスタンスのリスト + */ + public static UpdatePersonalUserForm convertFrom(LoginUser loginUser) { + return new UpdatePersonalUserForm( + loginUser.getIdEmployee(), + loginUser.getNmEmployee(), + loginUser.getKnEmployee(), + loginUser.getMailAddress(), + loginUser.getPassword(), + null + ); + } + + /** + * 画面から渡ってきたパラメータのチェック + * + * @param updatePersonalUserForm 画面から渡ってきたパラメータ + * @return true: エラー無し false:エラーあり(必須を満たしていない) + */ + public static boolean hasErrorParameter(UpdatePersonalUserForm updatePersonalUserForm) { + + boolean errorFlag = !isNullOrBlank(updatePersonalUserForm.getNmEmployee()); + + if (!isNullOrBlank(updatePersonalUserForm.getKnEmployee())) { + errorFlag = true; + } + if (!isNullOrBlank(updatePersonalUserForm.getMailAddress())) { + errorFlag = true; + } + if (!isNullOrBlank(updatePersonalUserForm.getPassword())) { + errorFlag = true; + } + + + return errorFlag; + } + + /** + * パスワードの仕様チェック + * パスワードが仕様を満たしてないか確認 + * + * @param password 更新対象のパスワード + * @param passwordConfirm 更新対象の確認用パスワード + * @return 空文字: エラー無し それ以外:エラー内容 + */ + public static String validatePassword(String password, String passwordConfirm) { + + final String ERROR = "パスワードが一致していません"; + + if (areBothBlank(password, passwordConfirm)) { + // どちらもnullまたは空白の場合はOK + return ""; + } + + // どちらかがnullまたは空白の場合のエラーハンドリング + if (isEitherBlank(password, passwordConfirm)) { + return ERROR; + } + + // 値が異なった場合はエラーハンドリング + if (!password.equals(passwordConfirm)) { + return ERROR; + } + return ""; + + } + + /** + * 仮引数を null or 空 判定する + * + * @param str 判定対象の文字列 + * @return true:null or 空 false:null or 空 では無い + */ + private static boolean isNullOrBlank(String str) { + if (null == str) { + return true; + } + return str.isBlank(); + } + + /** + * パスワードが今回更新対象に含まれているかチェック + * + * @param password 更新対象のパスワード + * @param passwordConfirm 更新対象の確認用パスワード + * @return true:どちらもnullまたは空白の場合 false:それ以外 + */ + private static boolean areBothBlank(String password, String passwordConfirm) { + return (password == null || password.isBlank()) && (passwordConfirm == null || passwordConfirm.isBlank()); + } + + /** + * パスワードが今回更新対象に含まれているかチェック その2 + * + * @param password 更新対象のパスワード + * @param passwordConfirm 更新対象の確認用パスワード + * @return true: 問題なし false:どちらかがnullまたは空白の場合 + */ + private static boolean isEitherBlank(String password, String passwordConfirm) { + return password == null || password.isBlank() || passwordConfirm == null || passwordConfirm.isBlank(); + } +} diff --git a/src/main/java/com/example/rhizome/exception/InsufficientPermissionException.java b/src/main/java/com/example/rhizome/exception/InsufficientPermissionException.java new file mode 100644 index 0000000..934015a --- /dev/null +++ b/src/main/java/com/example/rhizome/exception/InsufficientPermissionException.java @@ -0,0 +1,12 @@ +package com.example.rhizome.exception; + +/** + * 権限不足の例外を表現するクラスです。 + */ +public class InsufficientPermissionException extends RuntimeException { + + public InsufficientPermissionException(String message) { + super(message); + } + +} diff --git a/src/main/java/com/example/rhizome/exception/NoSessionException.java b/src/main/java/com/example/rhizome/exception/NoSessionException.java new file mode 100644 index 0000000..258d7a5 --- /dev/null +++ b/src/main/java/com/example/rhizome/exception/NoSessionException.java @@ -0,0 +1,12 @@ +package com.example.rhizome.exception; + +/** + * 権限不足の例外を表現するクラスです。 + */ +public class NoSessionException extends RuntimeException { + + public NoSessionException(String message) { + super(message); + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..88b15aa --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.datasource.url=jdbc:mysql://localhost:3306/rezodb +spring.datasource.username=rezouser +spring.datasource.password=Rezo_0000 diff --git a/src/main/resources/static/css/all.css b/src/main/resources/static/css/all.css new file mode 100644 index 0000000..50cf460 --- /dev/null +++ b/src/main/resources/static/css/all.css @@ -0,0 +1,10563 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +.fa { + font-family: var(--fa-style-family, "Font Awesome 6 Free"); + font-weight: var(--fa-style, 900); +} + +.fa, +.fa-classic, +.fa-sharp, +.fas, +.fa-solid, +.far, +.fa-regular, +.fab, +.fa-brands { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: var(--fa-display, inline-block); + font-style: normal; + font-variant: normal; + line-height: 1; + text-rendering: auto; +} + +.fas, +.fa-classic, +.fa-solid, +.far, +.fa-regular { + font-family: 'Font Awesome 6 Free'; +} + +.fab, +.fa-brands { + font-family: 'Font Awesome 6 Brands'; +} + +.fa-1x { + font-size: 1em; +} + +.fa-2x { + font-size: 2em; +} + +.fa-3x { + font-size: 3em; +} + +.fa-4x { + font-size: 4em; +} + +.fa-5x { + font-size: 5em; +} + +.fa-6x { + font-size: 6em; +} + +.fa-7x { + font-size: 7em; +} + +.fa-8x { + font-size: 8em; +} + +.fa-9x { + font-size: 9em; +} + +.fa-10x { + font-size: 10em; +} + +.fa-2xs { + font-size: 0.625em; + line-height: 0.1em; + vertical-align: 0.225em; +} + +.fa-xs { + font-size: 0.75em; + line-height: 0.08333em; + vertical-align: 0.125em; +} + +.fa-sm { + font-size: 0.875em; + line-height: 0.07143em; + vertical-align: 0.05357em; +} + +.fa-lg { + font-size: 1.25em; + line-height: 0.05em; + vertical-align: -0.075em; +} + +.fa-xl { + font-size: 1.5em; + line-height: 0.04167em; + vertical-align: -0.125em; +} + +.fa-2xl { + font-size: 2em; + line-height: 0.03125em; + vertical-align: -0.1875em; +} + +.fa-fw { + text-align: center; + width: 1.25em; +} + +.fa-ul { + list-style-type: none; + margin-left: var(--fa-li-margin, 2.5em); + padding-left: 0; +} + +.fa-ul > li { + position: relative; +} + +.fa-li { + left: calc(var(--fa-li-width, 2em) * -1); + position: absolute; + text-align: center; + width: var(--fa-li-width, 2em); + line-height: inherit; +} + +.fa-border { + border-color: var(--fa-border-color, #eee); + border-radius: var(--fa-border-radius, 0.1em); + border-style: var(--fa-border-style, solid); + border-width: var(--fa-border-width, 0.08em); + padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); +} + +.fa-pull-left { + float: left; + margin-right: var(--fa-pull-margin, 0.3em); +} + +.fa-pull-right { + float: right; + margin-left: var(--fa-pull-margin, 0.3em); +} + +.fa-beat { + -webkit-animation-name: fa-beat; + animation-name: fa-beat; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); +} + +.fa-bounce { + -webkit-animation-name: fa-bounce; + animation-name: fa-bounce; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); +} + +.fa-fade { + -webkit-animation-name: fa-fade; + animation-name: fa-fade; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); +} + +.fa-beat-fade { + -webkit-animation-name: fa-beat-fade; + animation-name: fa-beat-fade; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); +} + +.fa-flip { + -webkit-animation-name: fa-flip; + animation-name: fa-flip; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); +} + +.fa-shake { + -webkit-animation-name: fa-shake; + animation-name: fa-shake; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); +} + +.fa-spin { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 2s); + animation-duration: var(--fa-animation-duration, 2s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); +} + +.fa-spin-reverse { + --fa-animation-direction: reverse; +} + +.fa-pulse, +.fa-spin-pulse { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, steps(8)); + animation-timing-function: var(--fa-animation-timing, steps(8)); +} + +@media (prefers-reduced-motion: reduce) { + .fa-beat, + .fa-bounce, + .fa-fade, + .fa-beat-fade, + .fa-flip, + .fa-pulse, + .fa-shake, + .fa-spin, + .fa-spin-pulse { + -webkit-animation-delay: -1ms; + animation-delay: -1ms; + -webkit-animation-duration: 1ms; + animation-duration: 1ms; + -webkit-animation-iteration-count: 1; + animation-iteration-count: 1; + -webkit-transition-delay: 0s; + transition-delay: 0s; + -webkit-transition-duration: 0s; + transition-duration: 0s; + } +} + +@-webkit-keyframes fa-beat { + 0%, 90% { + -webkit-transform: scale(1); + transform: scale(1); + } + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); + } +} + +@keyframes fa-beat { + 0%, 90% { + -webkit-transform: scale(1); + transform: scale(1); + } + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); + } +} + +@-webkit-keyframes fa-bounce { + 0% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + } + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + } + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + } + 57% { + -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + } + 64% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 100% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } +} + +@keyframes fa-bounce { + 0% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + } + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + } + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + } + 57% { + -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + } + 64% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 100% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } +} + +@-webkit-keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); + } +} + +@keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); + } +} + +@-webkit-keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); + } +} + +@keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); + } +} + +@-webkit-keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + } +} + +@keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + } +} + +@-webkit-keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); + } + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + 8%, 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); + } + 12%, 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); + } + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); + } + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); + } + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); + } + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); + } + 40%, 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); + } + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + 8%, 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); + } + 12%, 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); + } + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); + } + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); + } + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); + } + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); + } + 40%, 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.fa-rotate-90 { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +.fa-rotate-180 { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} + +.fa-rotate-270 { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); +} + +.fa-flip-horizontal { + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); +} + +.fa-flip-vertical { + -webkit-transform: scale(1, -1); + transform: scale(1, -1); +} + +.fa-flip-both, +.fa-flip-horizontal.fa-flip-vertical { + -webkit-transform: scale(-1, -1); + transform: scale(-1, -1); +} + +.fa-rotate-by { + -webkit-transform: rotate(var(--fa-rotate-angle, none)); + transform: rotate(var(--fa-rotate-angle, none)); +} + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; +} + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; + z-index: var(--fa-stack-z-index, auto); +} + +.fa-stack-1x { + line-height: inherit; +} + +.fa-stack-2x { + font-size: 2em; +} + +.fa-inverse { + color: var(--fa-inverse, #fff); +} + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ + +.fa-0::before { + content: "\30"; +} + +.fa-1::before { + content: "\31"; +} + +.fa-2::before { + content: "\32"; +} + +.fa-3::before { + content: "\33"; +} + +.fa-4::before { + content: "\34"; +} + +.fa-5::before { + content: "\35"; +} + +.fa-6::before { + content: "\36"; +} + +.fa-7::before { + content: "\37"; +} + +.fa-8::before { + content: "\38"; +} + +.fa-9::before { + content: "\39"; +} + +.fa-fill-drip::before { + content: "\f576"; +} + +.fa-arrows-to-circle::before { + content: "\e4bd"; +} + +.fa-circle-chevron-right::before { + content: "\f138"; +} + +.fa-chevron-circle-right::before { + content: "\f138"; +} + +.fa-at::before { + content: "\40"; +} + +.fa-trash-can::before { + content: "\f2ed"; +} + +.fa-trash-alt::before { + content: "\f2ed"; +} + +.fa-text-height::before { + content: "\f034"; +} + +.fa-user-xmark::before { + content: "\f235"; +} + +.fa-user-times::before { + content: "\f235"; +} + +.fa-stethoscope::before { + content: "\f0f1"; +} + +.fa-message::before { + content: "\f27a"; +} + +.fa-comment-alt::before { + content: "\f27a"; +} + +.fa-info::before { + content: "\f129"; +} + +.fa-down-left-and-up-right-to-center::before { + content: "\f422"; +} + +.fa-compress-alt::before { + content: "\f422"; +} + +.fa-explosion::before { + content: "\e4e9"; +} + +.fa-file-lines::before { + content: "\f15c"; +} + +.fa-file-alt::before { + content: "\f15c"; +} + +.fa-file-text::before { + content: "\f15c"; +} + +.fa-wave-square::before { + content: "\f83e"; +} + +.fa-ring::before { + content: "\f70b"; +} + +.fa-building-un::before { + content: "\e4d9"; +} + +.fa-dice-three::before { + content: "\f527"; +} + +.fa-calendar-days::before { + content: "\f073"; +} + +.fa-calendar-alt::before { + content: "\f073"; +} + +.fa-anchor-circle-check::before { + content: "\e4aa"; +} + +.fa-building-circle-arrow-right::before { + content: "\e4d1"; +} + +.fa-volleyball::before { + content: "\f45f"; +} + +.fa-volleyball-ball::before { + content: "\f45f"; +} + +.fa-arrows-up-to-line::before { + content: "\e4c2"; +} + +.fa-sort-down::before { + content: "\f0dd"; +} + +.fa-sort-desc::before { + content: "\f0dd"; +} + +.fa-circle-minus::before { + content: "\f056"; +} + +.fa-minus-circle::before { + content: "\f056"; +} + +.fa-door-open::before { + content: "\f52b"; +} + +.fa-right-from-bracket::before { + content: "\f2f5"; +} + +.fa-sign-out-alt::before { + content: "\f2f5"; +} + +.fa-atom::before { + content: "\f5d2"; +} + +.fa-soap::before { + content: "\e06e"; +} + +.fa-icons::before { + content: "\f86d"; +} + +.fa-heart-music-camera-bolt::before { + content: "\f86d"; +} + +.fa-microphone-lines-slash::before { + content: "\f539"; +} + +.fa-microphone-alt-slash::before { + content: "\f539"; +} + +.fa-bridge-circle-check::before { + content: "\e4c9"; +} + +.fa-pump-medical::before { + content: "\e06a"; +} + +.fa-fingerprint::before { + content: "\f577"; +} + +.fa-hand-point-right::before { + content: "\f0a4"; +} + +.fa-magnifying-glass-location::before { + content: "\f689"; +} + +.fa-search-location::before { + content: "\f689"; +} + +.fa-forward-step::before { + content: "\f051"; +} + +.fa-step-forward::before { + content: "\f051"; +} + +.fa-face-smile-beam::before { + content: "\f5b8"; +} + +.fa-smile-beam::before { + content: "\f5b8"; +} + +.fa-flag-checkered::before { + content: "\f11e"; +} + +.fa-football::before { + content: "\f44e"; +} + +.fa-football-ball::before { + content: "\f44e"; +} + +.fa-school-circle-exclamation::before { + content: "\e56c"; +} + +.fa-crop::before { + content: "\f125"; +} + +.fa-angles-down::before { + content: "\f103"; +} + +.fa-angle-double-down::before { + content: "\f103"; +} + +.fa-users-rectangle::before { + content: "\e594"; +} + +.fa-people-roof::before { + content: "\e537"; +} + +.fa-people-line::before { + content: "\e534"; +} + +.fa-beer-mug-empty::before { + content: "\f0fc"; +} + +.fa-beer::before { + content: "\f0fc"; +} + +.fa-diagram-predecessor::before { + content: "\e477"; +} + +.fa-arrow-up-long::before { + content: "\f176"; +} + +.fa-long-arrow-up::before { + content: "\f176"; +} + +.fa-fire-flame-simple::before { + content: "\f46a"; +} + +.fa-burn::before { + content: "\f46a"; +} + +.fa-person::before { + content: "\f183"; +} + +.fa-male::before { + content: "\f183"; +} + +.fa-laptop::before { + content: "\f109"; +} + +.fa-file-csv::before { + content: "\f6dd"; +} + +.fa-menorah::before { + content: "\f676"; +} + +.fa-truck-plane::before { + content: "\e58f"; +} + +.fa-record-vinyl::before { + content: "\f8d9"; +} + +.fa-face-grin-stars::before { + content: "\f587"; +} + +.fa-grin-stars::before { + content: "\f587"; +} + +.fa-bong::before { + content: "\f55c"; +} + +.fa-spaghetti-monster-flying::before { + content: "\f67b"; +} + +.fa-pastafarianism::before { + content: "\f67b"; +} + +.fa-arrow-down-up-across-line::before { + content: "\e4af"; +} + +.fa-spoon::before { + content: "\f2e5"; +} + +.fa-utensil-spoon::before { + content: "\f2e5"; +} + +.fa-jar-wheat::before { + content: "\e517"; +} + +.fa-envelopes-bulk::before { + content: "\f674"; +} + +.fa-mail-bulk::before { + content: "\f674"; +} + +.fa-file-circle-exclamation::before { + content: "\e4eb"; +} + +.fa-circle-h::before { + content: "\f47e"; +} + +.fa-hospital-symbol::before { + content: "\f47e"; +} + +.fa-pager::before { + content: "\f815"; +} + +.fa-address-book::before { + content: "\f2b9"; +} + +.fa-contact-book::before { + content: "\f2b9"; +} + +.fa-strikethrough::before { + content: "\f0cc"; +} + +.fa-k::before { + content: "\4b"; +} + +.fa-landmark-flag::before { + content: "\e51c"; +} + +.fa-pencil::before { + content: "\f303"; +} + +.fa-pencil-alt::before { + content: "\f303"; +} + +.fa-backward::before { + content: "\f04a"; +} + +.fa-caret-right::before { + content: "\f0da"; +} + +.fa-comments::before { + content: "\f086"; +} + +.fa-paste::before { + content: "\f0ea"; +} + +.fa-file-clipboard::before { + content: "\f0ea"; +} + +.fa-code-pull-request::before { + content: "\e13c"; +} + +.fa-clipboard-list::before { + content: "\f46d"; +} + +.fa-truck-ramp-box::before { + content: "\f4de"; +} + +.fa-truck-loading::before { + content: "\f4de"; +} + +.fa-user-check::before { + content: "\f4fc"; +} + +.fa-vial-virus::before { + content: "\e597"; +} + +.fa-sheet-plastic::before { + content: "\e571"; +} + +.fa-blog::before { + content: "\f781"; +} + +.fa-user-ninja::before { + content: "\f504"; +} + +.fa-person-arrow-up-from-line::before { + content: "\e539"; +} + +.fa-scroll-torah::before { + content: "\f6a0"; +} + +.fa-torah::before { + content: "\f6a0"; +} + +.fa-broom-ball::before { + content: "\f458"; +} + +.fa-quidditch::before { + content: "\f458"; +} + +.fa-quidditch-broom-ball::before { + content: "\f458"; +} + +.fa-toggle-off::before { + content: "\f204"; +} + +.fa-box-archive::before { + content: "\f187"; +} + +.fa-archive::before { + content: "\f187"; +} + +.fa-person-drowning::before { + content: "\e545"; +} + +.fa-arrow-down-9-1::before { + content: "\f886"; +} + +.fa-sort-numeric-desc::before { + content: "\f886"; +} + +.fa-sort-numeric-down-alt::before { + content: "\f886"; +} + +.fa-face-grin-tongue-squint::before { + content: "\f58a"; +} + +.fa-grin-tongue-squint::before { + content: "\f58a"; +} + +.fa-spray-can::before { + content: "\f5bd"; +} + +.fa-truck-monster::before { + content: "\f63b"; +} + +.fa-w::before { + content: "\57"; +} + +.fa-earth-africa::before { + content: "\f57c"; +} + +.fa-globe-africa::before { + content: "\f57c"; +} + +.fa-rainbow::before { + content: "\f75b"; +} + +.fa-circle-notch::before { + content: "\f1ce"; +} + +.fa-tablet-screen-button::before { + content: "\f3fa"; +} + +.fa-tablet-alt::before { + content: "\f3fa"; +} + +.fa-paw::before { + content: "\f1b0"; +} + +.fa-cloud::before { + content: "\f0c2"; +} + +.fa-trowel-bricks::before { + content: "\e58a"; +} + +.fa-face-flushed::before { + content: "\f579"; +} + +.fa-flushed::before { + content: "\f579"; +} + +.fa-hospital-user::before { + content: "\f80d"; +} + +.fa-tent-arrow-left-right::before { + content: "\e57f"; +} + +.fa-gavel::before { + content: "\f0e3"; +} + +.fa-legal::before { + content: "\f0e3"; +} + +.fa-binoculars::before { + content: "\f1e5"; +} + +.fa-microphone-slash::before { + content: "\f131"; +} + +.fa-box-tissue::before { + content: "\e05b"; +} + +.fa-motorcycle::before { + content: "\f21c"; +} + +.fa-bell-concierge::before { + content: "\f562"; +} + +.fa-concierge-bell::before { + content: "\f562"; +} + +.fa-pen-ruler::before { + content: "\f5ae"; +} + +.fa-pencil-ruler::before { + content: "\f5ae"; +} + +.fa-people-arrows::before { + content: "\e068"; +} + +.fa-people-arrows-left-right::before { + content: "\e068"; +} + +.fa-mars-and-venus-burst::before { + content: "\e523"; +} + +.fa-square-caret-right::before { + content: "\f152"; +} + +.fa-caret-square-right::before { + content: "\f152"; +} + +.fa-scissors::before { + content: "\f0c4"; +} + +.fa-cut::before { + content: "\f0c4"; +} + +.fa-sun-plant-wilt::before { + content: "\e57a"; +} + +.fa-toilets-portable::before { + content: "\e584"; +} + +.fa-hockey-puck::before { + content: "\f453"; +} + +.fa-table::before { + content: "\f0ce"; +} + +.fa-magnifying-glass-arrow-right::before { + content: "\e521"; +} + +.fa-tachograph-digital::before { + content: "\f566"; +} + +.fa-digital-tachograph::before { + content: "\f566"; +} + +.fa-users-slash::before { + content: "\e073"; +} + +.fa-clover::before { + content: "\e139"; +} + +.fa-reply::before { + content: "\f3e5"; +} + +.fa-mail-reply::before { + content: "\f3e5"; +} + +.fa-star-and-crescent::before { + content: "\f699"; +} + +.fa-house-fire::before { + content: "\e50c"; +} + +.fa-square-minus::before { + content: "\f146"; +} + +.fa-minus-square::before { + content: "\f146"; +} + +.fa-helicopter::before { + content: "\f533"; +} + +.fa-compass::before { + content: "\f14e"; +} + +.fa-square-caret-down::before { + content: "\f150"; +} + +.fa-caret-square-down::before { + content: "\f150"; +} + +.fa-file-circle-question::before { + content: "\e4ef"; +} + +.fa-laptop-code::before { + content: "\f5fc"; +} + +.fa-swatchbook::before { + content: "\f5c3"; +} + +.fa-prescription-bottle::before { + content: "\f485"; +} + +.fa-bars::before { + content: "\f0c9"; +} + +.fa-navicon::before { + content: "\f0c9"; +} + +.fa-people-group::before { + content: "\e533"; +} + +.fa-hourglass-end::before { + content: "\f253"; +} + +.fa-hourglass-3::before { + content: "\f253"; +} + +.fa-heart-crack::before { + content: "\f7a9"; +} + +.fa-heart-broken::before { + content: "\f7a9"; +} + +.fa-square-up-right::before { + content: "\f360"; +} + +.fa-external-link-square-alt::before { + content: "\f360"; +} + +.fa-face-kiss-beam::before { + content: "\f597"; +} + +.fa-kiss-beam::before { + content: "\f597"; +} + +.fa-film::before { + content: "\f008"; +} + +.fa-ruler-horizontal::before { + content: "\f547"; +} + +.fa-people-robbery::before { + content: "\e536"; +} + +.fa-lightbulb::before { + content: "\f0eb"; +} + +.fa-caret-left::before { + content: "\f0d9"; +} + +.fa-circle-exclamation::before { + content: "\f06a"; +} + +.fa-exclamation-circle::before { + content: "\f06a"; +} + +.fa-school-circle-xmark::before { + content: "\e56d"; +} + +.fa-arrow-right-from-bracket::before { + content: "\f08b"; +} + +.fa-sign-out::before { + content: "\f08b"; +} + +.fa-circle-chevron-down::before { + content: "\f13a"; +} + +.fa-chevron-circle-down::before { + content: "\f13a"; +} + +.fa-unlock-keyhole::before { + content: "\f13e"; +} + +.fa-unlock-alt::before { + content: "\f13e"; +} + +.fa-cloud-showers-heavy::before { + content: "\f740"; +} + +.fa-headphones-simple::before { + content: "\f58f"; +} + +.fa-headphones-alt::before { + content: "\f58f"; +} + +.fa-sitemap::before { + content: "\f0e8"; +} + +.fa-circle-dollar-to-slot::before { + content: "\f4b9"; +} + +.fa-donate::before { + content: "\f4b9"; +} + +.fa-memory::before { + content: "\f538"; +} + +.fa-road-spikes::before { + content: "\e568"; +} + +.fa-fire-burner::before { + content: "\e4f1"; +} + +.fa-flag::before { + content: "\f024"; +} + +.fa-hanukiah::before { + content: "\f6e6"; +} + +.fa-feather::before { + content: "\f52d"; +} + +.fa-volume-low::before { + content: "\f027"; +} + +.fa-volume-down::before { + content: "\f027"; +} + +.fa-comment-slash::before { + content: "\f4b3"; +} + +.fa-cloud-sun-rain::before { + content: "\f743"; +} + +.fa-compress::before { + content: "\f066"; +} + +.fa-wheat-awn::before { + content: "\e2cd"; +} + +.fa-wheat-alt::before { + content: "\e2cd"; +} + +.fa-ankh::before { + content: "\f644"; +} + +.fa-hands-holding-child::before { + content: "\e4fa"; +} + +.fa-asterisk::before { + content: "\2a"; +} + +.fa-square-check::before { + content: "\f14a"; +} + +.fa-check-square::before { + content: "\f14a"; +} + +.fa-peseta-sign::before { + content: "\e221"; +} + +.fa-heading::before { + content: "\f1dc"; +} + +.fa-header::before { + content: "\f1dc"; +} + +.fa-ghost::before { + content: "\f6e2"; +} + +.fa-list::before { + content: "\f03a"; +} + +.fa-list-squares::before { + content: "\f03a"; +} + +.fa-square-phone-flip::before { + content: "\f87b"; +} + +.fa-phone-square-alt::before { + content: "\f87b"; +} + +.fa-cart-plus::before { + content: "\f217"; +} + +.fa-gamepad::before { + content: "\f11b"; +} + +.fa-circle-dot::before { + content: "\f192"; +} + +.fa-dot-circle::before { + content: "\f192"; +} + +.fa-face-dizzy::before { + content: "\f567"; +} + +.fa-dizzy::before { + content: "\f567"; +} + +.fa-egg::before { + content: "\f7fb"; +} + +.fa-house-medical-circle-xmark::before { + content: "\e513"; +} + +.fa-campground::before { + content: "\f6bb"; +} + +.fa-folder-plus::before { + content: "\f65e"; +} + +.fa-futbol::before { + content: "\f1e3"; +} + +.fa-futbol-ball::before { + content: "\f1e3"; +} + +.fa-soccer-ball::before { + content: "\f1e3"; +} + +.fa-paintbrush::before { + content: "\f1fc"; +} + +.fa-paint-brush::before { + content: "\f1fc"; +} + +.fa-lock::before { + content: "\f023"; +} + +.fa-gas-pump::before { + content: "\f52f"; +} + +.fa-hot-tub-person::before { + content: "\f593"; +} + +.fa-hot-tub::before { + content: "\f593"; +} + +.fa-map-location::before { + content: "\f59f"; +} + +.fa-map-marked::before { + content: "\f59f"; +} + +.fa-house-flood-water::before { + content: "\e50e"; +} + +.fa-tree::before { + content: "\f1bb"; +} + +.fa-bridge-lock::before { + content: "\e4cc"; +} + +.fa-sack-dollar::before { + content: "\f81d"; +} + +.fa-pen-to-square::before { + content: "\f044"; +} + +.fa-edit::before { + content: "\f044"; +} + +.fa-car-side::before { + content: "\f5e4"; +} + +.fa-share-nodes::before { + content: "\f1e0"; +} + +.fa-share-alt::before { + content: "\f1e0"; +} + +.fa-heart-circle-minus::before { + content: "\e4ff"; +} + +.fa-hourglass-half::before { + content: "\f252"; +} + +.fa-hourglass-2::before { + content: "\f252"; +} + +.fa-microscope::before { + content: "\f610"; +} + +.fa-sink::before { + content: "\e06d"; +} + +.fa-bag-shopping::before { + content: "\f290"; +} + +.fa-shopping-bag::before { + content: "\f290"; +} + +.fa-arrow-down-z-a::before { + content: "\f881"; +} + +.fa-sort-alpha-desc::before { + content: "\f881"; +} + +.fa-sort-alpha-down-alt::before { + content: "\f881"; +} + +.fa-mitten::before { + content: "\f7b5"; +} + +.fa-person-rays::before { + content: "\e54d"; +} + +.fa-users::before { + content: "\f0c0"; +} + +.fa-eye-slash::before { + content: "\f070"; +} + +.fa-flask-vial::before { + content: "\e4f3"; +} + +.fa-hand::before { + content: "\f256"; +} + +.fa-hand-paper::before { + content: "\f256"; +} + +.fa-om::before { + content: "\f679"; +} + +.fa-worm::before { + content: "\e599"; +} + +.fa-house-circle-xmark::before { + content: "\e50b"; +} + +.fa-plug::before { + content: "\f1e6"; +} + +.fa-chevron-up::before { + content: "\f077"; +} + +.fa-hand-spock::before { + content: "\f259"; +} + +.fa-stopwatch::before { + content: "\f2f2"; +} + +.fa-face-kiss::before { + content: "\f596"; +} + +.fa-kiss::before { + content: "\f596"; +} + +.fa-bridge-circle-xmark::before { + content: "\e4cb"; +} + +.fa-face-grin-tongue::before { + content: "\f589"; +} + +.fa-grin-tongue::before { + content: "\f589"; +} + +.fa-chess-bishop::before { + content: "\f43a"; +} + +.fa-face-grin-wink::before { + content: "\f58c"; +} + +.fa-grin-wink::before { + content: "\f58c"; +} + +.fa-ear-deaf::before { + content: "\f2a4"; +} + +.fa-deaf::before { + content: "\f2a4"; +} + +.fa-deafness::before { + content: "\f2a4"; +} + +.fa-hard-of-hearing::before { + content: "\f2a4"; +} + +.fa-road-circle-check::before { + content: "\e564"; +} + +.fa-dice-five::before { + content: "\f523"; +} + +.fa-square-rss::before { + content: "\f143"; +} + +.fa-rss-square::before { + content: "\f143"; +} + +.fa-land-mine-on::before { + content: "\e51b"; +} + +.fa-i-cursor::before { + content: "\f246"; +} + +.fa-stamp::before { + content: "\f5bf"; +} + +.fa-stairs::before { + content: "\e289"; +} + +.fa-i::before { + content: "\49"; +} + +.fa-hryvnia-sign::before { + content: "\f6f2"; +} + +.fa-hryvnia::before { + content: "\f6f2"; +} + +.fa-pills::before { + content: "\f484"; +} + +.fa-face-grin-wide::before { + content: "\f581"; +} + +.fa-grin-alt::before { + content: "\f581"; +} + +.fa-tooth::before { + content: "\f5c9"; +} + +.fa-v::before { + content: "\56"; +} + +.fa-bangladeshi-taka-sign::before { + content: "\e2e6"; +} + +.fa-bicycle::before { + content: "\f206"; +} + +.fa-staff-snake::before { + content: "\e579"; +} + +.fa-rod-asclepius::before { + content: "\e579"; +} + +.fa-rod-snake::before { + content: "\e579"; +} + +.fa-staff-aesculapius::before { + content: "\e579"; +} + +.fa-head-side-cough-slash::before { + content: "\e062"; +} + +.fa-truck-medical::before { + content: "\f0f9"; +} + +.fa-ambulance::before { + content: "\f0f9"; +} + +.fa-wheat-awn-circle-exclamation::before { + content: "\e598"; +} + +.fa-snowman::before { + content: "\f7d0"; +} + +.fa-mortar-pestle::before { + content: "\f5a7"; +} + +.fa-road-barrier::before { + content: "\e562"; +} + +.fa-school::before { + content: "\f549"; +} + +.fa-igloo::before { + content: "\f7ae"; +} + +.fa-joint::before { + content: "\f595"; +} + +.fa-angle-right::before { + content: "\f105"; +} + +.fa-horse::before { + content: "\f6f0"; +} + +.fa-q::before { + content: "\51"; +} + +.fa-g::before { + content: "\47"; +} + +.fa-notes-medical::before { + content: "\f481"; +} + +.fa-temperature-half::before { + content: "\f2c9"; +} + +.fa-temperature-2::before { + content: "\f2c9"; +} + +.fa-thermometer-2::before { + content: "\f2c9"; +} + +.fa-thermometer-half::before { + content: "\f2c9"; +} + +.fa-dong-sign::before { + content: "\e169"; +} + +.fa-capsules::before { + content: "\f46b"; +} + +.fa-poo-storm::before { + content: "\f75a"; +} + +.fa-poo-bolt::before { + content: "\f75a"; +} + +.fa-face-frown-open::before { + content: "\f57a"; +} + +.fa-frown-open::before { + content: "\f57a"; +} + +.fa-hand-point-up::before { + content: "\f0a6"; +} + +.fa-money-bill::before { + content: "\f0d6"; +} + +.fa-bookmark::before { + content: "\f02e"; +} + +.fa-align-justify::before { + content: "\f039"; +} + +.fa-umbrella-beach::before { + content: "\f5ca"; +} + +.fa-helmet-un::before { + content: "\e503"; +} + +.fa-bullseye::before { + content: "\f140"; +} + +.fa-bacon::before { + content: "\f7e5"; +} + +.fa-hand-point-down::before { + content: "\f0a7"; +} + +.fa-arrow-up-from-bracket::before { + content: "\e09a"; +} + +.fa-folder::before { + content: "\f07b"; +} + +.fa-folder-blank::before { + content: "\f07b"; +} + +.fa-file-waveform::before { + content: "\f478"; +} + +.fa-file-medical-alt::before { + content: "\f478"; +} + +.fa-radiation::before { + content: "\f7b9"; +} + +.fa-chart-simple::before { + content: "\e473"; +} + +.fa-mars-stroke::before { + content: "\f229"; +} + +.fa-vial::before { + content: "\f492"; +} + +.fa-gauge::before { + content: "\f624"; +} + +.fa-dashboard::before { + content: "\f624"; +} + +.fa-gauge-med::before { + content: "\f624"; +} + +.fa-tachometer-alt-average::before { + content: "\f624"; +} + +.fa-wand-magic-sparkles::before { + content: "\e2ca"; +} + +.fa-magic-wand-sparkles::before { + content: "\e2ca"; +} + +.fa-e::before { + content: "\45"; +} + +.fa-pen-clip::before { + content: "\f305"; +} + +.fa-pen-alt::before { + content: "\f305"; +} + +.fa-bridge-circle-exclamation::before { + content: "\e4ca"; +} + +.fa-user::before { + content: "\f007"; +} + +.fa-school-circle-check::before { + content: "\e56b"; +} + +.fa-dumpster::before { + content: "\f793"; +} + +.fa-van-shuttle::before { + content: "\f5b6"; +} + +.fa-shuttle-van::before { + content: "\f5b6"; +} + +.fa-building-user::before { + content: "\e4da"; +} + +.fa-square-caret-left::before { + content: "\f191"; +} + +.fa-caret-square-left::before { + content: "\f191"; +} + +.fa-highlighter::before { + content: "\f591"; +} + +.fa-key::before { + content: "\f084"; +} + +.fa-bullhorn::before { + content: "\f0a1"; +} + +.fa-globe::before { + content: "\f0ac"; +} + +.fa-synagogue::before { + content: "\f69b"; +} + +.fa-person-half-dress::before { + content: "\e548"; +} + +.fa-road-bridge::before { + content: "\e563"; +} + +.fa-location-arrow::before { + content: "\f124"; +} + +.fa-c::before { + content: "\43"; +} + +.fa-tablet-button::before { + content: "\f10a"; +} + +.fa-building-lock::before { + content: "\e4d6"; +} + +.fa-pizza-slice::before { + content: "\f818"; +} + +.fa-money-bill-wave::before { + content: "\f53a"; +} + +.fa-chart-area::before { + content: "\f1fe"; +} + +.fa-area-chart::before { + content: "\f1fe"; +} + +.fa-house-flag::before { + content: "\e50d"; +} + +.fa-person-circle-minus::before { + content: "\e540"; +} + +.fa-ban::before { + content: "\f05e"; +} + +.fa-cancel::before { + content: "\f05e"; +} + +.fa-camera-rotate::before { + content: "\e0d8"; +} + +.fa-spray-can-sparkles::before { + content: "\f5d0"; +} + +.fa-air-freshener::before { + content: "\f5d0"; +} + +.fa-star::before { + content: "\f005"; +} + +.fa-repeat::before { + content: "\f363"; +} + +.fa-cross::before { + content: "\f654"; +} + +.fa-box::before { + content: "\f466"; +} + +.fa-venus-mars::before { + content: "\f228"; +} + +.fa-arrow-pointer::before { + content: "\f245"; +} + +.fa-mouse-pointer::before { + content: "\f245"; +} + +.fa-maximize::before { + content: "\f31e"; +} + +.fa-expand-arrows-alt::before { + content: "\f31e"; +} + +.fa-charging-station::before { + content: "\f5e7"; +} + +.fa-shapes::before { + content: "\f61f"; +} + +.fa-triangle-circle-square::before { + content: "\f61f"; +} + +.fa-shuffle::before { + content: "\f074"; +} + +.fa-random::before { + content: "\f074"; +} + +.fa-person-running::before { + content: "\f70c"; +} + +.fa-running::before { + content: "\f70c"; +} + +.fa-mobile-retro::before { + content: "\e527"; +} + +.fa-grip-lines-vertical::before { + content: "\f7a5"; +} + +.fa-spider::before { + content: "\f717"; +} + +.fa-hands-bound::before { + content: "\e4f9"; +} + +.fa-file-invoice-dollar::before { + content: "\f571"; +} + +.fa-plane-circle-exclamation::before { + content: "\e556"; +} + +.fa-x-ray::before { + content: "\f497"; +} + +.fa-spell-check::before { + content: "\f891"; +} + +.fa-slash::before { + content: "\f715"; +} + +.fa-computer-mouse::before { + content: "\f8cc"; +} + +.fa-mouse::before { + content: "\f8cc"; +} + +.fa-arrow-right-to-bracket::before { + content: "\f090"; +} + +.fa-sign-in::before { + content: "\f090"; +} + +.fa-shop-slash::before { + content: "\e070"; +} + +.fa-store-alt-slash::before { + content: "\e070"; +} + +.fa-server::before { + content: "\f233"; +} + +.fa-virus-covid-slash::before { + content: "\e4a9"; +} + +.fa-shop-lock::before { + content: "\e4a5"; +} + +.fa-hourglass-start::before { + content: "\f251"; +} + +.fa-hourglass-1::before { + content: "\f251"; +} + +.fa-blender-phone::before { + content: "\f6b6"; +} + +.fa-building-wheat::before { + content: "\e4db"; +} + +.fa-person-breastfeeding::before { + content: "\e53a"; +} + +.fa-right-to-bracket::before { + content: "\f2f6"; +} + +.fa-sign-in-alt::before { + content: "\f2f6"; +} + +.fa-venus::before { + content: "\f221"; +} + +.fa-passport::before { + content: "\f5ab"; +} + +.fa-heart-pulse::before { + content: "\f21e"; +} + +.fa-heartbeat::before { + content: "\f21e"; +} + +.fa-people-carry-box::before { + content: "\f4ce"; +} + +.fa-people-carry::before { + content: "\f4ce"; +} + +.fa-temperature-high::before { + content: "\f769"; +} + +.fa-microchip::before { + content: "\f2db"; +} + +.fa-crown::before { + content: "\f521"; +} + +.fa-weight-hanging::before { + content: "\f5cd"; +} + +.fa-xmarks-lines::before { + content: "\e59a"; +} + +.fa-file-prescription::before { + content: "\f572"; +} + +.fa-weight-scale::before { + content: "\f496"; +} + +.fa-weight::before { + content: "\f496"; +} + +.fa-user-group::before { + content: "\f500"; +} + +.fa-user-friends::before { + content: "\f500"; +} + +.fa-arrow-up-a-z::before { + content: "\f15e"; +} + +.fa-sort-alpha-up::before { + content: "\f15e"; +} + +.fa-chess-knight::before { + content: "\f441"; +} + +.fa-face-laugh-squint::before { + content: "\f59b"; +} + +.fa-laugh-squint::before { + content: "\f59b"; +} + +.fa-wheelchair::before { + content: "\f193"; +} + +.fa-circle-arrow-up::before { + content: "\f0aa"; +} + +.fa-arrow-circle-up::before { + content: "\f0aa"; +} + +.fa-toggle-on::before { + content: "\f205"; +} + +.fa-person-walking::before { + content: "\f554"; +} + +.fa-walking::before { + content: "\f554"; +} + +.fa-l::before { + content: "\4c"; +} + +.fa-fire::before { + content: "\f06d"; +} + +.fa-bed-pulse::before { + content: "\f487"; +} + +.fa-procedures::before { + content: "\f487"; +} + +.fa-shuttle-space::before { + content: "\f197"; +} + +.fa-space-shuttle::before { + content: "\f197"; +} + +.fa-face-laugh::before { + content: "\f599"; +} + +.fa-laugh::before { + content: "\f599"; +} + +.fa-folder-open::before { + content: "\f07c"; +} + +.fa-heart-circle-plus::before { + content: "\e500"; +} + +.fa-code-fork::before { + content: "\e13b"; +} + +.fa-city::before { + content: "\f64f"; +} + +.fa-microphone-lines::before { + content: "\f3c9"; +} + +.fa-microphone-alt::before { + content: "\f3c9"; +} + +.fa-pepper-hot::before { + content: "\f816"; +} + +.fa-unlock::before { + content: "\f09c"; +} + +.fa-colon-sign::before { + content: "\e140"; +} + +.fa-headset::before { + content: "\f590"; +} + +.fa-store-slash::before { + content: "\e071"; +} + +.fa-road-circle-xmark::before { + content: "\e566"; +} + +.fa-user-minus::before { + content: "\f503"; +} + +.fa-mars-stroke-up::before { + content: "\f22a"; +} + +.fa-mars-stroke-v::before { + content: "\f22a"; +} + +.fa-champagne-glasses::before { + content: "\f79f"; +} + +.fa-glass-cheers::before { + content: "\f79f"; +} + +.fa-clipboard::before { + content: "\f328"; +} + +.fa-house-circle-exclamation::before { + content: "\e50a"; +} + +.fa-file-arrow-up::before { + content: "\f574"; +} + +.fa-file-upload::before { + content: "\f574"; +} + +.fa-wifi::before { + content: "\f1eb"; +} + +.fa-wifi-3::before { + content: "\f1eb"; +} + +.fa-wifi-strong::before { + content: "\f1eb"; +} + +.fa-bath::before { + content: "\f2cd"; +} + +.fa-bathtub::before { + content: "\f2cd"; +} + +.fa-underline::before { + content: "\f0cd"; +} + +.fa-user-pen::before { + content: "\f4ff"; +} + +.fa-user-edit::before { + content: "\f4ff"; +} + +.fa-signature::before { + content: "\f5b7"; +} + +.fa-stroopwafel::before { + content: "\f551"; +} + +.fa-bold::before { + content: "\f032"; +} + +.fa-anchor-lock::before { + content: "\e4ad"; +} + +.fa-building-ngo::before { + content: "\e4d7"; +} + +.fa-manat-sign::before { + content: "\e1d5"; +} + +.fa-not-equal::before { + content: "\f53e"; +} + +.fa-border-top-left::before { + content: "\f853"; +} + +.fa-border-style::before { + content: "\f853"; +} + +.fa-map-location-dot::before { + content: "\f5a0"; +} + +.fa-map-marked-alt::before { + content: "\f5a0"; +} + +.fa-jedi::before { + content: "\f669"; +} + +.fa-square-poll-vertical::before { + content: "\f681"; +} + +.fa-poll::before { + content: "\f681"; +} + +.fa-mug-hot::before { + content: "\f7b6"; +} + +.fa-car-battery::before { + content: "\f5df"; +} + +.fa-battery-car::before { + content: "\f5df"; +} + +.fa-gift::before { + content: "\f06b"; +} + +.fa-dice-two::before { + content: "\f528"; +} + +.fa-chess-queen::before { + content: "\f445"; +} + +.fa-glasses::before { + content: "\f530"; +} + +.fa-chess-board::before { + content: "\f43c"; +} + +.fa-building-circle-check::before { + content: "\e4d2"; +} + +.fa-person-chalkboard::before { + content: "\e53d"; +} + +.fa-mars-stroke-right::before { + content: "\f22b"; +} + +.fa-mars-stroke-h::before { + content: "\f22b"; +} + +.fa-hand-back-fist::before { + content: "\f255"; +} + +.fa-hand-rock::before { + content: "\f255"; +} + +.fa-square-caret-up::before { + content: "\f151"; +} + +.fa-caret-square-up::before { + content: "\f151"; +} + +.fa-cloud-showers-water::before { + content: "\e4e4"; +} + +.fa-chart-bar::before { + content: "\f080"; +} + +.fa-bar-chart::before { + content: "\f080"; +} + +.fa-hands-bubbles::before { + content: "\e05e"; +} + +.fa-hands-wash::before { + content: "\e05e"; +} + +.fa-less-than-equal::before { + content: "\f537"; +} + +.fa-train::before { + content: "\f238"; +} + +.fa-eye-low-vision::before { + content: "\f2a8"; +} + +.fa-low-vision::before { + content: "\f2a8"; +} + +.fa-crow::before { + content: "\f520"; +} + +.fa-sailboat::before { + content: "\e445"; +} + +.fa-window-restore::before { + content: "\f2d2"; +} + +.fa-square-plus::before { + content: "\f0fe"; +} + +.fa-plus-square::before { + content: "\f0fe"; +} + +.fa-torii-gate::before { + content: "\f6a1"; +} + +.fa-frog::before { + content: "\f52e"; +} + +.fa-bucket::before { + content: "\e4cf"; +} + +.fa-image::before { + content: "\f03e"; +} + +.fa-microphone::before { + content: "\f130"; +} + +.fa-cow::before { + content: "\f6c8"; +} + +.fa-caret-up::before { + content: "\f0d8"; +} + +.fa-screwdriver::before { + content: "\f54a"; +} + +.fa-folder-closed::before { + content: "\e185"; +} + +.fa-house-tsunami::before { + content: "\e515"; +} + +.fa-square-nfi::before { + content: "\e576"; +} + +.fa-arrow-up-from-ground-water::before { + content: "\e4b5"; +} + +.fa-martini-glass::before { + content: "\f57b"; +} + +.fa-glass-martini-alt::before { + content: "\f57b"; +} + +.fa-rotate-left::before { + content: "\f2ea"; +} + +.fa-rotate-back::before { + content: "\f2ea"; +} + +.fa-rotate-backward::before { + content: "\f2ea"; +} + +.fa-undo-alt::before { + content: "\f2ea"; +} + +.fa-table-columns::before { + content: "\f0db"; +} + +.fa-columns::before { + content: "\f0db"; +} + +.fa-lemon::before { + content: "\f094"; +} + +.fa-head-side-mask::before { + content: "\e063"; +} + +.fa-handshake::before { + content: "\f2b5"; +} + +.fa-gem::before { + content: "\f3a5"; +} + +.fa-dolly::before { + content: "\f472"; +} + +.fa-dolly-box::before { + content: "\f472"; +} + +.fa-smoking::before { + content: "\f48d"; +} + +.fa-minimize::before { + content: "\f78c"; +} + +.fa-compress-arrows-alt::before { + content: "\f78c"; +} + +.fa-monument::before { + content: "\f5a6"; +} + +.fa-snowplow::before { + content: "\f7d2"; +} + +.fa-angles-right::before { + content: "\f101"; +} + +.fa-angle-double-right::before { + content: "\f101"; +} + +.fa-cannabis::before { + content: "\f55f"; +} + +.fa-circle-play::before { + content: "\f144"; +} + +.fa-play-circle::before { + content: "\f144"; +} + +.fa-tablets::before { + content: "\f490"; +} + +.fa-ethernet::before { + content: "\f796"; +} + +.fa-euro-sign::before { + content: "\f153"; +} + +.fa-eur::before { + content: "\f153"; +} + +.fa-euro::before { + content: "\f153"; +} + +.fa-chair::before { + content: "\f6c0"; +} + +.fa-circle-check::before { + content: "\f058"; +} + +.fa-check-circle::before { + content: "\f058"; +} + +.fa-circle-stop::before { + content: "\f28d"; +} + +.fa-stop-circle::before { + content: "\f28d"; +} + +.fa-compass-drafting::before { + content: "\f568"; +} + +.fa-drafting-compass::before { + content: "\f568"; +} + +.fa-plate-wheat::before { + content: "\e55a"; +} + +.fa-icicles::before { + content: "\f7ad"; +} + +.fa-person-shelter::before { + content: "\e54f"; +} + +.fa-neuter::before { + content: "\f22c"; +} + +.fa-id-badge::before { + content: "\f2c1"; +} + +.fa-marker::before { + content: "\f5a1"; +} + +.fa-face-laugh-beam::before { + content: "\f59a"; +} + +.fa-laugh-beam::before { + content: "\f59a"; +} + +.fa-helicopter-symbol::before { + content: "\e502"; +} + +.fa-universal-access::before { + content: "\f29a"; +} + +.fa-circle-chevron-up::before { + content: "\f139"; +} + +.fa-chevron-circle-up::before { + content: "\f139"; +} + +.fa-lari-sign::before { + content: "\e1c8"; +} + +.fa-volcano::before { + content: "\f770"; +} + +.fa-person-walking-dashed-line-arrow-right::before { + content: "\e553"; +} + +.fa-sterling-sign::before { + content: "\f154"; +} + +.fa-gbp::before { + content: "\f154"; +} + +.fa-pound-sign::before { + content: "\f154"; +} + +.fa-viruses::before { + content: "\e076"; +} + +.fa-square-person-confined::before { + content: "\e577"; +} + +.fa-user-tie::before { + content: "\f508"; +} + +.fa-arrow-down-long::before { + content: "\f175"; +} + +.fa-long-arrow-down::before { + content: "\f175"; +} + +.fa-tent-arrow-down-to-line::before { + content: "\e57e"; +} + +.fa-certificate::before { + content: "\f0a3"; +} + +.fa-reply-all::before { + content: "\f122"; +} + +.fa-mail-reply-all::before { + content: "\f122"; +} + +.fa-suitcase::before { + content: "\f0f2"; +} + +.fa-person-skating::before { + content: "\f7c5"; +} + +.fa-skating::before { + content: "\f7c5"; +} + +.fa-filter-circle-dollar::before { + content: "\f662"; +} + +.fa-funnel-dollar::before { + content: "\f662"; +} + +.fa-camera-retro::before { + content: "\f083"; +} + +.fa-circle-arrow-down::before { + content: "\f0ab"; +} + +.fa-arrow-circle-down::before { + content: "\f0ab"; +} + +.fa-file-import::before { + content: "\f56f"; +} + +.fa-arrow-right-to-file::before { + content: "\f56f"; +} + +.fa-square-arrow-up-right::before { + content: "\f14c"; +} + +.fa-external-link-square::before { + content: "\f14c"; +} + +.fa-box-open::before { + content: "\f49e"; +} + +.fa-scroll::before { + content: "\f70e"; +} + +.fa-spa::before { + content: "\f5bb"; +} + +.fa-location-pin-lock::before { + content: "\e51f"; +} + +.fa-pause::before { + content: "\f04c"; +} + +.fa-hill-avalanche::before { + content: "\e507"; +} + +.fa-temperature-empty::before { + content: "\f2cb"; +} + +.fa-temperature-0::before { + content: "\f2cb"; +} + +.fa-thermometer-0::before { + content: "\f2cb"; +} + +.fa-thermometer-empty::before { + content: "\f2cb"; +} + +.fa-bomb::before { + content: "\f1e2"; +} + +.fa-registered::before { + content: "\f25d"; +} + +.fa-address-card::before { + content: "\f2bb"; +} + +.fa-contact-card::before { + content: "\f2bb"; +} + +.fa-vcard::before { + content: "\f2bb"; +} + +.fa-scale-unbalanced-flip::before { + content: "\f516"; +} + +.fa-balance-scale-right::before { + content: "\f516"; +} + +.fa-subscript::before { + content: "\f12c"; +} + +.fa-diamond-turn-right::before { + content: "\f5eb"; +} + +.fa-directions::before { + content: "\f5eb"; +} + +.fa-burst::before { + content: "\e4dc"; +} + +.fa-house-laptop::before { + content: "\e066"; +} + +.fa-laptop-house::before { + content: "\e066"; +} + +.fa-face-tired::before { + content: "\f5c8"; +} + +.fa-tired::before { + content: "\f5c8"; +} + +.fa-money-bills::before { + content: "\e1f3"; +} + +.fa-smog::before { + content: "\f75f"; +} + +.fa-crutch::before { + content: "\f7f7"; +} + +.fa-cloud-arrow-up::before { + content: "\f0ee"; +} + +.fa-cloud-upload::before { + content: "\f0ee"; +} + +.fa-cloud-upload-alt::before { + content: "\f0ee"; +} + +.fa-palette::before { + content: "\f53f"; +} + +.fa-arrows-turn-right::before { + content: "\e4c0"; +} + +.fa-vest::before { + content: "\e085"; +} + +.fa-ferry::before { + content: "\e4ea"; +} + +.fa-arrows-down-to-people::before { + content: "\e4b9"; +} + +.fa-seedling::before { + content: "\f4d8"; +} + +.fa-sprout::before { + content: "\f4d8"; +} + +.fa-left-right::before { + content: "\f337"; +} + +.fa-arrows-alt-h::before { + content: "\f337"; +} + +.fa-boxes-packing::before { + content: "\e4c7"; +} + +.fa-circle-arrow-left::before { + content: "\f0a8"; +} + +.fa-arrow-circle-left::before { + content: "\f0a8"; +} + +.fa-group-arrows-rotate::before { + content: "\e4f6"; +} + +.fa-bowl-food::before { + content: "\e4c6"; +} + +.fa-candy-cane::before { + content: "\f786"; +} + +.fa-arrow-down-wide-short::before { + content: "\f160"; +} + +.fa-sort-amount-asc::before { + content: "\f160"; +} + +.fa-sort-amount-down::before { + content: "\f160"; +} + +.fa-cloud-bolt::before { + content: "\f76c"; +} + +.fa-thunderstorm::before { + content: "\f76c"; +} + +.fa-text-slash::before { + content: "\f87d"; +} + +.fa-remove-format::before { + content: "\f87d"; +} + +.fa-face-smile-wink::before { + content: "\f4da"; +} + +.fa-smile-wink::before { + content: "\f4da"; +} + +.fa-file-word::before { + content: "\f1c2"; +} + +.fa-file-powerpoint::before { + content: "\f1c4"; +} + +.fa-arrows-left-right::before { + content: "\f07e"; +} + +.fa-arrows-h::before { + content: "\f07e"; +} + +.fa-house-lock::before { + content: "\e510"; +} + +.fa-cloud-arrow-down::before { + content: "\f0ed"; +} + +.fa-cloud-download::before { + content: "\f0ed"; +} + +.fa-cloud-download-alt::before { + content: "\f0ed"; +} + +.fa-children::before { + content: "\e4e1"; +} + +.fa-chalkboard::before { + content: "\f51b"; +} + +.fa-blackboard::before { + content: "\f51b"; +} + +.fa-user-large-slash::before { + content: "\f4fa"; +} + +.fa-user-alt-slash::before { + content: "\f4fa"; +} + +.fa-envelope-open::before { + content: "\f2b6"; +} + +.fa-handshake-simple-slash::before { + content: "\e05f"; +} + +.fa-handshake-alt-slash::before { + content: "\e05f"; +} + +.fa-mattress-pillow::before { + content: "\e525"; +} + +.fa-guarani-sign::before { + content: "\e19a"; +} + +.fa-arrows-rotate::before { + content: "\f021"; +} + +.fa-refresh::before { + content: "\f021"; +} + +.fa-sync::before { + content: "\f021"; +} + +.fa-fire-extinguisher::before { + content: "\f134"; +} + +.fa-cruzeiro-sign::before { + content: "\e152"; +} + +.fa-greater-than-equal::before { + content: "\f532"; +} + +.fa-shield-halved::before { + content: "\f3ed"; +} + +.fa-shield-alt::before { + content: "\f3ed"; +} + +.fa-book-atlas::before { + content: "\f558"; +} + +.fa-atlas::before { + content: "\f558"; +} + +.fa-virus::before { + content: "\e074"; +} + +.fa-envelope-circle-check::before { + content: "\e4e8"; +} + +.fa-layer-group::before { + content: "\f5fd"; +} + +.fa-arrows-to-dot::before { + content: "\e4be"; +} + +.fa-archway::before { + content: "\f557"; +} + +.fa-heart-circle-check::before { + content: "\e4fd"; +} + +.fa-house-chimney-crack::before { + content: "\f6f1"; +} + +.fa-house-damage::before { + content: "\f6f1"; +} + +.fa-file-zipper::before { + content: "\f1c6"; +} + +.fa-file-archive::before { + content: "\f1c6"; +} + +.fa-square::before { + content: "\f0c8"; +} + +.fa-martini-glass-empty::before { + content: "\f000"; +} + +.fa-glass-martini::before { + content: "\f000"; +} + +.fa-couch::before { + content: "\f4b8"; +} + +.fa-cedi-sign::before { + content: "\e0df"; +} + +.fa-italic::before { + content: "\f033"; +} + +.fa-church::before { + content: "\f51d"; +} + +.fa-comments-dollar::before { + content: "\f653"; +} + +.fa-democrat::before { + content: "\f747"; +} + +.fa-z::before { + content: "\5a"; +} + +.fa-person-skiing::before { + content: "\f7c9"; +} + +.fa-skiing::before { + content: "\f7c9"; +} + +.fa-road-lock::before { + content: "\e567"; +} + +.fa-a::before { + content: "\41"; +} + +.fa-temperature-arrow-down::before { + content: "\e03f"; +} + +.fa-temperature-down::before { + content: "\e03f"; +} + +.fa-feather-pointed::before { + content: "\f56b"; +} + +.fa-feather-alt::before { + content: "\f56b"; +} + +.fa-p::before { + content: "\50"; +} + +.fa-snowflake::before { + content: "\f2dc"; +} + +.fa-newspaper::before { + content: "\f1ea"; +} + +.fa-rectangle-ad::before { + content: "\f641"; +} + +.fa-ad::before { + content: "\f641"; +} + +.fa-circle-arrow-right::before { + content: "\f0a9"; +} + +.fa-arrow-circle-right::before { + content: "\f0a9"; +} + +.fa-filter-circle-xmark::before { + content: "\e17b"; +} + +.fa-locust::before { + content: "\e520"; +} + +.fa-sort::before { + content: "\f0dc"; +} + +.fa-unsorted::before { + content: "\f0dc"; +} + +.fa-list-ol::before { + content: "\f0cb"; +} + +.fa-list-1-2::before { + content: "\f0cb"; +} + +.fa-list-numeric::before { + content: "\f0cb"; +} + +.fa-person-dress-burst::before { + content: "\e544"; +} + +.fa-money-check-dollar::before { + content: "\f53d"; +} + +.fa-money-check-alt::before { + content: "\f53d"; +} + +.fa-vector-square::before { + content: "\f5cb"; +} + +.fa-bread-slice::before { + content: "\f7ec"; +} + +.fa-language::before { + content: "\f1ab"; +} + +.fa-face-kiss-wink-heart::before { + content: "\f598"; +} + +.fa-kiss-wink-heart::before { + content: "\f598"; +} + +.fa-filter::before { + content: "\f0b0"; +} + +.fa-question::before { + content: "\3f"; +} + +.fa-file-signature::before { + content: "\f573"; +} + +.fa-up-down-left-right::before { + content: "\f0b2"; +} + +.fa-arrows-alt::before { + content: "\f0b2"; +} + +.fa-house-chimney-user::before { + content: "\e065"; +} + +.fa-hand-holding-heart::before { + content: "\f4be"; +} + +.fa-puzzle-piece::before { + content: "\f12e"; +} + +.fa-money-check::before { + content: "\f53c"; +} + +.fa-star-half-stroke::before { + content: "\f5c0"; +} + +.fa-star-half-alt::before { + content: "\f5c0"; +} + +.fa-code::before { + content: "\f121"; +} + +.fa-whiskey-glass::before { + content: "\f7a0"; +} + +.fa-glass-whiskey::before { + content: "\f7a0"; +} + +.fa-building-circle-exclamation::before { + content: "\e4d3"; +} + +.fa-magnifying-glass-chart::before { + content: "\e522"; +} + +.fa-arrow-up-right-from-square::before { + content: "\f08e"; +} + +.fa-external-link::before { + content: "\f08e"; +} + +.fa-cubes-stacked::before { + content: "\e4e6"; +} + +.fa-won-sign::before { + content: "\f159"; +} + +.fa-krw::before { + content: "\f159"; +} + +.fa-won::before { + content: "\f159"; +} + +.fa-virus-covid::before { + content: "\e4a8"; +} + +.fa-austral-sign::before { + content: "\e0a9"; +} + +.fa-f::before { + content: "\46"; +} + +.fa-leaf::before { + content: "\f06c"; +} + +.fa-road::before { + content: "\f018"; +} + +.fa-taxi::before { + content: "\f1ba"; +} + +.fa-cab::before { + content: "\f1ba"; +} + +.fa-person-circle-plus::before { + content: "\e541"; +} + +.fa-chart-pie::before { + content: "\f200"; +} + +.fa-pie-chart::before { + content: "\f200"; +} + +.fa-bolt-lightning::before { + content: "\e0b7"; +} + +.fa-sack-xmark::before { + content: "\e56a"; +} + +.fa-file-excel::before { + content: "\f1c3"; +} + +.fa-file-contract::before { + content: "\f56c"; +} + +.fa-fish-fins::before { + content: "\e4f2"; +} + +.fa-building-flag::before { + content: "\e4d5"; +} + +.fa-face-grin-beam::before { + content: "\f582"; +} + +.fa-grin-beam::before { + content: "\f582"; +} + +.fa-object-ungroup::before { + content: "\f248"; +} + +.fa-poop::before { + content: "\f619"; +} + +.fa-location-pin::before { + content: "\f041"; +} + +.fa-map-marker::before { + content: "\f041"; +} + +.fa-kaaba::before { + content: "\f66b"; +} + +.fa-toilet-paper::before { + content: "\f71e"; +} + +.fa-helmet-safety::before { + content: "\f807"; +} + +.fa-hard-hat::before { + content: "\f807"; +} + +.fa-hat-hard::before { + content: "\f807"; +} + +.fa-eject::before { + content: "\f052"; +} + +.fa-circle-right::before { + content: "\f35a"; +} + +.fa-arrow-alt-circle-right::before { + content: "\f35a"; +} + +.fa-plane-circle-check::before { + content: "\e555"; +} + +.fa-face-rolling-eyes::before { + content: "\f5a5"; +} + +.fa-meh-rolling-eyes::before { + content: "\f5a5"; +} + +.fa-object-group::before { + content: "\f247"; +} + +.fa-chart-line::before { + content: "\f201"; +} + +.fa-line-chart::before { + content: "\f201"; +} + +.fa-mask-ventilator::before { + content: "\e524"; +} + +.fa-arrow-right::before { + content: "\f061"; +} + +.fa-signs-post::before { + content: "\f277"; +} + +.fa-map-signs::before { + content: "\f277"; +} + +.fa-cash-register::before { + content: "\f788"; +} + +.fa-person-circle-question::before { + content: "\e542"; +} + +.fa-h::before { + content: "\48"; +} + +.fa-tarp::before { + content: "\e57b"; +} + +.fa-screwdriver-wrench::before { + content: "\f7d9"; +} + +.fa-tools::before { + content: "\f7d9"; +} + +.fa-arrows-to-eye::before { + content: "\e4bf"; +} + +.fa-plug-circle-bolt::before { + content: "\e55b"; +} + +.fa-heart::before { + content: "\f004"; +} + +.fa-mars-and-venus::before { + content: "\f224"; +} + +.fa-house-user::before { + content: "\e1b0"; +} + +.fa-home-user::before { + content: "\e1b0"; +} + +.fa-dumpster-fire::before { + content: "\f794"; +} + +.fa-house-crack::before { + content: "\e3b1"; +} + +.fa-martini-glass-citrus::before { + content: "\f561"; +} + +.fa-cocktail::before { + content: "\f561"; +} + +.fa-face-surprise::before { + content: "\f5c2"; +} + +.fa-surprise::before { + content: "\f5c2"; +} + +.fa-bottle-water::before { + content: "\e4c5"; +} + +.fa-circle-pause::before { + content: "\f28b"; +} + +.fa-pause-circle::before { + content: "\f28b"; +} + +.fa-toilet-paper-slash::before { + content: "\e072"; +} + +.fa-apple-whole::before { + content: "\f5d1"; +} + +.fa-apple-alt::before { + content: "\f5d1"; +} + +.fa-kitchen-set::before { + content: "\e51a"; +} + +.fa-r::before { + content: "\52"; +} + +.fa-temperature-quarter::before { + content: "\f2ca"; +} + +.fa-temperature-1::before { + content: "\f2ca"; +} + +.fa-thermometer-1::before { + content: "\f2ca"; +} + +.fa-thermometer-quarter::before { + content: "\f2ca"; +} + +.fa-cube::before { + content: "\f1b2"; +} + +.fa-bitcoin-sign::before { + content: "\e0b4"; +} + +.fa-shield-dog::before { + content: "\e573"; +} + +.fa-solar-panel::before { + content: "\f5ba"; +} + +.fa-lock-open::before { + content: "\f3c1"; +} + +.fa-elevator::before { + content: "\e16d"; +} + +.fa-money-bill-transfer::before { + content: "\e528"; +} + +.fa-money-bill-trend-up::before { + content: "\e529"; +} + +.fa-house-flood-water-circle-arrow-right::before { + content: "\e50f"; +} + +.fa-square-poll-horizontal::before { + content: "\f682"; +} + +.fa-poll-h::before { + content: "\f682"; +} + +.fa-circle::before { + content: "\f111"; +} + +.fa-backward-fast::before { + content: "\f049"; +} + +.fa-fast-backward::before { + content: "\f049"; +} + +.fa-recycle::before { + content: "\f1b8"; +} + +.fa-user-astronaut::before { + content: "\f4fb"; +} + +.fa-plane-slash::before { + content: "\e069"; +} + +.fa-trademark::before { + content: "\f25c"; +} + +.fa-basketball::before { + content: "\f434"; +} + +.fa-basketball-ball::before { + content: "\f434"; +} + +.fa-satellite-dish::before { + content: "\f7c0"; +} + +.fa-circle-up::before { + content: "\f35b"; +} + +.fa-arrow-alt-circle-up::before { + content: "\f35b"; +} + +.fa-mobile-screen-button::before { + content: "\f3cd"; +} + +.fa-mobile-alt::before { + content: "\f3cd"; +} + +.fa-volume-high::before { + content: "\f028"; +} + +.fa-volume-up::before { + content: "\f028"; +} + +.fa-users-rays::before { + content: "\e593"; +} + +.fa-wallet::before { + content: "\f555"; +} + +.fa-clipboard-check::before { + content: "\f46c"; +} + +.fa-file-audio::before { + content: "\f1c7"; +} + +.fa-burger::before { + content: "\f805"; +} + +.fa-hamburger::before { + content: "\f805"; +} + +.fa-wrench::before { + content: "\f0ad"; +} + +.fa-bugs::before { + content: "\e4d0"; +} + +.fa-rupee-sign::before { + content: "\f156"; +} + +.fa-rupee::before { + content: "\f156"; +} + +.fa-file-image::before { + content: "\f1c5"; +} + +.fa-circle-question::before { + content: "\f059"; +} + +.fa-question-circle::before { + content: "\f059"; +} + +.fa-plane-departure::before { + content: "\f5b0"; +} + +.fa-handshake-slash::before { + content: "\e060"; +} + +.fa-book-bookmark::before { + content: "\e0bb"; +} + +.fa-code-branch::before { + content: "\f126"; +} + +.fa-hat-cowboy::before { + content: "\f8c0"; +} + +.fa-bridge::before { + content: "\e4c8"; +} + +.fa-phone-flip::before { + content: "\f879"; +} + +.fa-phone-alt::before { + content: "\f879"; +} + +.fa-truck-front::before { + content: "\e2b7"; +} + +.fa-cat::before { + content: "\f6be"; +} + +.fa-anchor-circle-exclamation::before { + content: "\e4ab"; +} + +.fa-truck-field::before { + content: "\e58d"; +} + +.fa-route::before { + content: "\f4d7"; +} + +.fa-clipboard-question::before { + content: "\e4e3"; +} + +.fa-panorama::before { + content: "\e209"; +} + +.fa-comment-medical::before { + content: "\f7f5"; +} + +.fa-teeth-open::before { + content: "\f62f"; +} + +.fa-file-circle-minus::before { + content: "\e4ed"; +} + +.fa-tags::before { + content: "\f02c"; +} + +.fa-wine-glass::before { + content: "\f4e3"; +} + +.fa-forward-fast::before { + content: "\f050"; +} + +.fa-fast-forward::before { + content: "\f050"; +} + +.fa-face-meh-blank::before { + content: "\f5a4"; +} + +.fa-meh-blank::before { + content: "\f5a4"; +} + +.fa-square-parking::before { + content: "\f540"; +} + +.fa-parking::before { + content: "\f540"; +} + +.fa-house-signal::before { + content: "\e012"; +} + +.fa-bars-progress::before { + content: "\f828"; +} + +.fa-tasks-alt::before { + content: "\f828"; +} + +.fa-faucet-drip::before { + content: "\e006"; +} + +.fa-cart-flatbed::before { + content: "\f474"; +} + +.fa-dolly-flatbed::before { + content: "\f474"; +} + +.fa-ban-smoking::before { + content: "\f54d"; +} + +.fa-smoking-ban::before { + content: "\f54d"; +} + +.fa-terminal::before { + content: "\f120"; +} + +.fa-mobile-button::before { + content: "\f10b"; +} + +.fa-house-medical-flag::before { + content: "\e514"; +} + +.fa-basket-shopping::before { + content: "\f291"; +} + +.fa-shopping-basket::before { + content: "\f291"; +} + +.fa-tape::before { + content: "\f4db"; +} + +.fa-bus-simple::before { + content: "\f55e"; +} + +.fa-bus-alt::before { + content: "\f55e"; +} + +.fa-eye::before { + content: "\f06e"; +} + +.fa-face-sad-cry::before { + content: "\f5b3"; +} + +.fa-sad-cry::before { + content: "\f5b3"; +} + +.fa-audio-description::before { + content: "\f29e"; +} + +.fa-person-military-to-person::before { + content: "\e54c"; +} + +.fa-file-shield::before { + content: "\e4f0"; +} + +.fa-user-slash::before { + content: "\f506"; +} + +.fa-pen::before { + content: "\f304"; +} + +.fa-tower-observation::before { + content: "\e586"; +} + +.fa-file-code::before { + content: "\f1c9"; +} + +.fa-signal::before { + content: "\f012"; +} + +.fa-signal-5::before { + content: "\f012"; +} + +.fa-signal-perfect::before { + content: "\f012"; +} + +.fa-bus::before { + content: "\f207"; +} + +.fa-heart-circle-xmark::before { + content: "\e501"; +} + +.fa-house-chimney::before { + content: "\e3af"; +} + +.fa-home-lg::before { + content: "\e3af"; +} + +.fa-window-maximize::before { + content: "\f2d0"; +} + +.fa-face-frown::before { + content: "\f119"; +} + +.fa-frown::before { + content: "\f119"; +} + +.fa-prescription::before { + content: "\f5b1"; +} + +.fa-shop::before { + content: "\f54f"; +} + +.fa-store-alt::before { + content: "\f54f"; +} + +.fa-floppy-disk::before { + content: "\f0c7"; +} + +.fa-save::before { + content: "\f0c7"; +} + +.fa-vihara::before { + content: "\f6a7"; +} + +.fa-scale-unbalanced::before { + content: "\f515"; +} + +.fa-balance-scale-left::before { + content: "\f515"; +} + +.fa-sort-up::before { + content: "\f0de"; +} + +.fa-sort-asc::before { + content: "\f0de"; +} + +.fa-comment-dots::before { + content: "\f4ad"; +} + +.fa-commenting::before { + content: "\f4ad"; +} + +.fa-plant-wilt::before { + content: "\e5aa"; +} + +.fa-diamond::before { + content: "\f219"; +} + +.fa-face-grin-squint::before { + content: "\f585"; +} + +.fa-grin-squint::before { + content: "\f585"; +} + +.fa-hand-holding-dollar::before { + content: "\f4c0"; +} + +.fa-hand-holding-usd::before { + content: "\f4c0"; +} + +.fa-bacterium::before { + content: "\e05a"; +} + +.fa-hand-pointer::before { + content: "\f25a"; +} + +.fa-drum-steelpan::before { + content: "\f56a"; +} + +.fa-hand-scissors::before { + content: "\f257"; +} + +.fa-hands-praying::before { + content: "\f684"; +} + +.fa-praying-hands::before { + content: "\f684"; +} + +.fa-arrow-rotate-right::before { + content: "\f01e"; +} + +.fa-arrow-right-rotate::before { + content: "\f01e"; +} + +.fa-arrow-rotate-forward::before { + content: "\f01e"; +} + +.fa-redo::before { + content: "\f01e"; +} + +.fa-biohazard::before { + content: "\f780"; +} + +.fa-location-crosshairs::before { + content: "\f601"; +} + +.fa-location::before { + content: "\f601"; +} + +.fa-mars-double::before { + content: "\f227"; +} + +.fa-child-dress::before { + content: "\e59c"; +} + +.fa-users-between-lines::before { + content: "\e591"; +} + +.fa-lungs-virus::before { + content: "\e067"; +} + +.fa-face-grin-tears::before { + content: "\f588"; +} + +.fa-grin-tears::before { + content: "\f588"; +} + +.fa-phone::before { + content: "\f095"; +} + +.fa-calendar-xmark::before { + content: "\f273"; +} + +.fa-calendar-times::before { + content: "\f273"; +} + +.fa-child-reaching::before { + content: "\e59d"; +} + +.fa-head-side-virus::before { + content: "\e064"; +} + +.fa-user-gear::before { + content: "\f4fe"; +} + +.fa-user-cog::before { + content: "\f4fe"; +} + +.fa-arrow-up-1-9::before { + content: "\f163"; +} + +.fa-sort-numeric-up::before { + content: "\f163"; +} + +.fa-door-closed::before { + content: "\f52a"; +} + +.fa-shield-virus::before { + content: "\e06c"; +} + +.fa-dice-six::before { + content: "\f526"; +} + +.fa-mosquito-net::before { + content: "\e52c"; +} + +.fa-bridge-water::before { + content: "\e4ce"; +} + +.fa-person-booth::before { + content: "\f756"; +} + +.fa-text-width::before { + content: "\f035"; +} + +.fa-hat-wizard::before { + content: "\f6e8"; +} + +.fa-pen-fancy::before { + content: "\f5ac"; +} + +.fa-person-digging::before { + content: "\f85e"; +} + +.fa-digging::before { + content: "\f85e"; +} + +.fa-trash::before { + content: "\f1f8"; +} + +.fa-gauge-simple::before { + content: "\f629"; +} + +.fa-gauge-simple-med::before { + content: "\f629"; +} + +.fa-tachometer-average::before { + content: "\f629"; +} + +.fa-book-medical::before { + content: "\f7e6"; +} + +.fa-poo::before { + content: "\f2fe"; +} + +.fa-quote-right::before { + content: "\f10e"; +} + +.fa-quote-right-alt::before { + content: "\f10e"; +} + +.fa-shirt::before { + content: "\f553"; +} + +.fa-t-shirt::before { + content: "\f553"; +} + +.fa-tshirt::before { + content: "\f553"; +} + +.fa-cubes::before { + content: "\f1b3"; +} + +.fa-divide::before { + content: "\f529"; +} + +.fa-tenge-sign::before { + content: "\f7d7"; +} + +.fa-tenge::before { + content: "\f7d7"; +} + +.fa-headphones::before { + content: "\f025"; +} + +.fa-hands-holding::before { + content: "\f4c2"; +} + +.fa-hands-clapping::before { + content: "\e1a8"; +} + +.fa-republican::before { + content: "\f75e"; +} + +.fa-arrow-left::before { + content: "\f060"; +} + +.fa-person-circle-xmark::before { + content: "\e543"; +} + +.fa-ruler::before { + content: "\f545"; +} + +.fa-align-left::before { + content: "\f036"; +} + +.fa-dice-d6::before { + content: "\f6d1"; +} + +.fa-restroom::before { + content: "\f7bd"; +} + +.fa-j::before { + content: "\4a"; +} + +.fa-users-viewfinder::before { + content: "\e595"; +} + +.fa-file-video::before { + content: "\f1c8"; +} + +.fa-up-right-from-square::before { + content: "\f35d"; +} + +.fa-external-link-alt::before { + content: "\f35d"; +} + +.fa-table-cells::before { + content: "\f00a"; +} + +.fa-th::before { + content: "\f00a"; +} + +.fa-file-pdf::before { + content: "\f1c1"; +} + +.fa-book-bible::before { + content: "\f647"; +} + +.fa-bible::before { + content: "\f647"; +} + +.fa-o::before { + content: "\4f"; +} + +.fa-suitcase-medical::before { + content: "\f0fa"; +} + +.fa-medkit::before { + content: "\f0fa"; +} + +.fa-user-secret::before { + content: "\f21b"; +} + +.fa-otter::before { + content: "\f700"; +} + +.fa-person-dress::before { + content: "\f182"; +} + +.fa-female::before { + content: "\f182"; +} + +.fa-comment-dollar::before { + content: "\f651"; +} + +.fa-business-time::before { + content: "\f64a"; +} + +.fa-briefcase-clock::before { + content: "\f64a"; +} + +.fa-table-cells-large::before { + content: "\f009"; +} + +.fa-th-large::before { + content: "\f009"; +} + +.fa-book-tanakh::before { + content: "\f827"; +} + +.fa-tanakh::before { + content: "\f827"; +} + +.fa-phone-volume::before { + content: "\f2a0"; +} + +.fa-volume-control-phone::before { + content: "\f2a0"; +} + +.fa-hat-cowboy-side::before { + content: "\f8c1"; +} + +.fa-clipboard-user::before { + content: "\f7f3"; +} + +.fa-child::before { + content: "\f1ae"; +} + +.fa-lira-sign::before { + content: "\f195"; +} + +.fa-satellite::before { + content: "\f7bf"; +} + +.fa-plane-lock::before { + content: "\e558"; +} + +.fa-tag::before { + content: "\f02b"; +} + +.fa-comment::before { + content: "\f075"; +} + +.fa-cake-candles::before { + content: "\f1fd"; +} + +.fa-birthday-cake::before { + content: "\f1fd"; +} + +.fa-cake::before { + content: "\f1fd"; +} + +.fa-envelope::before { + content: "\f0e0"; +} + +.fa-angles-up::before { + content: "\f102"; +} + +.fa-angle-double-up::before { + content: "\f102"; +} + +.fa-paperclip::before { + content: "\f0c6"; +} + +.fa-arrow-right-to-city::before { + content: "\e4b3"; +} + +.fa-ribbon::before { + content: "\f4d6"; +} + +.fa-lungs::before { + content: "\f604"; +} + +.fa-arrow-up-9-1::before { + content: "\f887"; +} + +.fa-sort-numeric-up-alt::before { + content: "\f887"; +} + +.fa-litecoin-sign::before { + content: "\e1d3"; +} + +.fa-border-none::before { + content: "\f850"; +} + +.fa-circle-nodes::before { + content: "\e4e2"; +} + +.fa-parachute-box::before { + content: "\f4cd"; +} + +.fa-indent::before { + content: "\f03c"; +} + +.fa-truck-field-un::before { + content: "\e58e"; +} + +.fa-hourglass::before { + content: "\f254"; +} + +.fa-hourglass-empty::before { + content: "\f254"; +} + +.fa-mountain::before { + content: "\f6fc"; +} + +.fa-user-doctor::before { + content: "\f0f0"; +} + +.fa-user-md::before { + content: "\f0f0"; +} + +.fa-circle-info::before { + content: "\f05a"; +} + +.fa-info-circle::before { + content: "\f05a"; +} + +.fa-cloud-meatball::before { + content: "\f73b"; +} + +.fa-camera::before { + content: "\f030"; +} + +.fa-camera-alt::before { + content: "\f030"; +} + +.fa-square-virus::before { + content: "\e578"; +} + +.fa-meteor::before { + content: "\f753"; +} + +.fa-car-on::before { + content: "\e4dd"; +} + +.fa-sleigh::before { + content: "\f7cc"; +} + +.fa-arrow-down-1-9::before { + content: "\f162"; +} + +.fa-sort-numeric-asc::before { + content: "\f162"; +} + +.fa-sort-numeric-down::before { + content: "\f162"; +} + +.fa-hand-holding-droplet::before { + content: "\f4c1"; +} + +.fa-hand-holding-water::before { + content: "\f4c1"; +} + +.fa-water::before { + content: "\f773"; +} + +.fa-calendar-check::before { + content: "\f274"; +} + +.fa-braille::before { + content: "\f2a1"; +} + +.fa-prescription-bottle-medical::before { + content: "\f486"; +} + +.fa-prescription-bottle-alt::before { + content: "\f486"; +} + +.fa-landmark::before { + content: "\f66f"; +} + +.fa-truck::before { + content: "\f0d1"; +} + +.fa-crosshairs::before { + content: "\f05b"; +} + +.fa-person-cane::before { + content: "\e53c"; +} + +.fa-tent::before { + content: "\e57d"; +} + +.fa-vest-patches::before { + content: "\e086"; +} + +.fa-check-double::before { + content: "\f560"; +} + +.fa-arrow-down-a-z::before { + content: "\f15d"; +} + +.fa-sort-alpha-asc::before { + content: "\f15d"; +} + +.fa-sort-alpha-down::before { + content: "\f15d"; +} + +.fa-money-bill-wheat::before { + content: "\e52a"; +} + +.fa-cookie::before { + content: "\f563"; +} + +.fa-arrow-rotate-left::before { + content: "\f0e2"; +} + +.fa-arrow-left-rotate::before { + content: "\f0e2"; +} + +.fa-arrow-rotate-back::before { + content: "\f0e2"; +} + +.fa-arrow-rotate-backward::before { + content: "\f0e2"; +} + +.fa-undo::before { + content: "\f0e2"; +} + +.fa-hard-drive::before { + content: "\f0a0"; +} + +.fa-hdd::before { + content: "\f0a0"; +} + +.fa-face-grin-squint-tears::before { + content: "\f586"; +} + +.fa-grin-squint-tears::before { + content: "\f586"; +} + +.fa-dumbbell::before { + content: "\f44b"; +} + +.fa-rectangle-list::before { + content: "\f022"; +} + +.fa-list-alt::before { + content: "\f022"; +} + +.fa-tarp-droplet::before { + content: "\e57c"; +} + +.fa-house-medical-circle-check::before { + content: "\e511"; +} + +.fa-person-skiing-nordic::before { + content: "\f7ca"; +} + +.fa-skiing-nordic::before { + content: "\f7ca"; +} + +.fa-calendar-plus::before { + content: "\f271"; +} + +.fa-plane-arrival::before { + content: "\f5af"; +} + +.fa-circle-left::before { + content: "\f359"; +} + +.fa-arrow-alt-circle-left::before { + content: "\f359"; +} + +.fa-train-subway::before { + content: "\f239"; +} + +.fa-subway::before { + content: "\f239"; +} + +.fa-chart-gantt::before { + content: "\e0e4"; +} + +.fa-indian-rupee-sign::before { + content: "\e1bc"; +} + +.fa-indian-rupee::before { + content: "\e1bc"; +} + +.fa-inr::before { + content: "\e1bc"; +} + +.fa-crop-simple::before { + content: "\f565"; +} + +.fa-crop-alt::before { + content: "\f565"; +} + +.fa-money-bill-1::before { + content: "\f3d1"; +} + +.fa-money-bill-alt::before { + content: "\f3d1"; +} + +.fa-left-long::before { + content: "\f30a"; +} + +.fa-long-arrow-alt-left::before { + content: "\f30a"; +} + +.fa-dna::before { + content: "\f471"; +} + +.fa-virus-slash::before { + content: "\e075"; +} + +.fa-minus::before { + content: "\f068"; +} + +.fa-subtract::before { + content: "\f068"; +} + +.fa-chess::before { + content: "\f439"; +} + +.fa-arrow-left-long::before { + content: "\f177"; +} + +.fa-long-arrow-left::before { + content: "\f177"; +} + +.fa-plug-circle-check::before { + content: "\e55c"; +} + +.fa-street-view::before { + content: "\f21d"; +} + +.fa-franc-sign::before { + content: "\e18f"; +} + +.fa-volume-off::before { + content: "\f026"; +} + +.fa-hands-asl-interpreting::before { + content: "\f2a3"; +} + +.fa-american-sign-language-interpreting::before { + content: "\f2a3"; +} + +.fa-asl-interpreting::before { + content: "\f2a3"; +} + +.fa-hands-american-sign-language-interpreting::before { + content: "\f2a3"; +} + +.fa-gear::before { + content: "\f013"; +} + +.fa-cog::before { + content: "\f013"; +} + +.fa-droplet-slash::before { + content: "\f5c7"; +} + +.fa-tint-slash::before { + content: "\f5c7"; +} + +.fa-mosque::before { + content: "\f678"; +} + +.fa-mosquito::before { + content: "\e52b"; +} + +.fa-star-of-david::before { + content: "\f69a"; +} + +.fa-person-military-rifle::before { + content: "\e54b"; +} + +.fa-cart-shopping::before { + content: "\f07a"; +} + +.fa-shopping-cart::before { + content: "\f07a"; +} + +.fa-vials::before { + content: "\f493"; +} + +.fa-plug-circle-plus::before { + content: "\e55f"; +} + +.fa-place-of-worship::before { + content: "\f67f"; +} + +.fa-grip-vertical::before { + content: "\f58e"; +} + +.fa-arrow-turn-up::before { + content: "\f148"; +} + +.fa-level-up::before { + content: "\f148"; +} + +.fa-u::before { + content: "\55"; +} + +.fa-square-root-variable::before { + content: "\f698"; +} + +.fa-square-root-alt::before { + content: "\f698"; +} + +.fa-clock::before { + content: "\f017"; +} + +.fa-clock-four::before { + content: "\f017"; +} + +.fa-backward-step::before { + content: "\f048"; +} + +.fa-step-backward::before { + content: "\f048"; +} + +.fa-pallet::before { + content: "\f482"; +} + +.fa-faucet::before { + content: "\e005"; +} + +.fa-baseball-bat-ball::before { + content: "\f432"; +} + +.fa-s::before { + content: "\53"; +} + +.fa-timeline::before { + content: "\e29c"; +} + +.fa-keyboard::before { + content: "\f11c"; +} + +.fa-caret-down::before { + content: "\f0d7"; +} + +.fa-house-chimney-medical::before { + content: "\f7f2"; +} + +.fa-clinic-medical::before { + content: "\f7f2"; +} + +.fa-temperature-three-quarters::before { + content: "\f2c8"; +} + +.fa-temperature-3::before { + content: "\f2c8"; +} + +.fa-thermometer-3::before { + content: "\f2c8"; +} + +.fa-thermometer-three-quarters::before { + content: "\f2c8"; +} + +.fa-mobile-screen::before { + content: "\f3cf"; +} + +.fa-mobile-android-alt::before { + content: "\f3cf"; +} + +.fa-plane-up::before { + content: "\e22d"; +} + +.fa-piggy-bank::before { + content: "\f4d3"; +} + +.fa-battery-half::before { + content: "\f242"; +} + +.fa-battery-3::before { + content: "\f242"; +} + +.fa-mountain-city::before { + content: "\e52e"; +} + +.fa-coins::before { + content: "\f51e"; +} + +.fa-khanda::before { + content: "\f66d"; +} + +.fa-sliders::before { + content: "\f1de"; +} + +.fa-sliders-h::before { + content: "\f1de"; +} + +.fa-folder-tree::before { + content: "\f802"; +} + +.fa-network-wired::before { + content: "\f6ff"; +} + +.fa-map-pin::before { + content: "\f276"; +} + +.fa-hamsa::before { + content: "\f665"; +} + +.fa-cent-sign::before { + content: "\e3f5"; +} + +.fa-flask::before { + content: "\f0c3"; +} + +.fa-person-pregnant::before { + content: "\e31e"; +} + +.fa-wand-sparkles::before { + content: "\f72b"; +} + +.fa-ellipsis-vertical::before { + content: "\f142"; +} + +.fa-ellipsis-v::before { + content: "\f142"; +} + +.fa-ticket::before { + content: "\f145"; +} + +.fa-power-off::before { + content: "\f011"; +} + +.fa-right-long::before { + content: "\f30b"; +} + +.fa-long-arrow-alt-right::before { + content: "\f30b"; +} + +.fa-flag-usa::before { + content: "\f74d"; +} + +.fa-laptop-file::before { + content: "\e51d"; +} + +.fa-tty::before { + content: "\f1e4"; +} + +.fa-teletype::before { + content: "\f1e4"; +} + +.fa-diagram-next::before { + content: "\e476"; +} + +.fa-person-rifle::before { + content: "\e54e"; +} + +.fa-house-medical-circle-exclamation::before { + content: "\e512"; +} + +.fa-closed-captioning::before { + content: "\f20a"; +} + +.fa-person-hiking::before { + content: "\f6ec"; +} + +.fa-hiking::before { + content: "\f6ec"; +} + +.fa-venus-double::before { + content: "\f226"; +} + +.fa-images::before { + content: "\f302"; +} + +.fa-calculator::before { + content: "\f1ec"; +} + +.fa-people-pulling::before { + content: "\e535"; +} + +.fa-n::before { + content: "\4e"; +} + +.fa-cable-car::before { + content: "\f7da"; +} + +.fa-tram::before { + content: "\f7da"; +} + +.fa-cloud-rain::before { + content: "\f73d"; +} + +.fa-building-circle-xmark::before { + content: "\e4d4"; +} + +.fa-ship::before { + content: "\f21a"; +} + +.fa-arrows-down-to-line::before { + content: "\e4b8"; +} + +.fa-download::before { + content: "\f019"; +} + +.fa-face-grin::before { + content: "\f580"; +} + +.fa-grin::before { + content: "\f580"; +} + +.fa-delete-left::before { + content: "\f55a"; +} + +.fa-backspace::before { + content: "\f55a"; +} + +.fa-eye-dropper::before { + content: "\f1fb"; +} + +.fa-eye-dropper-empty::before { + content: "\f1fb"; +} + +.fa-eyedropper::before { + content: "\f1fb"; +} + +.fa-file-circle-check::before { + content: "\e5a0"; +} + +.fa-forward::before { + content: "\f04e"; +} + +.fa-mobile::before { + content: "\f3ce"; +} + +.fa-mobile-android::before { + content: "\f3ce"; +} + +.fa-mobile-phone::before { + content: "\f3ce"; +} + +.fa-face-meh::before { + content: "\f11a"; +} + +.fa-meh::before { + content: "\f11a"; +} + +.fa-align-center::before { + content: "\f037"; +} + +.fa-book-skull::before { + content: "\f6b7"; +} + +.fa-book-dead::before { + content: "\f6b7"; +} + +.fa-id-card::before { + content: "\f2c2"; +} + +.fa-drivers-license::before { + content: "\f2c2"; +} + +.fa-outdent::before { + content: "\f03b"; +} + +.fa-dedent::before { + content: "\f03b"; +} + +.fa-heart-circle-exclamation::before { + content: "\e4fe"; +} + +.fa-house::before { + content: "\f015"; +} + +.fa-home::before { + content: "\f015"; +} + +.fa-home-alt::before { + content: "\f015"; +} + +.fa-home-lg-alt::before { + content: "\f015"; +} + +.fa-calendar-week::before { + content: "\f784"; +} + +.fa-laptop-medical::before { + content: "\f812"; +} + +.fa-b::before { + content: "\42"; +} + +.fa-file-medical::before { + content: "\f477"; +} + +.fa-dice-one::before { + content: "\f525"; +} + +.fa-kiwi-bird::before { + content: "\f535"; +} + +.fa-arrow-right-arrow-left::before { + content: "\f0ec"; +} + +.fa-exchange::before { + content: "\f0ec"; +} + +.fa-rotate-right::before { + content: "\f2f9"; +} + +.fa-redo-alt::before { + content: "\f2f9"; +} + +.fa-rotate-forward::before { + content: "\f2f9"; +} + +.fa-utensils::before { + content: "\f2e7"; +} + +.fa-cutlery::before { + content: "\f2e7"; +} + +.fa-arrow-up-wide-short::before { + content: "\f161"; +} + +.fa-sort-amount-up::before { + content: "\f161"; +} + +.fa-mill-sign::before { + content: "\e1ed"; +} + +.fa-bowl-rice::before { + content: "\e2eb"; +} + +.fa-skull::before { + content: "\f54c"; +} + +.fa-tower-broadcast::before { + content: "\f519"; +} + +.fa-broadcast-tower::before { + content: "\f519"; +} + +.fa-truck-pickup::before { + content: "\f63c"; +} + +.fa-up-long::before { + content: "\f30c"; +} + +.fa-long-arrow-alt-up::before { + content: "\f30c"; +} + +.fa-stop::before { + content: "\f04d"; +} + +.fa-code-merge::before { + content: "\f387"; +} + +.fa-upload::before { + content: "\f093"; +} + +.fa-hurricane::before { + content: "\f751"; +} + +.fa-mound::before { + content: "\e52d"; +} + +.fa-toilet-portable::before { + content: "\e583"; +} + +.fa-compact-disc::before { + content: "\f51f"; +} + +.fa-file-arrow-down::before { + content: "\f56d"; +} + +.fa-file-download::before { + content: "\f56d"; +} + +.fa-caravan::before { + content: "\f8ff"; +} + +.fa-shield-cat::before { + content: "\e572"; +} + +.fa-bolt::before { + content: "\f0e7"; +} + +.fa-zap::before { + content: "\f0e7"; +} + +.fa-glass-water::before { + content: "\e4f4"; +} + +.fa-oil-well::before { + content: "\e532"; +} + +.fa-vault::before { + content: "\e2c5"; +} + +.fa-mars::before { + content: "\f222"; +} + +.fa-toilet::before { + content: "\f7d8"; +} + +.fa-plane-circle-xmark::before { + content: "\e557"; +} + +.fa-yen-sign::before { + content: "\f157"; +} + +.fa-cny::before { + content: "\f157"; +} + +.fa-jpy::before { + content: "\f157"; +} + +.fa-rmb::before { + content: "\f157"; +} + +.fa-yen::before { + content: "\f157"; +} + +.fa-ruble-sign::before { + content: "\f158"; +} + +.fa-rouble::before { + content: "\f158"; +} + +.fa-rub::before { + content: "\f158"; +} + +.fa-ruble::before { + content: "\f158"; +} + +.fa-sun::before { + content: "\f185"; +} + +.fa-guitar::before { + content: "\f7a6"; +} + +.fa-face-laugh-wink::before { + content: "\f59c"; +} + +.fa-laugh-wink::before { + content: "\f59c"; +} + +.fa-horse-head::before { + content: "\f7ab"; +} + +.fa-bore-hole::before { + content: "\e4c3"; +} + +.fa-industry::before { + content: "\f275"; +} + +.fa-circle-down::before { + content: "\f358"; +} + +.fa-arrow-alt-circle-down::before { + content: "\f358"; +} + +.fa-arrows-turn-to-dots::before { + content: "\e4c1"; +} + +.fa-florin-sign::before { + content: "\e184"; +} + +.fa-arrow-down-short-wide::before { + content: "\f884"; +} + +.fa-sort-amount-desc::before { + content: "\f884"; +} + +.fa-sort-amount-down-alt::before { + content: "\f884"; +} + +.fa-less-than::before { + content: "\3c"; +} + +.fa-angle-down::before { + content: "\f107"; +} + +.fa-car-tunnel::before { + content: "\e4de"; +} + +.fa-head-side-cough::before { + content: "\e061"; +} + +.fa-grip-lines::before { + content: "\f7a4"; +} + +.fa-thumbs-down::before { + content: "\f165"; +} + +.fa-user-lock::before { + content: "\f502"; +} + +.fa-arrow-right-long::before { + content: "\f178"; +} + +.fa-long-arrow-right::before { + content: "\f178"; +} + +.fa-anchor-circle-xmark::before { + content: "\e4ac"; +} + +.fa-ellipsis::before { + content: "\f141"; +} + +.fa-ellipsis-h::before { + content: "\f141"; +} + +.fa-chess-pawn::before { + content: "\f443"; +} + +.fa-kit-medical::before { + content: "\f479"; +} + +.fa-first-aid::before { + content: "\f479"; +} + +.fa-person-through-window::before { + content: "\e5a9"; +} + +.fa-toolbox::before { + content: "\f552"; +} + +.fa-hands-holding-circle::before { + content: "\e4fb"; +} + +.fa-bug::before { + content: "\f188"; +} + +.fa-credit-card::before { + content: "\f09d"; +} + +.fa-credit-card-alt::before { + content: "\f09d"; +} + +.fa-car::before { + content: "\f1b9"; +} + +.fa-automobile::before { + content: "\f1b9"; +} + +.fa-hand-holding-hand::before { + content: "\e4f7"; +} + +.fa-book-open-reader::before { + content: "\f5da"; +} + +.fa-book-reader::before { + content: "\f5da"; +} + +.fa-mountain-sun::before { + content: "\e52f"; +} + +.fa-arrows-left-right-to-line::before { + content: "\e4ba"; +} + +.fa-dice-d20::before { + content: "\f6cf"; +} + +.fa-truck-droplet::before { + content: "\e58c"; +} + +.fa-file-circle-xmark::before { + content: "\e5a1"; +} + +.fa-temperature-arrow-up::before { + content: "\e040"; +} + +.fa-temperature-up::before { + content: "\e040"; +} + +.fa-medal::before { + content: "\f5a2"; +} + +.fa-bed::before { + content: "\f236"; +} + +.fa-square-h::before { + content: "\f0fd"; +} + +.fa-h-square::before { + content: "\f0fd"; +} + +.fa-podcast::before { + content: "\f2ce"; +} + +.fa-temperature-full::before { + content: "\f2c7"; +} + +.fa-temperature-4::before { + content: "\f2c7"; +} + +.fa-thermometer-4::before { + content: "\f2c7"; +} + +.fa-thermometer-full::before { + content: "\f2c7"; +} + +.fa-bell::before { + content: "\f0f3"; +} + +.fa-superscript::before { + content: "\f12b"; +} + +.fa-plug-circle-xmark::before { + content: "\e560"; +} + +.fa-star-of-life::before { + content: "\f621"; +} + +.fa-phone-slash::before { + content: "\f3dd"; +} + +.fa-paint-roller::before { + content: "\f5aa"; +} + +.fa-handshake-angle::before { + content: "\f4c4"; +} + +.fa-hands-helping::before { + content: "\f4c4"; +} + +.fa-location-dot::before { + content: "\f3c5"; +} + +.fa-map-marker-alt::before { + content: "\f3c5"; +} + +.fa-file::before { + content: "\f15b"; +} + +.fa-greater-than::before { + content: "\3e"; +} + +.fa-person-swimming::before { + content: "\f5c4"; +} + +.fa-swimmer::before { + content: "\f5c4"; +} + +.fa-arrow-down::before { + content: "\f063"; +} + +.fa-droplet::before { + content: "\f043"; +} + +.fa-tint::before { + content: "\f043"; +} + +.fa-eraser::before { + content: "\f12d"; +} + +.fa-earth-americas::before { + content: "\f57d"; +} + +.fa-earth::before { + content: "\f57d"; +} + +.fa-earth-america::before { + content: "\f57d"; +} + +.fa-globe-americas::before { + content: "\f57d"; +} + +.fa-person-burst::before { + content: "\e53b"; +} + +.fa-dove::before { + content: "\f4ba"; +} + +.fa-battery-empty::before { + content: "\f244"; +} + +.fa-battery-0::before { + content: "\f244"; +} + +.fa-socks::before { + content: "\f696"; +} + +.fa-inbox::before { + content: "\f01c"; +} + +.fa-section::before { + content: "\e447"; +} + +.fa-gauge-high::before { + content: "\f625"; +} + +.fa-tachometer-alt::before { + content: "\f625"; +} + +.fa-tachometer-alt-fast::before { + content: "\f625"; +} + +.fa-envelope-open-text::before { + content: "\f658"; +} + +.fa-hospital::before { + content: "\f0f8"; +} + +.fa-hospital-alt::before { + content: "\f0f8"; +} + +.fa-hospital-wide::before { + content: "\f0f8"; +} + +.fa-wine-bottle::before { + content: "\f72f"; +} + +.fa-chess-rook::before { + content: "\f447"; +} + +.fa-bars-staggered::before { + content: "\f550"; +} + +.fa-reorder::before { + content: "\f550"; +} + +.fa-stream::before { + content: "\f550"; +} + +.fa-dharmachakra::before { + content: "\f655"; +} + +.fa-hotdog::before { + content: "\f80f"; +} + +.fa-person-walking-with-cane::before { + content: "\f29d"; +} + +.fa-blind::before { + content: "\f29d"; +} + +.fa-drum::before { + content: "\f569"; +} + +.fa-ice-cream::before { + content: "\f810"; +} + +.fa-heart-circle-bolt::before { + content: "\e4fc"; +} + +.fa-fax::before { + content: "\f1ac"; +} + +.fa-paragraph::before { + content: "\f1dd"; +} + +.fa-check-to-slot::before { + content: "\f772"; +} + +.fa-vote-yea::before { + content: "\f772"; +} + +.fa-star-half::before { + content: "\f089"; +} + +.fa-boxes-stacked::before { + content: "\f468"; +} + +.fa-boxes::before { + content: "\f468"; +} + +.fa-boxes-alt::before { + content: "\f468"; +} + +.fa-link::before { + content: "\f0c1"; +} + +.fa-chain::before { + content: "\f0c1"; +} + +.fa-ear-listen::before { + content: "\f2a2"; +} + +.fa-assistive-listening-systems::before { + content: "\f2a2"; +} + +.fa-tree-city::before { + content: "\e587"; +} + +.fa-play::before { + content: "\f04b"; +} + +.fa-font::before { + content: "\f031"; +} + +.fa-rupiah-sign::before { + content: "\e23d"; +} + +.fa-magnifying-glass::before { + content: "\f002"; +} + +.fa-search::before { + content: "\f002"; +} + +.fa-table-tennis-paddle-ball::before { + content: "\f45d"; +} + +.fa-ping-pong-paddle-ball::before { + content: "\f45d"; +} + +.fa-table-tennis::before { + content: "\f45d"; +} + +.fa-person-dots-from-line::before { + content: "\f470"; +} + +.fa-diagnoses::before { + content: "\f470"; +} + +.fa-trash-can-arrow-up::before { + content: "\f82a"; +} + +.fa-trash-restore-alt::before { + content: "\f82a"; +} + +.fa-naira-sign::before { + content: "\e1f6"; +} + +.fa-cart-arrow-down::before { + content: "\f218"; +} + +.fa-walkie-talkie::before { + content: "\f8ef"; +} + +.fa-file-pen::before { + content: "\f31c"; +} + +.fa-file-edit::before { + content: "\f31c"; +} + +.fa-receipt::before { + content: "\f543"; +} + +.fa-square-pen::before { + content: "\f14b"; +} + +.fa-pen-square::before { + content: "\f14b"; +} + +.fa-pencil-square::before { + content: "\f14b"; +} + +.fa-suitcase-rolling::before { + content: "\f5c1"; +} + +.fa-person-circle-exclamation::before { + content: "\e53f"; +} + +.fa-chevron-down::before { + content: "\f078"; +} + +.fa-battery-full::before { + content: "\f240"; +} + +.fa-battery::before { + content: "\f240"; +} + +.fa-battery-5::before { + content: "\f240"; +} + +.fa-skull-crossbones::before { + content: "\f714"; +} + +.fa-code-compare::before { + content: "\e13a"; +} + +.fa-list-ul::before { + content: "\f0ca"; +} + +.fa-list-dots::before { + content: "\f0ca"; +} + +.fa-school-lock::before { + content: "\e56f"; +} + +.fa-tower-cell::before { + content: "\e585"; +} + +.fa-down-long::before { + content: "\f309"; +} + +.fa-long-arrow-alt-down::before { + content: "\f309"; +} + +.fa-ranking-star::before { + content: "\e561"; +} + +.fa-chess-king::before { + content: "\f43f"; +} + +.fa-person-harassing::before { + content: "\e549"; +} + +.fa-brazilian-real-sign::before { + content: "\e46c"; +} + +.fa-landmark-dome::before { + content: "\f752"; +} + +.fa-landmark-alt::before { + content: "\f752"; +} + +.fa-arrow-up::before { + content: "\f062"; +} + +.fa-tv::before { + content: "\f26c"; +} + +.fa-television::before { + content: "\f26c"; +} + +.fa-tv-alt::before { + content: "\f26c"; +} + +.fa-shrimp::before { + content: "\e448"; +} + +.fa-list-check::before { + content: "\f0ae"; +} + +.fa-tasks::before { + content: "\f0ae"; +} + +.fa-jug-detergent::before { + content: "\e519"; +} + +.fa-circle-user::before { + content: "\f2bd"; +} + +.fa-user-circle::before { + content: "\f2bd"; +} + +.fa-user-shield::before { + content: "\f505"; +} + +.fa-wind::before { + content: "\f72e"; +} + +.fa-car-burst::before { + content: "\f5e1"; +} + +.fa-car-crash::before { + content: "\f5e1"; +} + +.fa-y::before { + content: "\59"; +} + +.fa-person-snowboarding::before { + content: "\f7ce"; +} + +.fa-snowboarding::before { + content: "\f7ce"; +} + +.fa-truck-fast::before { + content: "\f48b"; +} + +.fa-shipping-fast::before { + content: "\f48b"; +} + +.fa-fish::before { + content: "\f578"; +} + +.fa-user-graduate::before { + content: "\f501"; +} + +.fa-circle-half-stroke::before { + content: "\f042"; +} + +.fa-adjust::before { + content: "\f042"; +} + +.fa-clapperboard::before { + content: "\e131"; +} + +.fa-circle-radiation::before { + content: "\f7ba"; +} + +.fa-radiation-alt::before { + content: "\f7ba"; +} + +.fa-baseball::before { + content: "\f433"; +} + +.fa-baseball-ball::before { + content: "\f433"; +} + +.fa-jet-fighter-up::before { + content: "\e518"; +} + +.fa-diagram-project::before { + content: "\f542"; +} + +.fa-project-diagram::before { + content: "\f542"; +} + +.fa-copy::before { + content: "\f0c5"; +} + +.fa-volume-xmark::before { + content: "\f6a9"; +} + +.fa-volume-mute::before { + content: "\f6a9"; +} + +.fa-volume-times::before { + content: "\f6a9"; +} + +.fa-hand-sparkles::before { + content: "\e05d"; +} + +.fa-grip::before { + content: "\f58d"; +} + +.fa-grip-horizontal::before { + content: "\f58d"; +} + +.fa-share-from-square::before { + content: "\f14d"; +} + +.fa-share-square::before { + content: "\f14d"; +} + +.fa-child-combatant::before { + content: "\e4e0"; +} + +.fa-child-rifle::before { + content: "\e4e0"; +} + +.fa-gun::before { + content: "\e19b"; +} + +.fa-square-phone::before { + content: "\f098"; +} + +.fa-phone-square::before { + content: "\f098"; +} + +.fa-plus::before { + content: "\2b"; +} + +.fa-add::before { + content: "\2b"; +} + +.fa-expand::before { + content: "\f065"; +} + +.fa-computer::before { + content: "\e4e5"; +} + +.fa-xmark::before { + content: "\f00d"; +} + +.fa-close::before { + content: "\f00d"; +} + +.fa-multiply::before { + content: "\f00d"; +} + +.fa-remove::before { + content: "\f00d"; +} + +.fa-times::before { + content: "\f00d"; +} + +.fa-arrows-up-down-left-right::before { + content: "\f047"; +} + +.fa-arrows::before { + content: "\f047"; +} + +.fa-chalkboard-user::before { + content: "\f51c"; +} + +.fa-chalkboard-teacher::before { + content: "\f51c"; +} + +.fa-peso-sign::before { + content: "\e222"; +} + +.fa-building-shield::before { + content: "\e4d8"; +} + +.fa-baby::before { + content: "\f77c"; +} + +.fa-users-line::before { + content: "\e592"; +} + +.fa-quote-left::before { + content: "\f10d"; +} + +.fa-quote-left-alt::before { + content: "\f10d"; +} + +.fa-tractor::before { + content: "\f722"; +} + +.fa-trash-arrow-up::before { + content: "\f829"; +} + +.fa-trash-restore::before { + content: "\f829"; +} + +.fa-arrow-down-up-lock::before { + content: "\e4b0"; +} + +.fa-lines-leaning::before { + content: "\e51e"; +} + +.fa-ruler-combined::before { + content: "\f546"; +} + +.fa-copyright::before { + content: "\f1f9"; +} + +.fa-equals::before { + content: "\3d"; +} + +.fa-blender::before { + content: "\f517"; +} + +.fa-teeth::before { + content: "\f62e"; +} + +.fa-shekel-sign::before { + content: "\f20b"; +} + +.fa-ils::before { + content: "\f20b"; +} + +.fa-shekel::before { + content: "\f20b"; +} + +.fa-sheqel::before { + content: "\f20b"; +} + +.fa-sheqel-sign::before { + content: "\f20b"; +} + +.fa-map::before { + content: "\f279"; +} + +.fa-rocket::before { + content: "\f135"; +} + +.fa-photo-film::before { + content: "\f87c"; +} + +.fa-photo-video::before { + content: "\f87c"; +} + +.fa-folder-minus::before { + content: "\f65d"; +} + +.fa-store::before { + content: "\f54e"; +} + +.fa-arrow-trend-up::before { + content: "\e098"; +} + +.fa-plug-circle-minus::before { + content: "\e55e"; +} + +.fa-sign-hanging::before { + content: "\f4d9"; +} + +.fa-sign::before { + content: "\f4d9"; +} + +.fa-bezier-curve::before { + content: "\f55b"; +} + +.fa-bell-slash::before { + content: "\f1f6"; +} + +.fa-tablet::before { + content: "\f3fb"; +} + +.fa-tablet-android::before { + content: "\f3fb"; +} + +.fa-school-flag::before { + content: "\e56e"; +} + +.fa-fill::before { + content: "\f575"; +} + +.fa-angle-up::before { + content: "\f106"; +} + +.fa-drumstick-bite::before { + content: "\f6d7"; +} + +.fa-holly-berry::before { + content: "\f7aa"; +} + +.fa-chevron-left::before { + content: "\f053"; +} + +.fa-bacteria::before { + content: "\e059"; +} + +.fa-hand-lizard::before { + content: "\f258"; +} + +.fa-notdef::before { + content: "\e1fe"; +} + +.fa-disease::before { + content: "\f7fa"; +} + +.fa-briefcase-medical::before { + content: "\f469"; +} + +.fa-genderless::before { + content: "\f22d"; +} + +.fa-chevron-right::before { + content: "\f054"; +} + +.fa-retweet::before { + content: "\f079"; +} + +.fa-car-rear::before { + content: "\f5de"; +} + +.fa-car-alt::before { + content: "\f5de"; +} + +.fa-pump-soap::before { + content: "\e06b"; +} + +.fa-video-slash::before { + content: "\f4e2"; +} + +.fa-battery-quarter::before { + content: "\f243"; +} + +.fa-battery-2::before { + content: "\f243"; +} + +.fa-radio::before { + content: "\f8d7"; +} + +.fa-baby-carriage::before { + content: "\f77d"; +} + +.fa-carriage-baby::before { + content: "\f77d"; +} + +.fa-traffic-light::before { + content: "\f637"; +} + +.fa-thermometer::before { + content: "\f491"; +} + +.fa-vr-cardboard::before { + content: "\f729"; +} + +.fa-hand-middle-finger::before { + content: "\f806"; +} + +.fa-percent::before { + content: "\25"; +} + +.fa-percentage::before { + content: "\25"; +} + +.fa-truck-moving::before { + content: "\f4df"; +} + +.fa-glass-water-droplet::before { + content: "\e4f5"; +} + +.fa-display::before { + content: "\e163"; +} + +.fa-face-smile::before { + content: "\f118"; +} + +.fa-smile::before { + content: "\f118"; +} + +.fa-thumbtack::before { + content: "\f08d"; +} + +.fa-thumb-tack::before { + content: "\f08d"; +} + +.fa-trophy::before { + content: "\f091"; +} + +.fa-person-praying::before { + content: "\f683"; +} + +.fa-pray::before { + content: "\f683"; +} + +.fa-hammer::before { + content: "\f6e3"; +} + +.fa-hand-peace::before { + content: "\f25b"; +} + +.fa-rotate::before { + content: "\f2f1"; +} + +.fa-sync-alt::before { + content: "\f2f1"; +} + +.fa-spinner::before { + content: "\f110"; +} + +.fa-robot::before { + content: "\f544"; +} + +.fa-peace::before { + content: "\f67c"; +} + +.fa-gears::before { + content: "\f085"; +} + +.fa-cogs::before { + content: "\f085"; +} + +.fa-warehouse::before { + content: "\f494"; +} + +.fa-arrow-up-right-dots::before { + content: "\e4b7"; +} + +.fa-splotch::before { + content: "\f5bc"; +} + +.fa-face-grin-hearts::before { + content: "\f584"; +} + +.fa-grin-hearts::before { + content: "\f584"; +} + +.fa-dice-four::before { + content: "\f524"; +} + +.fa-sim-card::before { + content: "\f7c4"; +} + +.fa-transgender::before { + content: "\f225"; +} + +.fa-transgender-alt::before { + content: "\f225"; +} + +.fa-mercury::before { + content: "\f223"; +} + +.fa-arrow-turn-down::before { + content: "\f149"; +} + +.fa-level-down::before { + content: "\f149"; +} + +.fa-person-falling-burst::before { + content: "\e547"; +} + +.fa-award::before { + content: "\f559"; +} + +.fa-ticket-simple::before { + content: "\f3ff"; +} + +.fa-ticket-alt::before { + content: "\f3ff"; +} + +.fa-building::before { + content: "\f1ad"; +} + +.fa-angles-left::before { + content: "\f100"; +} + +.fa-angle-double-left::before { + content: "\f100"; +} + +.fa-qrcode::before { + content: "\f029"; +} + +.fa-clock-rotate-left::before { + content: "\f1da"; +} + +.fa-history::before { + content: "\f1da"; +} + +.fa-face-grin-beam-sweat::before { + content: "\f583"; +} + +.fa-grin-beam-sweat::before { + content: "\f583"; +} + +.fa-file-export::before { + content: "\f56e"; +} + +.fa-arrow-right-from-file::before { + content: "\f56e"; +} + +.fa-shield::before { + content: "\f132"; +} + +.fa-shield-blank::before { + content: "\f132"; +} + +.fa-arrow-up-short-wide::before { + content: "\f885"; +} + +.fa-sort-amount-up-alt::before { + content: "\f885"; +} + +.fa-house-medical::before { + content: "\e3b2"; +} + +.fa-golf-ball-tee::before { + content: "\f450"; +} + +.fa-golf-ball::before { + content: "\f450"; +} + +.fa-circle-chevron-left::before { + content: "\f137"; +} + +.fa-chevron-circle-left::before { + content: "\f137"; +} + +.fa-house-chimney-window::before { + content: "\e00d"; +} + +.fa-pen-nib::before { + content: "\f5ad"; +} + +.fa-tent-arrow-turn-left::before { + content: "\e580"; +} + +.fa-tents::before { + content: "\e582"; +} + +.fa-wand-magic::before { + content: "\f0d0"; +} + +.fa-magic::before { + content: "\f0d0"; +} + +.fa-dog::before { + content: "\f6d3"; +} + +.fa-carrot::before { + content: "\f787"; +} + +.fa-moon::before { + content: "\f186"; +} + +.fa-wine-glass-empty::before { + content: "\f5ce"; +} + +.fa-wine-glass-alt::before { + content: "\f5ce"; +} + +.fa-cheese::before { + content: "\f7ef"; +} + +.fa-yin-yang::before { + content: "\f6ad"; +} + +.fa-music::before { + content: "\f001"; +} + +.fa-code-commit::before { + content: "\f386"; +} + +.fa-temperature-low::before { + content: "\f76b"; +} + +.fa-person-biking::before { + content: "\f84a"; +} + +.fa-biking::before { + content: "\f84a"; +} + +.fa-broom::before { + content: "\f51a"; +} + +.fa-shield-heart::before { + content: "\e574"; +} + +.fa-gopuram::before { + content: "\f664"; +} + +.fa-earth-oceania::before { + content: "\e47b"; +} + +.fa-globe-oceania::before { + content: "\e47b"; +} + +.fa-square-xmark::before { + content: "\f2d3"; +} + +.fa-times-square::before { + content: "\f2d3"; +} + +.fa-xmark-square::before { + content: "\f2d3"; +} + +.fa-hashtag::before { + content: "\23"; +} + +.fa-up-right-and-down-left-from-center::before { + content: "\f424"; +} + +.fa-expand-alt::before { + content: "\f424"; +} + +.fa-oil-can::before { + content: "\f613"; +} + +.fa-t::before { + content: "\54"; +} + +.fa-hippo::before { + content: "\f6ed"; +} + +.fa-chart-column::before { + content: "\e0e3"; +} + +.fa-infinity::before { + content: "\f534"; +} + +.fa-vial-circle-check::before { + content: "\e596"; +} + +.fa-person-arrow-down-to-line::before { + content: "\e538"; +} + +.fa-voicemail::before { + content: "\f897"; +} + +.fa-fan::before { + content: "\f863"; +} + +.fa-person-walking-luggage::before { + content: "\e554"; +} + +.fa-up-down::before { + content: "\f338"; +} + +.fa-arrows-alt-v::before { + content: "\f338"; +} + +.fa-cloud-moon-rain::before { + content: "\f73c"; +} + +.fa-calendar::before { + content: "\f133"; +} + +.fa-trailer::before { + content: "\e041"; +} + +.fa-bahai::before { + content: "\f666"; +} + +.fa-haykal::before { + content: "\f666"; +} + +.fa-sd-card::before { + content: "\f7c2"; +} + +.fa-dragon::before { + content: "\f6d5"; +} + +.fa-shoe-prints::before { + content: "\f54b"; +} + +.fa-circle-plus::before { + content: "\f055"; +} + +.fa-plus-circle::before { + content: "\f055"; +} + +.fa-face-grin-tongue-wink::before { + content: "\f58b"; +} + +.fa-grin-tongue-wink::before { + content: "\f58b"; +} + +.fa-hand-holding::before { + content: "\f4bd"; +} + +.fa-plug-circle-exclamation::before { + content: "\e55d"; +} + +.fa-link-slash::before { + content: "\f127"; +} + +.fa-chain-broken::before { + content: "\f127"; +} + +.fa-chain-slash::before { + content: "\f127"; +} + +.fa-unlink::before { + content: "\f127"; +} + +.fa-clone::before { + content: "\f24d"; +} + +.fa-person-walking-arrow-loop-left::before { + content: "\e551"; +} + +.fa-arrow-up-z-a::before { + content: "\f882"; +} + +.fa-sort-alpha-up-alt::before { + content: "\f882"; +} + +.fa-fire-flame-curved::before { + content: "\f7e4"; +} + +.fa-fire-alt::before { + content: "\f7e4"; +} + +.fa-tornado::before { + content: "\f76f"; +} + +.fa-file-circle-plus::before { + content: "\e494"; +} + +.fa-book-quran::before { + content: "\f687"; +} + +.fa-quran::before { + content: "\f687"; +} + +.fa-anchor::before { + content: "\f13d"; +} + +.fa-border-all::before { + content: "\f84c"; +} + +.fa-face-angry::before { + content: "\f556"; +} + +.fa-angry::before { + content: "\f556"; +} + +.fa-cookie-bite::before { + content: "\f564"; +} + +.fa-arrow-trend-down::before { + content: "\e097"; +} + +.fa-rss::before { + content: "\f09e"; +} + +.fa-feed::before { + content: "\f09e"; +} + +.fa-draw-polygon::before { + content: "\f5ee"; +} + +.fa-scale-balanced::before { + content: "\f24e"; +} + +.fa-balance-scale::before { + content: "\f24e"; +} + +.fa-gauge-simple-high::before { + content: "\f62a"; +} + +.fa-tachometer::before { + content: "\f62a"; +} + +.fa-tachometer-fast::before { + content: "\f62a"; +} + +.fa-shower::before { + content: "\f2cc"; +} + +.fa-desktop::before { + content: "\f390"; +} + +.fa-desktop-alt::before { + content: "\f390"; +} + +.fa-m::before { + content: "\4d"; +} + +.fa-table-list::before { + content: "\f00b"; +} + +.fa-th-list::before { + content: "\f00b"; +} + +.fa-comment-sms::before { + content: "\f7cd"; +} + +.fa-sms::before { + content: "\f7cd"; +} + +.fa-book::before { + content: "\f02d"; +} + +.fa-user-plus::before { + content: "\f234"; +} + +.fa-check::before { + content: "\f00c"; +} + +.fa-battery-three-quarters::before { + content: "\f241"; +} + +.fa-battery-4::before { + content: "\f241"; +} + +.fa-house-circle-check::before { + content: "\e509"; +} + +.fa-angle-left::before { + content: "\f104"; +} + +.fa-diagram-successor::before { + content: "\e47a"; +} + +.fa-truck-arrow-right::before { + content: "\e58b"; +} + +.fa-arrows-split-up-and-left::before { + content: "\e4bc"; +} + +.fa-hand-fist::before { + content: "\f6de"; +} + +.fa-fist-raised::before { + content: "\f6de"; +} + +.fa-cloud-moon::before { + content: "\f6c3"; +} + +.fa-briefcase::before { + content: "\f0b1"; +} + +.fa-person-falling::before { + content: "\e546"; +} + +.fa-image-portrait::before { + content: "\f3e0"; +} + +.fa-portrait::before { + content: "\f3e0"; +} + +.fa-user-tag::before { + content: "\f507"; +} + +.fa-rug::before { + content: "\e569"; +} + +.fa-earth-europe::before { + content: "\f7a2"; +} + +.fa-globe-europe::before { + content: "\f7a2"; +} + +.fa-cart-flatbed-suitcase::before { + content: "\f59d"; +} + +.fa-luggage-cart::before { + content: "\f59d"; +} + +.fa-rectangle-xmark::before { + content: "\f410"; +} + +.fa-rectangle-times::before { + content: "\f410"; +} + +.fa-times-rectangle::before { + content: "\f410"; +} + +.fa-window-close::before { + content: "\f410"; +} + +.fa-baht-sign::before { + content: "\e0ac"; +} + +.fa-book-open::before { + content: "\f518"; +} + +.fa-book-journal-whills::before { + content: "\f66a"; +} + +.fa-journal-whills::before { + content: "\f66a"; +} + +.fa-handcuffs::before { + content: "\e4f8"; +} + +.fa-triangle-exclamation::before { + content: "\f071"; +} + +.fa-exclamation-triangle::before { + content: "\f071"; +} + +.fa-warning::before { + content: "\f071"; +} + +.fa-database::before { + content: "\f1c0"; +} + +.fa-share::before { + content: "\f064"; +} + +.fa-arrow-turn-right::before { + content: "\f064"; +} + +.fa-mail-forward::before { + content: "\f064"; +} + +.fa-bottle-droplet::before { + content: "\e4c4"; +} + +.fa-mask-face::before { + content: "\e1d7"; +} + +.fa-hill-rockslide::before { + content: "\e508"; +} + +.fa-right-left::before { + content: "\f362"; +} + +.fa-exchange-alt::before { + content: "\f362"; +} + +.fa-paper-plane::before { + content: "\f1d8"; +} + +.fa-road-circle-exclamation::before { + content: "\e565"; +} + +.fa-dungeon::before { + content: "\f6d9"; +} + +.fa-align-right::before { + content: "\f038"; +} + +.fa-money-bill-1-wave::before { + content: "\f53b"; +} + +.fa-money-bill-wave-alt::before { + content: "\f53b"; +} + +.fa-life-ring::before { + content: "\f1cd"; +} + +.fa-hands::before { + content: "\f2a7"; +} + +.fa-sign-language::before { + content: "\f2a7"; +} + +.fa-signing::before { + content: "\f2a7"; +} + +.fa-calendar-day::before { + content: "\f783"; +} + +.fa-water-ladder::before { + content: "\f5c5"; +} + +.fa-ladder-water::before { + content: "\f5c5"; +} + +.fa-swimming-pool::before { + content: "\f5c5"; +} + +.fa-arrows-up-down::before { + content: "\f07d"; +} + +.fa-arrows-v::before { + content: "\f07d"; +} + +.fa-face-grimace::before { + content: "\f57f"; +} + +.fa-grimace::before { + content: "\f57f"; +} + +.fa-wheelchair-move::before { + content: "\e2ce"; +} + +.fa-wheelchair-alt::before { + content: "\e2ce"; +} + +.fa-turn-down::before { + content: "\f3be"; +} + +.fa-level-down-alt::before { + content: "\f3be"; +} + +.fa-person-walking-arrow-right::before { + content: "\e552"; +} + +.fa-square-envelope::before { + content: "\f199"; +} + +.fa-envelope-square::before { + content: "\f199"; +} + +.fa-dice::before { + content: "\f522"; +} + +.fa-bowling-ball::before { + content: "\f436"; +} + +.fa-brain::before { + content: "\f5dc"; +} + +.fa-bandage::before { + content: "\f462"; +} + +.fa-band-aid::before { + content: "\f462"; +} + +.fa-calendar-minus::before { + content: "\f272"; +} + +.fa-circle-xmark::before { + content: "\f057"; +} + +.fa-times-circle::before { + content: "\f057"; +} + +.fa-xmark-circle::before { + content: "\f057"; +} + +.fa-gifts::before { + content: "\f79c"; +} + +.fa-hotel::before { + content: "\f594"; +} + +.fa-earth-asia::before { + content: "\f57e"; +} + +.fa-globe-asia::before { + content: "\f57e"; +} + +.fa-id-card-clip::before { + content: "\f47f"; +} + +.fa-id-card-alt::before { + content: "\f47f"; +} + +.fa-magnifying-glass-plus::before { + content: "\f00e"; +} + +.fa-search-plus::before { + content: "\f00e"; +} + +.fa-thumbs-up::before { + content: "\f164"; +} + +.fa-user-clock::before { + content: "\f4fd"; +} + +.fa-hand-dots::before { + content: "\f461"; +} + +.fa-allergies::before { + content: "\f461"; +} + +.fa-file-invoice::before { + content: "\f570"; +} + +.fa-window-minimize::before { + content: "\f2d1"; +} + +.fa-mug-saucer::before { + content: "\f0f4"; +} + +.fa-coffee::before { + content: "\f0f4"; +} + +.fa-brush::before { + content: "\f55d"; +} + +.fa-mask::before { + content: "\f6fa"; +} + +.fa-magnifying-glass-minus::before { + content: "\f010"; +} + +.fa-search-minus::before { + content: "\f010"; +} + +.fa-ruler-vertical::before { + content: "\f548"; +} + +.fa-user-large::before { + content: "\f406"; +} + +.fa-user-alt::before { + content: "\f406"; +} + +.fa-train-tram::before { + content: "\e5b4"; +} + +.fa-user-nurse::before { + content: "\f82f"; +} + +.fa-syringe::before { + content: "\f48e"; +} + +.fa-cloud-sun::before { + content: "\f6c4"; +} + +.fa-stopwatch-20::before { + content: "\e06f"; +} + +.fa-square-full::before { + content: "\f45c"; +} + +.fa-magnet::before { + content: "\f076"; +} + +.fa-jar::before { + content: "\e516"; +} + +.fa-note-sticky::before { + content: "\f249"; +} + +.fa-sticky-note::before { + content: "\f249"; +} + +.fa-bug-slash::before { + content: "\e490"; +} + +.fa-arrow-up-from-water-pump::before { + content: "\e4b6"; +} + +.fa-bone::before { + content: "\f5d7"; +} + +.fa-user-injured::before { + content: "\f728"; +} + +.fa-face-sad-tear::before { + content: "\f5b4"; +} + +.fa-sad-tear::before { + content: "\f5b4"; +} + +.fa-plane::before { + content: "\f072"; +} + +.fa-tent-arrows-down::before { + content: "\e581"; +} + +.fa-exclamation::before { + content: "\21"; +} + +.fa-arrows-spin::before { + content: "\e4bb"; +} + +.fa-print::before { + content: "\f02f"; +} + +.fa-turkish-lira-sign::before { + content: "\e2bb"; +} + +.fa-try::before { + content: "\e2bb"; +} + +.fa-turkish-lira::before { + content: "\e2bb"; +} + +.fa-dollar-sign::before { + content: "\24"; +} + +.fa-dollar::before { + content: "\24"; +} + +.fa-usd::before { + content: "\24"; +} + +.fa-x::before { + content: "\58"; +} + +.fa-magnifying-glass-dollar::before { + content: "\f688"; +} + +.fa-search-dollar::before { + content: "\f688"; +} + +.fa-users-gear::before { + content: "\f509"; +} + +.fa-users-cog::before { + content: "\f509"; +} + +.fa-person-military-pointing::before { + content: "\e54a"; +} + +.fa-building-columns::before { + content: "\f19c"; +} + +.fa-bank::before { + content: "\f19c"; +} + +.fa-institution::before { + content: "\f19c"; +} + +.fa-museum::before { + content: "\f19c"; +} + +.fa-university::before { + content: "\f19c"; +} + +.fa-umbrella::before { + content: "\f0e9"; +} + +.fa-trowel::before { + content: "\e589"; +} + +.fa-d::before { + content: "\44"; +} + +.fa-stapler::before { + content: "\e5af"; +} + +.fa-masks-theater::before { + content: "\f630"; +} + +.fa-theater-masks::before { + content: "\f630"; +} + +.fa-kip-sign::before { + content: "\e1c4"; +} + +.fa-hand-point-left::before { + content: "\f0a5"; +} + +.fa-handshake-simple::before { + content: "\f4c6"; +} + +.fa-handshake-alt::before { + content: "\f4c6"; +} + +.fa-jet-fighter::before { + content: "\f0fb"; +} + +.fa-fighter-jet::before { + content: "\f0fb"; +} + +.fa-square-share-nodes::before { + content: "\f1e1"; +} + +.fa-share-alt-square::before { + content: "\f1e1"; +} + +.fa-barcode::before { + content: "\f02a"; +} + +.fa-plus-minus::before { + content: "\e43c"; +} + +.fa-video::before { + content: "\f03d"; +} + +.fa-video-camera::before { + content: "\f03d"; +} + +.fa-graduation-cap::before { + content: "\f19d"; +} + +.fa-mortar-board::before { + content: "\f19d"; +} + +.fa-hand-holding-medical::before { + content: "\e05c"; +} + +.fa-person-circle-check::before { + content: "\e53e"; +} + +.fa-turn-up::before { + content: "\f3bf"; +} + +.fa-level-up-alt::before { + content: "\f3bf"; +} + +.sr-only, +.fa-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.sr-only-focusable:not(:focus), +.fa-sr-only-focusable:not(:focus) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +:root, :host { + --fa-style-family-brands: 'Font Awesome 6 Brands'; + --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; +} + +@font-face { + font-family: 'Font Awesome 6 Brands'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); +} + +.fab, +.fa-brands { + font-weight: 400; +} + +.fa-monero:before { + content: "\f3d0"; +} + +.fa-hooli:before { + content: "\f427"; +} + +.fa-yelp:before { + content: "\f1e9"; +} + +.fa-cc-visa:before { + content: "\f1f0"; +} + +.fa-lastfm:before { + content: "\f202"; +} + +.fa-shopware:before { + content: "\f5b5"; +} + +.fa-creative-commons-nc:before { + content: "\f4e8"; +} + +.fa-aws:before { + content: "\f375"; +} + +.fa-redhat:before { + content: "\f7bc"; +} + +.fa-yoast:before { + content: "\f2b1"; +} + +.fa-cloudflare:before { + content: "\e07d"; +} + +.fa-ups:before { + content: "\f7e0"; +} + +.fa-wpexplorer:before { + content: "\f2de"; +} + +.fa-dyalog:before { + content: "\f399"; +} + +.fa-bity:before { + content: "\f37a"; +} + +.fa-stackpath:before { + content: "\f842"; +} + +.fa-buysellads:before { + content: "\f20d"; +} + +.fa-first-order:before { + content: "\f2b0"; +} + +.fa-modx:before { + content: "\f285"; +} + +.fa-guilded:before { + content: "\e07e"; +} + +.fa-vnv:before { + content: "\f40b"; +} + +.fa-square-js:before { + content: "\f3b9"; +} + +.fa-js-square:before { + content: "\f3b9"; +} + +.fa-microsoft:before { + content: "\f3ca"; +} + +.fa-qq:before { + content: "\f1d6"; +} + +.fa-orcid:before { + content: "\f8d2"; +} + +.fa-java:before { + content: "\f4e4"; +} + +.fa-invision:before { + content: "\f7b0"; +} + +.fa-creative-commons-pd-alt:before { + content: "\f4ed"; +} + +.fa-centercode:before { + content: "\f380"; +} + +.fa-glide-g:before { + content: "\f2a6"; +} + +.fa-drupal:before { + content: "\f1a9"; +} + +.fa-hire-a-helper:before { + content: "\f3b0"; +} + +.fa-creative-commons-by:before { + content: "\f4e7"; +} + +.fa-unity:before { + content: "\e049"; +} + +.fa-whmcs:before { + content: "\f40d"; +} + +.fa-rocketchat:before { + content: "\f3e8"; +} + +.fa-vk:before { + content: "\f189"; +} + +.fa-untappd:before { + content: "\f405"; +} + +.fa-mailchimp:before { + content: "\f59e"; +} + +.fa-css3-alt:before { + content: "\f38b"; +} + +.fa-square-reddit:before { + content: "\f1a2"; +} + +.fa-reddit-square:before { + content: "\f1a2"; +} + +.fa-vimeo-v:before { + content: "\f27d"; +} + +.fa-contao:before { + content: "\f26d"; +} + +.fa-square-font-awesome:before { + content: "\e5ad"; +} + +.fa-deskpro:before { + content: "\f38f"; +} + +.fa-sistrix:before { + content: "\f3ee"; +} + +.fa-square-instagram:before { + content: "\e055"; +} + +.fa-instagram-square:before { + content: "\e055"; +} + +.fa-battle-net:before { + content: "\f835"; +} + +.fa-the-red-yeti:before { + content: "\f69d"; +} + +.fa-square-hacker-news:before { + content: "\f3af"; +} + +.fa-hacker-news-square:before { + content: "\f3af"; +} + +.fa-edge:before { + content: "\f282"; +} + +.fa-threads:before { + content: "\e618"; +} + +.fa-napster:before { + content: "\f3d2"; +} + +.fa-square-snapchat:before { + content: "\f2ad"; +} + +.fa-snapchat-square:before { + content: "\f2ad"; +} + +.fa-google-plus-g:before { + content: "\f0d5"; +} + +.fa-artstation:before { + content: "\f77a"; +} + +.fa-markdown:before { + content: "\f60f"; +} + +.fa-sourcetree:before { + content: "\f7d3"; +} + +.fa-google-plus:before { + content: "\f2b3"; +} + +.fa-diaspora:before { + content: "\f791"; +} + +.fa-foursquare:before { + content: "\f180"; +} + +.fa-stack-overflow:before { + content: "\f16c"; +} + +.fa-github-alt:before { + content: "\f113"; +} + +.fa-phoenix-squadron:before { + content: "\f511"; +} + +.fa-pagelines:before { + content: "\f18c"; +} + +.fa-algolia:before { + content: "\f36c"; +} + +.fa-red-river:before { + content: "\f3e3"; +} + +.fa-creative-commons-sa:before { + content: "\f4ef"; +} + +.fa-safari:before { + content: "\f267"; +} + +.fa-google:before { + content: "\f1a0"; +} + +.fa-square-font-awesome-stroke:before { + content: "\f35c"; +} + +.fa-font-awesome-alt:before { + content: "\f35c"; +} + +.fa-atlassian:before { + content: "\f77b"; +} + +.fa-linkedin-in:before { + content: "\f0e1"; +} + +.fa-digital-ocean:before { + content: "\f391"; +} + +.fa-nimblr:before { + content: "\f5a8"; +} + +.fa-chromecast:before { + content: "\f838"; +} + +.fa-evernote:before { + content: "\f839"; +} + +.fa-hacker-news:before { + content: "\f1d4"; +} + +.fa-creative-commons-sampling:before { + content: "\f4f0"; +} + +.fa-adversal:before { + content: "\f36a"; +} + +.fa-creative-commons:before { + content: "\f25e"; +} + +.fa-watchman-monitoring:before { + content: "\e087"; +} + +.fa-fonticons:before { + content: "\f280"; +} + +.fa-weixin:before { + content: "\f1d7"; +} + +.fa-shirtsinbulk:before { + content: "\f214"; +} + +.fa-codepen:before { + content: "\f1cb"; +} + +.fa-git-alt:before { + content: "\f841"; +} + +.fa-lyft:before { + content: "\f3c3"; +} + +.fa-rev:before { + content: "\f5b2"; +} + +.fa-windows:before { + content: "\f17a"; +} + +.fa-wizards-of-the-coast:before { + content: "\f730"; +} + +.fa-square-viadeo:before { + content: "\f2aa"; +} + +.fa-viadeo-square:before { + content: "\f2aa"; +} + +.fa-meetup:before { + content: "\f2e0"; +} + +.fa-centos:before { + content: "\f789"; +} + +.fa-adn:before { + content: "\f170"; +} + +.fa-cloudsmith:before { + content: "\f384"; +} + +.fa-pied-piper-alt:before { + content: "\f1a8"; +} + +.fa-square-dribbble:before { + content: "\f397"; +} + +.fa-dribbble-square:before { + content: "\f397"; +} + +.fa-codiepie:before { + content: "\f284"; +} + +.fa-node:before { + content: "\f419"; +} + +.fa-mix:before { + content: "\f3cb"; +} + +.fa-steam:before { + content: "\f1b6"; +} + +.fa-cc-apple-pay:before { + content: "\f416"; +} + +.fa-scribd:before { + content: "\f28a"; +} + +.fa-debian:before { + content: "\e60b"; +} + +.fa-openid:before { + content: "\f19b"; +} + +.fa-instalod:before { + content: "\e081"; +} + +.fa-expeditedssl:before { + content: "\f23e"; +} + +.fa-sellcast:before { + content: "\f2da"; +} + +.fa-square-twitter:before { + content: "\f081"; +} + +.fa-twitter-square:before { + content: "\f081"; +} + +.fa-r-project:before { + content: "\f4f7"; +} + +.fa-delicious:before { + content: "\f1a5"; +} + +.fa-freebsd:before { + content: "\f3a4"; +} + +.fa-vuejs:before { + content: "\f41f"; +} + +.fa-accusoft:before { + content: "\f369"; +} + +.fa-ioxhost:before { + content: "\f208"; +} + +.fa-fonticons-fi:before { + content: "\f3a2"; +} + +.fa-app-store:before { + content: "\f36f"; +} + +.fa-cc-mastercard:before { + content: "\f1f1"; +} + +.fa-itunes-note:before { + content: "\f3b5"; +} + +.fa-golang:before { + content: "\e40f"; +} + +.fa-kickstarter:before { + content: "\f3bb"; +} + +.fa-grav:before { + content: "\f2d6"; +} + +.fa-weibo:before { + content: "\f18a"; +} + +.fa-uncharted:before { + content: "\e084"; +} + +.fa-firstdraft:before { + content: "\f3a1"; +} + +.fa-square-youtube:before { + content: "\f431"; +} + +.fa-youtube-square:before { + content: "\f431"; +} + +.fa-wikipedia-w:before { + content: "\f266"; +} + +.fa-wpressr:before { + content: "\f3e4"; +} + +.fa-rendact:before { + content: "\f3e4"; +} + +.fa-angellist:before { + content: "\f209"; +} + +.fa-galactic-republic:before { + content: "\f50c"; +} + +.fa-nfc-directional:before { + content: "\e530"; +} + +.fa-skype:before { + content: "\f17e"; +} + +.fa-joget:before { + content: "\f3b7"; +} + +.fa-fedora:before { + content: "\f798"; +} + +.fa-stripe-s:before { + content: "\f42a"; +} + +.fa-meta:before { + content: "\e49b"; +} + +.fa-laravel:before { + content: "\f3bd"; +} + +.fa-hotjar:before { + content: "\f3b1"; +} + +.fa-bluetooth-b:before { + content: "\f294"; +} + +.fa-sticker-mule:before { + content: "\f3f7"; +} + +.fa-creative-commons-zero:before { + content: "\f4f3"; +} + +.fa-hips:before { + content: "\f452"; +} + +.fa-behance:before { + content: "\f1b4"; +} + +.fa-reddit:before { + content: "\f1a1"; +} + +.fa-discord:before { + content: "\f392"; +} + +.fa-chrome:before { + content: "\f268"; +} + +.fa-app-store-ios:before { + content: "\f370"; +} + +.fa-cc-discover:before { + content: "\f1f2"; +} + +.fa-wpbeginner:before { + content: "\f297"; +} + +.fa-confluence:before { + content: "\f78d"; +} + +.fa-mdb:before { + content: "\f8ca"; +} + +.fa-dochub:before { + content: "\f394"; +} + +.fa-accessible-icon:before { + content: "\f368"; +} + +.fa-ebay:before { + content: "\f4f4"; +} + +.fa-amazon:before { + content: "\f270"; +} + +.fa-unsplash:before { + content: "\e07c"; +} + +.fa-yarn:before { + content: "\f7e3"; +} + +.fa-square-steam:before { + content: "\f1b7"; +} + +.fa-steam-square:before { + content: "\f1b7"; +} + +.fa-500px:before { + content: "\f26e"; +} + +.fa-square-vimeo:before { + content: "\f194"; +} + +.fa-vimeo-square:before { + content: "\f194"; +} + +.fa-asymmetrik:before { + content: "\f372"; +} + +.fa-font-awesome:before { + content: "\f2b4"; +} + +.fa-font-awesome-flag:before { + content: "\f2b4"; +} + +.fa-font-awesome-logo-full:before { + content: "\f2b4"; +} + +.fa-gratipay:before { + content: "\f184"; +} + +.fa-apple:before { + content: "\f179"; +} + +.fa-hive:before { + content: "\e07f"; +} + +.fa-gitkraken:before { + content: "\f3a6"; +} + +.fa-keybase:before { + content: "\f4f5"; +} + +.fa-apple-pay:before { + content: "\f415"; +} + +.fa-padlet:before { + content: "\e4a0"; +} + +.fa-amazon-pay:before { + content: "\f42c"; +} + +.fa-square-github:before { + content: "\f092"; +} + +.fa-github-square:before { + content: "\f092"; +} + +.fa-stumbleupon:before { + content: "\f1a4"; +} + +.fa-fedex:before { + content: "\f797"; +} + +.fa-phoenix-framework:before { + content: "\f3dc"; +} + +.fa-shopify:before { + content: "\e057"; +} + +.fa-neos:before { + content: "\f612"; +} + +.fa-square-threads:before { + content: "\e619"; +} + +.fa-hackerrank:before { + content: "\f5f7"; +} + +.fa-researchgate:before { + content: "\f4f8"; +} + +.fa-swift:before { + content: "\f8e1"; +} + +.fa-angular:before { + content: "\f420"; +} + +.fa-speakap:before { + content: "\f3f3"; +} + +.fa-angrycreative:before { + content: "\f36e"; +} + +.fa-y-combinator:before { + content: "\f23b"; +} + +.fa-empire:before { + content: "\f1d1"; +} + +.fa-envira:before { + content: "\f299"; +} + +.fa-square-gitlab:before { + content: "\e5ae"; +} + +.fa-gitlab-square:before { + content: "\e5ae"; +} + +.fa-studiovinari:before { + content: "\f3f8"; +} + +.fa-pied-piper:before { + content: "\f2ae"; +} + +.fa-wordpress:before { + content: "\f19a"; +} + +.fa-product-hunt:before { + content: "\f288"; +} + +.fa-firefox:before { + content: "\f269"; +} + +.fa-linode:before { + content: "\f2b8"; +} + +.fa-goodreads:before { + content: "\f3a8"; +} + +.fa-square-odnoklassniki:before { + content: "\f264"; +} + +.fa-odnoklassniki-square:before { + content: "\f264"; +} + +.fa-jsfiddle:before { + content: "\f1cc"; +} + +.fa-sith:before { + content: "\f512"; +} + +.fa-themeisle:before { + content: "\f2b2"; +} + +.fa-page4:before { + content: "\f3d7"; +} + +.fa-hashnode:before { + content: "\e499"; +} + +.fa-react:before { + content: "\f41b"; +} + +.fa-cc-paypal:before { + content: "\f1f4"; +} + +.fa-squarespace:before { + content: "\f5be"; +} + +.fa-cc-stripe:before { + content: "\f1f5"; +} + +.fa-creative-commons-share:before { + content: "\f4f2"; +} + +.fa-bitcoin:before { + content: "\f379"; +} + +.fa-keycdn:before { + content: "\f3ba"; +} + +.fa-opera:before { + content: "\f26a"; +} + +.fa-itch-io:before { + content: "\f83a"; +} + +.fa-umbraco:before { + content: "\f8e8"; +} + +.fa-galactic-senate:before { + content: "\f50d"; +} + +.fa-ubuntu:before { + content: "\f7df"; +} + +.fa-draft2digital:before { + content: "\f396"; +} + +.fa-stripe:before { + content: "\f429"; +} + +.fa-houzz:before { + content: "\f27c"; +} + +.fa-gg:before { + content: "\f260"; +} + +.fa-dhl:before { + content: "\f790"; +} + +.fa-square-pinterest:before { + content: "\f0d3"; +} + +.fa-pinterest-square:before { + content: "\f0d3"; +} + +.fa-xing:before { + content: "\f168"; +} + +.fa-blackberry:before { + content: "\f37b"; +} + +.fa-creative-commons-pd:before { + content: "\f4ec"; +} + +.fa-playstation:before { + content: "\f3df"; +} + +.fa-quinscape:before { + content: "\f459"; +} + +.fa-less:before { + content: "\f41d"; +} + +.fa-blogger-b:before { + content: "\f37d"; +} + +.fa-opencart:before { + content: "\f23d"; +} + +.fa-vine:before { + content: "\f1ca"; +} + +.fa-paypal:before { + content: "\f1ed"; +} + +.fa-gitlab:before { + content: "\f296"; +} + +.fa-typo3:before { + content: "\f42b"; +} + +.fa-reddit-alien:before { + content: "\f281"; +} + +.fa-yahoo:before { + content: "\f19e"; +} + +.fa-dailymotion:before { + content: "\e052"; +} + +.fa-affiliatetheme:before { + content: "\f36b"; +} + +.fa-pied-piper-pp:before { + content: "\f1a7"; +} + +.fa-bootstrap:before { + content: "\f836"; +} + +.fa-odnoklassniki:before { + content: "\f263"; +} + +.fa-nfc-symbol:before { + content: "\e531"; +} + +.fa-ethereum:before { + content: "\f42e"; +} + +.fa-speaker-deck:before { + content: "\f83c"; +} + +.fa-creative-commons-nc-eu:before { + content: "\f4e9"; +} + +.fa-patreon:before { + content: "\f3d9"; +} + +.fa-avianex:before { + content: "\f374"; +} + +.fa-ello:before { + content: "\f5f1"; +} + +.fa-gofore:before { + content: "\f3a7"; +} + +.fa-bimobject:before { + content: "\f378"; +} + +.fa-facebook-f:before { + content: "\f39e"; +} + +.fa-square-google-plus:before { + content: "\f0d4"; +} + +.fa-google-plus-square:before { + content: "\f0d4"; +} + +.fa-mandalorian:before { + content: "\f50f"; +} + +.fa-first-order-alt:before { + content: "\f50a"; +} + +.fa-osi:before { + content: "\f41a"; +} + +.fa-google-wallet:before { + content: "\f1ee"; +} + +.fa-d-and-d-beyond:before { + content: "\f6ca"; +} + +.fa-periscope:before { + content: "\f3da"; +} + +.fa-fulcrum:before { + content: "\f50b"; +} + +.fa-cloudscale:before { + content: "\f383"; +} + +.fa-forumbee:before { + content: "\f211"; +} + +.fa-mizuni:before { + content: "\f3cc"; +} + +.fa-schlix:before { + content: "\f3ea"; +} + +.fa-square-xing:before { + content: "\f169"; +} + +.fa-xing-square:before { + content: "\f169"; +} + +.fa-bandcamp:before { + content: "\f2d5"; +} + +.fa-wpforms:before { + content: "\f298"; +} + +.fa-cloudversify:before { + content: "\f385"; +} + +.fa-usps:before { + content: "\f7e1"; +} + +.fa-megaport:before { + content: "\f5a3"; +} + +.fa-magento:before { + content: "\f3c4"; +} + +.fa-spotify:before { + content: "\f1bc"; +} + +.fa-optin-monster:before { + content: "\f23c"; +} + +.fa-fly:before { + content: "\f417"; +} + +.fa-aviato:before { + content: "\f421"; +} + +.fa-itunes:before { + content: "\f3b4"; +} + +.fa-cuttlefish:before { + content: "\f38c"; +} + +.fa-blogger:before { + content: "\f37c"; +} + +.fa-flickr:before { + content: "\f16e"; +} + +.fa-viber:before { + content: "\f409"; +} + +.fa-soundcloud:before { + content: "\f1be"; +} + +.fa-digg:before { + content: "\f1a6"; +} + +.fa-tencent-weibo:before { + content: "\f1d5"; +} + +.fa-symfony:before { + content: "\f83d"; +} + +.fa-maxcdn:before { + content: "\f136"; +} + +.fa-etsy:before { + content: "\f2d7"; +} + +.fa-facebook-messenger:before { + content: "\f39f"; +} + +.fa-audible:before { + content: "\f373"; +} + +.fa-think-peaks:before { + content: "\f731"; +} + +.fa-bilibili:before { + content: "\e3d9"; +} + +.fa-erlang:before { + content: "\f39d"; +} + +.fa-x-twitter:before { + content: "\e61b"; +} + +.fa-cotton-bureau:before { + content: "\f89e"; +} + +.fa-dashcube:before { + content: "\f210"; +} + +.fa-42-group:before { + content: "\e080"; +} + +.fa-innosoft:before { + content: "\e080"; +} + +.fa-stack-exchange:before { + content: "\f18d"; +} + +.fa-elementor:before { + content: "\f430"; +} + +.fa-square-pied-piper:before { + content: "\e01e"; +} + +.fa-pied-piper-square:before { + content: "\e01e"; +} + +.fa-creative-commons-nd:before { + content: "\f4eb"; +} + +.fa-palfed:before { + content: "\f3d8"; +} + +.fa-superpowers:before { + content: "\f2dd"; +} + +.fa-resolving:before { + content: "\f3e7"; +} + +.fa-xbox:before { + content: "\f412"; +} + +.fa-searchengin:before { + content: "\f3eb"; +} + +.fa-tiktok:before { + content: "\e07b"; +} + +.fa-square-facebook:before { + content: "\f082"; +} + +.fa-facebook-square:before { + content: "\f082"; +} + +.fa-renren:before { + content: "\f18b"; +} + +.fa-linux:before { + content: "\f17c"; +} + +.fa-glide:before { + content: "\f2a5"; +} + +.fa-linkedin:before { + content: "\f08c"; +} + +.fa-hubspot:before { + content: "\f3b2"; +} + +.fa-deploydog:before { + content: "\f38e"; +} + +.fa-twitch:before { + content: "\f1e8"; +} + +.fa-ravelry:before { + content: "\f2d9"; +} + +.fa-mixer:before { + content: "\e056"; +} + +.fa-square-lastfm:before { + content: "\f203"; +} + +.fa-lastfm-square:before { + content: "\f203"; +} + +.fa-vimeo:before { + content: "\f40a"; +} + +.fa-mendeley:before { + content: "\f7b3"; +} + +.fa-uniregistry:before { + content: "\f404"; +} + +.fa-figma:before { + content: "\f799"; +} + +.fa-creative-commons-remix:before { + content: "\f4ee"; +} + +.fa-cc-amazon-pay:before { + content: "\f42d"; +} + +.fa-dropbox:before { + content: "\f16b"; +} + +.fa-instagram:before { + content: "\f16d"; +} + +.fa-cmplid:before { + content: "\e360"; +} + +.fa-facebook:before { + content: "\f09a"; +} + +.fa-gripfire:before { + content: "\f3ac"; +} + +.fa-jedi-order:before { + content: "\f50e"; +} + +.fa-uikit:before { + content: "\f403"; +} + +.fa-fort-awesome-alt:before { + content: "\f3a3"; +} + +.fa-phabricator:before { + content: "\f3db"; +} + +.fa-ussunnah:before { + content: "\f407"; +} + +.fa-earlybirds:before { + content: "\f39a"; +} + +.fa-trade-federation:before { + content: "\f513"; +} + +.fa-autoprefixer:before { + content: "\f41c"; +} + +.fa-whatsapp:before { + content: "\f232"; +} + +.fa-slideshare:before { + content: "\f1e7"; +} + +.fa-google-play:before { + content: "\f3ab"; +} + +.fa-viadeo:before { + content: "\f2a9"; +} + +.fa-line:before { + content: "\f3c0"; +} + +.fa-google-drive:before { + content: "\f3aa"; +} + +.fa-servicestack:before { + content: "\f3ec"; +} + +.fa-simplybuilt:before { + content: "\f215"; +} + +.fa-bitbucket:before { + content: "\f171"; +} + +.fa-imdb:before { + content: "\f2d8"; +} + +.fa-deezer:before { + content: "\e077"; +} + +.fa-raspberry-pi:before { + content: "\f7bb"; +} + +.fa-jira:before { + content: "\f7b1"; +} + +.fa-docker:before { + content: "\f395"; +} + +.fa-screenpal:before { + content: "\e570"; +} + +.fa-bluetooth:before { + content: "\f293"; +} + +.fa-gitter:before { + content: "\f426"; +} + +.fa-d-and-d:before { + content: "\f38d"; +} + +.fa-microblog:before { + content: "\e01a"; +} + +.fa-cc-diners-club:before { + content: "\f24c"; +} + +.fa-gg-circle:before { + content: "\f261"; +} + +.fa-pied-piper-hat:before { + content: "\f4e5"; +} + +.fa-kickstarter-k:before { + content: "\f3bc"; +} + +.fa-yandex:before { + content: "\f413"; +} + +.fa-readme:before { + content: "\f4d5"; +} + +.fa-html5:before { + content: "\f13b"; +} + +.fa-sellsy:before { + content: "\f213"; +} + +.fa-sass:before { + content: "\f41e"; +} + +.fa-wirsindhandwerk:before { + content: "\e2d0"; +} + +.fa-wsh:before { + content: "\e2d0"; +} + +.fa-buromobelexperte:before { + content: "\f37f"; +} + +.fa-salesforce:before { + content: "\f83b"; +} + +.fa-octopus-deploy:before { + content: "\e082"; +} + +.fa-medapps:before { + content: "\f3c6"; +} + +.fa-ns8:before { + content: "\f3d5"; +} + +.fa-pinterest-p:before { + content: "\f231"; +} + +.fa-apper:before { + content: "\f371"; +} + +.fa-fort-awesome:before { + content: "\f286"; +} + +.fa-waze:before { + content: "\f83f"; +} + +.fa-cc-jcb:before { + content: "\f24b"; +} + +.fa-snapchat:before { + content: "\f2ab"; +} + +.fa-snapchat-ghost:before { + content: "\f2ab"; +} + +.fa-fantasy-flight-games:before { + content: "\f6dc"; +} + +.fa-rust:before { + content: "\e07a"; +} + +.fa-wix:before { + content: "\f5cf"; +} + +.fa-square-behance:before { + content: "\f1b5"; +} + +.fa-behance-square:before { + content: "\f1b5"; +} + +.fa-supple:before { + content: "\f3f9"; +} + +.fa-rebel:before { + content: "\f1d0"; +} + +.fa-css3:before { + content: "\f13c"; +} + +.fa-staylinked:before { + content: "\f3f5"; +} + +.fa-kaggle:before { + content: "\f5fa"; +} + +.fa-space-awesome:before { + content: "\e5ac"; +} + +.fa-deviantart:before { + content: "\f1bd"; +} + +.fa-cpanel:before { + content: "\f388"; +} + +.fa-goodreads-g:before { + content: "\f3a9"; +} + +.fa-square-git:before { + content: "\f1d2"; +} + +.fa-git-square:before { + content: "\f1d2"; +} + +.fa-square-tumblr:before { + content: "\f174"; +} + +.fa-tumblr-square:before { + content: "\f174"; +} + +.fa-trello:before { + content: "\f181"; +} + +.fa-creative-commons-nc-jp:before { + content: "\f4ea"; +} + +.fa-get-pocket:before { + content: "\f265"; +} + +.fa-perbyte:before { + content: "\e083"; +} + +.fa-grunt:before { + content: "\f3ad"; +} + +.fa-weebly:before { + content: "\f5cc"; +} + +.fa-connectdevelop:before { + content: "\f20e"; +} + +.fa-leanpub:before { + content: "\f212"; +} + +.fa-black-tie:before { + content: "\f27e"; +} + +.fa-themeco:before { + content: "\f5c6"; +} + +.fa-python:before { + content: "\f3e2"; +} + +.fa-android:before { + content: "\f17b"; +} + +.fa-bots:before { + content: "\e340"; +} + +.fa-free-code-camp:before { + content: "\f2c5"; +} + +.fa-hornbill:before { + content: "\f592"; +} + +.fa-js:before { + content: "\f3b8"; +} + +.fa-ideal:before { + content: "\e013"; +} + +.fa-git:before { + content: "\f1d3"; +} + +.fa-dev:before { + content: "\f6cc"; +} + +.fa-sketch:before { + content: "\f7c6"; +} + +.fa-yandex-international:before { + content: "\f414"; +} + +.fa-cc-amex:before { + content: "\f1f3"; +} + +.fa-uber:before { + content: "\f402"; +} + +.fa-github:before { + content: "\f09b"; +} + +.fa-php:before { + content: "\f457"; +} + +.fa-alipay:before { + content: "\f642"; +} + +.fa-youtube:before { + content: "\f167"; +} + +.fa-skyatlas:before { + content: "\f216"; +} + +.fa-firefox-browser:before { + content: "\e007"; +} + +.fa-replyd:before { + content: "\f3e6"; +} + +.fa-suse:before { + content: "\f7d6"; +} + +.fa-jenkins:before { + content: "\f3b6"; +} + +.fa-twitter:before { + content: "\f099"; +} + +.fa-rockrms:before { + content: "\f3e9"; +} + +.fa-pinterest:before { + content: "\f0d2"; +} + +.fa-buffer:before { + content: "\f837"; +} + +.fa-npm:before { + content: "\f3d4"; +} + +.fa-yammer:before { + content: "\f840"; +} + +.fa-btc:before { + content: "\f15a"; +} + +.fa-dribbble:before { + content: "\f17d"; +} + +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} + +.fa-internet-explorer:before { + content: "\f26b"; +} + +.fa-stubber:before { + content: "\e5c7"; +} + +.fa-telegram:before { + content: "\f2c6"; +} + +.fa-telegram-plane:before { + content: "\f2c6"; +} + +.fa-old-republic:before { + content: "\f510"; +} + +.fa-odysee:before { + content: "\e5c6"; +} + +.fa-square-whatsapp:before { + content: "\f40c"; +} + +.fa-whatsapp-square:before { + content: "\f40c"; +} + +.fa-node-js:before { + content: "\f3d3"; +} + +.fa-edge-legacy:before { + content: "\e078"; +} + +.fa-slack:before { + content: "\f198"; +} + +.fa-slack-hash:before { + content: "\f198"; +} + +.fa-medrt:before { + content: "\f3c8"; +} + +.fa-usb:before { + content: "\f287"; +} + +.fa-tumblr:before { + content: "\f173"; +} + +.fa-vaadin:before { + content: "\f408"; +} + +.fa-quora:before { + content: "\f2c4"; +} + +.fa-square-x-twitter:before { + content: "\e61a"; +} + +.fa-reacteurope:before { + content: "\f75d"; +} + +.fa-medium:before { + content: "\f23a"; +} + +.fa-medium-m:before { + content: "\f23a"; +} + +.fa-amilia:before { + content: "\f36d"; +} + +.fa-mixcloud:before { + content: "\f289"; +} + +.fa-flipboard:before { + content: "\f44d"; +} + +.fa-viacoin:before { + content: "\f237"; +} + +.fa-critical-role:before { + content: "\f6c9"; +} + +.fa-sitrox:before { + content: "\e44a"; +} + +.fa-discourse:before { + content: "\f393"; +} + +.fa-joomla:before { + content: "\f1aa"; +} + +.fa-mastodon:before { + content: "\f4f6"; +} + +.fa-airbnb:before { + content: "\f834"; +} + +.fa-wolf-pack-battalion:before { + content: "\f514"; +} + +.fa-buy-n-large:before { + content: "\f8a6"; +} + +.fa-gulp:before { + content: "\f3ae"; +} + +.fa-creative-commons-sampling-plus:before { + content: "\f4f1"; +} + +.fa-strava:before { + content: "\f428"; +} + +.fa-ember:before { + content: "\f423"; +} + +.fa-canadian-maple-leaf:before { + content: "\f785"; +} + +.fa-teamspeak:before { + content: "\f4f9"; +} + +.fa-pushed:before { + content: "\f3e1"; +} + +.fa-wordpress-simple:before { + content: "\f411"; +} + +.fa-nutritionix:before { + content: "\f3d6"; +} + +.fa-wodu:before { + content: "\e088"; +} + +.fa-google-pay:before { + content: "\e079"; +} + +.fa-intercom:before { + content: "\f7af"; +} + +.fa-zhihu:before { + content: "\f63f"; +} + +.fa-korvue:before { + content: "\f42f"; +} + +.fa-pix:before { + content: "\e43a"; +} + +.fa-steam-symbol:before { + content: "\f3f6"; +} + +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; +} + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); +} + +.far, +.fa-regular { + font-weight: 400; +} + +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; +} + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 900; + font-display: block; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); +} + +.fas, +.fa-solid { + font-weight: 900; +} + +@font-face { + font-family: 'Font Awesome 5 Brands'; + font-display: block; + font-weight: 400; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); +} + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-display: block; + font-weight: 900; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); +} + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-display: block; + font-weight: 400; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); +} + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); +} + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); +} + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); + unicode-range: U+F003, U+F006, U+F014, U+F016-F017, U+F01A-F01B, U+F01D, U+F022, U+F03E, U+F044, U+F046, U+F05C-F05D, U+F06E, U+F070, U+F087-F088, U+F08A, U+F094, U+F096-F097, U+F09D, U+F0A0, U+F0A2, U+F0A4-F0A7, U+F0C5, U+F0C7, U+F0E5-F0E6, U+F0EB, U+F0F6-F0F8, U+F10C, U+F114-F115, U+F118-F11A, U+F11C-F11D, U+F133, U+F147, U+F14E, U+F150-F152, U+F185-F186, U+F18E, U+F190-F192, U+F196, U+F1C1-F1C9, U+F1D9, U+F1DB, U+F1E3, U+F1EA, U+F1F7, U+F1F9, U+F20A, U+F247-F248, U+F24A, U+F24D, U+F255-F25B, U+F25D, U+F271-F274, U+F278, U+F27B, U+F28C, U+F28E, U+F29C, U+F2B5, U+F2B7, U+F2BA, U+F2BC, U+F2BE, U+F2C0-F2C1, U+F2C3, U+F2D0, U+F2D2, U+F2D4, U+F2DC; +} + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype"); + unicode-range: U+F041, U+F047, U+F065-F066, U+F07D-F07E, U+F080, U+F08B, U+F08E, U+F090, U+F09A, U+F0AC, U+F0AE, U+F0B2, U+F0D0, U+F0D6, U+F0E4, U+F0EC, U+F10A-F10B, U+F123, U+F13E, U+F148-F149, U+F14C, U+F156, U+F15E, U+F160-F161, U+F163, U+F175-F178, U+F195, U+F1F8, U+F219, U+F27A; +} diff --git a/src/main/resources/static/css/brands.css b/src/main/resources/static/css/brands.css new file mode 100644 index 0000000..5a99fcb --- /dev/null +++ b/src/main/resources/static/css/brands.css @@ -0,0 +1,2046 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-brands: 'Font Awesome 6 Brands'; + --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; +} + +@font-face { + font-family: 'Font Awesome 6 Brands'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); +} + +.fab, +.fa-brands { + font-weight: 400; +} + +.fa-monero:before { + content: "\f3d0"; +} + +.fa-hooli:before { + content: "\f427"; +} + +.fa-yelp:before { + content: "\f1e9"; +} + +.fa-cc-visa:before { + content: "\f1f0"; +} + +.fa-lastfm:before { + content: "\f202"; +} + +.fa-shopware:before { + content: "\f5b5"; +} + +.fa-creative-commons-nc:before { + content: "\f4e8"; +} + +.fa-aws:before { + content: "\f375"; +} + +.fa-redhat:before { + content: "\f7bc"; +} + +.fa-yoast:before { + content: "\f2b1"; +} + +.fa-cloudflare:before { + content: "\e07d"; +} + +.fa-ups:before { + content: "\f7e0"; +} + +.fa-wpexplorer:before { + content: "\f2de"; +} + +.fa-dyalog:before { + content: "\f399"; +} + +.fa-bity:before { + content: "\f37a"; +} + +.fa-stackpath:before { + content: "\f842"; +} + +.fa-buysellads:before { + content: "\f20d"; +} + +.fa-first-order:before { + content: "\f2b0"; +} + +.fa-modx:before { + content: "\f285"; +} + +.fa-guilded:before { + content: "\e07e"; +} + +.fa-vnv:before { + content: "\f40b"; +} + +.fa-square-js:before { + content: "\f3b9"; +} + +.fa-js-square:before { + content: "\f3b9"; +} + +.fa-microsoft:before { + content: "\f3ca"; +} + +.fa-qq:before { + content: "\f1d6"; +} + +.fa-orcid:before { + content: "\f8d2"; +} + +.fa-java:before { + content: "\f4e4"; +} + +.fa-invision:before { + content: "\f7b0"; +} + +.fa-creative-commons-pd-alt:before { + content: "\f4ed"; +} + +.fa-centercode:before { + content: "\f380"; +} + +.fa-glide-g:before { + content: "\f2a6"; +} + +.fa-drupal:before { + content: "\f1a9"; +} + +.fa-hire-a-helper:before { + content: "\f3b0"; +} + +.fa-creative-commons-by:before { + content: "\f4e7"; +} + +.fa-unity:before { + content: "\e049"; +} + +.fa-whmcs:before { + content: "\f40d"; +} + +.fa-rocketchat:before { + content: "\f3e8"; +} + +.fa-vk:before { + content: "\f189"; +} + +.fa-untappd:before { + content: "\f405"; +} + +.fa-mailchimp:before { + content: "\f59e"; +} + +.fa-css3-alt:before { + content: "\f38b"; +} + +.fa-square-reddit:before { + content: "\f1a2"; +} + +.fa-reddit-square:before { + content: "\f1a2"; +} + +.fa-vimeo-v:before { + content: "\f27d"; +} + +.fa-contao:before { + content: "\f26d"; +} + +.fa-square-font-awesome:before { + content: "\e5ad"; +} + +.fa-deskpro:before { + content: "\f38f"; +} + +.fa-sistrix:before { + content: "\f3ee"; +} + +.fa-square-instagram:before { + content: "\e055"; +} + +.fa-instagram-square:before { + content: "\e055"; +} + +.fa-battle-net:before { + content: "\f835"; +} + +.fa-the-red-yeti:before { + content: "\f69d"; +} + +.fa-square-hacker-news:before { + content: "\f3af"; +} + +.fa-hacker-news-square:before { + content: "\f3af"; +} + +.fa-edge:before { + content: "\f282"; +} + +.fa-threads:before { + content: "\e618"; +} + +.fa-napster:before { + content: "\f3d2"; +} + +.fa-square-snapchat:before { + content: "\f2ad"; +} + +.fa-snapchat-square:before { + content: "\f2ad"; +} + +.fa-google-plus-g:before { + content: "\f0d5"; +} + +.fa-artstation:before { + content: "\f77a"; +} + +.fa-markdown:before { + content: "\f60f"; +} + +.fa-sourcetree:before { + content: "\f7d3"; +} + +.fa-google-plus:before { + content: "\f2b3"; +} + +.fa-diaspora:before { + content: "\f791"; +} + +.fa-foursquare:before { + content: "\f180"; +} + +.fa-stack-overflow:before { + content: "\f16c"; +} + +.fa-github-alt:before { + content: "\f113"; +} + +.fa-phoenix-squadron:before { + content: "\f511"; +} + +.fa-pagelines:before { + content: "\f18c"; +} + +.fa-algolia:before { + content: "\f36c"; +} + +.fa-red-river:before { + content: "\f3e3"; +} + +.fa-creative-commons-sa:before { + content: "\f4ef"; +} + +.fa-safari:before { + content: "\f267"; +} + +.fa-google:before { + content: "\f1a0"; +} + +.fa-square-font-awesome-stroke:before { + content: "\f35c"; +} + +.fa-font-awesome-alt:before { + content: "\f35c"; +} + +.fa-atlassian:before { + content: "\f77b"; +} + +.fa-linkedin-in:before { + content: "\f0e1"; +} + +.fa-digital-ocean:before { + content: "\f391"; +} + +.fa-nimblr:before { + content: "\f5a8"; +} + +.fa-chromecast:before { + content: "\f838"; +} + +.fa-evernote:before { + content: "\f839"; +} + +.fa-hacker-news:before { + content: "\f1d4"; +} + +.fa-creative-commons-sampling:before { + content: "\f4f0"; +} + +.fa-adversal:before { + content: "\f36a"; +} + +.fa-creative-commons:before { + content: "\f25e"; +} + +.fa-watchman-monitoring:before { + content: "\e087"; +} + +.fa-fonticons:before { + content: "\f280"; +} + +.fa-weixin:before { + content: "\f1d7"; +} + +.fa-shirtsinbulk:before { + content: "\f214"; +} + +.fa-codepen:before { + content: "\f1cb"; +} + +.fa-git-alt:before { + content: "\f841"; +} + +.fa-lyft:before { + content: "\f3c3"; +} + +.fa-rev:before { + content: "\f5b2"; +} + +.fa-windows:before { + content: "\f17a"; +} + +.fa-wizards-of-the-coast:before { + content: "\f730"; +} + +.fa-square-viadeo:before { + content: "\f2aa"; +} + +.fa-viadeo-square:before { + content: "\f2aa"; +} + +.fa-meetup:before { + content: "\f2e0"; +} + +.fa-centos:before { + content: "\f789"; +} + +.fa-adn:before { + content: "\f170"; +} + +.fa-cloudsmith:before { + content: "\f384"; +} + +.fa-pied-piper-alt:before { + content: "\f1a8"; +} + +.fa-square-dribbble:before { + content: "\f397"; +} + +.fa-dribbble-square:before { + content: "\f397"; +} + +.fa-codiepie:before { + content: "\f284"; +} + +.fa-node:before { + content: "\f419"; +} + +.fa-mix:before { + content: "\f3cb"; +} + +.fa-steam:before { + content: "\f1b6"; +} + +.fa-cc-apple-pay:before { + content: "\f416"; +} + +.fa-scribd:before { + content: "\f28a"; +} + +.fa-debian:before { + content: "\e60b"; +} + +.fa-openid:before { + content: "\f19b"; +} + +.fa-instalod:before { + content: "\e081"; +} + +.fa-expeditedssl:before { + content: "\f23e"; +} + +.fa-sellcast:before { + content: "\f2da"; +} + +.fa-square-twitter:before { + content: "\f081"; +} + +.fa-twitter-square:before { + content: "\f081"; +} + +.fa-r-project:before { + content: "\f4f7"; +} + +.fa-delicious:before { + content: "\f1a5"; +} + +.fa-freebsd:before { + content: "\f3a4"; +} + +.fa-vuejs:before { + content: "\f41f"; +} + +.fa-accusoft:before { + content: "\f369"; +} + +.fa-ioxhost:before { + content: "\f208"; +} + +.fa-fonticons-fi:before { + content: "\f3a2"; +} + +.fa-app-store:before { + content: "\f36f"; +} + +.fa-cc-mastercard:before { + content: "\f1f1"; +} + +.fa-itunes-note:before { + content: "\f3b5"; +} + +.fa-golang:before { + content: "\e40f"; +} + +.fa-kickstarter:before { + content: "\f3bb"; +} + +.fa-grav:before { + content: "\f2d6"; +} + +.fa-weibo:before { + content: "\f18a"; +} + +.fa-uncharted:before { + content: "\e084"; +} + +.fa-firstdraft:before { + content: "\f3a1"; +} + +.fa-square-youtube:before { + content: "\f431"; +} + +.fa-youtube-square:before { + content: "\f431"; +} + +.fa-wikipedia-w:before { + content: "\f266"; +} + +.fa-wpressr:before { + content: "\f3e4"; +} + +.fa-rendact:before { + content: "\f3e4"; +} + +.fa-angellist:before { + content: "\f209"; +} + +.fa-galactic-republic:before { + content: "\f50c"; +} + +.fa-nfc-directional:before { + content: "\e530"; +} + +.fa-skype:before { + content: "\f17e"; +} + +.fa-joget:before { + content: "\f3b7"; +} + +.fa-fedora:before { + content: "\f798"; +} + +.fa-stripe-s:before { + content: "\f42a"; +} + +.fa-meta:before { + content: "\e49b"; +} + +.fa-laravel:before { + content: "\f3bd"; +} + +.fa-hotjar:before { + content: "\f3b1"; +} + +.fa-bluetooth-b:before { + content: "\f294"; +} + +.fa-sticker-mule:before { + content: "\f3f7"; +} + +.fa-creative-commons-zero:before { + content: "\f4f3"; +} + +.fa-hips:before { + content: "\f452"; +} + +.fa-behance:before { + content: "\f1b4"; +} + +.fa-reddit:before { + content: "\f1a1"; +} + +.fa-discord:before { + content: "\f392"; +} + +.fa-chrome:before { + content: "\f268"; +} + +.fa-app-store-ios:before { + content: "\f370"; +} + +.fa-cc-discover:before { + content: "\f1f2"; +} + +.fa-wpbeginner:before { + content: "\f297"; +} + +.fa-confluence:before { + content: "\f78d"; +} + +.fa-mdb:before { + content: "\f8ca"; +} + +.fa-dochub:before { + content: "\f394"; +} + +.fa-accessible-icon:before { + content: "\f368"; +} + +.fa-ebay:before { + content: "\f4f4"; +} + +.fa-amazon:before { + content: "\f270"; +} + +.fa-unsplash:before { + content: "\e07c"; +} + +.fa-yarn:before { + content: "\f7e3"; +} + +.fa-square-steam:before { + content: "\f1b7"; +} + +.fa-steam-square:before { + content: "\f1b7"; +} + +.fa-500px:before { + content: "\f26e"; +} + +.fa-square-vimeo:before { + content: "\f194"; +} + +.fa-vimeo-square:before { + content: "\f194"; +} + +.fa-asymmetrik:before { + content: "\f372"; +} + +.fa-font-awesome:before { + content: "\f2b4"; +} + +.fa-font-awesome-flag:before { + content: "\f2b4"; +} + +.fa-font-awesome-logo-full:before { + content: "\f2b4"; +} + +.fa-gratipay:before { + content: "\f184"; +} + +.fa-apple:before { + content: "\f179"; +} + +.fa-hive:before { + content: "\e07f"; +} + +.fa-gitkraken:before { + content: "\f3a6"; +} + +.fa-keybase:before { + content: "\f4f5"; +} + +.fa-apple-pay:before { + content: "\f415"; +} + +.fa-padlet:before { + content: "\e4a0"; +} + +.fa-amazon-pay:before { + content: "\f42c"; +} + +.fa-square-github:before { + content: "\f092"; +} + +.fa-github-square:before { + content: "\f092"; +} + +.fa-stumbleupon:before { + content: "\f1a4"; +} + +.fa-fedex:before { + content: "\f797"; +} + +.fa-phoenix-framework:before { + content: "\f3dc"; +} + +.fa-shopify:before { + content: "\e057"; +} + +.fa-neos:before { + content: "\f612"; +} + +.fa-square-threads:before { + content: "\e619"; +} + +.fa-hackerrank:before { + content: "\f5f7"; +} + +.fa-researchgate:before { + content: "\f4f8"; +} + +.fa-swift:before { + content: "\f8e1"; +} + +.fa-angular:before { + content: "\f420"; +} + +.fa-speakap:before { + content: "\f3f3"; +} + +.fa-angrycreative:before { + content: "\f36e"; +} + +.fa-y-combinator:before { + content: "\f23b"; +} + +.fa-empire:before { + content: "\f1d1"; +} + +.fa-envira:before { + content: "\f299"; +} + +.fa-square-gitlab:before { + content: "\e5ae"; +} + +.fa-gitlab-square:before { + content: "\e5ae"; +} + +.fa-studiovinari:before { + content: "\f3f8"; +} + +.fa-pied-piper:before { + content: "\f2ae"; +} + +.fa-wordpress:before { + content: "\f19a"; +} + +.fa-product-hunt:before { + content: "\f288"; +} + +.fa-firefox:before { + content: "\f269"; +} + +.fa-linode:before { + content: "\f2b8"; +} + +.fa-goodreads:before { + content: "\f3a8"; +} + +.fa-square-odnoklassniki:before { + content: "\f264"; +} + +.fa-odnoklassniki-square:before { + content: "\f264"; +} + +.fa-jsfiddle:before { + content: "\f1cc"; +} + +.fa-sith:before { + content: "\f512"; +} + +.fa-themeisle:before { + content: "\f2b2"; +} + +.fa-page4:before { + content: "\f3d7"; +} + +.fa-hashnode:before { + content: "\e499"; +} + +.fa-react:before { + content: "\f41b"; +} + +.fa-cc-paypal:before { + content: "\f1f4"; +} + +.fa-squarespace:before { + content: "\f5be"; +} + +.fa-cc-stripe:before { + content: "\f1f5"; +} + +.fa-creative-commons-share:before { + content: "\f4f2"; +} + +.fa-bitcoin:before { + content: "\f379"; +} + +.fa-keycdn:before { + content: "\f3ba"; +} + +.fa-opera:before { + content: "\f26a"; +} + +.fa-itch-io:before { + content: "\f83a"; +} + +.fa-umbraco:before { + content: "\f8e8"; +} + +.fa-galactic-senate:before { + content: "\f50d"; +} + +.fa-ubuntu:before { + content: "\f7df"; +} + +.fa-draft2digital:before { + content: "\f396"; +} + +.fa-stripe:before { + content: "\f429"; +} + +.fa-houzz:before { + content: "\f27c"; +} + +.fa-gg:before { + content: "\f260"; +} + +.fa-dhl:before { + content: "\f790"; +} + +.fa-square-pinterest:before { + content: "\f0d3"; +} + +.fa-pinterest-square:before { + content: "\f0d3"; +} + +.fa-xing:before { + content: "\f168"; +} + +.fa-blackberry:before { + content: "\f37b"; +} + +.fa-creative-commons-pd:before { + content: "\f4ec"; +} + +.fa-playstation:before { + content: "\f3df"; +} + +.fa-quinscape:before { + content: "\f459"; +} + +.fa-less:before { + content: "\f41d"; +} + +.fa-blogger-b:before { + content: "\f37d"; +} + +.fa-opencart:before { + content: "\f23d"; +} + +.fa-vine:before { + content: "\f1ca"; +} + +.fa-paypal:before { + content: "\f1ed"; +} + +.fa-gitlab:before { + content: "\f296"; +} + +.fa-typo3:before { + content: "\f42b"; +} + +.fa-reddit-alien:before { + content: "\f281"; +} + +.fa-yahoo:before { + content: "\f19e"; +} + +.fa-dailymotion:before { + content: "\e052"; +} + +.fa-affiliatetheme:before { + content: "\f36b"; +} + +.fa-pied-piper-pp:before { + content: "\f1a7"; +} + +.fa-bootstrap:before { + content: "\f836"; +} + +.fa-odnoklassniki:before { + content: "\f263"; +} + +.fa-nfc-symbol:before { + content: "\e531"; +} + +.fa-ethereum:before { + content: "\f42e"; +} + +.fa-speaker-deck:before { + content: "\f83c"; +} + +.fa-creative-commons-nc-eu:before { + content: "\f4e9"; +} + +.fa-patreon:before { + content: "\f3d9"; +} + +.fa-avianex:before { + content: "\f374"; +} + +.fa-ello:before { + content: "\f5f1"; +} + +.fa-gofore:before { + content: "\f3a7"; +} + +.fa-bimobject:before { + content: "\f378"; +} + +.fa-facebook-f:before { + content: "\f39e"; +} + +.fa-square-google-plus:before { + content: "\f0d4"; +} + +.fa-google-plus-square:before { + content: "\f0d4"; +} + +.fa-mandalorian:before { + content: "\f50f"; +} + +.fa-first-order-alt:before { + content: "\f50a"; +} + +.fa-osi:before { + content: "\f41a"; +} + +.fa-google-wallet:before { + content: "\f1ee"; +} + +.fa-d-and-d-beyond:before { + content: "\f6ca"; +} + +.fa-periscope:before { + content: "\f3da"; +} + +.fa-fulcrum:before { + content: "\f50b"; +} + +.fa-cloudscale:before { + content: "\f383"; +} + +.fa-forumbee:before { + content: "\f211"; +} + +.fa-mizuni:before { + content: "\f3cc"; +} + +.fa-schlix:before { + content: "\f3ea"; +} + +.fa-square-xing:before { + content: "\f169"; +} + +.fa-xing-square:before { + content: "\f169"; +} + +.fa-bandcamp:before { + content: "\f2d5"; +} + +.fa-wpforms:before { + content: "\f298"; +} + +.fa-cloudversify:before { + content: "\f385"; +} + +.fa-usps:before { + content: "\f7e1"; +} + +.fa-megaport:before { + content: "\f5a3"; +} + +.fa-magento:before { + content: "\f3c4"; +} + +.fa-spotify:before { + content: "\f1bc"; +} + +.fa-optin-monster:before { + content: "\f23c"; +} + +.fa-fly:before { + content: "\f417"; +} + +.fa-aviato:before { + content: "\f421"; +} + +.fa-itunes:before { + content: "\f3b4"; +} + +.fa-cuttlefish:before { + content: "\f38c"; +} + +.fa-blogger:before { + content: "\f37c"; +} + +.fa-flickr:before { + content: "\f16e"; +} + +.fa-viber:before { + content: "\f409"; +} + +.fa-soundcloud:before { + content: "\f1be"; +} + +.fa-digg:before { + content: "\f1a6"; +} + +.fa-tencent-weibo:before { + content: "\f1d5"; +} + +.fa-symfony:before { + content: "\f83d"; +} + +.fa-maxcdn:before { + content: "\f136"; +} + +.fa-etsy:before { + content: "\f2d7"; +} + +.fa-facebook-messenger:before { + content: "\f39f"; +} + +.fa-audible:before { + content: "\f373"; +} + +.fa-think-peaks:before { + content: "\f731"; +} + +.fa-bilibili:before { + content: "\e3d9"; +} + +.fa-erlang:before { + content: "\f39d"; +} + +.fa-x-twitter:before { + content: "\e61b"; +} + +.fa-cotton-bureau:before { + content: "\f89e"; +} + +.fa-dashcube:before { + content: "\f210"; +} + +.fa-42-group:before { + content: "\e080"; +} + +.fa-innosoft:before { + content: "\e080"; +} + +.fa-stack-exchange:before { + content: "\f18d"; +} + +.fa-elementor:before { + content: "\f430"; +} + +.fa-square-pied-piper:before { + content: "\e01e"; +} + +.fa-pied-piper-square:before { + content: "\e01e"; +} + +.fa-creative-commons-nd:before { + content: "\f4eb"; +} + +.fa-palfed:before { + content: "\f3d8"; +} + +.fa-superpowers:before { + content: "\f2dd"; +} + +.fa-resolving:before { + content: "\f3e7"; +} + +.fa-xbox:before { + content: "\f412"; +} + +.fa-searchengin:before { + content: "\f3eb"; +} + +.fa-tiktok:before { + content: "\e07b"; +} + +.fa-square-facebook:before { + content: "\f082"; +} + +.fa-facebook-square:before { + content: "\f082"; +} + +.fa-renren:before { + content: "\f18b"; +} + +.fa-linux:before { + content: "\f17c"; +} + +.fa-glide:before { + content: "\f2a5"; +} + +.fa-linkedin:before { + content: "\f08c"; +} + +.fa-hubspot:before { + content: "\f3b2"; +} + +.fa-deploydog:before { + content: "\f38e"; +} + +.fa-twitch:before { + content: "\f1e8"; +} + +.fa-ravelry:before { + content: "\f2d9"; +} + +.fa-mixer:before { + content: "\e056"; +} + +.fa-square-lastfm:before { + content: "\f203"; +} + +.fa-lastfm-square:before { + content: "\f203"; +} + +.fa-vimeo:before { + content: "\f40a"; +} + +.fa-mendeley:before { + content: "\f7b3"; +} + +.fa-uniregistry:before { + content: "\f404"; +} + +.fa-figma:before { + content: "\f799"; +} + +.fa-creative-commons-remix:before { + content: "\f4ee"; +} + +.fa-cc-amazon-pay:before { + content: "\f42d"; +} + +.fa-dropbox:before { + content: "\f16b"; +} + +.fa-instagram:before { + content: "\f16d"; +} + +.fa-cmplid:before { + content: "\e360"; +} + +.fa-facebook:before { + content: "\f09a"; +} + +.fa-gripfire:before { + content: "\f3ac"; +} + +.fa-jedi-order:before { + content: "\f50e"; +} + +.fa-uikit:before { + content: "\f403"; +} + +.fa-fort-awesome-alt:before { + content: "\f3a3"; +} + +.fa-phabricator:before { + content: "\f3db"; +} + +.fa-ussunnah:before { + content: "\f407"; +} + +.fa-earlybirds:before { + content: "\f39a"; +} + +.fa-trade-federation:before { + content: "\f513"; +} + +.fa-autoprefixer:before { + content: "\f41c"; +} + +.fa-whatsapp:before { + content: "\f232"; +} + +.fa-slideshare:before { + content: "\f1e7"; +} + +.fa-google-play:before { + content: "\f3ab"; +} + +.fa-viadeo:before { + content: "\f2a9"; +} + +.fa-line:before { + content: "\f3c0"; +} + +.fa-google-drive:before { + content: "\f3aa"; +} + +.fa-servicestack:before { + content: "\f3ec"; +} + +.fa-simplybuilt:before { + content: "\f215"; +} + +.fa-bitbucket:before { + content: "\f171"; +} + +.fa-imdb:before { + content: "\f2d8"; +} + +.fa-deezer:before { + content: "\e077"; +} + +.fa-raspberry-pi:before { + content: "\f7bb"; +} + +.fa-jira:before { + content: "\f7b1"; +} + +.fa-docker:before { + content: "\f395"; +} + +.fa-screenpal:before { + content: "\e570"; +} + +.fa-bluetooth:before { + content: "\f293"; +} + +.fa-gitter:before { + content: "\f426"; +} + +.fa-d-and-d:before { + content: "\f38d"; +} + +.fa-microblog:before { + content: "\e01a"; +} + +.fa-cc-diners-club:before { + content: "\f24c"; +} + +.fa-gg-circle:before { + content: "\f261"; +} + +.fa-pied-piper-hat:before { + content: "\f4e5"; +} + +.fa-kickstarter-k:before { + content: "\f3bc"; +} + +.fa-yandex:before { + content: "\f413"; +} + +.fa-readme:before { + content: "\f4d5"; +} + +.fa-html5:before { + content: "\f13b"; +} + +.fa-sellsy:before { + content: "\f213"; +} + +.fa-sass:before { + content: "\f41e"; +} + +.fa-wirsindhandwerk:before { + content: "\e2d0"; +} + +.fa-wsh:before { + content: "\e2d0"; +} + +.fa-buromobelexperte:before { + content: "\f37f"; +} + +.fa-salesforce:before { + content: "\f83b"; +} + +.fa-octopus-deploy:before { + content: "\e082"; +} + +.fa-medapps:before { + content: "\f3c6"; +} + +.fa-ns8:before { + content: "\f3d5"; +} + +.fa-pinterest-p:before { + content: "\f231"; +} + +.fa-apper:before { + content: "\f371"; +} + +.fa-fort-awesome:before { + content: "\f286"; +} + +.fa-waze:before { + content: "\f83f"; +} + +.fa-cc-jcb:before { + content: "\f24b"; +} + +.fa-snapchat:before { + content: "\f2ab"; +} + +.fa-snapchat-ghost:before { + content: "\f2ab"; +} + +.fa-fantasy-flight-games:before { + content: "\f6dc"; +} + +.fa-rust:before { + content: "\e07a"; +} + +.fa-wix:before { + content: "\f5cf"; +} + +.fa-square-behance:before { + content: "\f1b5"; +} + +.fa-behance-square:before { + content: "\f1b5"; +} + +.fa-supple:before { + content: "\f3f9"; +} + +.fa-rebel:before { + content: "\f1d0"; +} + +.fa-css3:before { + content: "\f13c"; +} + +.fa-staylinked:before { + content: "\f3f5"; +} + +.fa-kaggle:before { + content: "\f5fa"; +} + +.fa-space-awesome:before { + content: "\e5ac"; +} + +.fa-deviantart:before { + content: "\f1bd"; +} + +.fa-cpanel:before { + content: "\f388"; +} + +.fa-goodreads-g:before { + content: "\f3a9"; +} + +.fa-square-git:before { + content: "\f1d2"; +} + +.fa-git-square:before { + content: "\f1d2"; +} + +.fa-square-tumblr:before { + content: "\f174"; +} + +.fa-tumblr-square:before { + content: "\f174"; +} + +.fa-trello:before { + content: "\f181"; +} + +.fa-creative-commons-nc-jp:before { + content: "\f4ea"; +} + +.fa-get-pocket:before { + content: "\f265"; +} + +.fa-perbyte:before { + content: "\e083"; +} + +.fa-grunt:before { + content: "\f3ad"; +} + +.fa-weebly:before { + content: "\f5cc"; +} + +.fa-connectdevelop:before { + content: "\f20e"; +} + +.fa-leanpub:before { + content: "\f212"; +} + +.fa-black-tie:before { + content: "\f27e"; +} + +.fa-themeco:before { + content: "\f5c6"; +} + +.fa-python:before { + content: "\f3e2"; +} + +.fa-android:before { + content: "\f17b"; +} + +.fa-bots:before { + content: "\e340"; +} + +.fa-free-code-camp:before { + content: "\f2c5"; +} + +.fa-hornbill:before { + content: "\f592"; +} + +.fa-js:before { + content: "\f3b8"; +} + +.fa-ideal:before { + content: "\e013"; +} + +.fa-git:before { + content: "\f1d3"; +} + +.fa-dev:before { + content: "\f6cc"; +} + +.fa-sketch:before { + content: "\f7c6"; +} + +.fa-yandex-international:before { + content: "\f414"; +} + +.fa-cc-amex:before { + content: "\f1f3"; +} + +.fa-uber:before { + content: "\f402"; +} + +.fa-github:before { + content: "\f09b"; +} + +.fa-php:before { + content: "\f457"; +} + +.fa-alipay:before { + content: "\f642"; +} + +.fa-youtube:before { + content: "\f167"; +} + +.fa-skyatlas:before { + content: "\f216"; +} + +.fa-firefox-browser:before { + content: "\e007"; +} + +.fa-replyd:before { + content: "\f3e6"; +} + +.fa-suse:before { + content: "\f7d6"; +} + +.fa-jenkins:before { + content: "\f3b6"; +} + +.fa-twitter:before { + content: "\f099"; +} + +.fa-rockrms:before { + content: "\f3e9"; +} + +.fa-pinterest:before { + content: "\f0d2"; +} + +.fa-buffer:before { + content: "\f837"; +} + +.fa-npm:before { + content: "\f3d4"; +} + +.fa-yammer:before { + content: "\f840"; +} + +.fa-btc:before { + content: "\f15a"; +} + +.fa-dribbble:before { + content: "\f17d"; +} + +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} + +.fa-internet-explorer:before { + content: "\f26b"; +} + +.fa-stubber:before { + content: "\e5c7"; +} + +.fa-telegram:before { + content: "\f2c6"; +} + +.fa-telegram-plane:before { + content: "\f2c6"; +} + +.fa-old-republic:before { + content: "\f510"; +} + +.fa-odysee:before { + content: "\e5c6"; +} + +.fa-square-whatsapp:before { + content: "\f40c"; +} + +.fa-whatsapp-square:before { + content: "\f40c"; +} + +.fa-node-js:before { + content: "\f3d3"; +} + +.fa-edge-legacy:before { + content: "\e078"; +} + +.fa-slack:before { + content: "\f198"; +} + +.fa-slack-hash:before { + content: "\f198"; +} + +.fa-medrt:before { + content: "\f3c8"; +} + +.fa-usb:before { + content: "\f287"; +} + +.fa-tumblr:before { + content: "\f173"; +} + +.fa-vaadin:before { + content: "\f408"; +} + +.fa-quora:before { + content: "\f2c4"; +} + +.fa-square-x-twitter:before { + content: "\e61a"; +} + +.fa-reacteurope:before { + content: "\f75d"; +} + +.fa-medium:before { + content: "\f23a"; +} + +.fa-medium-m:before { + content: "\f23a"; +} + +.fa-amilia:before { + content: "\f36d"; +} + +.fa-mixcloud:before { + content: "\f289"; +} + +.fa-flipboard:before { + content: "\f44d"; +} + +.fa-viacoin:before { + content: "\f237"; +} + +.fa-critical-role:before { + content: "\f6c9"; +} + +.fa-sitrox:before { + content: "\e44a"; +} + +.fa-discourse:before { + content: "\f393"; +} + +.fa-joomla:before { + content: "\f1aa"; +} + +.fa-mastodon:before { + content: "\f4f6"; +} + +.fa-airbnb:before { + content: "\f834"; +} + +.fa-wolf-pack-battalion:before { + content: "\f514"; +} + +.fa-buy-n-large:before { + content: "\f8a6"; +} + +.fa-gulp:before { + content: "\f3ae"; +} + +.fa-creative-commons-sampling-plus:before { + content: "\f4f1"; +} + +.fa-strava:before { + content: "\f428"; +} + +.fa-ember:before { + content: "\f423"; +} + +.fa-canadian-maple-leaf:before { + content: "\f785"; +} + +.fa-teamspeak:before { + content: "\f4f9"; +} + +.fa-pushed:before { + content: "\f3e1"; +} + +.fa-wordpress-simple:before { + content: "\f411"; +} + +.fa-nutritionix:before { + content: "\f3d6"; +} + +.fa-wodu:before { + content: "\e088"; +} + +.fa-google-pay:before { + content: "\e079"; +} + +.fa-intercom:before { + content: "\f7af"; +} + +.fa-zhihu:before { + content: "\f63f"; +} + +.fa-korvue:before { + content: "\f42f"; +} + +.fa-pix:before { + content: "\e43a"; +} + +.fa-steam-symbol:before { + content: "\f3f6"; +} diff --git a/src/main/resources/static/css/fontawesome.css b/src/main/resources/static/css/fontawesome.css new file mode 100644 index 0000000..9acf450 --- /dev/null +++ b/src/main/resources/static/css/fontawesome.css @@ -0,0 +1,8438 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +.fa { + font-family: var(--fa-style-family, "Font Awesome 6 Free"); + font-weight: var(--fa-style, 900); +} + +.fa, +.fa-classic, +.fa-sharp, +.fas, +.fa-solid, +.far, +.fa-regular, +.fab, +.fa-brands { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: var(--fa-display, inline-block); + font-style: normal; + font-variant: normal; + line-height: 1; + text-rendering: auto; +} + +.fas, +.fa-classic, +.fa-solid, +.far, +.fa-regular { + font-family: 'Font Awesome 6 Free'; +} + +.fab, +.fa-brands { + font-family: 'Font Awesome 6 Brands'; +} + +.fa-1x { + font-size: 1em; +} + +.fa-2x { + font-size: 2em; +} + +.fa-3x { + font-size: 3em; +} + +.fa-4x { + font-size: 4em; +} + +.fa-5x { + font-size: 5em; +} + +.fa-6x { + font-size: 6em; +} + +.fa-7x { + font-size: 7em; +} + +.fa-8x { + font-size: 8em; +} + +.fa-9x { + font-size: 9em; +} + +.fa-10x { + font-size: 10em; +} + +.fa-2xs { + font-size: 0.625em; + line-height: 0.1em; + vertical-align: 0.225em; +} + +.fa-xs { + font-size: 0.75em; + line-height: 0.08333em; + vertical-align: 0.125em; +} + +.fa-sm { + font-size: 0.875em; + line-height: 0.07143em; + vertical-align: 0.05357em; +} + +.fa-lg { + font-size: 1.25em; + line-height: 0.05em; + vertical-align: -0.075em; +} + +.fa-xl { + font-size: 1.5em; + line-height: 0.04167em; + vertical-align: -0.125em; +} + +.fa-2xl { + font-size: 2em; + line-height: 0.03125em; + vertical-align: -0.1875em; +} + +.fa-fw { + text-align: center; + width: 1.25em; +} + +.fa-ul { + list-style-type: none; + margin-left: var(--fa-li-margin, 2.5em); + padding-left: 0; +} + +.fa-ul > li { + position: relative; +} + +.fa-li { + left: calc(var(--fa-li-width, 2em) * -1); + position: absolute; + text-align: center; + width: var(--fa-li-width, 2em); + line-height: inherit; +} + +.fa-border { + border-color: var(--fa-border-color, #eee); + border-radius: var(--fa-border-radius, 0.1em); + border-style: var(--fa-border-style, solid); + border-width: var(--fa-border-width, 0.08em); + padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); +} + +.fa-pull-left { + float: left; + margin-right: var(--fa-pull-margin, 0.3em); +} + +.fa-pull-right { + float: right; + margin-left: var(--fa-pull-margin, 0.3em); +} + +.fa-beat { + -webkit-animation-name: fa-beat; + animation-name: fa-beat; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); +} + +.fa-bounce { + -webkit-animation-name: fa-bounce; + animation-name: fa-bounce; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); +} + +.fa-fade { + -webkit-animation-name: fa-fade; + animation-name: fa-fade; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); +} + +.fa-beat-fade { + -webkit-animation-name: fa-beat-fade; + animation-name: fa-beat-fade; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); +} + +.fa-flip { + -webkit-animation-name: fa-flip; + animation-name: fa-flip; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); +} + +.fa-shake { + -webkit-animation-name: fa-shake; + animation-name: fa-shake; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); +} + +.fa-spin { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 2s); + animation-duration: var(--fa-animation-duration, 2s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); +} + +.fa-spin-reverse { + --fa-animation-direction: reverse; +} + +.fa-pulse, +.fa-spin-pulse { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, steps(8)); + animation-timing-function: var(--fa-animation-timing, steps(8)); +} + +@media (prefers-reduced-motion: reduce) { + .fa-beat, + .fa-bounce, + .fa-fade, + .fa-beat-fade, + .fa-flip, + .fa-pulse, + .fa-shake, + .fa-spin, + .fa-spin-pulse { + -webkit-animation-delay: -1ms; + animation-delay: -1ms; + -webkit-animation-duration: 1ms; + animation-duration: 1ms; + -webkit-animation-iteration-count: 1; + animation-iteration-count: 1; + -webkit-transition-delay: 0s; + transition-delay: 0s; + -webkit-transition-duration: 0s; + transition-duration: 0s; + } +} + +@-webkit-keyframes fa-beat { + 0%, 90% { + -webkit-transform: scale(1); + transform: scale(1); + } + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); + } +} + +@keyframes fa-beat { + 0%, 90% { + -webkit-transform: scale(1); + transform: scale(1); + } + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); + } +} + +@-webkit-keyframes fa-bounce { + 0% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + } + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + } + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + } + 57% { + -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + } + 64% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 100% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } +} + +@keyframes fa-bounce { + 0% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + } + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + } + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + } + 57% { + -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + } + 64% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 100% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } +} + +@-webkit-keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); + } +} + +@keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); + } +} + +@-webkit-keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); + } +} + +@keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); + } +} + +@-webkit-keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + } +} + +@keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + } +} + +@-webkit-keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); + } + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + 8%, 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); + } + 12%, 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); + } + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); + } + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); + } + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); + } + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); + } + 40%, 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); + } + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + 8%, 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); + } + 12%, 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); + } + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); + } + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); + } + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); + } + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); + } + 40%, 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.fa-rotate-90 { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +.fa-rotate-180 { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} + +.fa-rotate-270 { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); +} + +.fa-flip-horizontal { + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); +} + +.fa-flip-vertical { + -webkit-transform: scale(1, -1); + transform: scale(1, -1); +} + +.fa-flip-both, +.fa-flip-horizontal.fa-flip-vertical { + -webkit-transform: scale(-1, -1); + transform: scale(-1, -1); +} + +.fa-rotate-by { + -webkit-transform: rotate(var(--fa-rotate-angle, none)); + transform: rotate(var(--fa-rotate-angle, none)); +} + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; +} + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; + z-index: var(--fa-stack-z-index, auto); +} + +.fa-stack-1x { + line-height: inherit; +} + +.fa-stack-2x { + font-size: 2em; +} + +.fa-inverse { + color: var(--fa-inverse, #fff); +} + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ + +.fa-0::before { + content: "\30"; +} + +.fa-1::before { + content: "\31"; +} + +.fa-2::before { + content: "\32"; +} + +.fa-3::before { + content: "\33"; +} + +.fa-4::before { + content: "\34"; +} + +.fa-5::before { + content: "\35"; +} + +.fa-6::before { + content: "\36"; +} + +.fa-7::before { + content: "\37"; +} + +.fa-8::before { + content: "\38"; +} + +.fa-9::before { + content: "\39"; +} + +.fa-fill-drip::before { + content: "\f576"; +} + +.fa-arrows-to-circle::before { + content: "\e4bd"; +} + +.fa-circle-chevron-right::before { + content: "\f138"; +} + +.fa-chevron-circle-right::before { + content: "\f138"; +} + +.fa-at::before { + content: "\40"; +} + +.fa-trash-can::before { + content: "\f2ed"; +} + +.fa-trash-alt::before { + content: "\f2ed"; +} + +.fa-text-height::before { + content: "\f034"; +} + +.fa-user-xmark::before { + content: "\f235"; +} + +.fa-user-times::before { + content: "\f235"; +} + +.fa-stethoscope::before { + content: "\f0f1"; +} + +.fa-message::before { + content: "\f27a"; +} + +.fa-comment-alt::before { + content: "\f27a"; +} + +.fa-info::before { + content: "\f129"; +} + +.fa-down-left-and-up-right-to-center::before { + content: "\f422"; +} + +.fa-compress-alt::before { + content: "\f422"; +} + +.fa-explosion::before { + content: "\e4e9"; +} + +.fa-file-lines::before { + content: "\f15c"; +} + +.fa-file-alt::before { + content: "\f15c"; +} + +.fa-file-text::before { + content: "\f15c"; +} + +.fa-wave-square::before { + content: "\f83e"; +} + +.fa-ring::before { + content: "\f70b"; +} + +.fa-building-un::before { + content: "\e4d9"; +} + +.fa-dice-three::before { + content: "\f527"; +} + +.fa-calendar-days::before { + content: "\f073"; +} + +.fa-calendar-alt::before { + content: "\f073"; +} + +.fa-anchor-circle-check::before { + content: "\e4aa"; +} + +.fa-building-circle-arrow-right::before { + content: "\e4d1"; +} + +.fa-volleyball::before { + content: "\f45f"; +} + +.fa-volleyball-ball::before { + content: "\f45f"; +} + +.fa-arrows-up-to-line::before { + content: "\e4c2"; +} + +.fa-sort-down::before { + content: "\f0dd"; +} + +.fa-sort-desc::before { + content: "\f0dd"; +} + +.fa-circle-minus::before { + content: "\f056"; +} + +.fa-minus-circle::before { + content: "\f056"; +} + +.fa-door-open::before { + content: "\f52b"; +} + +.fa-right-from-bracket::before { + content: "\f2f5"; +} + +.fa-sign-out-alt::before { + content: "\f2f5"; +} + +.fa-atom::before { + content: "\f5d2"; +} + +.fa-soap::before { + content: "\e06e"; +} + +.fa-icons::before { + content: "\f86d"; +} + +.fa-heart-music-camera-bolt::before { + content: "\f86d"; +} + +.fa-microphone-lines-slash::before { + content: "\f539"; +} + +.fa-microphone-alt-slash::before { + content: "\f539"; +} + +.fa-bridge-circle-check::before { + content: "\e4c9"; +} + +.fa-pump-medical::before { + content: "\e06a"; +} + +.fa-fingerprint::before { + content: "\f577"; +} + +.fa-hand-point-right::before { + content: "\f0a4"; +} + +.fa-magnifying-glass-location::before { + content: "\f689"; +} + +.fa-search-location::before { + content: "\f689"; +} + +.fa-forward-step::before { + content: "\f051"; +} + +.fa-step-forward::before { + content: "\f051"; +} + +.fa-face-smile-beam::before { + content: "\f5b8"; +} + +.fa-smile-beam::before { + content: "\f5b8"; +} + +.fa-flag-checkered::before { + content: "\f11e"; +} + +.fa-football::before { + content: "\f44e"; +} + +.fa-football-ball::before { + content: "\f44e"; +} + +.fa-school-circle-exclamation::before { + content: "\e56c"; +} + +.fa-crop::before { + content: "\f125"; +} + +.fa-angles-down::before { + content: "\f103"; +} + +.fa-angle-double-down::before { + content: "\f103"; +} + +.fa-users-rectangle::before { + content: "\e594"; +} + +.fa-people-roof::before { + content: "\e537"; +} + +.fa-people-line::before { + content: "\e534"; +} + +.fa-beer-mug-empty::before { + content: "\f0fc"; +} + +.fa-beer::before { + content: "\f0fc"; +} + +.fa-diagram-predecessor::before { + content: "\e477"; +} + +.fa-arrow-up-long::before { + content: "\f176"; +} + +.fa-long-arrow-up::before { + content: "\f176"; +} + +.fa-fire-flame-simple::before { + content: "\f46a"; +} + +.fa-burn::before { + content: "\f46a"; +} + +.fa-person::before { + content: "\f183"; +} + +.fa-male::before { + content: "\f183"; +} + +.fa-laptop::before { + content: "\f109"; +} + +.fa-file-csv::before { + content: "\f6dd"; +} + +.fa-menorah::before { + content: "\f676"; +} + +.fa-truck-plane::before { + content: "\e58f"; +} + +.fa-record-vinyl::before { + content: "\f8d9"; +} + +.fa-face-grin-stars::before { + content: "\f587"; +} + +.fa-grin-stars::before { + content: "\f587"; +} + +.fa-bong::before { + content: "\f55c"; +} + +.fa-spaghetti-monster-flying::before { + content: "\f67b"; +} + +.fa-pastafarianism::before { + content: "\f67b"; +} + +.fa-arrow-down-up-across-line::before { + content: "\e4af"; +} + +.fa-spoon::before { + content: "\f2e5"; +} + +.fa-utensil-spoon::before { + content: "\f2e5"; +} + +.fa-jar-wheat::before { + content: "\e517"; +} + +.fa-envelopes-bulk::before { + content: "\f674"; +} + +.fa-mail-bulk::before { + content: "\f674"; +} + +.fa-file-circle-exclamation::before { + content: "\e4eb"; +} + +.fa-circle-h::before { + content: "\f47e"; +} + +.fa-hospital-symbol::before { + content: "\f47e"; +} + +.fa-pager::before { + content: "\f815"; +} + +.fa-address-book::before { + content: "\f2b9"; +} + +.fa-contact-book::before { + content: "\f2b9"; +} + +.fa-strikethrough::before { + content: "\f0cc"; +} + +.fa-k::before { + content: "\4b"; +} + +.fa-landmark-flag::before { + content: "\e51c"; +} + +.fa-pencil::before { + content: "\f303"; +} + +.fa-pencil-alt::before { + content: "\f303"; +} + +.fa-backward::before { + content: "\f04a"; +} + +.fa-caret-right::before { + content: "\f0da"; +} + +.fa-comments::before { + content: "\f086"; +} + +.fa-paste::before { + content: "\f0ea"; +} + +.fa-file-clipboard::before { + content: "\f0ea"; +} + +.fa-code-pull-request::before { + content: "\e13c"; +} + +.fa-clipboard-list::before { + content: "\f46d"; +} + +.fa-truck-ramp-box::before { + content: "\f4de"; +} + +.fa-truck-loading::before { + content: "\f4de"; +} + +.fa-user-check::before { + content: "\f4fc"; +} + +.fa-vial-virus::before { + content: "\e597"; +} + +.fa-sheet-plastic::before { + content: "\e571"; +} + +.fa-blog::before { + content: "\f781"; +} + +.fa-user-ninja::before { + content: "\f504"; +} + +.fa-person-arrow-up-from-line::before { + content: "\e539"; +} + +.fa-scroll-torah::before { + content: "\f6a0"; +} + +.fa-torah::before { + content: "\f6a0"; +} + +.fa-broom-ball::before { + content: "\f458"; +} + +.fa-quidditch::before { + content: "\f458"; +} + +.fa-quidditch-broom-ball::before { + content: "\f458"; +} + +.fa-toggle-off::before { + content: "\f204"; +} + +.fa-box-archive::before { + content: "\f187"; +} + +.fa-archive::before { + content: "\f187"; +} + +.fa-person-drowning::before { + content: "\e545"; +} + +.fa-arrow-down-9-1::before { + content: "\f886"; +} + +.fa-sort-numeric-desc::before { + content: "\f886"; +} + +.fa-sort-numeric-down-alt::before { + content: "\f886"; +} + +.fa-face-grin-tongue-squint::before { + content: "\f58a"; +} + +.fa-grin-tongue-squint::before { + content: "\f58a"; +} + +.fa-spray-can::before { + content: "\f5bd"; +} + +.fa-truck-monster::before { + content: "\f63b"; +} + +.fa-w::before { + content: "\57"; +} + +.fa-earth-africa::before { + content: "\f57c"; +} + +.fa-globe-africa::before { + content: "\f57c"; +} + +.fa-rainbow::before { + content: "\f75b"; +} + +.fa-circle-notch::before { + content: "\f1ce"; +} + +.fa-tablet-screen-button::before { + content: "\f3fa"; +} + +.fa-tablet-alt::before { + content: "\f3fa"; +} + +.fa-paw::before { + content: "\f1b0"; +} + +.fa-cloud::before { + content: "\f0c2"; +} + +.fa-trowel-bricks::before { + content: "\e58a"; +} + +.fa-face-flushed::before { + content: "\f579"; +} + +.fa-flushed::before { + content: "\f579"; +} + +.fa-hospital-user::before { + content: "\f80d"; +} + +.fa-tent-arrow-left-right::before { + content: "\e57f"; +} + +.fa-gavel::before { + content: "\f0e3"; +} + +.fa-legal::before { + content: "\f0e3"; +} + +.fa-binoculars::before { + content: "\f1e5"; +} + +.fa-microphone-slash::before { + content: "\f131"; +} + +.fa-box-tissue::before { + content: "\e05b"; +} + +.fa-motorcycle::before { + content: "\f21c"; +} + +.fa-bell-concierge::before { + content: "\f562"; +} + +.fa-concierge-bell::before { + content: "\f562"; +} + +.fa-pen-ruler::before { + content: "\f5ae"; +} + +.fa-pencil-ruler::before { + content: "\f5ae"; +} + +.fa-people-arrows::before { + content: "\e068"; +} + +.fa-people-arrows-left-right::before { + content: "\e068"; +} + +.fa-mars-and-venus-burst::before { + content: "\e523"; +} + +.fa-square-caret-right::before { + content: "\f152"; +} + +.fa-caret-square-right::before { + content: "\f152"; +} + +.fa-scissors::before { + content: "\f0c4"; +} + +.fa-cut::before { + content: "\f0c4"; +} + +.fa-sun-plant-wilt::before { + content: "\e57a"; +} + +.fa-toilets-portable::before { + content: "\e584"; +} + +.fa-hockey-puck::before { + content: "\f453"; +} + +.fa-table::before { + content: "\f0ce"; +} + +.fa-magnifying-glass-arrow-right::before { + content: "\e521"; +} + +.fa-tachograph-digital::before { + content: "\f566"; +} + +.fa-digital-tachograph::before { + content: "\f566"; +} + +.fa-users-slash::before { + content: "\e073"; +} + +.fa-clover::before { + content: "\e139"; +} + +.fa-reply::before { + content: "\f3e5"; +} + +.fa-mail-reply::before { + content: "\f3e5"; +} + +.fa-star-and-crescent::before { + content: "\f699"; +} + +.fa-house-fire::before { + content: "\e50c"; +} + +.fa-square-minus::before { + content: "\f146"; +} + +.fa-minus-square::before { + content: "\f146"; +} + +.fa-helicopter::before { + content: "\f533"; +} + +.fa-compass::before { + content: "\f14e"; +} + +.fa-square-caret-down::before { + content: "\f150"; +} + +.fa-caret-square-down::before { + content: "\f150"; +} + +.fa-file-circle-question::before { + content: "\e4ef"; +} + +.fa-laptop-code::before { + content: "\f5fc"; +} + +.fa-swatchbook::before { + content: "\f5c3"; +} + +.fa-prescription-bottle::before { + content: "\f485"; +} + +.fa-bars::before { + content: "\f0c9"; +} + +.fa-navicon::before { + content: "\f0c9"; +} + +.fa-people-group::before { + content: "\e533"; +} + +.fa-hourglass-end::before { + content: "\f253"; +} + +.fa-hourglass-3::before { + content: "\f253"; +} + +.fa-heart-crack::before { + content: "\f7a9"; +} + +.fa-heart-broken::before { + content: "\f7a9"; +} + +.fa-square-up-right::before { + content: "\f360"; +} + +.fa-external-link-square-alt::before { + content: "\f360"; +} + +.fa-face-kiss-beam::before { + content: "\f597"; +} + +.fa-kiss-beam::before { + content: "\f597"; +} + +.fa-film::before { + content: "\f008"; +} + +.fa-ruler-horizontal::before { + content: "\f547"; +} + +.fa-people-robbery::before { + content: "\e536"; +} + +.fa-lightbulb::before { + content: "\f0eb"; +} + +.fa-caret-left::before { + content: "\f0d9"; +} + +.fa-circle-exclamation::before { + content: "\f06a"; +} + +.fa-exclamation-circle::before { + content: "\f06a"; +} + +.fa-school-circle-xmark::before { + content: "\e56d"; +} + +.fa-arrow-right-from-bracket::before { + content: "\f08b"; +} + +.fa-sign-out::before { + content: "\f08b"; +} + +.fa-circle-chevron-down::before { + content: "\f13a"; +} + +.fa-chevron-circle-down::before { + content: "\f13a"; +} + +.fa-unlock-keyhole::before { + content: "\f13e"; +} + +.fa-unlock-alt::before { + content: "\f13e"; +} + +.fa-cloud-showers-heavy::before { + content: "\f740"; +} + +.fa-headphones-simple::before { + content: "\f58f"; +} + +.fa-headphones-alt::before { + content: "\f58f"; +} + +.fa-sitemap::before { + content: "\f0e8"; +} + +.fa-circle-dollar-to-slot::before { + content: "\f4b9"; +} + +.fa-donate::before { + content: "\f4b9"; +} + +.fa-memory::before { + content: "\f538"; +} + +.fa-road-spikes::before { + content: "\e568"; +} + +.fa-fire-burner::before { + content: "\e4f1"; +} + +.fa-flag::before { + content: "\f024"; +} + +.fa-hanukiah::before { + content: "\f6e6"; +} + +.fa-feather::before { + content: "\f52d"; +} + +.fa-volume-low::before { + content: "\f027"; +} + +.fa-volume-down::before { + content: "\f027"; +} + +.fa-comment-slash::before { + content: "\f4b3"; +} + +.fa-cloud-sun-rain::before { + content: "\f743"; +} + +.fa-compress::before { + content: "\f066"; +} + +.fa-wheat-awn::before { + content: "\e2cd"; +} + +.fa-wheat-alt::before { + content: "\e2cd"; +} + +.fa-ankh::before { + content: "\f644"; +} + +.fa-hands-holding-child::before { + content: "\e4fa"; +} + +.fa-asterisk::before { + content: "\2a"; +} + +.fa-square-check::before { + content: "\f14a"; +} + +.fa-check-square::before { + content: "\f14a"; +} + +.fa-peseta-sign::before { + content: "\e221"; +} + +.fa-heading::before { + content: "\f1dc"; +} + +.fa-header::before { + content: "\f1dc"; +} + +.fa-ghost::before { + content: "\f6e2"; +} + +.fa-list::before { + content: "\f03a"; +} + +.fa-list-squares::before { + content: "\f03a"; +} + +.fa-square-phone-flip::before { + content: "\f87b"; +} + +.fa-phone-square-alt::before { + content: "\f87b"; +} + +.fa-cart-plus::before { + content: "\f217"; +} + +.fa-gamepad::before { + content: "\f11b"; +} + +.fa-circle-dot::before { + content: "\f192"; +} + +.fa-dot-circle::before { + content: "\f192"; +} + +.fa-face-dizzy::before { + content: "\f567"; +} + +.fa-dizzy::before { + content: "\f567"; +} + +.fa-egg::before { + content: "\f7fb"; +} + +.fa-house-medical-circle-xmark::before { + content: "\e513"; +} + +.fa-campground::before { + content: "\f6bb"; +} + +.fa-folder-plus::before { + content: "\f65e"; +} + +.fa-futbol::before { + content: "\f1e3"; +} + +.fa-futbol-ball::before { + content: "\f1e3"; +} + +.fa-soccer-ball::before { + content: "\f1e3"; +} + +.fa-paintbrush::before { + content: "\f1fc"; +} + +.fa-paint-brush::before { + content: "\f1fc"; +} + +.fa-lock::before { + content: "\f023"; +} + +.fa-gas-pump::before { + content: "\f52f"; +} + +.fa-hot-tub-person::before { + content: "\f593"; +} + +.fa-hot-tub::before { + content: "\f593"; +} + +.fa-map-location::before { + content: "\f59f"; +} + +.fa-map-marked::before { + content: "\f59f"; +} + +.fa-house-flood-water::before { + content: "\e50e"; +} + +.fa-tree::before { + content: "\f1bb"; +} + +.fa-bridge-lock::before { + content: "\e4cc"; +} + +.fa-sack-dollar::before { + content: "\f81d"; +} + +.fa-pen-to-square::before { + content: "\f044"; +} + +.fa-edit::before { + content: "\f044"; +} + +.fa-car-side::before { + content: "\f5e4"; +} + +.fa-share-nodes::before { + content: "\f1e0"; +} + +.fa-share-alt::before { + content: "\f1e0"; +} + +.fa-heart-circle-minus::before { + content: "\e4ff"; +} + +.fa-hourglass-half::before { + content: "\f252"; +} + +.fa-hourglass-2::before { + content: "\f252"; +} + +.fa-microscope::before { + content: "\f610"; +} + +.fa-sink::before { + content: "\e06d"; +} + +.fa-bag-shopping::before { + content: "\f290"; +} + +.fa-shopping-bag::before { + content: "\f290"; +} + +.fa-arrow-down-z-a::before { + content: "\f881"; +} + +.fa-sort-alpha-desc::before { + content: "\f881"; +} + +.fa-sort-alpha-down-alt::before { + content: "\f881"; +} + +.fa-mitten::before { + content: "\f7b5"; +} + +.fa-person-rays::before { + content: "\e54d"; +} + +.fa-users::before { + content: "\f0c0"; +} + +.fa-eye-slash::before { + content: "\f070"; +} + +.fa-flask-vial::before { + content: "\e4f3"; +} + +.fa-hand::before { + content: "\f256"; +} + +.fa-hand-paper::before { + content: "\f256"; +} + +.fa-om::before { + content: "\f679"; +} + +.fa-worm::before { + content: "\e599"; +} + +.fa-house-circle-xmark::before { + content: "\e50b"; +} + +.fa-plug::before { + content: "\f1e6"; +} + +.fa-chevron-up::before { + content: "\f077"; +} + +.fa-hand-spock::before { + content: "\f259"; +} + +.fa-stopwatch::before { + content: "\f2f2"; +} + +.fa-face-kiss::before { + content: "\f596"; +} + +.fa-kiss::before { + content: "\f596"; +} + +.fa-bridge-circle-xmark::before { + content: "\e4cb"; +} + +.fa-face-grin-tongue::before { + content: "\f589"; +} + +.fa-grin-tongue::before { + content: "\f589"; +} + +.fa-chess-bishop::before { + content: "\f43a"; +} + +.fa-face-grin-wink::before { + content: "\f58c"; +} + +.fa-grin-wink::before { + content: "\f58c"; +} + +.fa-ear-deaf::before { + content: "\f2a4"; +} + +.fa-deaf::before { + content: "\f2a4"; +} + +.fa-deafness::before { + content: "\f2a4"; +} + +.fa-hard-of-hearing::before { + content: "\f2a4"; +} + +.fa-road-circle-check::before { + content: "\e564"; +} + +.fa-dice-five::before { + content: "\f523"; +} + +.fa-square-rss::before { + content: "\f143"; +} + +.fa-rss-square::before { + content: "\f143"; +} + +.fa-land-mine-on::before { + content: "\e51b"; +} + +.fa-i-cursor::before { + content: "\f246"; +} + +.fa-stamp::before { + content: "\f5bf"; +} + +.fa-stairs::before { + content: "\e289"; +} + +.fa-i::before { + content: "\49"; +} + +.fa-hryvnia-sign::before { + content: "\f6f2"; +} + +.fa-hryvnia::before { + content: "\f6f2"; +} + +.fa-pills::before { + content: "\f484"; +} + +.fa-face-grin-wide::before { + content: "\f581"; +} + +.fa-grin-alt::before { + content: "\f581"; +} + +.fa-tooth::before { + content: "\f5c9"; +} + +.fa-v::before { + content: "\56"; +} + +.fa-bangladeshi-taka-sign::before { + content: "\e2e6"; +} + +.fa-bicycle::before { + content: "\f206"; +} + +.fa-staff-snake::before { + content: "\e579"; +} + +.fa-rod-asclepius::before { + content: "\e579"; +} + +.fa-rod-snake::before { + content: "\e579"; +} + +.fa-staff-aesculapius::before { + content: "\e579"; +} + +.fa-head-side-cough-slash::before { + content: "\e062"; +} + +.fa-truck-medical::before { + content: "\f0f9"; +} + +.fa-ambulance::before { + content: "\f0f9"; +} + +.fa-wheat-awn-circle-exclamation::before { + content: "\e598"; +} + +.fa-snowman::before { + content: "\f7d0"; +} + +.fa-mortar-pestle::before { + content: "\f5a7"; +} + +.fa-road-barrier::before { + content: "\e562"; +} + +.fa-school::before { + content: "\f549"; +} + +.fa-igloo::before { + content: "\f7ae"; +} + +.fa-joint::before { + content: "\f595"; +} + +.fa-angle-right::before { + content: "\f105"; +} + +.fa-horse::before { + content: "\f6f0"; +} + +.fa-q::before { + content: "\51"; +} + +.fa-g::before { + content: "\47"; +} + +.fa-notes-medical::before { + content: "\f481"; +} + +.fa-temperature-half::before { + content: "\f2c9"; +} + +.fa-temperature-2::before { + content: "\f2c9"; +} + +.fa-thermometer-2::before { + content: "\f2c9"; +} + +.fa-thermometer-half::before { + content: "\f2c9"; +} + +.fa-dong-sign::before { + content: "\e169"; +} + +.fa-capsules::before { + content: "\f46b"; +} + +.fa-poo-storm::before { + content: "\f75a"; +} + +.fa-poo-bolt::before { + content: "\f75a"; +} + +.fa-face-frown-open::before { + content: "\f57a"; +} + +.fa-frown-open::before { + content: "\f57a"; +} + +.fa-hand-point-up::before { + content: "\f0a6"; +} + +.fa-money-bill::before { + content: "\f0d6"; +} + +.fa-bookmark::before { + content: "\f02e"; +} + +.fa-align-justify::before { + content: "\f039"; +} + +.fa-umbrella-beach::before { + content: "\f5ca"; +} + +.fa-helmet-un::before { + content: "\e503"; +} + +.fa-bullseye::before { + content: "\f140"; +} + +.fa-bacon::before { + content: "\f7e5"; +} + +.fa-hand-point-down::before { + content: "\f0a7"; +} + +.fa-arrow-up-from-bracket::before { + content: "\e09a"; +} + +.fa-folder::before { + content: "\f07b"; +} + +.fa-folder-blank::before { + content: "\f07b"; +} + +.fa-file-waveform::before { + content: "\f478"; +} + +.fa-file-medical-alt::before { + content: "\f478"; +} + +.fa-radiation::before { + content: "\f7b9"; +} + +.fa-chart-simple::before { + content: "\e473"; +} + +.fa-mars-stroke::before { + content: "\f229"; +} + +.fa-vial::before { + content: "\f492"; +} + +.fa-gauge::before { + content: "\f624"; +} + +.fa-dashboard::before { + content: "\f624"; +} + +.fa-gauge-med::before { + content: "\f624"; +} + +.fa-tachometer-alt-average::before { + content: "\f624"; +} + +.fa-wand-magic-sparkles::before { + content: "\e2ca"; +} + +.fa-magic-wand-sparkles::before { + content: "\e2ca"; +} + +.fa-e::before { + content: "\45"; +} + +.fa-pen-clip::before { + content: "\f305"; +} + +.fa-pen-alt::before { + content: "\f305"; +} + +.fa-bridge-circle-exclamation::before { + content: "\e4ca"; +} + +.fa-user::before { + content: "\f007"; +} + +.fa-school-circle-check::before { + content: "\e56b"; +} + +.fa-dumpster::before { + content: "\f793"; +} + +.fa-van-shuttle::before { + content: "\f5b6"; +} + +.fa-shuttle-van::before { + content: "\f5b6"; +} + +.fa-building-user::before { + content: "\e4da"; +} + +.fa-square-caret-left::before { + content: "\f191"; +} + +.fa-caret-square-left::before { + content: "\f191"; +} + +.fa-highlighter::before { + content: "\f591"; +} + +.fa-key::before { + content: "\f084"; +} + +.fa-bullhorn::before { + content: "\f0a1"; +} + +.fa-globe::before { + content: "\f0ac"; +} + +.fa-synagogue::before { + content: "\f69b"; +} + +.fa-person-half-dress::before { + content: "\e548"; +} + +.fa-road-bridge::before { + content: "\e563"; +} + +.fa-location-arrow::before { + content: "\f124"; +} + +.fa-c::before { + content: "\43"; +} + +.fa-tablet-button::before { + content: "\f10a"; +} + +.fa-building-lock::before { + content: "\e4d6"; +} + +.fa-pizza-slice::before { + content: "\f818"; +} + +.fa-money-bill-wave::before { + content: "\f53a"; +} + +.fa-chart-area::before { + content: "\f1fe"; +} + +.fa-area-chart::before { + content: "\f1fe"; +} + +.fa-house-flag::before { + content: "\e50d"; +} + +.fa-person-circle-minus::before { + content: "\e540"; +} + +.fa-ban::before { + content: "\f05e"; +} + +.fa-cancel::before { + content: "\f05e"; +} + +.fa-camera-rotate::before { + content: "\e0d8"; +} + +.fa-spray-can-sparkles::before { + content: "\f5d0"; +} + +.fa-air-freshener::before { + content: "\f5d0"; +} + +.fa-star::before { + content: "\f005"; +} + +.fa-repeat::before { + content: "\f363"; +} + +.fa-cross::before { + content: "\f654"; +} + +.fa-box::before { + content: "\f466"; +} + +.fa-venus-mars::before { + content: "\f228"; +} + +.fa-arrow-pointer::before { + content: "\f245"; +} + +.fa-mouse-pointer::before { + content: "\f245"; +} + +.fa-maximize::before { + content: "\f31e"; +} + +.fa-expand-arrows-alt::before { + content: "\f31e"; +} + +.fa-charging-station::before { + content: "\f5e7"; +} + +.fa-shapes::before { + content: "\f61f"; +} + +.fa-triangle-circle-square::before { + content: "\f61f"; +} + +.fa-shuffle::before { + content: "\f074"; +} + +.fa-random::before { + content: "\f074"; +} + +.fa-person-running::before { + content: "\f70c"; +} + +.fa-running::before { + content: "\f70c"; +} + +.fa-mobile-retro::before { + content: "\e527"; +} + +.fa-grip-lines-vertical::before { + content: "\f7a5"; +} + +.fa-spider::before { + content: "\f717"; +} + +.fa-hands-bound::before { + content: "\e4f9"; +} + +.fa-file-invoice-dollar::before { + content: "\f571"; +} + +.fa-plane-circle-exclamation::before { + content: "\e556"; +} + +.fa-x-ray::before { + content: "\f497"; +} + +.fa-spell-check::before { + content: "\f891"; +} + +.fa-slash::before { + content: "\f715"; +} + +.fa-computer-mouse::before { + content: "\f8cc"; +} + +.fa-mouse::before { + content: "\f8cc"; +} + +.fa-arrow-right-to-bracket::before { + content: "\f090"; +} + +.fa-sign-in::before { + content: "\f090"; +} + +.fa-shop-slash::before { + content: "\e070"; +} + +.fa-store-alt-slash::before { + content: "\e070"; +} + +.fa-server::before { + content: "\f233"; +} + +.fa-virus-covid-slash::before { + content: "\e4a9"; +} + +.fa-shop-lock::before { + content: "\e4a5"; +} + +.fa-hourglass-start::before { + content: "\f251"; +} + +.fa-hourglass-1::before { + content: "\f251"; +} + +.fa-blender-phone::before { + content: "\f6b6"; +} + +.fa-building-wheat::before { + content: "\e4db"; +} + +.fa-person-breastfeeding::before { + content: "\e53a"; +} + +.fa-right-to-bracket::before { + content: "\f2f6"; +} + +.fa-sign-in-alt::before { + content: "\f2f6"; +} + +.fa-venus::before { + content: "\f221"; +} + +.fa-passport::before { + content: "\f5ab"; +} + +.fa-heart-pulse::before { + content: "\f21e"; +} + +.fa-heartbeat::before { + content: "\f21e"; +} + +.fa-people-carry-box::before { + content: "\f4ce"; +} + +.fa-people-carry::before { + content: "\f4ce"; +} + +.fa-temperature-high::before { + content: "\f769"; +} + +.fa-microchip::before { + content: "\f2db"; +} + +.fa-crown::before { + content: "\f521"; +} + +.fa-weight-hanging::before { + content: "\f5cd"; +} + +.fa-xmarks-lines::before { + content: "\e59a"; +} + +.fa-file-prescription::before { + content: "\f572"; +} + +.fa-weight-scale::before { + content: "\f496"; +} + +.fa-weight::before { + content: "\f496"; +} + +.fa-user-group::before { + content: "\f500"; +} + +.fa-user-friends::before { + content: "\f500"; +} + +.fa-arrow-up-a-z::before { + content: "\f15e"; +} + +.fa-sort-alpha-up::before { + content: "\f15e"; +} + +.fa-chess-knight::before { + content: "\f441"; +} + +.fa-face-laugh-squint::before { + content: "\f59b"; +} + +.fa-laugh-squint::before { + content: "\f59b"; +} + +.fa-wheelchair::before { + content: "\f193"; +} + +.fa-circle-arrow-up::before { + content: "\f0aa"; +} + +.fa-arrow-circle-up::before { + content: "\f0aa"; +} + +.fa-toggle-on::before { + content: "\f205"; +} + +.fa-person-walking::before { + content: "\f554"; +} + +.fa-walking::before { + content: "\f554"; +} + +.fa-l::before { + content: "\4c"; +} + +.fa-fire::before { + content: "\f06d"; +} + +.fa-bed-pulse::before { + content: "\f487"; +} + +.fa-procedures::before { + content: "\f487"; +} + +.fa-shuttle-space::before { + content: "\f197"; +} + +.fa-space-shuttle::before { + content: "\f197"; +} + +.fa-face-laugh::before { + content: "\f599"; +} + +.fa-laugh::before { + content: "\f599"; +} + +.fa-folder-open::before { + content: "\f07c"; +} + +.fa-heart-circle-plus::before { + content: "\e500"; +} + +.fa-code-fork::before { + content: "\e13b"; +} + +.fa-city::before { + content: "\f64f"; +} + +.fa-microphone-lines::before { + content: "\f3c9"; +} + +.fa-microphone-alt::before { + content: "\f3c9"; +} + +.fa-pepper-hot::before { + content: "\f816"; +} + +.fa-unlock::before { + content: "\f09c"; +} + +.fa-colon-sign::before { + content: "\e140"; +} + +.fa-headset::before { + content: "\f590"; +} + +.fa-store-slash::before { + content: "\e071"; +} + +.fa-road-circle-xmark::before { + content: "\e566"; +} + +.fa-user-minus::before { + content: "\f503"; +} + +.fa-mars-stroke-up::before { + content: "\f22a"; +} + +.fa-mars-stroke-v::before { + content: "\f22a"; +} + +.fa-champagne-glasses::before { + content: "\f79f"; +} + +.fa-glass-cheers::before { + content: "\f79f"; +} + +.fa-clipboard::before { + content: "\f328"; +} + +.fa-house-circle-exclamation::before { + content: "\e50a"; +} + +.fa-file-arrow-up::before { + content: "\f574"; +} + +.fa-file-upload::before { + content: "\f574"; +} + +.fa-wifi::before { + content: "\f1eb"; +} + +.fa-wifi-3::before { + content: "\f1eb"; +} + +.fa-wifi-strong::before { + content: "\f1eb"; +} + +.fa-bath::before { + content: "\f2cd"; +} + +.fa-bathtub::before { + content: "\f2cd"; +} + +.fa-underline::before { + content: "\f0cd"; +} + +.fa-user-pen::before { + content: "\f4ff"; +} + +.fa-user-edit::before { + content: "\f4ff"; +} + +.fa-signature::before { + content: "\f5b7"; +} + +.fa-stroopwafel::before { + content: "\f551"; +} + +.fa-bold::before { + content: "\f032"; +} + +.fa-anchor-lock::before { + content: "\e4ad"; +} + +.fa-building-ngo::before { + content: "\e4d7"; +} + +.fa-manat-sign::before { + content: "\e1d5"; +} + +.fa-not-equal::before { + content: "\f53e"; +} + +.fa-border-top-left::before { + content: "\f853"; +} + +.fa-border-style::before { + content: "\f853"; +} + +.fa-map-location-dot::before { + content: "\f5a0"; +} + +.fa-map-marked-alt::before { + content: "\f5a0"; +} + +.fa-jedi::before { + content: "\f669"; +} + +.fa-square-poll-vertical::before { + content: "\f681"; +} + +.fa-poll::before { + content: "\f681"; +} + +.fa-mug-hot::before { + content: "\f7b6"; +} + +.fa-car-battery::before { + content: "\f5df"; +} + +.fa-battery-car::before { + content: "\f5df"; +} + +.fa-gift::before { + content: "\f06b"; +} + +.fa-dice-two::before { + content: "\f528"; +} + +.fa-chess-queen::before { + content: "\f445"; +} + +.fa-glasses::before { + content: "\f530"; +} + +.fa-chess-board::before { + content: "\f43c"; +} + +.fa-building-circle-check::before { + content: "\e4d2"; +} + +.fa-person-chalkboard::before { + content: "\e53d"; +} + +.fa-mars-stroke-right::before { + content: "\f22b"; +} + +.fa-mars-stroke-h::before { + content: "\f22b"; +} + +.fa-hand-back-fist::before { + content: "\f255"; +} + +.fa-hand-rock::before { + content: "\f255"; +} + +.fa-square-caret-up::before { + content: "\f151"; +} + +.fa-caret-square-up::before { + content: "\f151"; +} + +.fa-cloud-showers-water::before { + content: "\e4e4"; +} + +.fa-chart-bar::before { + content: "\f080"; +} + +.fa-bar-chart::before { + content: "\f080"; +} + +.fa-hands-bubbles::before { + content: "\e05e"; +} + +.fa-hands-wash::before { + content: "\e05e"; +} + +.fa-less-than-equal::before { + content: "\f537"; +} + +.fa-train::before { + content: "\f238"; +} + +.fa-eye-low-vision::before { + content: "\f2a8"; +} + +.fa-low-vision::before { + content: "\f2a8"; +} + +.fa-crow::before { + content: "\f520"; +} + +.fa-sailboat::before { + content: "\e445"; +} + +.fa-window-restore::before { + content: "\f2d2"; +} + +.fa-square-plus::before { + content: "\f0fe"; +} + +.fa-plus-square::before { + content: "\f0fe"; +} + +.fa-torii-gate::before { + content: "\f6a1"; +} + +.fa-frog::before { + content: "\f52e"; +} + +.fa-bucket::before { + content: "\e4cf"; +} + +.fa-image::before { + content: "\f03e"; +} + +.fa-microphone::before { + content: "\f130"; +} + +.fa-cow::before { + content: "\f6c8"; +} + +.fa-caret-up::before { + content: "\f0d8"; +} + +.fa-screwdriver::before { + content: "\f54a"; +} + +.fa-folder-closed::before { + content: "\e185"; +} + +.fa-house-tsunami::before { + content: "\e515"; +} + +.fa-square-nfi::before { + content: "\e576"; +} + +.fa-arrow-up-from-ground-water::before { + content: "\e4b5"; +} + +.fa-martini-glass::before { + content: "\f57b"; +} + +.fa-glass-martini-alt::before { + content: "\f57b"; +} + +.fa-rotate-left::before { + content: "\f2ea"; +} + +.fa-rotate-back::before { + content: "\f2ea"; +} + +.fa-rotate-backward::before { + content: "\f2ea"; +} + +.fa-undo-alt::before { + content: "\f2ea"; +} + +.fa-table-columns::before { + content: "\f0db"; +} + +.fa-columns::before { + content: "\f0db"; +} + +.fa-lemon::before { + content: "\f094"; +} + +.fa-head-side-mask::before { + content: "\e063"; +} + +.fa-handshake::before { + content: "\f2b5"; +} + +.fa-gem::before { + content: "\f3a5"; +} + +.fa-dolly::before { + content: "\f472"; +} + +.fa-dolly-box::before { + content: "\f472"; +} + +.fa-smoking::before { + content: "\f48d"; +} + +.fa-minimize::before { + content: "\f78c"; +} + +.fa-compress-arrows-alt::before { + content: "\f78c"; +} + +.fa-monument::before { + content: "\f5a6"; +} + +.fa-snowplow::before { + content: "\f7d2"; +} + +.fa-angles-right::before { + content: "\f101"; +} + +.fa-angle-double-right::before { + content: "\f101"; +} + +.fa-cannabis::before { + content: "\f55f"; +} + +.fa-circle-play::before { + content: "\f144"; +} + +.fa-play-circle::before { + content: "\f144"; +} + +.fa-tablets::before { + content: "\f490"; +} + +.fa-ethernet::before { + content: "\f796"; +} + +.fa-euro-sign::before { + content: "\f153"; +} + +.fa-eur::before { + content: "\f153"; +} + +.fa-euro::before { + content: "\f153"; +} + +.fa-chair::before { + content: "\f6c0"; +} + +.fa-circle-check::before { + content: "\f058"; +} + +.fa-check-circle::before { + content: "\f058"; +} + +.fa-circle-stop::before { + content: "\f28d"; +} + +.fa-stop-circle::before { + content: "\f28d"; +} + +.fa-compass-drafting::before { + content: "\f568"; +} + +.fa-drafting-compass::before { + content: "\f568"; +} + +.fa-plate-wheat::before { + content: "\e55a"; +} + +.fa-icicles::before { + content: "\f7ad"; +} + +.fa-person-shelter::before { + content: "\e54f"; +} + +.fa-neuter::before { + content: "\f22c"; +} + +.fa-id-badge::before { + content: "\f2c1"; +} + +.fa-marker::before { + content: "\f5a1"; +} + +.fa-face-laugh-beam::before { + content: "\f59a"; +} + +.fa-laugh-beam::before { + content: "\f59a"; +} + +.fa-helicopter-symbol::before { + content: "\e502"; +} + +.fa-universal-access::before { + content: "\f29a"; +} + +.fa-circle-chevron-up::before { + content: "\f139"; +} + +.fa-chevron-circle-up::before { + content: "\f139"; +} + +.fa-lari-sign::before { + content: "\e1c8"; +} + +.fa-volcano::before { + content: "\f770"; +} + +.fa-person-walking-dashed-line-arrow-right::before { + content: "\e553"; +} + +.fa-sterling-sign::before { + content: "\f154"; +} + +.fa-gbp::before { + content: "\f154"; +} + +.fa-pound-sign::before { + content: "\f154"; +} + +.fa-viruses::before { + content: "\e076"; +} + +.fa-square-person-confined::before { + content: "\e577"; +} + +.fa-user-tie::before { + content: "\f508"; +} + +.fa-arrow-down-long::before { + content: "\f175"; +} + +.fa-long-arrow-down::before { + content: "\f175"; +} + +.fa-tent-arrow-down-to-line::before { + content: "\e57e"; +} + +.fa-certificate::before { + content: "\f0a3"; +} + +.fa-reply-all::before { + content: "\f122"; +} + +.fa-mail-reply-all::before { + content: "\f122"; +} + +.fa-suitcase::before { + content: "\f0f2"; +} + +.fa-person-skating::before { + content: "\f7c5"; +} + +.fa-skating::before { + content: "\f7c5"; +} + +.fa-filter-circle-dollar::before { + content: "\f662"; +} + +.fa-funnel-dollar::before { + content: "\f662"; +} + +.fa-camera-retro::before { + content: "\f083"; +} + +.fa-circle-arrow-down::before { + content: "\f0ab"; +} + +.fa-arrow-circle-down::before { + content: "\f0ab"; +} + +.fa-file-import::before { + content: "\f56f"; +} + +.fa-arrow-right-to-file::before { + content: "\f56f"; +} + +.fa-square-arrow-up-right::before { + content: "\f14c"; +} + +.fa-external-link-square::before { + content: "\f14c"; +} + +.fa-box-open::before { + content: "\f49e"; +} + +.fa-scroll::before { + content: "\f70e"; +} + +.fa-spa::before { + content: "\f5bb"; +} + +.fa-location-pin-lock::before { + content: "\e51f"; +} + +.fa-pause::before { + content: "\f04c"; +} + +.fa-hill-avalanche::before { + content: "\e507"; +} + +.fa-temperature-empty::before { + content: "\f2cb"; +} + +.fa-temperature-0::before { + content: "\f2cb"; +} + +.fa-thermometer-0::before { + content: "\f2cb"; +} + +.fa-thermometer-empty::before { + content: "\f2cb"; +} + +.fa-bomb::before { + content: "\f1e2"; +} + +.fa-registered::before { + content: "\f25d"; +} + +.fa-address-card::before { + content: "\f2bb"; +} + +.fa-contact-card::before { + content: "\f2bb"; +} + +.fa-vcard::before { + content: "\f2bb"; +} + +.fa-scale-unbalanced-flip::before { + content: "\f516"; +} + +.fa-balance-scale-right::before { + content: "\f516"; +} + +.fa-subscript::before { + content: "\f12c"; +} + +.fa-diamond-turn-right::before { + content: "\f5eb"; +} + +.fa-directions::before { + content: "\f5eb"; +} + +.fa-burst::before { + content: "\e4dc"; +} + +.fa-house-laptop::before { + content: "\e066"; +} + +.fa-laptop-house::before { + content: "\e066"; +} + +.fa-face-tired::before { + content: "\f5c8"; +} + +.fa-tired::before { + content: "\f5c8"; +} + +.fa-money-bills::before { + content: "\e1f3"; +} + +.fa-smog::before { + content: "\f75f"; +} + +.fa-crutch::before { + content: "\f7f7"; +} + +.fa-cloud-arrow-up::before { + content: "\f0ee"; +} + +.fa-cloud-upload::before { + content: "\f0ee"; +} + +.fa-cloud-upload-alt::before { + content: "\f0ee"; +} + +.fa-palette::before { + content: "\f53f"; +} + +.fa-arrows-turn-right::before { + content: "\e4c0"; +} + +.fa-vest::before { + content: "\e085"; +} + +.fa-ferry::before { + content: "\e4ea"; +} + +.fa-arrows-down-to-people::before { + content: "\e4b9"; +} + +.fa-seedling::before { + content: "\f4d8"; +} + +.fa-sprout::before { + content: "\f4d8"; +} + +.fa-left-right::before { + content: "\f337"; +} + +.fa-arrows-alt-h::before { + content: "\f337"; +} + +.fa-boxes-packing::before { + content: "\e4c7"; +} + +.fa-circle-arrow-left::before { + content: "\f0a8"; +} + +.fa-arrow-circle-left::before { + content: "\f0a8"; +} + +.fa-group-arrows-rotate::before { + content: "\e4f6"; +} + +.fa-bowl-food::before { + content: "\e4c6"; +} + +.fa-candy-cane::before { + content: "\f786"; +} + +.fa-arrow-down-wide-short::before { + content: "\f160"; +} + +.fa-sort-amount-asc::before { + content: "\f160"; +} + +.fa-sort-amount-down::before { + content: "\f160"; +} + +.fa-cloud-bolt::before { + content: "\f76c"; +} + +.fa-thunderstorm::before { + content: "\f76c"; +} + +.fa-text-slash::before { + content: "\f87d"; +} + +.fa-remove-format::before { + content: "\f87d"; +} + +.fa-face-smile-wink::before { + content: "\f4da"; +} + +.fa-smile-wink::before { + content: "\f4da"; +} + +.fa-file-word::before { + content: "\f1c2"; +} + +.fa-file-powerpoint::before { + content: "\f1c4"; +} + +.fa-arrows-left-right::before { + content: "\f07e"; +} + +.fa-arrows-h::before { + content: "\f07e"; +} + +.fa-house-lock::before { + content: "\e510"; +} + +.fa-cloud-arrow-down::before { + content: "\f0ed"; +} + +.fa-cloud-download::before { + content: "\f0ed"; +} + +.fa-cloud-download-alt::before { + content: "\f0ed"; +} + +.fa-children::before { + content: "\e4e1"; +} + +.fa-chalkboard::before { + content: "\f51b"; +} + +.fa-blackboard::before { + content: "\f51b"; +} + +.fa-user-large-slash::before { + content: "\f4fa"; +} + +.fa-user-alt-slash::before { + content: "\f4fa"; +} + +.fa-envelope-open::before { + content: "\f2b6"; +} + +.fa-handshake-simple-slash::before { + content: "\e05f"; +} + +.fa-handshake-alt-slash::before { + content: "\e05f"; +} + +.fa-mattress-pillow::before { + content: "\e525"; +} + +.fa-guarani-sign::before { + content: "\e19a"; +} + +.fa-arrows-rotate::before { + content: "\f021"; +} + +.fa-refresh::before { + content: "\f021"; +} + +.fa-sync::before { + content: "\f021"; +} + +.fa-fire-extinguisher::before { + content: "\f134"; +} + +.fa-cruzeiro-sign::before { + content: "\e152"; +} + +.fa-greater-than-equal::before { + content: "\f532"; +} + +.fa-shield-halved::before { + content: "\f3ed"; +} + +.fa-shield-alt::before { + content: "\f3ed"; +} + +.fa-book-atlas::before { + content: "\f558"; +} + +.fa-atlas::before { + content: "\f558"; +} + +.fa-virus::before { + content: "\e074"; +} + +.fa-envelope-circle-check::before { + content: "\e4e8"; +} + +.fa-layer-group::before { + content: "\f5fd"; +} + +.fa-arrows-to-dot::before { + content: "\e4be"; +} + +.fa-archway::before { + content: "\f557"; +} + +.fa-heart-circle-check::before { + content: "\e4fd"; +} + +.fa-house-chimney-crack::before { + content: "\f6f1"; +} + +.fa-house-damage::before { + content: "\f6f1"; +} + +.fa-file-zipper::before { + content: "\f1c6"; +} + +.fa-file-archive::before { + content: "\f1c6"; +} + +.fa-square::before { + content: "\f0c8"; +} + +.fa-martini-glass-empty::before { + content: "\f000"; +} + +.fa-glass-martini::before { + content: "\f000"; +} + +.fa-couch::before { + content: "\f4b8"; +} + +.fa-cedi-sign::before { + content: "\e0df"; +} + +.fa-italic::before { + content: "\f033"; +} + +.fa-church::before { + content: "\f51d"; +} + +.fa-comments-dollar::before { + content: "\f653"; +} + +.fa-democrat::before { + content: "\f747"; +} + +.fa-z::before { + content: "\5a"; +} + +.fa-person-skiing::before { + content: "\f7c9"; +} + +.fa-skiing::before { + content: "\f7c9"; +} + +.fa-road-lock::before { + content: "\e567"; +} + +.fa-a::before { + content: "\41"; +} + +.fa-temperature-arrow-down::before { + content: "\e03f"; +} + +.fa-temperature-down::before { + content: "\e03f"; +} + +.fa-feather-pointed::before { + content: "\f56b"; +} + +.fa-feather-alt::before { + content: "\f56b"; +} + +.fa-p::before { + content: "\50"; +} + +.fa-snowflake::before { + content: "\f2dc"; +} + +.fa-newspaper::before { + content: "\f1ea"; +} + +.fa-rectangle-ad::before { + content: "\f641"; +} + +.fa-ad::before { + content: "\f641"; +} + +.fa-circle-arrow-right::before { + content: "\f0a9"; +} + +.fa-arrow-circle-right::before { + content: "\f0a9"; +} + +.fa-filter-circle-xmark::before { + content: "\e17b"; +} + +.fa-locust::before { + content: "\e520"; +} + +.fa-sort::before { + content: "\f0dc"; +} + +.fa-unsorted::before { + content: "\f0dc"; +} + +.fa-list-ol::before { + content: "\f0cb"; +} + +.fa-list-1-2::before { + content: "\f0cb"; +} + +.fa-list-numeric::before { + content: "\f0cb"; +} + +.fa-person-dress-burst::before { + content: "\e544"; +} + +.fa-money-check-dollar::before { + content: "\f53d"; +} + +.fa-money-check-alt::before { + content: "\f53d"; +} + +.fa-vector-square::before { + content: "\f5cb"; +} + +.fa-bread-slice::before { + content: "\f7ec"; +} + +.fa-language::before { + content: "\f1ab"; +} + +.fa-face-kiss-wink-heart::before { + content: "\f598"; +} + +.fa-kiss-wink-heart::before { + content: "\f598"; +} + +.fa-filter::before { + content: "\f0b0"; +} + +.fa-question::before { + content: "\3f"; +} + +.fa-file-signature::before { + content: "\f573"; +} + +.fa-up-down-left-right::before { + content: "\f0b2"; +} + +.fa-arrows-alt::before { + content: "\f0b2"; +} + +.fa-house-chimney-user::before { + content: "\e065"; +} + +.fa-hand-holding-heart::before { + content: "\f4be"; +} + +.fa-puzzle-piece::before { + content: "\f12e"; +} + +.fa-money-check::before { + content: "\f53c"; +} + +.fa-star-half-stroke::before { + content: "\f5c0"; +} + +.fa-star-half-alt::before { + content: "\f5c0"; +} + +.fa-code::before { + content: "\f121"; +} + +.fa-whiskey-glass::before { + content: "\f7a0"; +} + +.fa-glass-whiskey::before { + content: "\f7a0"; +} + +.fa-building-circle-exclamation::before { + content: "\e4d3"; +} + +.fa-magnifying-glass-chart::before { + content: "\e522"; +} + +.fa-arrow-up-right-from-square::before { + content: "\f08e"; +} + +.fa-external-link::before { + content: "\f08e"; +} + +.fa-cubes-stacked::before { + content: "\e4e6"; +} + +.fa-won-sign::before { + content: "\f159"; +} + +.fa-krw::before { + content: "\f159"; +} + +.fa-won::before { + content: "\f159"; +} + +.fa-virus-covid::before { + content: "\e4a8"; +} + +.fa-austral-sign::before { + content: "\e0a9"; +} + +.fa-f::before { + content: "\46"; +} + +.fa-leaf::before { + content: "\f06c"; +} + +.fa-road::before { + content: "\f018"; +} + +.fa-taxi::before { + content: "\f1ba"; +} + +.fa-cab::before { + content: "\f1ba"; +} + +.fa-person-circle-plus::before { + content: "\e541"; +} + +.fa-chart-pie::before { + content: "\f200"; +} + +.fa-pie-chart::before { + content: "\f200"; +} + +.fa-bolt-lightning::before { + content: "\e0b7"; +} + +.fa-sack-xmark::before { + content: "\e56a"; +} + +.fa-file-excel::before { + content: "\f1c3"; +} + +.fa-file-contract::before { + content: "\f56c"; +} + +.fa-fish-fins::before { + content: "\e4f2"; +} + +.fa-building-flag::before { + content: "\e4d5"; +} + +.fa-face-grin-beam::before { + content: "\f582"; +} + +.fa-grin-beam::before { + content: "\f582"; +} + +.fa-object-ungroup::before { + content: "\f248"; +} + +.fa-poop::before { + content: "\f619"; +} + +.fa-location-pin::before { + content: "\f041"; +} + +.fa-map-marker::before { + content: "\f041"; +} + +.fa-kaaba::before { + content: "\f66b"; +} + +.fa-toilet-paper::before { + content: "\f71e"; +} + +.fa-helmet-safety::before { + content: "\f807"; +} + +.fa-hard-hat::before { + content: "\f807"; +} + +.fa-hat-hard::before { + content: "\f807"; +} + +.fa-eject::before { + content: "\f052"; +} + +.fa-circle-right::before { + content: "\f35a"; +} + +.fa-arrow-alt-circle-right::before { + content: "\f35a"; +} + +.fa-plane-circle-check::before { + content: "\e555"; +} + +.fa-face-rolling-eyes::before { + content: "\f5a5"; +} + +.fa-meh-rolling-eyes::before { + content: "\f5a5"; +} + +.fa-object-group::before { + content: "\f247"; +} + +.fa-chart-line::before { + content: "\f201"; +} + +.fa-line-chart::before { + content: "\f201"; +} + +.fa-mask-ventilator::before { + content: "\e524"; +} + +.fa-arrow-right::before { + content: "\f061"; +} + +.fa-signs-post::before { + content: "\f277"; +} + +.fa-map-signs::before { + content: "\f277"; +} + +.fa-cash-register::before { + content: "\f788"; +} + +.fa-person-circle-question::before { + content: "\e542"; +} + +.fa-h::before { + content: "\48"; +} + +.fa-tarp::before { + content: "\e57b"; +} + +.fa-screwdriver-wrench::before { + content: "\f7d9"; +} + +.fa-tools::before { + content: "\f7d9"; +} + +.fa-arrows-to-eye::before { + content: "\e4bf"; +} + +.fa-plug-circle-bolt::before { + content: "\e55b"; +} + +.fa-heart::before { + content: "\f004"; +} + +.fa-mars-and-venus::before { + content: "\f224"; +} + +.fa-house-user::before { + content: "\e1b0"; +} + +.fa-home-user::before { + content: "\e1b0"; +} + +.fa-dumpster-fire::before { + content: "\f794"; +} + +.fa-house-crack::before { + content: "\e3b1"; +} + +.fa-martini-glass-citrus::before { + content: "\f561"; +} + +.fa-cocktail::before { + content: "\f561"; +} + +.fa-face-surprise::before { + content: "\f5c2"; +} + +.fa-surprise::before { + content: "\f5c2"; +} + +.fa-bottle-water::before { + content: "\e4c5"; +} + +.fa-circle-pause::before { + content: "\f28b"; +} + +.fa-pause-circle::before { + content: "\f28b"; +} + +.fa-toilet-paper-slash::before { + content: "\e072"; +} + +.fa-apple-whole::before { + content: "\f5d1"; +} + +.fa-apple-alt::before { + content: "\f5d1"; +} + +.fa-kitchen-set::before { + content: "\e51a"; +} + +.fa-r::before { + content: "\52"; +} + +.fa-temperature-quarter::before { + content: "\f2ca"; +} + +.fa-temperature-1::before { + content: "\f2ca"; +} + +.fa-thermometer-1::before { + content: "\f2ca"; +} + +.fa-thermometer-quarter::before { + content: "\f2ca"; +} + +.fa-cube::before { + content: "\f1b2"; +} + +.fa-bitcoin-sign::before { + content: "\e0b4"; +} + +.fa-shield-dog::before { + content: "\e573"; +} + +.fa-solar-panel::before { + content: "\f5ba"; +} + +.fa-lock-open::before { + content: "\f3c1"; +} + +.fa-elevator::before { + content: "\e16d"; +} + +.fa-money-bill-transfer::before { + content: "\e528"; +} + +.fa-money-bill-trend-up::before { + content: "\e529"; +} + +.fa-house-flood-water-circle-arrow-right::before { + content: "\e50f"; +} + +.fa-square-poll-horizontal::before { + content: "\f682"; +} + +.fa-poll-h::before { + content: "\f682"; +} + +.fa-circle::before { + content: "\f111"; +} + +.fa-backward-fast::before { + content: "\f049"; +} + +.fa-fast-backward::before { + content: "\f049"; +} + +.fa-recycle::before { + content: "\f1b8"; +} + +.fa-user-astronaut::before { + content: "\f4fb"; +} + +.fa-plane-slash::before { + content: "\e069"; +} + +.fa-trademark::before { + content: "\f25c"; +} + +.fa-basketball::before { + content: "\f434"; +} + +.fa-basketball-ball::before { + content: "\f434"; +} + +.fa-satellite-dish::before { + content: "\f7c0"; +} + +.fa-circle-up::before { + content: "\f35b"; +} + +.fa-arrow-alt-circle-up::before { + content: "\f35b"; +} + +.fa-mobile-screen-button::before { + content: "\f3cd"; +} + +.fa-mobile-alt::before { + content: "\f3cd"; +} + +.fa-volume-high::before { + content: "\f028"; +} + +.fa-volume-up::before { + content: "\f028"; +} + +.fa-users-rays::before { + content: "\e593"; +} + +.fa-wallet::before { + content: "\f555"; +} + +.fa-clipboard-check::before { + content: "\f46c"; +} + +.fa-file-audio::before { + content: "\f1c7"; +} + +.fa-burger::before { + content: "\f805"; +} + +.fa-hamburger::before { + content: "\f805"; +} + +.fa-wrench::before { + content: "\f0ad"; +} + +.fa-bugs::before { + content: "\e4d0"; +} + +.fa-rupee-sign::before { + content: "\f156"; +} + +.fa-rupee::before { + content: "\f156"; +} + +.fa-file-image::before { + content: "\f1c5"; +} + +.fa-circle-question::before { + content: "\f059"; +} + +.fa-question-circle::before { + content: "\f059"; +} + +.fa-plane-departure::before { + content: "\f5b0"; +} + +.fa-handshake-slash::before { + content: "\e060"; +} + +.fa-book-bookmark::before { + content: "\e0bb"; +} + +.fa-code-branch::before { + content: "\f126"; +} + +.fa-hat-cowboy::before { + content: "\f8c0"; +} + +.fa-bridge::before { + content: "\e4c8"; +} + +.fa-phone-flip::before { + content: "\f879"; +} + +.fa-phone-alt::before { + content: "\f879"; +} + +.fa-truck-front::before { + content: "\e2b7"; +} + +.fa-cat::before { + content: "\f6be"; +} + +.fa-anchor-circle-exclamation::before { + content: "\e4ab"; +} + +.fa-truck-field::before { + content: "\e58d"; +} + +.fa-route::before { + content: "\f4d7"; +} + +.fa-clipboard-question::before { + content: "\e4e3"; +} + +.fa-panorama::before { + content: "\e209"; +} + +.fa-comment-medical::before { + content: "\f7f5"; +} + +.fa-teeth-open::before { + content: "\f62f"; +} + +.fa-file-circle-minus::before { + content: "\e4ed"; +} + +.fa-tags::before { + content: "\f02c"; +} + +.fa-wine-glass::before { + content: "\f4e3"; +} + +.fa-forward-fast::before { + content: "\f050"; +} + +.fa-fast-forward::before { + content: "\f050"; +} + +.fa-face-meh-blank::before { + content: "\f5a4"; +} + +.fa-meh-blank::before { + content: "\f5a4"; +} + +.fa-square-parking::before { + content: "\f540"; +} + +.fa-parking::before { + content: "\f540"; +} + +.fa-house-signal::before { + content: "\e012"; +} + +.fa-bars-progress::before { + content: "\f828"; +} + +.fa-tasks-alt::before { + content: "\f828"; +} + +.fa-faucet-drip::before { + content: "\e006"; +} + +.fa-cart-flatbed::before { + content: "\f474"; +} + +.fa-dolly-flatbed::before { + content: "\f474"; +} + +.fa-ban-smoking::before { + content: "\f54d"; +} + +.fa-smoking-ban::before { + content: "\f54d"; +} + +.fa-terminal::before { + content: "\f120"; +} + +.fa-mobile-button::before { + content: "\f10b"; +} + +.fa-house-medical-flag::before { + content: "\e514"; +} + +.fa-basket-shopping::before { + content: "\f291"; +} + +.fa-shopping-basket::before { + content: "\f291"; +} + +.fa-tape::before { + content: "\f4db"; +} + +.fa-bus-simple::before { + content: "\f55e"; +} + +.fa-bus-alt::before { + content: "\f55e"; +} + +.fa-eye::before { + content: "\f06e"; +} + +.fa-face-sad-cry::before { + content: "\f5b3"; +} + +.fa-sad-cry::before { + content: "\f5b3"; +} + +.fa-audio-description::before { + content: "\f29e"; +} + +.fa-person-military-to-person::before { + content: "\e54c"; +} + +.fa-file-shield::before { + content: "\e4f0"; +} + +.fa-user-slash::before { + content: "\f506"; +} + +.fa-pen::before { + content: "\f304"; +} + +.fa-tower-observation::before { + content: "\e586"; +} + +.fa-file-code::before { + content: "\f1c9"; +} + +.fa-signal::before { + content: "\f012"; +} + +.fa-signal-5::before { + content: "\f012"; +} + +.fa-signal-perfect::before { + content: "\f012"; +} + +.fa-bus::before { + content: "\f207"; +} + +.fa-heart-circle-xmark::before { + content: "\e501"; +} + +.fa-house-chimney::before { + content: "\e3af"; +} + +.fa-home-lg::before { + content: "\e3af"; +} + +.fa-window-maximize::before { + content: "\f2d0"; +} + +.fa-face-frown::before { + content: "\f119"; +} + +.fa-frown::before { + content: "\f119"; +} + +.fa-prescription::before { + content: "\f5b1"; +} + +.fa-shop::before { + content: "\f54f"; +} + +.fa-store-alt::before { + content: "\f54f"; +} + +.fa-floppy-disk::before { + content: "\f0c7"; +} + +.fa-save::before { + content: "\f0c7"; +} + +.fa-vihara::before { + content: "\f6a7"; +} + +.fa-scale-unbalanced::before { + content: "\f515"; +} + +.fa-balance-scale-left::before { + content: "\f515"; +} + +.fa-sort-up::before { + content: "\f0de"; +} + +.fa-sort-asc::before { + content: "\f0de"; +} + +.fa-comment-dots::before { + content: "\f4ad"; +} + +.fa-commenting::before { + content: "\f4ad"; +} + +.fa-plant-wilt::before { + content: "\e5aa"; +} + +.fa-diamond::before { + content: "\f219"; +} + +.fa-face-grin-squint::before { + content: "\f585"; +} + +.fa-grin-squint::before { + content: "\f585"; +} + +.fa-hand-holding-dollar::before { + content: "\f4c0"; +} + +.fa-hand-holding-usd::before { + content: "\f4c0"; +} + +.fa-bacterium::before { + content: "\e05a"; +} + +.fa-hand-pointer::before { + content: "\f25a"; +} + +.fa-drum-steelpan::before { + content: "\f56a"; +} + +.fa-hand-scissors::before { + content: "\f257"; +} + +.fa-hands-praying::before { + content: "\f684"; +} + +.fa-praying-hands::before { + content: "\f684"; +} + +.fa-arrow-rotate-right::before { + content: "\f01e"; +} + +.fa-arrow-right-rotate::before { + content: "\f01e"; +} + +.fa-arrow-rotate-forward::before { + content: "\f01e"; +} + +.fa-redo::before { + content: "\f01e"; +} + +.fa-biohazard::before { + content: "\f780"; +} + +.fa-location-crosshairs::before { + content: "\f601"; +} + +.fa-location::before { + content: "\f601"; +} + +.fa-mars-double::before { + content: "\f227"; +} + +.fa-child-dress::before { + content: "\e59c"; +} + +.fa-users-between-lines::before { + content: "\e591"; +} + +.fa-lungs-virus::before { + content: "\e067"; +} + +.fa-face-grin-tears::before { + content: "\f588"; +} + +.fa-grin-tears::before { + content: "\f588"; +} + +.fa-phone::before { + content: "\f095"; +} + +.fa-calendar-xmark::before { + content: "\f273"; +} + +.fa-calendar-times::before { + content: "\f273"; +} + +.fa-child-reaching::before { + content: "\e59d"; +} + +.fa-head-side-virus::before { + content: "\e064"; +} + +.fa-user-gear::before { + content: "\f4fe"; +} + +.fa-user-cog::before { + content: "\f4fe"; +} + +.fa-arrow-up-1-9::before { + content: "\f163"; +} + +.fa-sort-numeric-up::before { + content: "\f163"; +} + +.fa-door-closed::before { + content: "\f52a"; +} + +.fa-shield-virus::before { + content: "\e06c"; +} + +.fa-dice-six::before { + content: "\f526"; +} + +.fa-mosquito-net::before { + content: "\e52c"; +} + +.fa-bridge-water::before { + content: "\e4ce"; +} + +.fa-person-booth::before { + content: "\f756"; +} + +.fa-text-width::before { + content: "\f035"; +} + +.fa-hat-wizard::before { + content: "\f6e8"; +} + +.fa-pen-fancy::before { + content: "\f5ac"; +} + +.fa-person-digging::before { + content: "\f85e"; +} + +.fa-digging::before { + content: "\f85e"; +} + +.fa-trash::before { + content: "\f1f8"; +} + +.fa-gauge-simple::before { + content: "\f629"; +} + +.fa-gauge-simple-med::before { + content: "\f629"; +} + +.fa-tachometer-average::before { + content: "\f629"; +} + +.fa-book-medical::before { + content: "\f7e6"; +} + +.fa-poo::before { + content: "\f2fe"; +} + +.fa-quote-right::before { + content: "\f10e"; +} + +.fa-quote-right-alt::before { + content: "\f10e"; +} + +.fa-shirt::before { + content: "\f553"; +} + +.fa-t-shirt::before { + content: "\f553"; +} + +.fa-tshirt::before { + content: "\f553"; +} + +.fa-cubes::before { + content: "\f1b3"; +} + +.fa-divide::before { + content: "\f529"; +} + +.fa-tenge-sign::before { + content: "\f7d7"; +} + +.fa-tenge::before { + content: "\f7d7"; +} + +.fa-headphones::before { + content: "\f025"; +} + +.fa-hands-holding::before { + content: "\f4c2"; +} + +.fa-hands-clapping::before { + content: "\e1a8"; +} + +.fa-republican::before { + content: "\f75e"; +} + +.fa-arrow-left::before { + content: "\f060"; +} + +.fa-person-circle-xmark::before { + content: "\e543"; +} + +.fa-ruler::before { + content: "\f545"; +} + +.fa-align-left::before { + content: "\f036"; +} + +.fa-dice-d6::before { + content: "\f6d1"; +} + +.fa-restroom::before { + content: "\f7bd"; +} + +.fa-j::before { + content: "\4a"; +} + +.fa-users-viewfinder::before { + content: "\e595"; +} + +.fa-file-video::before { + content: "\f1c8"; +} + +.fa-up-right-from-square::before { + content: "\f35d"; +} + +.fa-external-link-alt::before { + content: "\f35d"; +} + +.fa-table-cells::before { + content: "\f00a"; +} + +.fa-th::before { + content: "\f00a"; +} + +.fa-file-pdf::before { + content: "\f1c1"; +} + +.fa-book-bible::before { + content: "\f647"; +} + +.fa-bible::before { + content: "\f647"; +} + +.fa-o::before { + content: "\4f"; +} + +.fa-suitcase-medical::before { + content: "\f0fa"; +} + +.fa-medkit::before { + content: "\f0fa"; +} + +.fa-user-secret::before { + content: "\f21b"; +} + +.fa-otter::before { + content: "\f700"; +} + +.fa-person-dress::before { + content: "\f182"; +} + +.fa-female::before { + content: "\f182"; +} + +.fa-comment-dollar::before { + content: "\f651"; +} + +.fa-business-time::before { + content: "\f64a"; +} + +.fa-briefcase-clock::before { + content: "\f64a"; +} + +.fa-table-cells-large::before { + content: "\f009"; +} + +.fa-th-large::before { + content: "\f009"; +} + +.fa-book-tanakh::before { + content: "\f827"; +} + +.fa-tanakh::before { + content: "\f827"; +} + +.fa-phone-volume::before { + content: "\f2a0"; +} + +.fa-volume-control-phone::before { + content: "\f2a0"; +} + +.fa-hat-cowboy-side::before { + content: "\f8c1"; +} + +.fa-clipboard-user::before { + content: "\f7f3"; +} + +.fa-child::before { + content: "\f1ae"; +} + +.fa-lira-sign::before { + content: "\f195"; +} + +.fa-satellite::before { + content: "\f7bf"; +} + +.fa-plane-lock::before { + content: "\e558"; +} + +.fa-tag::before { + content: "\f02b"; +} + +.fa-comment::before { + content: "\f075"; +} + +.fa-cake-candles::before { + content: "\f1fd"; +} + +.fa-birthday-cake::before { + content: "\f1fd"; +} + +.fa-cake::before { + content: "\f1fd"; +} + +.fa-envelope::before { + content: "\f0e0"; +} + +.fa-angles-up::before { + content: "\f102"; +} + +.fa-angle-double-up::before { + content: "\f102"; +} + +.fa-paperclip::before { + content: "\f0c6"; +} + +.fa-arrow-right-to-city::before { + content: "\e4b3"; +} + +.fa-ribbon::before { + content: "\f4d6"; +} + +.fa-lungs::before { + content: "\f604"; +} + +.fa-arrow-up-9-1::before { + content: "\f887"; +} + +.fa-sort-numeric-up-alt::before { + content: "\f887"; +} + +.fa-litecoin-sign::before { + content: "\e1d3"; +} + +.fa-border-none::before { + content: "\f850"; +} + +.fa-circle-nodes::before { + content: "\e4e2"; +} + +.fa-parachute-box::before { + content: "\f4cd"; +} + +.fa-indent::before { + content: "\f03c"; +} + +.fa-truck-field-un::before { + content: "\e58e"; +} + +.fa-hourglass::before { + content: "\f254"; +} + +.fa-hourglass-empty::before { + content: "\f254"; +} + +.fa-mountain::before { + content: "\f6fc"; +} + +.fa-user-doctor::before { + content: "\f0f0"; +} + +.fa-user-md::before { + content: "\f0f0"; +} + +.fa-circle-info::before { + content: "\f05a"; +} + +.fa-info-circle::before { + content: "\f05a"; +} + +.fa-cloud-meatball::before { + content: "\f73b"; +} + +.fa-camera::before { + content: "\f030"; +} + +.fa-camera-alt::before { + content: "\f030"; +} + +.fa-square-virus::before { + content: "\e578"; +} + +.fa-meteor::before { + content: "\f753"; +} + +.fa-car-on::before { + content: "\e4dd"; +} + +.fa-sleigh::before { + content: "\f7cc"; +} + +.fa-arrow-down-1-9::before { + content: "\f162"; +} + +.fa-sort-numeric-asc::before { + content: "\f162"; +} + +.fa-sort-numeric-down::before { + content: "\f162"; +} + +.fa-hand-holding-droplet::before { + content: "\f4c1"; +} + +.fa-hand-holding-water::before { + content: "\f4c1"; +} + +.fa-water::before { + content: "\f773"; +} + +.fa-calendar-check::before { + content: "\f274"; +} + +.fa-braille::before { + content: "\f2a1"; +} + +.fa-prescription-bottle-medical::before { + content: "\f486"; +} + +.fa-prescription-bottle-alt::before { + content: "\f486"; +} + +.fa-landmark::before { + content: "\f66f"; +} + +.fa-truck::before { + content: "\f0d1"; +} + +.fa-crosshairs::before { + content: "\f05b"; +} + +.fa-person-cane::before { + content: "\e53c"; +} + +.fa-tent::before { + content: "\e57d"; +} + +.fa-vest-patches::before { + content: "\e086"; +} + +.fa-check-double::before { + content: "\f560"; +} + +.fa-arrow-down-a-z::before { + content: "\f15d"; +} + +.fa-sort-alpha-asc::before { + content: "\f15d"; +} + +.fa-sort-alpha-down::before { + content: "\f15d"; +} + +.fa-money-bill-wheat::before { + content: "\e52a"; +} + +.fa-cookie::before { + content: "\f563"; +} + +.fa-arrow-rotate-left::before { + content: "\f0e2"; +} + +.fa-arrow-left-rotate::before { + content: "\f0e2"; +} + +.fa-arrow-rotate-back::before { + content: "\f0e2"; +} + +.fa-arrow-rotate-backward::before { + content: "\f0e2"; +} + +.fa-undo::before { + content: "\f0e2"; +} + +.fa-hard-drive::before { + content: "\f0a0"; +} + +.fa-hdd::before { + content: "\f0a0"; +} + +.fa-face-grin-squint-tears::before { + content: "\f586"; +} + +.fa-grin-squint-tears::before { + content: "\f586"; +} + +.fa-dumbbell::before { + content: "\f44b"; +} + +.fa-rectangle-list::before { + content: "\f022"; +} + +.fa-list-alt::before { + content: "\f022"; +} + +.fa-tarp-droplet::before { + content: "\e57c"; +} + +.fa-house-medical-circle-check::before { + content: "\e511"; +} + +.fa-person-skiing-nordic::before { + content: "\f7ca"; +} + +.fa-skiing-nordic::before { + content: "\f7ca"; +} + +.fa-calendar-plus::before { + content: "\f271"; +} + +.fa-plane-arrival::before { + content: "\f5af"; +} + +.fa-circle-left::before { + content: "\f359"; +} + +.fa-arrow-alt-circle-left::before { + content: "\f359"; +} + +.fa-train-subway::before { + content: "\f239"; +} + +.fa-subway::before { + content: "\f239"; +} + +.fa-chart-gantt::before { + content: "\e0e4"; +} + +.fa-indian-rupee-sign::before { + content: "\e1bc"; +} + +.fa-indian-rupee::before { + content: "\e1bc"; +} + +.fa-inr::before { + content: "\e1bc"; +} + +.fa-crop-simple::before { + content: "\f565"; +} + +.fa-crop-alt::before { + content: "\f565"; +} + +.fa-money-bill-1::before { + content: "\f3d1"; +} + +.fa-money-bill-alt::before { + content: "\f3d1"; +} + +.fa-left-long::before { + content: "\f30a"; +} + +.fa-long-arrow-alt-left::before { + content: "\f30a"; +} + +.fa-dna::before { + content: "\f471"; +} + +.fa-virus-slash::before { + content: "\e075"; +} + +.fa-minus::before { + content: "\f068"; +} + +.fa-subtract::before { + content: "\f068"; +} + +.fa-chess::before { + content: "\f439"; +} + +.fa-arrow-left-long::before { + content: "\f177"; +} + +.fa-long-arrow-left::before { + content: "\f177"; +} + +.fa-plug-circle-check::before { + content: "\e55c"; +} + +.fa-street-view::before { + content: "\f21d"; +} + +.fa-franc-sign::before { + content: "\e18f"; +} + +.fa-volume-off::before { + content: "\f026"; +} + +.fa-hands-asl-interpreting::before { + content: "\f2a3"; +} + +.fa-american-sign-language-interpreting::before { + content: "\f2a3"; +} + +.fa-asl-interpreting::before { + content: "\f2a3"; +} + +.fa-hands-american-sign-language-interpreting::before { + content: "\f2a3"; +} + +.fa-gear::before { + content: "\f013"; +} + +.fa-cog::before { + content: "\f013"; +} + +.fa-droplet-slash::before { + content: "\f5c7"; +} + +.fa-tint-slash::before { + content: "\f5c7"; +} + +.fa-mosque::before { + content: "\f678"; +} + +.fa-mosquito::before { + content: "\e52b"; +} + +.fa-star-of-david::before { + content: "\f69a"; +} + +.fa-person-military-rifle::before { + content: "\e54b"; +} + +.fa-cart-shopping::before { + content: "\f07a"; +} + +.fa-shopping-cart::before { + content: "\f07a"; +} + +.fa-vials::before { + content: "\f493"; +} + +.fa-plug-circle-plus::before { + content: "\e55f"; +} + +.fa-place-of-worship::before { + content: "\f67f"; +} + +.fa-grip-vertical::before { + content: "\f58e"; +} + +.fa-arrow-turn-up::before { + content: "\f148"; +} + +.fa-level-up::before { + content: "\f148"; +} + +.fa-u::before { + content: "\55"; +} + +.fa-square-root-variable::before { + content: "\f698"; +} + +.fa-square-root-alt::before { + content: "\f698"; +} + +.fa-clock::before { + content: "\f017"; +} + +.fa-clock-four::before { + content: "\f017"; +} + +.fa-backward-step::before { + content: "\f048"; +} + +.fa-step-backward::before { + content: "\f048"; +} + +.fa-pallet::before { + content: "\f482"; +} + +.fa-faucet::before { + content: "\e005"; +} + +.fa-baseball-bat-ball::before { + content: "\f432"; +} + +.fa-s::before { + content: "\53"; +} + +.fa-timeline::before { + content: "\e29c"; +} + +.fa-keyboard::before { + content: "\f11c"; +} + +.fa-caret-down::before { + content: "\f0d7"; +} + +.fa-house-chimney-medical::before { + content: "\f7f2"; +} + +.fa-clinic-medical::before { + content: "\f7f2"; +} + +.fa-temperature-three-quarters::before { + content: "\f2c8"; +} + +.fa-temperature-3::before { + content: "\f2c8"; +} + +.fa-thermometer-3::before { + content: "\f2c8"; +} + +.fa-thermometer-three-quarters::before { + content: "\f2c8"; +} + +.fa-mobile-screen::before { + content: "\f3cf"; +} + +.fa-mobile-android-alt::before { + content: "\f3cf"; +} + +.fa-plane-up::before { + content: "\e22d"; +} + +.fa-piggy-bank::before { + content: "\f4d3"; +} + +.fa-battery-half::before { + content: "\f242"; +} + +.fa-battery-3::before { + content: "\f242"; +} + +.fa-mountain-city::before { + content: "\e52e"; +} + +.fa-coins::before { + content: "\f51e"; +} + +.fa-khanda::before { + content: "\f66d"; +} + +.fa-sliders::before { + content: "\f1de"; +} + +.fa-sliders-h::before { + content: "\f1de"; +} + +.fa-folder-tree::before { + content: "\f802"; +} + +.fa-network-wired::before { + content: "\f6ff"; +} + +.fa-map-pin::before { + content: "\f276"; +} + +.fa-hamsa::before { + content: "\f665"; +} + +.fa-cent-sign::before { + content: "\e3f5"; +} + +.fa-flask::before { + content: "\f0c3"; +} + +.fa-person-pregnant::before { + content: "\e31e"; +} + +.fa-wand-sparkles::before { + content: "\f72b"; +} + +.fa-ellipsis-vertical::before { + content: "\f142"; +} + +.fa-ellipsis-v::before { + content: "\f142"; +} + +.fa-ticket::before { + content: "\f145"; +} + +.fa-power-off::before { + content: "\f011"; +} + +.fa-right-long::before { + content: "\f30b"; +} + +.fa-long-arrow-alt-right::before { + content: "\f30b"; +} + +.fa-flag-usa::before { + content: "\f74d"; +} + +.fa-laptop-file::before { + content: "\e51d"; +} + +.fa-tty::before { + content: "\f1e4"; +} + +.fa-teletype::before { + content: "\f1e4"; +} + +.fa-diagram-next::before { + content: "\e476"; +} + +.fa-person-rifle::before { + content: "\e54e"; +} + +.fa-house-medical-circle-exclamation::before { + content: "\e512"; +} + +.fa-closed-captioning::before { + content: "\f20a"; +} + +.fa-person-hiking::before { + content: "\f6ec"; +} + +.fa-hiking::before { + content: "\f6ec"; +} + +.fa-venus-double::before { + content: "\f226"; +} + +.fa-images::before { + content: "\f302"; +} + +.fa-calculator::before { + content: "\f1ec"; +} + +.fa-people-pulling::before { + content: "\e535"; +} + +.fa-n::before { + content: "\4e"; +} + +.fa-cable-car::before { + content: "\f7da"; +} + +.fa-tram::before { + content: "\f7da"; +} + +.fa-cloud-rain::before { + content: "\f73d"; +} + +.fa-building-circle-xmark::before { + content: "\e4d4"; +} + +.fa-ship::before { + content: "\f21a"; +} + +.fa-arrows-down-to-line::before { + content: "\e4b8"; +} + +.fa-download::before { + content: "\f019"; +} + +.fa-face-grin::before { + content: "\f580"; +} + +.fa-grin::before { + content: "\f580"; +} + +.fa-delete-left::before { + content: "\f55a"; +} + +.fa-backspace::before { + content: "\f55a"; +} + +.fa-eye-dropper::before { + content: "\f1fb"; +} + +.fa-eye-dropper-empty::before { + content: "\f1fb"; +} + +.fa-eyedropper::before { + content: "\f1fb"; +} + +.fa-file-circle-check::before { + content: "\e5a0"; +} + +.fa-forward::before { + content: "\f04e"; +} + +.fa-mobile::before { + content: "\f3ce"; +} + +.fa-mobile-android::before { + content: "\f3ce"; +} + +.fa-mobile-phone::before { + content: "\f3ce"; +} + +.fa-face-meh::before { + content: "\f11a"; +} + +.fa-meh::before { + content: "\f11a"; +} + +.fa-align-center::before { + content: "\f037"; +} + +.fa-book-skull::before { + content: "\f6b7"; +} + +.fa-book-dead::before { + content: "\f6b7"; +} + +.fa-id-card::before { + content: "\f2c2"; +} + +.fa-drivers-license::before { + content: "\f2c2"; +} + +.fa-outdent::before { + content: "\f03b"; +} + +.fa-dedent::before { + content: "\f03b"; +} + +.fa-heart-circle-exclamation::before { + content: "\e4fe"; +} + +.fa-house::before { + content: "\f015"; +} + +.fa-home::before { + content: "\f015"; +} + +.fa-home-alt::before { + content: "\f015"; +} + +.fa-home-lg-alt::before { + content: "\f015"; +} + +.fa-calendar-week::before { + content: "\f784"; +} + +.fa-laptop-medical::before { + content: "\f812"; +} + +.fa-b::before { + content: "\42"; +} + +.fa-file-medical::before { + content: "\f477"; +} + +.fa-dice-one::before { + content: "\f525"; +} + +.fa-kiwi-bird::before { + content: "\f535"; +} + +.fa-arrow-right-arrow-left::before { + content: "\f0ec"; +} + +.fa-exchange::before { + content: "\f0ec"; +} + +.fa-rotate-right::before { + content: "\f2f9"; +} + +.fa-redo-alt::before { + content: "\f2f9"; +} + +.fa-rotate-forward::before { + content: "\f2f9"; +} + +.fa-utensils::before { + content: "\f2e7"; +} + +.fa-cutlery::before { + content: "\f2e7"; +} + +.fa-arrow-up-wide-short::before { + content: "\f161"; +} + +.fa-sort-amount-up::before { + content: "\f161"; +} + +.fa-mill-sign::before { + content: "\e1ed"; +} + +.fa-bowl-rice::before { + content: "\e2eb"; +} + +.fa-skull::before { + content: "\f54c"; +} + +.fa-tower-broadcast::before { + content: "\f519"; +} + +.fa-broadcast-tower::before { + content: "\f519"; +} + +.fa-truck-pickup::before { + content: "\f63c"; +} + +.fa-up-long::before { + content: "\f30c"; +} + +.fa-long-arrow-alt-up::before { + content: "\f30c"; +} + +.fa-stop::before { + content: "\f04d"; +} + +.fa-code-merge::before { + content: "\f387"; +} + +.fa-upload::before { + content: "\f093"; +} + +.fa-hurricane::before { + content: "\f751"; +} + +.fa-mound::before { + content: "\e52d"; +} + +.fa-toilet-portable::before { + content: "\e583"; +} + +.fa-compact-disc::before { + content: "\f51f"; +} + +.fa-file-arrow-down::before { + content: "\f56d"; +} + +.fa-file-download::before { + content: "\f56d"; +} + +.fa-caravan::before { + content: "\f8ff"; +} + +.fa-shield-cat::before { + content: "\e572"; +} + +.fa-bolt::before { + content: "\f0e7"; +} + +.fa-zap::before { + content: "\f0e7"; +} + +.fa-glass-water::before { + content: "\e4f4"; +} + +.fa-oil-well::before { + content: "\e532"; +} + +.fa-vault::before { + content: "\e2c5"; +} + +.fa-mars::before { + content: "\f222"; +} + +.fa-toilet::before { + content: "\f7d8"; +} + +.fa-plane-circle-xmark::before { + content: "\e557"; +} + +.fa-yen-sign::before { + content: "\f157"; +} + +.fa-cny::before { + content: "\f157"; +} + +.fa-jpy::before { + content: "\f157"; +} + +.fa-rmb::before { + content: "\f157"; +} + +.fa-yen::before { + content: "\f157"; +} + +.fa-ruble-sign::before { + content: "\f158"; +} + +.fa-rouble::before { + content: "\f158"; +} + +.fa-rub::before { + content: "\f158"; +} + +.fa-ruble::before { + content: "\f158"; +} + +.fa-sun::before { + content: "\f185"; +} + +.fa-guitar::before { + content: "\f7a6"; +} + +.fa-face-laugh-wink::before { + content: "\f59c"; +} + +.fa-laugh-wink::before { + content: "\f59c"; +} + +.fa-horse-head::before { + content: "\f7ab"; +} + +.fa-bore-hole::before { + content: "\e4c3"; +} + +.fa-industry::before { + content: "\f275"; +} + +.fa-circle-down::before { + content: "\f358"; +} + +.fa-arrow-alt-circle-down::before { + content: "\f358"; +} + +.fa-arrows-turn-to-dots::before { + content: "\e4c1"; +} + +.fa-florin-sign::before { + content: "\e184"; +} + +.fa-arrow-down-short-wide::before { + content: "\f884"; +} + +.fa-sort-amount-desc::before { + content: "\f884"; +} + +.fa-sort-amount-down-alt::before { + content: "\f884"; +} + +.fa-less-than::before { + content: "\3c"; +} + +.fa-angle-down::before { + content: "\f107"; +} + +.fa-car-tunnel::before { + content: "\e4de"; +} + +.fa-head-side-cough::before { + content: "\e061"; +} + +.fa-grip-lines::before { + content: "\f7a4"; +} + +.fa-thumbs-down::before { + content: "\f165"; +} + +.fa-user-lock::before { + content: "\f502"; +} + +.fa-arrow-right-long::before { + content: "\f178"; +} + +.fa-long-arrow-right::before { + content: "\f178"; +} + +.fa-anchor-circle-xmark::before { + content: "\e4ac"; +} + +.fa-ellipsis::before { + content: "\f141"; +} + +.fa-ellipsis-h::before { + content: "\f141"; +} + +.fa-chess-pawn::before { + content: "\f443"; +} + +.fa-kit-medical::before { + content: "\f479"; +} + +.fa-first-aid::before { + content: "\f479"; +} + +.fa-person-through-window::before { + content: "\e5a9"; +} + +.fa-toolbox::before { + content: "\f552"; +} + +.fa-hands-holding-circle::before { + content: "\e4fb"; +} + +.fa-bug::before { + content: "\f188"; +} + +.fa-credit-card::before { + content: "\f09d"; +} + +.fa-credit-card-alt::before { + content: "\f09d"; +} + +.fa-car::before { + content: "\f1b9"; +} + +.fa-automobile::before { + content: "\f1b9"; +} + +.fa-hand-holding-hand::before { + content: "\e4f7"; +} + +.fa-book-open-reader::before { + content: "\f5da"; +} + +.fa-book-reader::before { + content: "\f5da"; +} + +.fa-mountain-sun::before { + content: "\e52f"; +} + +.fa-arrows-left-right-to-line::before { + content: "\e4ba"; +} + +.fa-dice-d20::before { + content: "\f6cf"; +} + +.fa-truck-droplet::before { + content: "\e58c"; +} + +.fa-file-circle-xmark::before { + content: "\e5a1"; +} + +.fa-temperature-arrow-up::before { + content: "\e040"; +} + +.fa-temperature-up::before { + content: "\e040"; +} + +.fa-medal::before { + content: "\f5a2"; +} + +.fa-bed::before { + content: "\f236"; +} + +.fa-square-h::before { + content: "\f0fd"; +} + +.fa-h-square::before { + content: "\f0fd"; +} + +.fa-podcast::before { + content: "\f2ce"; +} + +.fa-temperature-full::before { + content: "\f2c7"; +} + +.fa-temperature-4::before { + content: "\f2c7"; +} + +.fa-thermometer-4::before { + content: "\f2c7"; +} + +.fa-thermometer-full::before { + content: "\f2c7"; +} + +.fa-bell::before { + content: "\f0f3"; +} + +.fa-superscript::before { + content: "\f12b"; +} + +.fa-plug-circle-xmark::before { + content: "\e560"; +} + +.fa-star-of-life::before { + content: "\f621"; +} + +.fa-phone-slash::before { + content: "\f3dd"; +} + +.fa-paint-roller::before { + content: "\f5aa"; +} + +.fa-handshake-angle::before { + content: "\f4c4"; +} + +.fa-hands-helping::before { + content: "\f4c4"; +} + +.fa-location-dot::before { + content: "\f3c5"; +} + +.fa-map-marker-alt::before { + content: "\f3c5"; +} + +.fa-file::before { + content: "\f15b"; +} + +.fa-greater-than::before { + content: "\3e"; +} + +.fa-person-swimming::before { + content: "\f5c4"; +} + +.fa-swimmer::before { + content: "\f5c4"; +} + +.fa-arrow-down::before { + content: "\f063"; +} + +.fa-droplet::before { + content: "\f043"; +} + +.fa-tint::before { + content: "\f043"; +} + +.fa-eraser::before { + content: "\f12d"; +} + +.fa-earth-americas::before { + content: "\f57d"; +} + +.fa-earth::before { + content: "\f57d"; +} + +.fa-earth-america::before { + content: "\f57d"; +} + +.fa-globe-americas::before { + content: "\f57d"; +} + +.fa-person-burst::before { + content: "\e53b"; +} + +.fa-dove::before { + content: "\f4ba"; +} + +.fa-battery-empty::before { + content: "\f244"; +} + +.fa-battery-0::before { + content: "\f244"; +} + +.fa-socks::before { + content: "\f696"; +} + +.fa-inbox::before { + content: "\f01c"; +} + +.fa-section::before { + content: "\e447"; +} + +.fa-gauge-high::before { + content: "\f625"; +} + +.fa-tachometer-alt::before { + content: "\f625"; +} + +.fa-tachometer-alt-fast::before { + content: "\f625"; +} + +.fa-envelope-open-text::before { + content: "\f658"; +} + +.fa-hospital::before { + content: "\f0f8"; +} + +.fa-hospital-alt::before { + content: "\f0f8"; +} + +.fa-hospital-wide::before { + content: "\f0f8"; +} + +.fa-wine-bottle::before { + content: "\f72f"; +} + +.fa-chess-rook::before { + content: "\f447"; +} + +.fa-bars-staggered::before { + content: "\f550"; +} + +.fa-reorder::before { + content: "\f550"; +} + +.fa-stream::before { + content: "\f550"; +} + +.fa-dharmachakra::before { + content: "\f655"; +} + +.fa-hotdog::before { + content: "\f80f"; +} + +.fa-person-walking-with-cane::before { + content: "\f29d"; +} + +.fa-blind::before { + content: "\f29d"; +} + +.fa-drum::before { + content: "\f569"; +} + +.fa-ice-cream::before { + content: "\f810"; +} + +.fa-heart-circle-bolt::before { + content: "\e4fc"; +} + +.fa-fax::before { + content: "\f1ac"; +} + +.fa-paragraph::before { + content: "\f1dd"; +} + +.fa-check-to-slot::before { + content: "\f772"; +} + +.fa-vote-yea::before { + content: "\f772"; +} + +.fa-star-half::before { + content: "\f089"; +} + +.fa-boxes-stacked::before { + content: "\f468"; +} + +.fa-boxes::before { + content: "\f468"; +} + +.fa-boxes-alt::before { + content: "\f468"; +} + +.fa-link::before { + content: "\f0c1"; +} + +.fa-chain::before { + content: "\f0c1"; +} + +.fa-ear-listen::before { + content: "\f2a2"; +} + +.fa-assistive-listening-systems::before { + content: "\f2a2"; +} + +.fa-tree-city::before { + content: "\e587"; +} + +.fa-play::before { + content: "\f04b"; +} + +.fa-font::before { + content: "\f031"; +} + +.fa-rupiah-sign::before { + content: "\e23d"; +} + +.fa-magnifying-glass::before { + content: "\f002"; +} + +.fa-search::before { + content: "\f002"; +} + +.fa-table-tennis-paddle-ball::before { + content: "\f45d"; +} + +.fa-ping-pong-paddle-ball::before { + content: "\f45d"; +} + +.fa-table-tennis::before { + content: "\f45d"; +} + +.fa-person-dots-from-line::before { + content: "\f470"; +} + +.fa-diagnoses::before { + content: "\f470"; +} + +.fa-trash-can-arrow-up::before { + content: "\f82a"; +} + +.fa-trash-restore-alt::before { + content: "\f82a"; +} + +.fa-naira-sign::before { + content: "\e1f6"; +} + +.fa-cart-arrow-down::before { + content: "\f218"; +} + +.fa-walkie-talkie::before { + content: "\f8ef"; +} + +.fa-file-pen::before { + content: "\f31c"; +} + +.fa-file-edit::before { + content: "\f31c"; +} + +.fa-receipt::before { + content: "\f543"; +} + +.fa-square-pen::before { + content: "\f14b"; +} + +.fa-pen-square::before { + content: "\f14b"; +} + +.fa-pencil-square::before { + content: "\f14b"; +} + +.fa-suitcase-rolling::before { + content: "\f5c1"; +} + +.fa-person-circle-exclamation::before { + content: "\e53f"; +} + +.fa-chevron-down::before { + content: "\f078"; +} + +.fa-battery-full::before { + content: "\f240"; +} + +.fa-battery::before { + content: "\f240"; +} + +.fa-battery-5::before { + content: "\f240"; +} + +.fa-skull-crossbones::before { + content: "\f714"; +} + +.fa-code-compare::before { + content: "\e13a"; +} + +.fa-list-ul::before { + content: "\f0ca"; +} + +.fa-list-dots::before { + content: "\f0ca"; +} + +.fa-school-lock::before { + content: "\e56f"; +} + +.fa-tower-cell::before { + content: "\e585"; +} + +.fa-down-long::before { + content: "\f309"; +} + +.fa-long-arrow-alt-down::before { + content: "\f309"; +} + +.fa-ranking-star::before { + content: "\e561"; +} + +.fa-chess-king::before { + content: "\f43f"; +} + +.fa-person-harassing::before { + content: "\e549"; +} + +.fa-brazilian-real-sign::before { + content: "\e46c"; +} + +.fa-landmark-dome::before { + content: "\f752"; +} + +.fa-landmark-alt::before { + content: "\f752"; +} + +.fa-arrow-up::before { + content: "\f062"; +} + +.fa-tv::before { + content: "\f26c"; +} + +.fa-television::before { + content: "\f26c"; +} + +.fa-tv-alt::before { + content: "\f26c"; +} + +.fa-shrimp::before { + content: "\e448"; +} + +.fa-list-check::before { + content: "\f0ae"; +} + +.fa-tasks::before { + content: "\f0ae"; +} + +.fa-jug-detergent::before { + content: "\e519"; +} + +.fa-circle-user::before { + content: "\f2bd"; +} + +.fa-user-circle::before { + content: "\f2bd"; +} + +.fa-user-shield::before { + content: "\f505"; +} + +.fa-wind::before { + content: "\f72e"; +} + +.fa-car-burst::before { + content: "\f5e1"; +} + +.fa-car-crash::before { + content: "\f5e1"; +} + +.fa-y::before { + content: "\59"; +} + +.fa-person-snowboarding::before { + content: "\f7ce"; +} + +.fa-snowboarding::before { + content: "\f7ce"; +} + +.fa-truck-fast::before { + content: "\f48b"; +} + +.fa-shipping-fast::before { + content: "\f48b"; +} + +.fa-fish::before { + content: "\f578"; +} + +.fa-user-graduate::before { + content: "\f501"; +} + +.fa-circle-half-stroke::before { + content: "\f042"; +} + +.fa-adjust::before { + content: "\f042"; +} + +.fa-clapperboard::before { + content: "\e131"; +} + +.fa-circle-radiation::before { + content: "\f7ba"; +} + +.fa-radiation-alt::before { + content: "\f7ba"; +} + +.fa-baseball::before { + content: "\f433"; +} + +.fa-baseball-ball::before { + content: "\f433"; +} + +.fa-jet-fighter-up::before { + content: "\e518"; +} + +.fa-diagram-project::before { + content: "\f542"; +} + +.fa-project-diagram::before { + content: "\f542"; +} + +.fa-copy::before { + content: "\f0c5"; +} + +.fa-volume-xmark::before { + content: "\f6a9"; +} + +.fa-volume-mute::before { + content: "\f6a9"; +} + +.fa-volume-times::before { + content: "\f6a9"; +} + +.fa-hand-sparkles::before { + content: "\e05d"; +} + +.fa-grip::before { + content: "\f58d"; +} + +.fa-grip-horizontal::before { + content: "\f58d"; +} + +.fa-share-from-square::before { + content: "\f14d"; +} + +.fa-share-square::before { + content: "\f14d"; +} + +.fa-child-combatant::before { + content: "\e4e0"; +} + +.fa-child-rifle::before { + content: "\e4e0"; +} + +.fa-gun::before { + content: "\e19b"; +} + +.fa-square-phone::before { + content: "\f098"; +} + +.fa-phone-square::before { + content: "\f098"; +} + +.fa-plus::before { + content: "\2b"; +} + +.fa-add::before { + content: "\2b"; +} + +.fa-expand::before { + content: "\f065"; +} + +.fa-computer::before { + content: "\e4e5"; +} + +.fa-xmark::before { + content: "\f00d"; +} + +.fa-close::before { + content: "\f00d"; +} + +.fa-multiply::before { + content: "\f00d"; +} + +.fa-remove::before { + content: "\f00d"; +} + +.fa-times::before { + content: "\f00d"; +} + +.fa-arrows-up-down-left-right::before { + content: "\f047"; +} + +.fa-arrows::before { + content: "\f047"; +} + +.fa-chalkboard-user::before { + content: "\f51c"; +} + +.fa-chalkboard-teacher::before { + content: "\f51c"; +} + +.fa-peso-sign::before { + content: "\e222"; +} + +.fa-building-shield::before { + content: "\e4d8"; +} + +.fa-baby::before { + content: "\f77c"; +} + +.fa-users-line::before { + content: "\e592"; +} + +.fa-quote-left::before { + content: "\f10d"; +} + +.fa-quote-left-alt::before { + content: "\f10d"; +} + +.fa-tractor::before { + content: "\f722"; +} + +.fa-trash-arrow-up::before { + content: "\f829"; +} + +.fa-trash-restore::before { + content: "\f829"; +} + +.fa-arrow-down-up-lock::before { + content: "\e4b0"; +} + +.fa-lines-leaning::before { + content: "\e51e"; +} + +.fa-ruler-combined::before { + content: "\f546"; +} + +.fa-copyright::before { + content: "\f1f9"; +} + +.fa-equals::before { + content: "\3d"; +} + +.fa-blender::before { + content: "\f517"; +} + +.fa-teeth::before { + content: "\f62e"; +} + +.fa-shekel-sign::before { + content: "\f20b"; +} + +.fa-ils::before { + content: "\f20b"; +} + +.fa-shekel::before { + content: "\f20b"; +} + +.fa-sheqel::before { + content: "\f20b"; +} + +.fa-sheqel-sign::before { + content: "\f20b"; +} + +.fa-map::before { + content: "\f279"; +} + +.fa-rocket::before { + content: "\f135"; +} + +.fa-photo-film::before { + content: "\f87c"; +} + +.fa-photo-video::before { + content: "\f87c"; +} + +.fa-folder-minus::before { + content: "\f65d"; +} + +.fa-store::before { + content: "\f54e"; +} + +.fa-arrow-trend-up::before { + content: "\e098"; +} + +.fa-plug-circle-minus::before { + content: "\e55e"; +} + +.fa-sign-hanging::before { + content: "\f4d9"; +} + +.fa-sign::before { + content: "\f4d9"; +} + +.fa-bezier-curve::before { + content: "\f55b"; +} + +.fa-bell-slash::before { + content: "\f1f6"; +} + +.fa-tablet::before { + content: "\f3fb"; +} + +.fa-tablet-android::before { + content: "\f3fb"; +} + +.fa-school-flag::before { + content: "\e56e"; +} + +.fa-fill::before { + content: "\f575"; +} + +.fa-angle-up::before { + content: "\f106"; +} + +.fa-drumstick-bite::before { + content: "\f6d7"; +} + +.fa-holly-berry::before { + content: "\f7aa"; +} + +.fa-chevron-left::before { + content: "\f053"; +} + +.fa-bacteria::before { + content: "\e059"; +} + +.fa-hand-lizard::before { + content: "\f258"; +} + +.fa-notdef::before { + content: "\e1fe"; +} + +.fa-disease::before { + content: "\f7fa"; +} + +.fa-briefcase-medical::before { + content: "\f469"; +} + +.fa-genderless::before { + content: "\f22d"; +} + +.fa-chevron-right::before { + content: "\f054"; +} + +.fa-retweet::before { + content: "\f079"; +} + +.fa-car-rear::before { + content: "\f5de"; +} + +.fa-car-alt::before { + content: "\f5de"; +} + +.fa-pump-soap::before { + content: "\e06b"; +} + +.fa-video-slash::before { + content: "\f4e2"; +} + +.fa-battery-quarter::before { + content: "\f243"; +} + +.fa-battery-2::before { + content: "\f243"; +} + +.fa-radio::before { + content: "\f8d7"; +} + +.fa-baby-carriage::before { + content: "\f77d"; +} + +.fa-carriage-baby::before { + content: "\f77d"; +} + +.fa-traffic-light::before { + content: "\f637"; +} + +.fa-thermometer::before { + content: "\f491"; +} + +.fa-vr-cardboard::before { + content: "\f729"; +} + +.fa-hand-middle-finger::before { + content: "\f806"; +} + +.fa-percent::before { + content: "\25"; +} + +.fa-percentage::before { + content: "\25"; +} + +.fa-truck-moving::before { + content: "\f4df"; +} + +.fa-glass-water-droplet::before { + content: "\e4f5"; +} + +.fa-display::before { + content: "\e163"; +} + +.fa-face-smile::before { + content: "\f118"; +} + +.fa-smile::before { + content: "\f118"; +} + +.fa-thumbtack::before { + content: "\f08d"; +} + +.fa-thumb-tack::before { + content: "\f08d"; +} + +.fa-trophy::before { + content: "\f091"; +} + +.fa-person-praying::before { + content: "\f683"; +} + +.fa-pray::before { + content: "\f683"; +} + +.fa-hammer::before { + content: "\f6e3"; +} + +.fa-hand-peace::before { + content: "\f25b"; +} + +.fa-rotate::before { + content: "\f2f1"; +} + +.fa-sync-alt::before { + content: "\f2f1"; +} + +.fa-spinner::before { + content: "\f110"; +} + +.fa-robot::before { + content: "\f544"; +} + +.fa-peace::before { + content: "\f67c"; +} + +.fa-gears::before { + content: "\f085"; +} + +.fa-cogs::before { + content: "\f085"; +} + +.fa-warehouse::before { + content: "\f494"; +} + +.fa-arrow-up-right-dots::before { + content: "\e4b7"; +} + +.fa-splotch::before { + content: "\f5bc"; +} + +.fa-face-grin-hearts::before { + content: "\f584"; +} + +.fa-grin-hearts::before { + content: "\f584"; +} + +.fa-dice-four::before { + content: "\f524"; +} + +.fa-sim-card::before { + content: "\f7c4"; +} + +.fa-transgender::before { + content: "\f225"; +} + +.fa-transgender-alt::before { + content: "\f225"; +} + +.fa-mercury::before { + content: "\f223"; +} + +.fa-arrow-turn-down::before { + content: "\f149"; +} + +.fa-level-down::before { + content: "\f149"; +} + +.fa-person-falling-burst::before { + content: "\e547"; +} + +.fa-award::before { + content: "\f559"; +} + +.fa-ticket-simple::before { + content: "\f3ff"; +} + +.fa-ticket-alt::before { + content: "\f3ff"; +} + +.fa-building::before { + content: "\f1ad"; +} + +.fa-angles-left::before { + content: "\f100"; +} + +.fa-angle-double-left::before { + content: "\f100"; +} + +.fa-qrcode::before { + content: "\f029"; +} + +.fa-clock-rotate-left::before { + content: "\f1da"; +} + +.fa-history::before { + content: "\f1da"; +} + +.fa-face-grin-beam-sweat::before { + content: "\f583"; +} + +.fa-grin-beam-sweat::before { + content: "\f583"; +} + +.fa-file-export::before { + content: "\f56e"; +} + +.fa-arrow-right-from-file::before { + content: "\f56e"; +} + +.fa-shield::before { + content: "\f132"; +} + +.fa-shield-blank::before { + content: "\f132"; +} + +.fa-arrow-up-short-wide::before { + content: "\f885"; +} + +.fa-sort-amount-up-alt::before { + content: "\f885"; +} + +.fa-house-medical::before { + content: "\e3b2"; +} + +.fa-golf-ball-tee::before { + content: "\f450"; +} + +.fa-golf-ball::before { + content: "\f450"; +} + +.fa-circle-chevron-left::before { + content: "\f137"; +} + +.fa-chevron-circle-left::before { + content: "\f137"; +} + +.fa-house-chimney-window::before { + content: "\e00d"; +} + +.fa-pen-nib::before { + content: "\f5ad"; +} + +.fa-tent-arrow-turn-left::before { + content: "\e580"; +} + +.fa-tents::before { + content: "\e582"; +} + +.fa-wand-magic::before { + content: "\f0d0"; +} + +.fa-magic::before { + content: "\f0d0"; +} + +.fa-dog::before { + content: "\f6d3"; +} + +.fa-carrot::before { + content: "\f787"; +} + +.fa-moon::before { + content: "\f186"; +} + +.fa-wine-glass-empty::before { + content: "\f5ce"; +} + +.fa-wine-glass-alt::before { + content: "\f5ce"; +} + +.fa-cheese::before { + content: "\f7ef"; +} + +.fa-yin-yang::before { + content: "\f6ad"; +} + +.fa-music::before { + content: "\f001"; +} + +.fa-code-commit::before { + content: "\f386"; +} + +.fa-temperature-low::before { + content: "\f76b"; +} + +.fa-person-biking::before { + content: "\f84a"; +} + +.fa-biking::before { + content: "\f84a"; +} + +.fa-broom::before { + content: "\f51a"; +} + +.fa-shield-heart::before { + content: "\e574"; +} + +.fa-gopuram::before { + content: "\f664"; +} + +.fa-earth-oceania::before { + content: "\e47b"; +} + +.fa-globe-oceania::before { + content: "\e47b"; +} + +.fa-square-xmark::before { + content: "\f2d3"; +} + +.fa-times-square::before { + content: "\f2d3"; +} + +.fa-xmark-square::before { + content: "\f2d3"; +} + +.fa-hashtag::before { + content: "\23"; +} + +.fa-up-right-and-down-left-from-center::before { + content: "\f424"; +} + +.fa-expand-alt::before { + content: "\f424"; +} + +.fa-oil-can::before { + content: "\f613"; +} + +.fa-t::before { + content: "\54"; +} + +.fa-hippo::before { + content: "\f6ed"; +} + +.fa-chart-column::before { + content: "\e0e3"; +} + +.fa-infinity::before { + content: "\f534"; +} + +.fa-vial-circle-check::before { + content: "\e596"; +} + +.fa-person-arrow-down-to-line::before { + content: "\e538"; +} + +.fa-voicemail::before { + content: "\f897"; +} + +.fa-fan::before { + content: "\f863"; +} + +.fa-person-walking-luggage::before { + content: "\e554"; +} + +.fa-up-down::before { + content: "\f338"; +} + +.fa-arrows-alt-v::before { + content: "\f338"; +} + +.fa-cloud-moon-rain::before { + content: "\f73c"; +} + +.fa-calendar::before { + content: "\f133"; +} + +.fa-trailer::before { + content: "\e041"; +} + +.fa-bahai::before { + content: "\f666"; +} + +.fa-haykal::before { + content: "\f666"; +} + +.fa-sd-card::before { + content: "\f7c2"; +} + +.fa-dragon::before { + content: "\f6d5"; +} + +.fa-shoe-prints::before { + content: "\f54b"; +} + +.fa-circle-plus::before { + content: "\f055"; +} + +.fa-plus-circle::before { + content: "\f055"; +} + +.fa-face-grin-tongue-wink::before { + content: "\f58b"; +} + +.fa-grin-tongue-wink::before { + content: "\f58b"; +} + +.fa-hand-holding::before { + content: "\f4bd"; +} + +.fa-plug-circle-exclamation::before { + content: "\e55d"; +} + +.fa-link-slash::before { + content: "\f127"; +} + +.fa-chain-broken::before { + content: "\f127"; +} + +.fa-chain-slash::before { + content: "\f127"; +} + +.fa-unlink::before { + content: "\f127"; +} + +.fa-clone::before { + content: "\f24d"; +} + +.fa-person-walking-arrow-loop-left::before { + content: "\e551"; +} + +.fa-arrow-up-z-a::before { + content: "\f882"; +} + +.fa-sort-alpha-up-alt::before { + content: "\f882"; +} + +.fa-fire-flame-curved::before { + content: "\f7e4"; +} + +.fa-fire-alt::before { + content: "\f7e4"; +} + +.fa-tornado::before { + content: "\f76f"; +} + +.fa-file-circle-plus::before { + content: "\e494"; +} + +.fa-book-quran::before { + content: "\f687"; +} + +.fa-quran::before { + content: "\f687"; +} + +.fa-anchor::before { + content: "\f13d"; +} + +.fa-border-all::before { + content: "\f84c"; +} + +.fa-face-angry::before { + content: "\f556"; +} + +.fa-angry::before { + content: "\f556"; +} + +.fa-cookie-bite::before { + content: "\f564"; +} + +.fa-arrow-trend-down::before { + content: "\e097"; +} + +.fa-rss::before { + content: "\f09e"; +} + +.fa-feed::before { + content: "\f09e"; +} + +.fa-draw-polygon::before { + content: "\f5ee"; +} + +.fa-scale-balanced::before { + content: "\f24e"; +} + +.fa-balance-scale::before { + content: "\f24e"; +} + +.fa-gauge-simple-high::before { + content: "\f62a"; +} + +.fa-tachometer::before { + content: "\f62a"; +} + +.fa-tachometer-fast::before { + content: "\f62a"; +} + +.fa-shower::before { + content: "\f2cc"; +} + +.fa-desktop::before { + content: "\f390"; +} + +.fa-desktop-alt::before { + content: "\f390"; +} + +.fa-m::before { + content: "\4d"; +} + +.fa-table-list::before { + content: "\f00b"; +} + +.fa-th-list::before { + content: "\f00b"; +} + +.fa-comment-sms::before { + content: "\f7cd"; +} + +.fa-sms::before { + content: "\f7cd"; +} + +.fa-book::before { + content: "\f02d"; +} + +.fa-user-plus::before { + content: "\f234"; +} + +.fa-check::before { + content: "\f00c"; +} + +.fa-battery-three-quarters::before { + content: "\f241"; +} + +.fa-battery-4::before { + content: "\f241"; +} + +.fa-house-circle-check::before { + content: "\e509"; +} + +.fa-angle-left::before { + content: "\f104"; +} + +.fa-diagram-successor::before { + content: "\e47a"; +} + +.fa-truck-arrow-right::before { + content: "\e58b"; +} + +.fa-arrows-split-up-and-left::before { + content: "\e4bc"; +} + +.fa-hand-fist::before { + content: "\f6de"; +} + +.fa-fist-raised::before { + content: "\f6de"; +} + +.fa-cloud-moon::before { + content: "\f6c3"; +} + +.fa-briefcase::before { + content: "\f0b1"; +} + +.fa-person-falling::before { + content: "\e546"; +} + +.fa-image-portrait::before { + content: "\f3e0"; +} + +.fa-portrait::before { + content: "\f3e0"; +} + +.fa-user-tag::before { + content: "\f507"; +} + +.fa-rug::before { + content: "\e569"; +} + +.fa-earth-europe::before { + content: "\f7a2"; +} + +.fa-globe-europe::before { + content: "\f7a2"; +} + +.fa-cart-flatbed-suitcase::before { + content: "\f59d"; +} + +.fa-luggage-cart::before { + content: "\f59d"; +} + +.fa-rectangle-xmark::before { + content: "\f410"; +} + +.fa-rectangle-times::before { + content: "\f410"; +} + +.fa-times-rectangle::before { + content: "\f410"; +} + +.fa-window-close::before { + content: "\f410"; +} + +.fa-baht-sign::before { + content: "\e0ac"; +} + +.fa-book-open::before { + content: "\f518"; +} + +.fa-book-journal-whills::before { + content: "\f66a"; +} + +.fa-journal-whills::before { + content: "\f66a"; +} + +.fa-handcuffs::before { + content: "\e4f8"; +} + +.fa-triangle-exclamation::before { + content: "\f071"; +} + +.fa-exclamation-triangle::before { + content: "\f071"; +} + +.fa-warning::before { + content: "\f071"; +} + +.fa-database::before { + content: "\f1c0"; +} + +.fa-share::before { + content: "\f064"; +} + +.fa-arrow-turn-right::before { + content: "\f064"; +} + +.fa-mail-forward::before { + content: "\f064"; +} + +.fa-bottle-droplet::before { + content: "\e4c4"; +} + +.fa-mask-face::before { + content: "\e1d7"; +} + +.fa-hill-rockslide::before { + content: "\e508"; +} + +.fa-right-left::before { + content: "\f362"; +} + +.fa-exchange-alt::before { + content: "\f362"; +} + +.fa-paper-plane::before { + content: "\f1d8"; +} + +.fa-road-circle-exclamation::before { + content: "\e565"; +} + +.fa-dungeon::before { + content: "\f6d9"; +} + +.fa-align-right::before { + content: "\f038"; +} + +.fa-money-bill-1-wave::before { + content: "\f53b"; +} + +.fa-money-bill-wave-alt::before { + content: "\f53b"; +} + +.fa-life-ring::before { + content: "\f1cd"; +} + +.fa-hands::before { + content: "\f2a7"; +} + +.fa-sign-language::before { + content: "\f2a7"; +} + +.fa-signing::before { + content: "\f2a7"; +} + +.fa-calendar-day::before { + content: "\f783"; +} + +.fa-water-ladder::before { + content: "\f5c5"; +} + +.fa-ladder-water::before { + content: "\f5c5"; +} + +.fa-swimming-pool::before { + content: "\f5c5"; +} + +.fa-arrows-up-down::before { + content: "\f07d"; +} + +.fa-arrows-v::before { + content: "\f07d"; +} + +.fa-face-grimace::before { + content: "\f57f"; +} + +.fa-grimace::before { + content: "\f57f"; +} + +.fa-wheelchair-move::before { + content: "\e2ce"; +} + +.fa-wheelchair-alt::before { + content: "\e2ce"; +} + +.fa-turn-down::before { + content: "\f3be"; +} + +.fa-level-down-alt::before { + content: "\f3be"; +} + +.fa-person-walking-arrow-right::before { + content: "\e552"; +} + +.fa-square-envelope::before { + content: "\f199"; +} + +.fa-envelope-square::before { + content: "\f199"; +} + +.fa-dice::before { + content: "\f522"; +} + +.fa-bowling-ball::before { + content: "\f436"; +} + +.fa-brain::before { + content: "\f5dc"; +} + +.fa-bandage::before { + content: "\f462"; +} + +.fa-band-aid::before { + content: "\f462"; +} + +.fa-calendar-minus::before { + content: "\f272"; +} + +.fa-circle-xmark::before { + content: "\f057"; +} + +.fa-times-circle::before { + content: "\f057"; +} + +.fa-xmark-circle::before { + content: "\f057"; +} + +.fa-gifts::before { + content: "\f79c"; +} + +.fa-hotel::before { + content: "\f594"; +} + +.fa-earth-asia::before { + content: "\f57e"; +} + +.fa-globe-asia::before { + content: "\f57e"; +} + +.fa-id-card-clip::before { + content: "\f47f"; +} + +.fa-id-card-alt::before { + content: "\f47f"; +} + +.fa-magnifying-glass-plus::before { + content: "\f00e"; +} + +.fa-search-plus::before { + content: "\f00e"; +} + +.fa-thumbs-up::before { + content: "\f164"; +} + +.fa-user-clock::before { + content: "\f4fd"; +} + +.fa-hand-dots::before { + content: "\f461"; +} + +.fa-allergies::before { + content: "\f461"; +} + +.fa-file-invoice::before { + content: "\f570"; +} + +.fa-window-minimize::before { + content: "\f2d1"; +} + +.fa-mug-saucer::before { + content: "\f0f4"; +} + +.fa-coffee::before { + content: "\f0f4"; +} + +.fa-brush::before { + content: "\f55d"; +} + +.fa-mask::before { + content: "\f6fa"; +} + +.fa-magnifying-glass-minus::before { + content: "\f010"; +} + +.fa-search-minus::before { + content: "\f010"; +} + +.fa-ruler-vertical::before { + content: "\f548"; +} + +.fa-user-large::before { + content: "\f406"; +} + +.fa-user-alt::before { + content: "\f406"; +} + +.fa-train-tram::before { + content: "\e5b4"; +} + +.fa-user-nurse::before { + content: "\f82f"; +} + +.fa-syringe::before { + content: "\f48e"; +} + +.fa-cloud-sun::before { + content: "\f6c4"; +} + +.fa-stopwatch-20::before { + content: "\e06f"; +} + +.fa-square-full::before { + content: "\f45c"; +} + +.fa-magnet::before { + content: "\f076"; +} + +.fa-jar::before { + content: "\e516"; +} + +.fa-note-sticky::before { + content: "\f249"; +} + +.fa-sticky-note::before { + content: "\f249"; +} + +.fa-bug-slash::before { + content: "\e490"; +} + +.fa-arrow-up-from-water-pump::before { + content: "\e4b6"; +} + +.fa-bone::before { + content: "\f5d7"; +} + +.fa-user-injured::before { + content: "\f728"; +} + +.fa-face-sad-tear::before { + content: "\f5b4"; +} + +.fa-sad-tear::before { + content: "\f5b4"; +} + +.fa-plane::before { + content: "\f072"; +} + +.fa-tent-arrows-down::before { + content: "\e581"; +} + +.fa-exclamation::before { + content: "\21"; +} + +.fa-arrows-spin::before { + content: "\e4bb"; +} + +.fa-print::before { + content: "\f02f"; +} + +.fa-turkish-lira-sign::before { + content: "\e2bb"; +} + +.fa-try::before { + content: "\e2bb"; +} + +.fa-turkish-lira::before { + content: "\e2bb"; +} + +.fa-dollar-sign::before { + content: "\24"; +} + +.fa-dollar::before { + content: "\24"; +} + +.fa-usd::before { + content: "\24"; +} + +.fa-x::before { + content: "\58"; +} + +.fa-magnifying-glass-dollar::before { + content: "\f688"; +} + +.fa-search-dollar::before { + content: "\f688"; +} + +.fa-users-gear::before { + content: "\f509"; +} + +.fa-users-cog::before { + content: "\f509"; +} + +.fa-person-military-pointing::before { + content: "\e54a"; +} + +.fa-building-columns::before { + content: "\f19c"; +} + +.fa-bank::before { + content: "\f19c"; +} + +.fa-institution::before { + content: "\f19c"; +} + +.fa-museum::before { + content: "\f19c"; +} + +.fa-university::before { + content: "\f19c"; +} + +.fa-umbrella::before { + content: "\f0e9"; +} + +.fa-trowel::before { + content: "\e589"; +} + +.fa-d::before { + content: "\44"; +} + +.fa-stapler::before { + content: "\e5af"; +} + +.fa-masks-theater::before { + content: "\f630"; +} + +.fa-theater-masks::before { + content: "\f630"; +} + +.fa-kip-sign::before { + content: "\e1c4"; +} + +.fa-hand-point-left::before { + content: "\f0a5"; +} + +.fa-handshake-simple::before { + content: "\f4c6"; +} + +.fa-handshake-alt::before { + content: "\f4c6"; +} + +.fa-jet-fighter::before { + content: "\f0fb"; +} + +.fa-fighter-jet::before { + content: "\f0fb"; +} + +.fa-square-share-nodes::before { + content: "\f1e1"; +} + +.fa-share-alt-square::before { + content: "\f1e1"; +} + +.fa-barcode::before { + content: "\f02a"; +} + +.fa-plus-minus::before { + content: "\e43c"; +} + +.fa-video::before { + content: "\f03d"; +} + +.fa-video-camera::before { + content: "\f03d"; +} + +.fa-graduation-cap::before { + content: "\f19d"; +} + +.fa-mortar-board::before { + content: "\f19d"; +} + +.fa-hand-holding-medical::before { + content: "\e05c"; +} + +.fa-person-circle-check::before { + content: "\e53e"; +} + +.fa-turn-up::before { + content: "\f3bf"; +} + +.fa-level-up-alt::before { + content: "\f3bf"; +} + +.sr-only, +.fa-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.sr-only-focusable:not(:focus), +.fa-sr-only-focusable:not(:focus) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} diff --git a/src/main/resources/static/css/regular.css b/src/main/resources/static/css/regular.css new file mode 100644 index 0000000..c45f3d0 --- /dev/null +++ b/src/main/resources/static/css/regular.css @@ -0,0 +1,22 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; +} + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); +} + +.far, +.fa-regular { + font-weight: 400; +} diff --git a/src/main/resources/static/css/solid.css b/src/main/resources/static/css/solid.css new file mode 100644 index 0000000..d11a1e4 --- /dev/null +++ b/src/main/resources/static/css/solid.css @@ -0,0 +1,22 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; +} + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 900; + font-display: block; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); +} + +.fas, +.fa-solid { + font-weight: 900; +} diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css new file mode 100644 index 0000000..ff37803 --- /dev/null +++ b/src/main/resources/static/css/style.css @@ -0,0 +1,171 @@ +@CHARSET "UTF-8"; + +/* グローバル */ +* { + color: #505050; +} + +h1 { + border-left: 10px solid #696969; + border-bottom: 1px solid #696969; + padding: 10px; + width: 50%; + max-width: 960px; + min-width: 640px; + font-size: 15pt; + font-weight: bold; + display: flex; /* フレックスボックスを使う */ + justify-content: space-between; /* 左右の要素を端に寄せる */ + align-items: center; /* 上下中央に配置 */ +} + +.rightSection { + display: flex; /* フレックスボックスを使う */ + align-items: center; /* 上下中央に配置 */ +} + + +/* 入力フォーム */ + +input, button, select { + padding: 5px 15px 5px 15px; + margin: 3px; + /* border-radius: 5px; /* CSS3草案 */ + /* -webkit-border-radius: 5px; /* Safari,Google Chrome用 */ + /* -moz-border-radius: 5px; /* Firefox用 */ +} + +input.readOnly { + background-color: #696969; + color: #ffffff; +} + +/* メッセージボックスデザイン */ + +.msgBox { + font-weight: bold; + text-align: center; + border: 1px solid #696969; + width: 500px; +} + +.error { + background-color: #ffb6c1; + color: #ff0000; +} + +.warning { + background-color: #ff8c00; + color: #ff0000; +} + +.info { + background-color: #b0c4de; + color: #000000; +} + +/* 個別デザイン */ + +th.header { + width: 150px; + text-align: right; +} + +.loginInfo { + font-size: 9pt; + color: #008080; + margin-right: 10px; /* ログアウトボタンとの間隔 */ +} + +.logoutButton { + font-size: 9pt; + background-color: #008080; + color: #ffffff; + border: none; + padding: 5px 10px; + cursor: pointer; +} + +td.btnArea { + text-align: right; +} + +.header-spacing { + margin-top: 20px; /* 上部に20ピクセルのマージン */ +} + +/* グリッドラインの追加 */ +.table-grid { + width: 100%; + border-collapse: collapse; +} + +.table-grid th, .table-grid td { + border: 1px solid #ccc; + padding: 8px; + text-align: left; +} + +.table-grid th, .half-table-grid th { + background-color: #f2f2f2; +} + +/* ストライプ効果(奇数行と偶数行で色を交互に) */ +.table-striped tbody tr:nth-child(odd) { + background-color: #f2f2f2; +} + +/* ホバー効果(マウスオーバー時に行の色を変更) */ +.table-hover tbody tr:hover { + background-color: #ccffcc; /* パステルグリーンの背景色 */ +} + +/* レスポンシブデザイン(小さい画面でスクロール) */ +.table-responsive { + overflow-x: auto; + display: block; +} + +a.menuClass { + color: #008080; /* ターコイズ色 */ + text-decoration: none; /* 下線をなくす */ + padding: 10px 20px; /* パディングを追加 */ + border: 1px solid #008080; /* 枠線を追加 */ + border-radius: 5px; /* 角を丸くする */ + display: inline-block; /* ブロック要素として表示 */ + transition: 0.3s; /* アニメーション効果 */ +} + +a.menuClass:hover { + background-color: #008080; /* マウスオーバー時の背景色 */ + color: #ffffff; /* マウスオーバー時の文字色 */ +} + +table.menuClass td { + padding: 20px; /* パディングを増やす */ + text-align: center; /* 中央寄せ */ + vertical-align: middle; /* 上下中央寄せ */ +} + +table.menuClass td.description { + text-align: left; /* 左寄せ */ + font-size: 14px; /* フォントサイズを少し大きく */ + color: #707070; /* 色を少し薄く */ + line-height: 1.5; /* 行間を調整 */ +} + +input[type="submit"], input[type="reset"], button { + color: #008080; /* ターコイズ色 */ + text-decoration: none; /* 下線をなくす */ + padding: 10px 20px; /* パディングを追加 */ + border: 1px solid #008080; /* 枠線を追加 */ + border-radius: 5px; /* 角を丸くする */ + background-color: transparent; /* 背景色を透明に */ + cursor: pointer; /* カーソルをポインターに */ + transition: 0.3s; /* アニメーション効果 */ +} + +input[type="submit"]:hover, input[type="reset"]:hover, button:hover { + background-color: #008080; /* マウスオーバー時の背景色 */ + color: #ffffff; /* マウスオーバー時の文字色 */ +} diff --git a/src/main/resources/static/css/svg-with-js.css b/src/main/resources/static/css/svg-with-js.css new file mode 100644 index 0000000..b437920 --- /dev/null +++ b/src/main/resources/static/css/svg-with-js.css @@ -0,0 +1,790 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +:root, :host { + --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Solid'; + --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Regular'; + --fa-font-light: normal 300 1em/1 'Font Awesome 6 Light'; + --fa-font-thin: normal 100 1em/1 'Font Awesome 6 Thin'; + --fa-font-duotone: normal 900 1em/1 'Font Awesome 6 Duotone'; + --fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp'; + --fa-font-sharp-regular: normal 400 1em/1 'Font Awesome 6 Sharp'; + --fa-font-sharp-light: normal 300 1em/1 'Font Awesome 6 Sharp'; + --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; +} + +svg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa { + overflow: visible; + box-sizing: content-box; +} + +.svg-inline--fa { + display: var(--fa-display, inline-block); + height: 1em; + overflow: visible; + vertical-align: -.125em; +} + +.svg-inline--fa.fa-2xs { + vertical-align: 0.1em; +} + +.svg-inline--fa.fa-xs { + vertical-align: 0em; +} + +.svg-inline--fa.fa-sm { + vertical-align: -0.07143em; +} + +.svg-inline--fa.fa-lg { + vertical-align: -0.2em; +} + +.svg-inline--fa.fa-xl { + vertical-align: -0.25em; +} + +.svg-inline--fa.fa-2xl { + vertical-align: -0.3125em; +} + +.svg-inline--fa.fa-pull-left { + margin-right: var(--fa-pull-margin, 0.3em); + width: auto; +} + +.svg-inline--fa.fa-pull-right { + margin-left: var(--fa-pull-margin, 0.3em); + width: auto; +} + +.svg-inline--fa.fa-li { + width: var(--fa-li-width, 2em); + top: 0.25em; +} + +.svg-inline--fa.fa-fw { + width: var(--fa-fw-width, 1.25em); +} + +.fa-layers svg.svg-inline--fa { + bottom: 0; + left: 0; + margin: auto; + position: absolute; + right: 0; + top: 0; +} + +.fa-layers-text, .fa-layers-counter { + display: inline-block; + position: absolute; + text-align: center; +} + +.fa-layers { + display: inline-block; + height: 1em; + position: relative; + text-align: center; + vertical-align: -.125em; + width: 1em; +} + +.fa-layers svg.svg-inline--fa { + -webkit-transform-origin: center center; + transform-origin: center center; +} + +.fa-layers-text { + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + -webkit-transform-origin: center center; + transform-origin: center center; +} + +.fa-layers-counter { + background-color: var(--fa-counter-background-color, #ff253a); + border-radius: var(--fa-counter-border-radius, 1em); + box-sizing: border-box; + color: var(--fa-inverse, #fff); + line-height: var(--fa-counter-line-height, 1); + max-width: var(--fa-counter-max-width, 5em); + min-width: var(--fa-counter-min-width, 1.5em); + overflow: hidden; + padding: var(--fa-counter-padding, 0.25em 0.5em); + right: var(--fa-right, 0); + text-overflow: ellipsis; + top: var(--fa-top, 0); + -webkit-transform: scale(var(--fa-counter-scale, 0.25)); + transform: scale(var(--fa-counter-scale, 0.25)); + -webkit-transform-origin: top right; + transform-origin: top right; +} + +.fa-layers-bottom-right { + bottom: var(--fa-bottom, 0); + right: var(--fa-right, 0); + top: auto; + -webkit-transform: scale(var(--fa-layers-scale, 0.25)); + transform: scale(var(--fa-layers-scale, 0.25)); + -webkit-transform-origin: bottom right; + transform-origin: bottom right; +} + +.fa-layers-bottom-left { + bottom: var(--fa-bottom, 0); + left: var(--fa-left, 0); + right: auto; + top: auto; + -webkit-transform: scale(var(--fa-layers-scale, 0.25)); + transform: scale(var(--fa-layers-scale, 0.25)); + -webkit-transform-origin: bottom left; + transform-origin: bottom left; +} + +.fa-layers-top-right { + top: var(--fa-top, 0); + right: var(--fa-right, 0); + -webkit-transform: scale(var(--fa-layers-scale, 0.25)); + transform: scale(var(--fa-layers-scale, 0.25)); + -webkit-transform-origin: top right; + transform-origin: top right; +} + +.fa-layers-top-left { + left: var(--fa-left, 0); + right: auto; + top: var(--fa-top, 0); + -webkit-transform: scale(var(--fa-layers-scale, 0.25)); + transform: scale(var(--fa-layers-scale, 0.25)); + -webkit-transform-origin: top left; + transform-origin: top left; +} + +.fa-1x { + font-size: 1em; +} + +.fa-2x { + font-size: 2em; +} + +.fa-3x { + font-size: 3em; +} + +.fa-4x { + font-size: 4em; +} + +.fa-5x { + font-size: 5em; +} + +.fa-6x { + font-size: 6em; +} + +.fa-7x { + font-size: 7em; +} + +.fa-8x { + font-size: 8em; +} + +.fa-9x { + font-size: 9em; +} + +.fa-10x { + font-size: 10em; +} + +.fa-2xs { + font-size: 0.625em; + line-height: 0.1em; + vertical-align: 0.225em; +} + +.fa-xs { + font-size: 0.75em; + line-height: 0.08333em; + vertical-align: 0.125em; +} + +.fa-sm { + font-size: 0.875em; + line-height: 0.07143em; + vertical-align: 0.05357em; +} + +.fa-lg { + font-size: 1.25em; + line-height: 0.05em; + vertical-align: -0.075em; +} + +.fa-xl { + font-size: 1.5em; + line-height: 0.04167em; + vertical-align: -0.125em; +} + +.fa-2xl { + font-size: 2em; + line-height: 0.03125em; + vertical-align: -0.1875em; +} + +.fa-fw { + text-align: center; + width: 1.25em; +} + +.fa-ul { + list-style-type: none; + margin-left: var(--fa-li-margin, 2.5em); + padding-left: 0; +} + +.fa-ul > li { + position: relative; +} + +.fa-li { + left: calc(var(--fa-li-width, 2em) * -1); + position: absolute; + text-align: center; + width: var(--fa-li-width, 2em); + line-height: inherit; +} + +.fa-border { + border-color: var(--fa-border-color, #eee); + border-radius: var(--fa-border-radius, 0.1em); + border-style: var(--fa-border-style, solid); + border-width: var(--fa-border-width, 0.08em); + padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); +} + +.fa-pull-left { + float: left; + margin-right: var(--fa-pull-margin, 0.3em); +} + +.fa-pull-right { + float: right; + margin-left: var(--fa-pull-margin, 0.3em); +} + +.fa-beat { + -webkit-animation-name: fa-beat; + animation-name: fa-beat; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); +} + +.fa-bounce { + -webkit-animation-name: fa-bounce; + animation-name: fa-bounce; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); +} + +.fa-fade { + -webkit-animation-name: fa-fade; + animation-name: fa-fade; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); +} + +.fa-beat-fade { + -webkit-animation-name: fa-beat-fade; + animation-name: fa-beat-fade; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); +} + +.fa-flip { + -webkit-animation-name: fa-flip; + animation-name: fa-flip; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); +} + +.fa-shake { + -webkit-animation-name: fa-shake; + animation-name: fa-shake; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); +} + +.fa-spin { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 2s); + animation-duration: var(--fa-animation-duration, 2s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); +} + +.fa-spin-reverse { + --fa-animation-direction: reverse; +} + +.fa-pulse, +.fa-spin-pulse { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, steps(8)); + animation-timing-function: var(--fa-animation-timing, steps(8)); +} + +@media (prefers-reduced-motion: reduce) { + .fa-beat, + .fa-bounce, + .fa-fade, + .fa-beat-fade, + .fa-flip, + .fa-pulse, + .fa-shake, + .fa-spin, + .fa-spin-pulse { + -webkit-animation-delay: -1ms; + animation-delay: -1ms; + -webkit-animation-duration: 1ms; + animation-duration: 1ms; + -webkit-animation-iteration-count: 1; + animation-iteration-count: 1; + -webkit-transition-delay: 0s; + transition-delay: 0s; + -webkit-transition-duration: 0s; + transition-duration: 0s; + } +} + +@-webkit-keyframes fa-beat { + 0%, 90% { + -webkit-transform: scale(1); + transform: scale(1); + } + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); + } +} + +@keyframes fa-beat { + 0%, 90% { + -webkit-transform: scale(1); + transform: scale(1); + } + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); + } +} + +@-webkit-keyframes fa-bounce { + 0% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + } + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + } + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + } + 57% { + -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + } + 64% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 100% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } +} + +@keyframes fa-bounce { + 0% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + } + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + } + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + } + 57% { + -webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); + } + 64% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } + 100% { + -webkit-transform: scale(1, 1) translateY(0); + transform: scale(1, 1) translateY(0); + } +} + +@-webkit-keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); + } +} + +@keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); + } +} + +@-webkit-keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); + } +} + +@keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); + } +} + +@-webkit-keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + } +} + +@keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + } +} + +@-webkit-keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); + } + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + 8%, 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); + } + 12%, 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); + } + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); + } + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); + } + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); + } + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); + } + 40%, 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); + } + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + 8%, 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); + } + 12%, 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); + } + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); + } + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); + } + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); + } + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); + } + 40%, 100% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.fa-rotate-90 { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +.fa-rotate-180 { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} + +.fa-rotate-270 { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); +} + +.fa-flip-horizontal { + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); +} + +.fa-flip-vertical { + -webkit-transform: scale(1, -1); + transform: scale(1, -1); +} + +.fa-flip-both, +.fa-flip-horizontal.fa-flip-vertical { + -webkit-transform: scale(-1, -1); + transform: scale(-1, -1); +} + +.fa-rotate-by { + -webkit-transform: rotate(var(--fa-rotate-angle, none)); + transform: rotate(var(--fa-rotate-angle, none)); +} + +.fa-stack { + display: inline-block; + vertical-align: middle; + height: 2em; + position: relative; + width: 2.5em; +} + +.fa-stack-1x, +.fa-stack-2x { + bottom: 0; + left: 0; + margin: auto; + position: absolute; + right: 0; + top: 0; + z-index: var(--fa-stack-z-index, auto); +} + +.svg-inline--fa.fa-stack-1x { + height: 1em; + width: 1.25em; +} + +.svg-inline--fa.fa-stack-2x { + height: 2em; + width: 2.5em; +} + +.fa-inverse { + color: var(--fa-inverse, #fff); +} + +.sr-only, +.fa-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.sr-only-focusable:not(:focus), +.fa-sr-only-focusable:not(:focus) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.svg-inline--fa .fa-primary { + fill: var(--fa-primary-color, currentColor); + opacity: var(--fa-primary-opacity, 1); +} + +.svg-inline--fa .fa-secondary { + fill: var(--fa-secondary-color, currentColor); + opacity: var(--fa-secondary-opacity, 0.4); +} + +.svg-inline--fa.fa-swap-opacity .fa-primary { + opacity: var(--fa-secondary-opacity, 0.4); +} + +.svg-inline--fa.fa-swap-opacity .fa-secondary { + opacity: var(--fa-primary-opacity, 1); +} + +.svg-inline--fa mask .fa-primary, +.svg-inline--fa mask .fa-secondary { + fill: black; +} + +.fad.fa-inverse, +.fa-duotone.fa-inverse { + color: var(--fa-inverse, #fff); +} diff --git a/src/main/resources/static/css/v4-font-face.css b/src/main/resources/static/css/v4-font-face.css new file mode 100644 index 0000000..3f505c0 --- /dev/null +++ b/src/main/resources/static/css/v4-font-face.css @@ -0,0 +1,30 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); +} + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); +} + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); + unicode-range: U+F003, U+F006, U+F014, U+F016-F017, U+F01A-F01B, U+F01D, U+F022, U+F03E, U+F044, U+F046, U+F05C-F05D, U+F06E, U+F070, U+F087-F088, U+F08A, U+F094, U+F096-F097, U+F09D, U+F0A0, U+F0A2, U+F0A4-F0A7, U+F0C5, U+F0C7, U+F0E5-F0E6, U+F0EB, U+F0F6-F0F8, U+F10C, U+F114-F115, U+F118-F11A, U+F11C-F11D, U+F133, U+F147, U+F14E, U+F150-F152, U+F185-F186, U+F18E, U+F190-F192, U+F196, U+F1C1-F1C9, U+F1D9, U+F1DB, U+F1E3, U+F1EA, U+F1F7, U+F1F9, U+F20A, U+F247-F248, U+F24A, U+F24D, U+F255-F25B, U+F25D, U+F271-F274, U+F278, U+F27B, U+F28C, U+F28E, U+F29C, U+F2B5, U+F2B7, U+F2BA, U+F2BC, U+F2BE, U+F2C0-F2C1, U+F2C3, U+F2D0, U+F2D2, U+F2D4, U+F2DC; +} + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype"); + unicode-range: U+F041, U+F047, U+F065-F066, U+F07D-F07E, U+F080, U+F08B, U+F08E, U+F090, U+F09A, U+F0AC, U+F0AE, U+F0B2, U+F0D0, U+F0D6, U+F0E4, U+F0EC, U+F10A-F10B, U+F123, U+F13E, U+F148-F149, U+F14C, U+F156, U+F15E, U+F160-F161, U+F163, U+F175-F178, U+F195, U+F1F8, U+F219, U+F27A; +} diff --git a/src/main/resources/static/css/v4-shims.css b/src/main/resources/static/css/v4-shims.css new file mode 100644 index 0000000..92f6110 --- /dev/null +++ b/src/main/resources/static/css/v4-shims.css @@ -0,0 +1,2818 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +.fa.fa-glass:before { + content: "\f000"; +} + +.fa.fa-envelope-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-envelope-o:before { + content: "\f0e0"; +} + +.fa.fa-star-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-star-o:before { + content: "\f005"; +} + +.fa.fa-remove:before { + content: "\f00d"; +} + +.fa.fa-close:before { + content: "\f00d"; +} + +.fa.fa-gear:before { + content: "\f013"; +} + +.fa.fa-trash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-trash-o:before { + content: "\f2ed"; +} + +.fa.fa-home:before { + content: "\f015"; +} + +.fa.fa-file-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-o:before { + content: "\f15b"; +} + +.fa.fa-clock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-clock-o:before { + content: "\f017"; +} + +.fa.fa-arrow-circle-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-arrow-circle-o-down:before { + content: "\f358"; +} + +.fa.fa-arrow-circle-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-arrow-circle-o-up:before { + content: "\f35b"; +} + +.fa.fa-play-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-play-circle-o:before { + content: "\f144"; +} + +.fa.fa-repeat:before { + content: "\f01e"; +} + +.fa.fa-rotate-right:before { + content: "\f01e"; +} + +.fa.fa-refresh:before { + content: "\f021"; +} + +.fa.fa-list-alt { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-list-alt:before { + content: "\f022"; +} + +.fa.fa-dedent:before { + content: "\f03b"; +} + +.fa.fa-video-camera:before { + content: "\f03d"; +} + +.fa.fa-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-picture-o:before { + content: "\f03e"; +} + +.fa.fa-photo { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-photo:before { + content: "\f03e"; +} + +.fa.fa-image { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-image:before { + content: "\f03e"; +} + +.fa.fa-map-marker:before { + content: "\f3c5"; +} + +.fa.fa-pencil-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-pencil-square-o:before { + content: "\f044"; +} + +.fa.fa-edit { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-edit:before { + content: "\f044"; +} + +.fa.fa-share-square-o:before { + content: "\f14d"; +} + +.fa.fa-check-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-check-square-o:before { + content: "\f14a"; +} + +.fa.fa-arrows:before { + content: "\f0b2"; +} + +.fa.fa-times-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-times-circle-o:before { + content: "\f057"; +} + +.fa.fa-check-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-check-circle-o:before { + content: "\f058"; +} + +.fa.fa-mail-forward:before { + content: "\f064"; +} + +.fa.fa-expand:before { + content: "\f424"; +} + +.fa.fa-compress:before { + content: "\f422"; +} + +.fa.fa-eye { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-eye-slash { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-warning:before { + content: "\f071"; +} + +.fa.fa-calendar:before { + content: "\f073"; +} + +.fa.fa-arrows-v:before { + content: "\f338"; +} + +.fa.fa-arrows-h:before { + content: "\f337"; +} + +.fa.fa-bar-chart:before { + content: "\e0e3"; +} + +.fa.fa-bar-chart-o:before { + content: "\e0e3"; +} + +.fa.fa-twitter-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-twitter-square:before { + content: "\f081"; +} + +.fa.fa-facebook-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-facebook-square:before { + content: "\f082"; +} + +.fa.fa-gears:before { + content: "\f085"; +} + +.fa.fa-thumbs-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-thumbs-o-up:before { + content: "\f164"; +} + +.fa.fa-thumbs-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-thumbs-o-down:before { + content: "\f165"; +} + +.fa.fa-heart-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-heart-o:before { + content: "\f004"; +} + +.fa.fa-sign-out:before { + content: "\f2f5"; +} + +.fa.fa-linkedin-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-linkedin-square:before { + content: "\f08c"; +} + +.fa.fa-thumb-tack:before { + content: "\f08d"; +} + +.fa.fa-external-link:before { + content: "\f35d"; +} + +.fa.fa-sign-in:before { + content: "\f2f6"; +} + +.fa.fa-github-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-github-square:before { + content: "\f092"; +} + +.fa.fa-lemon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-lemon-o:before { + content: "\f094"; +} + +.fa.fa-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-square-o:before { + content: "\f0c8"; +} + +.fa.fa-bookmark-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-bookmark-o:before { + content: "\f02e"; +} + +.fa.fa-twitter { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-facebook { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-facebook:before { + content: "\f39e"; +} + +.fa.fa-facebook-f { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-facebook-f:before { + content: "\f39e"; +} + +.fa.fa-github { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-credit-card { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-feed:before { + content: "\f09e"; +} + +.fa.fa-hdd-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hdd-o:before { + content: "\f0a0"; +} + +.fa.fa-hand-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-o-right:before { + content: "\f0a4"; +} + +.fa.fa-hand-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-o-left:before { + content: "\f0a5"; +} + +.fa.fa-hand-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-o-up:before { + content: "\f0a6"; +} + +.fa.fa-hand-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-o-down:before { + content: "\f0a7"; +} + +.fa.fa-globe:before { + content: "\f57d"; +} + +.fa.fa-tasks:before { + content: "\f828"; +} + +.fa.fa-arrows-alt:before { + content: "\f31e"; +} + +.fa.fa-group:before { + content: "\f0c0"; +} + +.fa.fa-chain:before { + content: "\f0c1"; +} + +.fa.fa-cut:before { + content: "\f0c4"; +} + +.fa.fa-files-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-files-o:before { + content: "\f0c5"; +} + +.fa.fa-floppy-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-floppy-o:before { + content: "\f0c7"; +} + +.fa.fa-save { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-save:before { + content: "\f0c7"; +} + +.fa.fa-navicon:before { + content: "\f0c9"; +} + +.fa.fa-reorder:before { + content: "\f0c9"; +} + +.fa.fa-magic:before { + content: "\e2ca"; +} + +.fa.fa-pinterest { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-pinterest-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-pinterest-square:before { + content: "\f0d3"; +} + +.fa.fa-google-plus-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-google-plus-square:before { + content: "\f0d4"; +} + +.fa.fa-google-plus { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-google-plus:before { + content: "\f0d5"; +} + +.fa.fa-money:before { + content: "\f3d1"; +} + +.fa.fa-unsorted:before { + content: "\f0dc"; +} + +.fa.fa-sort-desc:before { + content: "\f0dd"; +} + +.fa.fa-sort-asc:before { + content: "\f0de"; +} + +.fa.fa-linkedin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-linkedin:before { + content: "\f0e1"; +} + +.fa.fa-rotate-left:before { + content: "\f0e2"; +} + +.fa.fa-legal:before { + content: "\f0e3"; +} + +.fa.fa-tachometer:before { + content: "\f625"; +} + +.fa.fa-dashboard:before { + content: "\f625"; +} + +.fa.fa-comment-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-comment-o:before { + content: "\f075"; +} + +.fa.fa-comments-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-comments-o:before { + content: "\f086"; +} + +.fa.fa-flash:before { + content: "\f0e7"; +} + +.fa.fa-clipboard:before { + content: "\f0ea"; +} + +.fa.fa-lightbulb-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-lightbulb-o:before { + content: "\f0eb"; +} + +.fa.fa-exchange:before { + content: "\f362"; +} + +.fa.fa-cloud-download:before { + content: "\f0ed"; +} + +.fa.fa-cloud-upload:before { + content: "\f0ee"; +} + +.fa.fa-bell-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-bell-o:before { + content: "\f0f3"; +} + +.fa.fa-cutlery:before { + content: "\f2e7"; +} + +.fa.fa-file-text-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-text-o:before { + content: "\f15c"; +} + +.fa.fa-building-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-building-o:before { + content: "\f1ad"; +} + +.fa.fa-hospital-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hospital-o:before { + content: "\f0f8"; +} + +.fa.fa-tablet:before { + content: "\f3fa"; +} + +.fa.fa-mobile:before { + content: "\f3cd"; +} + +.fa.fa-mobile-phone:before { + content: "\f3cd"; +} + +.fa.fa-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-circle-o:before { + content: "\f111"; +} + +.fa.fa-mail-reply:before { + content: "\f3e5"; +} + +.fa.fa-github-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-folder-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-folder-o:before { + content: "\f07b"; +} + +.fa.fa-folder-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-folder-open-o:before { + content: "\f07c"; +} + +.fa.fa-smile-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-smile-o:before { + content: "\f118"; +} + +.fa.fa-frown-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-frown-o:before { + content: "\f119"; +} + +.fa.fa-meh-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-meh-o:before { + content: "\f11a"; +} + +.fa.fa-keyboard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-keyboard-o:before { + content: "\f11c"; +} + +.fa.fa-flag-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-flag-o:before { + content: "\f024"; +} + +.fa.fa-mail-reply-all:before { + content: "\f122"; +} + +.fa.fa-star-half-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-star-half-o:before { + content: "\f5c0"; +} + +.fa.fa-star-half-empty { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-star-half-empty:before { + content: "\f5c0"; +} + +.fa.fa-star-half-full { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-star-half-full:before { + content: "\f5c0"; +} + +.fa.fa-code-fork:before { + content: "\f126"; +} + +.fa.fa-chain-broken:before { + content: "\f127"; +} + +.fa.fa-unlink:before { + content: "\f127"; +} + +.fa.fa-calendar-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-calendar-o:before { + content: "\f133"; +} + +.fa.fa-maxcdn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-html5 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-css3 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-unlock-alt:before { + content: "\f09c"; +} + +.fa.fa-minus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-minus-square-o:before { + content: "\f146"; +} + +.fa.fa-level-up:before { + content: "\f3bf"; +} + +.fa.fa-level-down:before { + content: "\f3be"; +} + +.fa.fa-pencil-square:before { + content: "\f14b"; +} + +.fa.fa-external-link-square:before { + content: "\f360"; +} + +.fa.fa-compass { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-caret-square-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-caret-square-o-down:before { + content: "\f150"; +} + +.fa.fa-toggle-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-toggle-down:before { + content: "\f150"; +} + +.fa.fa-caret-square-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-caret-square-o-up:before { + content: "\f151"; +} + +.fa.fa-toggle-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-toggle-up:before { + content: "\f151"; +} + +.fa.fa-caret-square-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-caret-square-o-right:before { + content: "\f152"; +} + +.fa.fa-toggle-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-toggle-right:before { + content: "\f152"; +} + +.fa.fa-eur:before { + content: "\f153"; +} + +.fa.fa-euro:before { + content: "\f153"; +} + +.fa.fa-gbp:before { + content: "\f154"; +} + +.fa.fa-usd:before { + content: "\24"; +} + +.fa.fa-dollar:before { + content: "\24"; +} + +.fa.fa-inr:before { + content: "\e1bc"; +} + +.fa.fa-rupee:before { + content: "\e1bc"; +} + +.fa.fa-jpy:before { + content: "\f157"; +} + +.fa.fa-cny:before { + content: "\f157"; +} + +.fa.fa-rmb:before { + content: "\f157"; +} + +.fa.fa-yen:before { + content: "\f157"; +} + +.fa.fa-rub:before { + content: "\f158"; +} + +.fa.fa-ruble:before { + content: "\f158"; +} + +.fa.fa-rouble:before { + content: "\f158"; +} + +.fa.fa-krw:before { + content: "\f159"; +} + +.fa.fa-won:before { + content: "\f159"; +} + +.fa.fa-btc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-bitcoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-bitcoin:before { + content: "\f15a"; +} + +.fa.fa-file-text:before { + content: "\f15c"; +} + +.fa.fa-sort-alpha-asc:before { + content: "\f15d"; +} + +.fa.fa-sort-alpha-desc:before { + content: "\f881"; +} + +.fa.fa-sort-amount-asc:before { + content: "\f884"; +} + +.fa.fa-sort-amount-desc:before { + content: "\f160"; +} + +.fa.fa-sort-numeric-asc:before { + content: "\f162"; +} + +.fa.fa-sort-numeric-desc:before { + content: "\f886"; +} + +.fa.fa-youtube-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-youtube-square:before { + content: "\f431"; +} + +.fa.fa-youtube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-xing { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-xing-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-xing-square:before { + content: "\f169"; +} + +.fa.fa-youtube-play { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-youtube-play:before { + content: "\f167"; +} + +.fa.fa-dropbox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-stack-overflow { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-instagram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-flickr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-adn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-bitbucket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-bitbucket-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-bitbucket-square:before { + content: "\f171"; +} + +.fa.fa-tumblr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-tumblr-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-tumblr-square:before { + content: "\f174"; +} + +.fa.fa-long-arrow-down:before { + content: "\f309"; +} + +.fa.fa-long-arrow-up:before { + content: "\f30c"; +} + +.fa.fa-long-arrow-left:before { + content: "\f30a"; +} + +.fa.fa-long-arrow-right:before { + content: "\f30b"; +} + +.fa.fa-apple { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-windows { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-android { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-linux { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-dribbble { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-skype { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-foursquare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-trello { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-gratipay { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-gittip { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-gittip:before { + content: "\f184"; +} + +.fa.fa-sun-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-sun-o:before { + content: "\f185"; +} + +.fa.fa-moon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-moon-o:before { + content: "\f186"; +} + +.fa.fa-vk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-renren { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-pagelines { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-stack-exchange { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-arrow-circle-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-arrow-circle-o-right:before { + content: "\f35a"; +} + +.fa.fa-arrow-circle-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-arrow-circle-o-left:before { + content: "\f359"; +} + +.fa.fa-caret-square-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-caret-square-o-left:before { + content: "\f191"; +} + +.fa.fa-toggle-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-toggle-left:before { + content: "\f191"; +} + +.fa.fa-dot-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-dot-circle-o:before { + content: "\f192"; +} + +.fa.fa-vimeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-vimeo-square:before { + content: "\f194"; +} + +.fa.fa-try:before { + content: "\e2bb"; +} + +.fa.fa-turkish-lira:before { + content: "\e2bb"; +} + +.fa.fa-plus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-plus-square-o:before { + content: "\f0fe"; +} + +.fa.fa-slack { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wordpress { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-openid { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-institution:before { + content: "\f19c"; +} + +.fa.fa-bank:before { + content: "\f19c"; +} + +.fa.fa-mortar-board:before { + content: "\f19d"; +} + +.fa.fa-yahoo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-google { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-reddit { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-reddit-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-reddit-square:before { + content: "\f1a2"; +} + +.fa.fa-stumbleupon-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-stumbleupon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-delicious { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-digg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-pied-piper-pp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-pied-piper-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-drupal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-joomla { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-behance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-behance-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-behance-square:before { + content: "\f1b5"; +} + +.fa.fa-steam { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-steam-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-steam-square:before { + content: "\f1b7"; +} + +.fa.fa-automobile:before { + content: "\f1b9"; +} + +.fa.fa-cab:before { + content: "\f1ba"; +} + +.fa.fa-spotify { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-deviantart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-soundcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-file-pdf-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-pdf-o:before { + content: "\f1c1"; +} + +.fa.fa-file-word-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-word-o:before { + content: "\f1c2"; +} + +.fa.fa-file-excel-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-excel-o:before { + content: "\f1c3"; +} + +.fa.fa-file-powerpoint-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-powerpoint-o:before { + content: "\f1c4"; +} + +.fa.fa-file-image-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-image-o:before { + content: "\f1c5"; +} + +.fa.fa-file-photo-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-photo-o:before { + content: "\f1c5"; +} + +.fa.fa-file-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-picture-o:before { + content: "\f1c5"; +} + +.fa.fa-file-archive-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-archive-o:before { + content: "\f1c6"; +} + +.fa.fa-file-zip-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-zip-o:before { + content: "\f1c6"; +} + +.fa.fa-file-audio-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-audio-o:before { + content: "\f1c7"; +} + +.fa.fa-file-sound-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-sound-o:before { + content: "\f1c7"; +} + +.fa.fa-file-video-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-video-o:before { + content: "\f1c8"; +} + +.fa.fa-file-movie-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-movie-o:before { + content: "\f1c8"; +} + +.fa.fa-file-code-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-file-code-o:before { + content: "\f1c9"; +} + +.fa.fa-vine { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-codepen { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-jsfiddle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-life-bouy:before { + content: "\f1cd"; +} + +.fa.fa-life-buoy:before { + content: "\f1cd"; +} + +.fa.fa-life-saver:before { + content: "\f1cd"; +} + +.fa.fa-support:before { + content: "\f1cd"; +} + +.fa.fa-circle-o-notch:before { + content: "\f1ce"; +} + +.fa.fa-rebel { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-ra { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-ra:before { + content: "\f1d0"; +} + +.fa.fa-resistance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-resistance:before { + content: "\f1d0"; +} + +.fa.fa-empire { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-ge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-ge:before { + content: "\f1d1"; +} + +.fa.fa-git-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-git-square:before { + content: "\f1d2"; +} + +.fa.fa-git { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-hacker-news { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-y-combinator-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-y-combinator-square:before { + content: "\f1d4"; +} + +.fa.fa-yc-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-yc-square:before { + content: "\f1d4"; +} + +.fa.fa-tencent-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-qq { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-weixin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wechat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wechat:before { + content: "\f1d7"; +} + +.fa.fa-send:before { + content: "\f1d8"; +} + +.fa.fa-paper-plane-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-paper-plane-o:before { + content: "\f1d8"; +} + +.fa.fa-send-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-send-o:before { + content: "\f1d8"; +} + +.fa.fa-circle-thin { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-circle-thin:before { + content: "\f111"; +} + +.fa.fa-header:before { + content: "\f1dc"; +} + +.fa.fa-futbol-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-futbol-o:before { + content: "\f1e3"; +} + +.fa.fa-soccer-ball-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-soccer-ball-o:before { + content: "\f1e3"; +} + +.fa.fa-slideshare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-twitch { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-yelp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-newspaper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-newspaper-o:before { + content: "\f1ea"; +} + +.fa.fa-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-google-wallet { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-cc-visa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-cc-mastercard { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-cc-discover { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-cc-amex { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-cc-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-cc-stripe { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-bell-slash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-bell-slash-o:before { + content: "\f1f6"; +} + +.fa.fa-trash:before { + content: "\f2ed"; +} + +.fa.fa-copyright { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-eyedropper:before { + content: "\f1fb"; +} + +.fa.fa-area-chart:before { + content: "\f1fe"; +} + +.fa.fa-pie-chart:before { + content: "\f200"; +} + +.fa.fa-line-chart:before { + content: "\f201"; +} + +.fa.fa-lastfm { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-lastfm-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-lastfm-square:before { + content: "\f203"; +} + +.fa.fa-ioxhost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-angellist { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-cc { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-cc:before { + content: "\f20a"; +} + +.fa.fa-ils:before { + content: "\f20b"; +} + +.fa.fa-shekel:before { + content: "\f20b"; +} + +.fa.fa-sheqel:before { + content: "\f20b"; +} + +.fa.fa-buysellads { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-connectdevelop { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-dashcube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-forumbee { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-leanpub { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-sellsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-shirtsinbulk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-simplybuilt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-skyatlas { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-diamond { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-diamond:before { + content: "\f3a5"; +} + +.fa.fa-transgender:before { + content: "\f224"; +} + +.fa.fa-intersex:before { + content: "\f224"; +} + +.fa.fa-transgender-alt:before { + content: "\f225"; +} + +.fa.fa-facebook-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-facebook-official:before { + content: "\f09a"; +} + +.fa.fa-pinterest-p { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-whatsapp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-hotel:before { + content: "\f236"; +} + +.fa.fa-viacoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-medium { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-y-combinator { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-yc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-yc:before { + content: "\f23b"; +} + +.fa.fa-optin-monster { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-opencart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-expeditedssl { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-battery-4:before { + content: "\f240"; +} + +.fa.fa-battery:before { + content: "\f240"; +} + +.fa.fa-battery-3:before { + content: "\f241"; +} + +.fa.fa-battery-2:before { + content: "\f242"; +} + +.fa.fa-battery-1:before { + content: "\f243"; +} + +.fa.fa-battery-0:before { + content: "\f244"; +} + +.fa.fa-object-group { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-object-ungroup { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-sticky-note-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-sticky-note-o:before { + content: "\f249"; +} + +.fa.fa-cc-jcb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-cc-diners-club { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-clone { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hourglass-o:before { + content: "\f254"; +} + +.fa.fa-hourglass-1:before { + content: "\f251"; +} + +.fa.fa-hourglass-2:before { + content: "\f252"; +} + +.fa.fa-hourglass-3:before { + content: "\f253"; +} + +.fa.fa-hand-rock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-rock-o:before { + content: "\f255"; +} + +.fa.fa-hand-grab-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-grab-o:before { + content: "\f255"; +} + +.fa.fa-hand-paper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-paper-o:before { + content: "\f256"; +} + +.fa.fa-hand-stop-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-stop-o:before { + content: "\f256"; +} + +.fa.fa-hand-scissors-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-scissors-o:before { + content: "\f257"; +} + +.fa.fa-hand-lizard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-lizard-o:before { + content: "\f258"; +} + +.fa.fa-hand-spock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-spock-o:before { + content: "\f259"; +} + +.fa.fa-hand-pointer-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-pointer-o:before { + content: "\f25a"; +} + +.fa.fa-hand-peace-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-hand-peace-o:before { + content: "\f25b"; +} + +.fa.fa-registered { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-creative-commons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-gg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-gg-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-odnoklassniki { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-odnoklassniki-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-odnoklassniki-square:before { + content: "\f264"; +} + +.fa.fa-get-pocket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wikipedia-w { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-safari { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-chrome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-firefox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-opera { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-internet-explorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-television:before { + content: "\f26c"; +} + +.fa.fa-contao { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-500px { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-amazon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-calendar-plus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-calendar-plus-o:before { + content: "\f271"; +} + +.fa.fa-calendar-minus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-calendar-minus-o:before { + content: "\f272"; +} + +.fa.fa-calendar-times-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-calendar-times-o:before { + content: "\f273"; +} + +.fa.fa-calendar-check-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-calendar-check-o:before { + content: "\f274"; +} + +.fa.fa-map-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-map-o:before { + content: "\f279"; +} + +.fa.fa-commenting:before { + content: "\f4ad"; +} + +.fa.fa-commenting-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-commenting-o:before { + content: "\f4ad"; +} + +.fa.fa-houzz { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-vimeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-vimeo:before { + content: "\f27d"; +} + +.fa.fa-black-tie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-fonticons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-reddit-alien { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-edge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-credit-card-alt:before { + content: "\f09d"; +} + +.fa.fa-codiepie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-modx { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-fort-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-usb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-product-hunt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-mixcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-scribd { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-pause-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-pause-circle-o:before { + content: "\f28b"; +} + +.fa.fa-stop-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-stop-circle-o:before { + content: "\f28d"; +} + +.fa.fa-bluetooth { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-bluetooth-b { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-gitlab { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wpbeginner { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wpforms { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-envira { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wheelchair-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wheelchair-alt:before { + content: "\f368"; +} + +.fa.fa-question-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-question-circle-o:before { + content: "\f059"; +} + +.fa.fa-volume-control-phone:before { + content: "\f2a0"; +} + +.fa.fa-asl-interpreting:before { + content: "\f2a3"; +} + +.fa.fa-deafness:before { + content: "\f2a4"; +} + +.fa.fa-hard-of-hearing:before { + content: "\f2a4"; +} + +.fa.fa-glide { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-glide-g { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-signing:before { + content: "\f2a7"; +} + +.fa.fa-viadeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-viadeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-viadeo-square:before { + content: "\f2aa"; +} + +.fa.fa-snapchat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-snapchat-ghost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-snapchat-ghost:before { + content: "\f2ab"; +} + +.fa.fa-snapchat-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-snapchat-square:before { + content: "\f2ad"; +} + +.fa.fa-pied-piper { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-first-order { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-yoast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-themeisle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-google-plus-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-google-plus-official:before { + content: "\f2b3"; +} + +.fa.fa-google-plus-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-google-plus-circle:before { + content: "\f2b3"; +} + +.fa.fa-font-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-fa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-fa:before { + content: "\f2b4"; +} + +.fa.fa-handshake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-handshake-o:before { + content: "\f2b5"; +} + +.fa.fa-envelope-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-envelope-open-o:before { + content: "\f2b6"; +} + +.fa.fa-linode { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-address-book-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-address-book-o:before { + content: "\f2b9"; +} + +.fa.fa-vcard:before { + content: "\f2bb"; +} + +.fa.fa-address-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-address-card-o:before { + content: "\f2bb"; +} + +.fa.fa-vcard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-vcard-o:before { + content: "\f2bb"; +} + +.fa.fa-user-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-user-circle-o:before { + content: "\f2bd"; +} + +.fa.fa-user-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-user-o:before { + content: "\f007"; +} + +.fa.fa-id-badge { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-drivers-license:before { + content: "\f2c2"; +} + +.fa.fa-id-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-id-card-o:before { + content: "\f2c2"; +} + +.fa.fa-drivers-license-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-drivers-license-o:before { + content: "\f2c2"; +} + +.fa.fa-quora { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-free-code-camp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-telegram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-thermometer-4:before { + content: "\f2c7"; +} + +.fa.fa-thermometer:before { + content: "\f2c7"; +} + +.fa.fa-thermometer-3:before { + content: "\f2c8"; +} + +.fa.fa-thermometer-2:before { + content: "\f2c9"; +} + +.fa.fa-thermometer-1:before { + content: "\f2ca"; +} + +.fa.fa-thermometer-0:before { + content: "\f2cb"; +} + +.fa.fa-bathtub:before { + content: "\f2cd"; +} + +.fa.fa-s15:before { + content: "\f2cd"; +} + +.fa.fa-window-maximize { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-window-restore { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-times-rectangle:before { + content: "\f410"; +} + +.fa.fa-window-close-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-window-close-o:before { + content: "\f410"; +} + +.fa.fa-times-rectangle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-times-rectangle-o:before { + content: "\f410"; +} + +.fa.fa-bandcamp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-grav { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-etsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-imdb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-ravelry { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-eercast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-eercast:before { + content: "\f2da"; +} + +.fa.fa-snowflake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; +} + +.fa.fa-snowflake-o:before { + content: "\f2dc"; +} + +.fa.fa-superpowers { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-wpexplorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} + +.fa.fa-meetup { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; +} diff --git a/src/main/resources/static/css/v5-font-face.css b/src/main/resources/static/css/v5-font-face.css new file mode 100644 index 0000000..6c35197 --- /dev/null +++ b/src/main/resources/static/css/v5-font-face.css @@ -0,0 +1,25 @@ +/*! + * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2023 Fonticons, Inc. + */ +@font-face { + font-family: 'Font Awesome 5 Brands'; + font-display: block; + font-weight: 400; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); +} + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-display: block; + font-weight: 900; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); +} + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-display: block; + font-weight: 400; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); +} diff --git a/src/main/resources/static/js/common.js b/src/main/resources/static/js/common.js new file mode 100644 index 0000000..640a96a --- /dev/null +++ b/src/main/resources/static/js/common.js @@ -0,0 +1,31 @@ +function convertToKatakana(input) { + // 漢字とローマ字を削除 + const valueWithoutKanjiAndRomaji = input.value.replace(/[\u4E00-\u9FFF\u0041-\u009F]/g, ''); + + // ひらがなをカタカナに変換 + const katakanaValue = valueWithoutKanjiAndRomaji.replace(/[\u3041-\u3096]/g, function (match) { + const chr = match.charCodeAt(0) + 0x60; + return String.fromCharCode(chr); + }); + + input.value = katakanaValue; +} + +function logoutSubmit() { + const form = document.createElement('form'); + form.setAttribute('method', 'post'); + form.setAttribute('action', 'logout'); + + // 動的送信用のHidden + // 動的にFormを作成する場合は何かしら送信しないと、正しく動作しない + const inputField = document.createElement("input"); + inputField.setAttribute("type", "hidden"); + inputField.setAttribute("value", "logout"); + + form.appendChild(inputField); + + // フォームをDOMに追加 + document.body.appendChild(form); + + form.submit(); +} diff --git a/src/main/resources/static/webfonts/fa-brands-400.ttf b/src/main/resources/static/webfonts/fa-brands-400.ttf new file mode 100644 index 0000000..30f55b7 Binary files /dev/null and b/src/main/resources/static/webfonts/fa-brands-400.ttf differ diff --git a/src/main/resources/static/webfonts/fa-brands-400.woff2 b/src/main/resources/static/webfonts/fa-brands-400.woff2 new file mode 100644 index 0000000..8a480d9 Binary files /dev/null and b/src/main/resources/static/webfonts/fa-brands-400.woff2 differ diff --git a/src/main/resources/static/webfonts/fa-regular-400.ttf b/src/main/resources/static/webfonts/fa-regular-400.ttf new file mode 100644 index 0000000..c79589d Binary files /dev/null and b/src/main/resources/static/webfonts/fa-regular-400.ttf differ diff --git a/src/main/resources/static/webfonts/fa-regular-400.woff2 b/src/main/resources/static/webfonts/fa-regular-400.woff2 new file mode 100644 index 0000000..059a94e Binary files /dev/null and b/src/main/resources/static/webfonts/fa-regular-400.woff2 differ diff --git a/src/main/resources/static/webfonts/fa-solid-900.ttf b/src/main/resources/static/webfonts/fa-solid-900.ttf new file mode 100644 index 0000000..e479fb2 Binary files /dev/null and b/src/main/resources/static/webfonts/fa-solid-900.ttf differ diff --git a/src/main/resources/static/webfonts/fa-solid-900.woff2 b/src/main/resources/static/webfonts/fa-solid-900.woff2 new file mode 100644 index 0000000..88b0367 Binary files /dev/null and b/src/main/resources/static/webfonts/fa-solid-900.woff2 differ diff --git a/src/main/resources/static/webfonts/fa-v4compatibility.ttf b/src/main/resources/static/webfonts/fa-v4compatibility.ttf new file mode 100644 index 0000000..ba6cb25 Binary files /dev/null and b/src/main/resources/static/webfonts/fa-v4compatibility.ttf differ diff --git a/src/main/resources/static/webfonts/fa-v4compatibility.woff2 b/src/main/resources/static/webfonts/fa-v4compatibility.woff2 new file mode 100644 index 0000000..23b1c47 Binary files /dev/null and b/src/main/resources/static/webfonts/fa-v4compatibility.woff2 differ diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html new file mode 100644 index 0000000..3fb4864 --- /dev/null +++ b/src/main/resources/templates/error.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + エラー + + +

エラーが発生しました。

+ +
ログインからやり直してください。
+ログイン + + diff --git a/src/main/resources/templates/insertEmployeeConfirm.html b/src/main/resources/templates/insertEmployeeConfirm.html new file mode 100644 index 0000000..55bd6cb --- /dev/null +++ b/src/main/resources/templates/insertEmployeeConfirm.html @@ -0,0 +1,157 @@ + + + + + + + + + + + + 登録内容確認 + + + +

登録内容確認    +
+ ログイン者名: + +
+

+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
社員ID + +
社員名 + +
社員名フリガナ + +
メールアドレス + +
パスワード + +
管理者権限 + + +
所属部署 + +
+ +
+ 登録内容の編集 | メニューに戻る +
+ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/insertEmployeeInput.html b/src/main/resources/templates/insertEmployeeInput.html new file mode 100644 index 0000000..ff0c02d --- /dev/null +++ b/src/main/resources/templates/insertEmployeeInput.html @@ -0,0 +1,158 @@ + + + + + + + + + + + + 社員登録 + + + +

+ 社員登録    +
+ ログイン者名: + +
+

+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
社員ID + +
社員名 + +
社員名フリガナ + +
メールアドレス + +
パスワード + +
※半角英数字をそれぞれ1種類以上含む3-10文字 +
パスワード確認用 + +
管理者権限 + + +
所属部署 + +
+ +
+
+メニューに戻る + + \ No newline at end of file diff --git a/src/main/resources/templates/insertEmployeeResult.html b/src/main/resources/templates/insertEmployeeResult.html new file mode 100644 index 0000000..f299b4c --- /dev/null +++ b/src/main/resources/templates/insertEmployeeResult.html @@ -0,0 +1,40 @@ + + + + + + + + + + + + 社員登録完了 + + + +

社員登録が完了しました

+
+続けて登録する | メニューに戻る + + + \ No newline at end of file diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..24c68c4 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + ログイン + + + +

ログイン

+
+ +
+ +
+ + + + + + + + + + + + + +
メールアドレス + +
パスワード + +
+ + +
+
+ + + diff --git a/src/main/resources/templates/menu.html b/src/main/resources/templates/menu.html new file mode 100644 index 0000000..6d0ee4a --- /dev/null +++ b/src/main/resources/templates/menu.html @@ -0,0 +1,117 @@ + + + + + + + + + + + + メニュー + + + + +

+ メインメニュー    +
+ ログイン者名: + +
+

+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/selectEmployee.html b/src/main/resources/templates/selectEmployee.html new file mode 100644 index 0000000..47cf487 --- /dev/null +++ b/src/main/resources/templates/selectEmployee.html @@ -0,0 +1,157 @@ + + + + + + + + + + + + 検索 + + + +

+ 検索条件入力    +
+ ログイン者名: + +
+

+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
社員ID + +
社員名 + +
社員名フリガナ + +
メールアドレス + +
所属部署 + +
+ + + +
+
+
+メニューに戻る +
+

検索結果

+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
社員ID社員名フリガナメールアドレスパスワード管理者フラグ所属部署操作
+ +
+ + +
+ +
+ + +
+
+
+ + + 検索結果はありません。 + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/updateEmployeeInput.html b/src/main/resources/templates/updateEmployeeInput.html new file mode 100644 index 0000000..83d43a5 --- /dev/null +++ b/src/main/resources/templates/updateEmployeeInput.html @@ -0,0 +1,181 @@ + + + + + + + + + + + + 社員情報更新 + + + +

+ 社員情報更新    +
+ ログイン者名: + +
+

+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
社員ID + +
社員名 + +
社員名フリガナ + +
メールアドレス + +
パスワード + +
+ + ※半角英数字をそれぞれ1種類以上含む3-10文字 + +
パスワード確認用 + +
管理者権限 + + +
所属部署 + +
+ +
+
+一覧に戻る + + + + \ No newline at end of file diff --git a/src/main/resources/templates/updatePersonalEmployeeInput.html b/src/main/resources/templates/updatePersonalEmployeeInput.html new file mode 100644 index 0000000..1635ced --- /dev/null +++ b/src/main/resources/templates/updatePersonalEmployeeInput.html @@ -0,0 +1,108 @@ + + + + + + + + + + + + 社員情報更新 + + + +

+ 社員情報更新    +
+ ログイン者名: + +
+

+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
社員名 + +
社員名フリガナ + +
メールアドレス + +
パスワード + +
+ 更新する場合は入力してください
+ ※半角英数字をそれぞれ1種類以上含む3-10文字
+
パスワード確認 + +
+ +
+ +
+ + \ No newline at end of file diff --git a/src/main/resources/templates/updatePersonalEmployeeResult.html b/src/main/resources/templates/updatePersonalEmployeeResult.html new file mode 100644 index 0000000..9bee911 --- /dev/null +++ b/src/main/resources/templates/updatePersonalEmployeeResult.html @@ -0,0 +1,42 @@ + + + + + + + + + + + + 更新完了 + + + +

更新が完了しました

+
+戻る + + + + + \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/model/DepartmentTest.java b/src/test/java/com/example/rhizome/app/domain/model/DepartmentTest.java new file mode 100644 index 0000000..6abf44f --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/model/DepartmentTest.java @@ -0,0 +1,69 @@ +package com.example.rhizome.app.domain.model; + +import com.example.rhizome.app.infra.record.DepartmentEnum; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DepartmentTest { + + // テストデータの用意 + final static Department departmentTest = new Department( + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(), + DepartmentEnum.TEST_DEPARTMENT.getNmDepartment() + ); + + // テストデータの用意 + final static Department departmentNull = new Department( + DepartmentEnum.NULL_DEPARTMENT.getIdDepartment(), + DepartmentEnum.NULL_DEPARTMENT.getNmDepartment() + ); + + @Nested + static class GetIdDepartmentTest { + + @Test + void getIdDepartment_正常系_IdDepartmentの取得() { + // 期待値 + Integer expected = DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(); + // 実測値 + Integer actual = departmentTest.getIdDepartment(); + + assertEquals(expected, actual); + } + + @Test + void getIdDepartment_正常系_IdDepartmentの取得結果がnull() { + + Integer expected = DepartmentEnum.NULL_DEPARTMENT.getIdDepartment(); + Integer actual = departmentNull.getIdDepartment(); + + assertEquals(expected, actual); + } + + } + + @Nested + static class GetNmDepartmentTest { + + @Test + void getNmDepartment_正常系_NmDepartmentの取得() { + + String expected = DepartmentEnum.TEST_DEPARTMENT.getNmDepartment(); + String actual = departmentTest.getNmDepartment(); + + assertEquals(expected, actual); + } + + @Test + void getNmDepartment_正常系_NmDepartmentの取得結果がnull() { + + String expected = DepartmentEnum.NULL_DEPARTMENT.getNmDepartment(); + String actual = departmentNull.getNmDepartment(); + + assertEquals(expected, actual); + } + + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/model/EmployeeInfoTest.java b/src/test/java/com/example/rhizome/app/domain/model/EmployeeInfoTest.java new file mode 100644 index 0000000..095215f --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/model/EmployeeInfoTest.java @@ -0,0 +1,183 @@ +package com.example.rhizome.app.domain.model; + +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class EmployeeInfoTest { + + static EmployeeInfo testEmployeeInfo = new EmployeeInfo( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance(), + DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance() + ); + + static EmployeeInfo nullEmployeeInfo = new EmployeeInfo( + EmployeeEnum.NULL_EMPLOYEE.getEmployeeInstance(), + DepartmentEnum.NULL_DEPARTMENT.getDepartmentInstance() + ); + + @Nested + static class getIdEmployeeTest { + @Test + void getIdEmployee_正常系_IdEmployeeの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(); + Integer actual = testEmployeeInfo.getEmployee().getIdEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getIdEmployee_正常系_IdEmployeeの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getIdEmployee(); + Integer actual = nullEmployeeInfo.getEmployee().getIdEmployee(); + + assertEquals(expected, actual); + + } + } + + @Nested + static class getNmEmployeeTest { + @Test + void getNmEmployee_正常系_NmEmployeeの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(); + String actual = testEmployeeInfo.getEmployee().getNmEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getNmEmployee_正常系_NmEmployeeの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getNmEmployee(); + String actual = nullEmployeeInfo.getEmployee().getNmEmployee(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetKnEmployeeTest { + @Test + void getKnEmployee_正常系_KnEmployeeの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(); + String actual = testEmployeeInfo.getEmployee().getKnEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getKnEmployee_正常系_KnEmployeeの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getKnEmployee(); + String actual = nullEmployeeInfo.getEmployee().getKnEmployee(); + + assertEquals(expected, actual); + } + } + + + @Nested + static class GetMailAddressTest { + @Test + void getMailAddress_正常系_MailAddressの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(); + String actual = testEmployeeInfo.getEmployee().getMailAddress(); + + assertEquals(expected, actual); + + } + + @Test + void getMailAddress_正常系_MailAddressの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getMailAddress(); + String actual = nullEmployeeInfo.getEmployee().getMailAddress(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetPasswordTest { + @Test + void getPassword_正常系_Passwordの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getPassword(); + String actual = testEmployeeInfo.getEmployee().getPassword(); + + assertEquals(expected, actual); + + } + + @Test + void getPassword_正常系_Passwordの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getPassword(); + String actual = nullEmployeeInfo.getEmployee().getPassword(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetAdminAuthTest { + @Test + void getAdminAuth_正常系_AdminAuthの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(); + Integer actual = testEmployeeInfo.getEmployee().getAdminAuth(); + + assertEquals(expected, actual); + + } + + @Test + void getAdminAuth_正常系_AdminAuthの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getAdminAuth(); + Integer actual = nullEmployeeInfo.getEmployee().getAdminAuth(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetIdDepartmentTest { + @Test + void getIdDepartment_正常系_IdDepartmentの取得() { + Integer expected = DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(); + Integer actual = testEmployeeInfo.getDepartment().getIdDepartment(); + + assertEquals(expected, actual); + + } + + @Test + void getIdDepartment_正常系_IdDepartmentの取得結果がnull() { + Integer expected = DepartmentEnum.NULL_DEPARTMENT.getIdDepartment(); + Integer actual = nullEmployeeInfo.getDepartment().getIdDepartment(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetNmDepartmentTest { + @Test + void getNmDepartment_正常系_NmDepartmentの取得() { + String expected = DepartmentEnum.TEST_DEPARTMENT.getNmDepartment(); + String actual = testEmployeeInfo.getDepartment().getNmDepartment(); + + assertEquals(expected, actual); + + } + + @Test + void getNmDepartment_正常系_NmDepartmentの取得結果がnull() { + String expected = DepartmentEnum.NULL_DEPARTMENT.getNmDepartment(); + String actual = nullEmployeeInfo.getDepartment().getNmDepartment(); + + assertEquals(expected, actual); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/model/EmployeeSearchTest.java b/src/test/java/com/example/rhizome/app/domain/model/EmployeeSearchTest.java new file mode 100644 index 0000000..90f89e6 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/model/EmployeeSearchTest.java @@ -0,0 +1,127 @@ +package com.example.rhizome.app.domain.model; + +import com.example.rhizome.app.infra.record.EmployeeEnum; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class EmployeeSearchTest { + + static SearchConditionEmployee testSearchConditionEmployee = new SearchConditionEmployee( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ); + + static SearchConditionEmployee nullSearchConditionEmployee = new SearchConditionEmployee( + EmployeeEnum.NULL_EMPLOYEE.getIdEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getNmEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getKnEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getMailAddress(), + EmployeeEnum.NULL_EMPLOYEE.getIdDepartment() + ); + + @Nested + static class getIdEmployeeTest { + @Test + void getIdEmployee_正常系_IdEmployeeの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(); + Integer actual = testSearchConditionEmployee.getIdEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getIdEmployee_正常系_IdEmployeeの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getIdEmployee(); + Integer actual = nullSearchConditionEmployee.getIdEmployee(); + + assertEquals(expected, actual); + + } + } + + @Nested + static class getNmEmployeeTest { + @Test + void getNmEmployee_正常系_NmEmployeeの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(); + String actual = testSearchConditionEmployee.getNmEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getNmEmployee_正常系_NmEmployeeの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getNmEmployee(); + String actual = nullSearchConditionEmployee.getNmEmployee(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetKnEmployeeTest { + @Test + void getKnEmployee_正常系_KnEmployeeの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(); + String actual = testSearchConditionEmployee.getKnEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getKnEmployee_正常系_KnEmployeeの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getKnEmployee(); + String actual = nullSearchConditionEmployee.getKnEmployee(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetMailAddressTest { + @Test + void getMailAddress_正常系_MailAddressの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(); + String actual = testSearchConditionEmployee.getMailAddress(); + + assertEquals(expected, actual); + + } + + @Test + void getMailAddress_正常系_MailAddressの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getMailAddress(); + String actual = nullSearchConditionEmployee.getMailAddress(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetIdDepartmentTest { + @Test + void getIdDepartment_正常系_IdDepartmentの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment(); + Integer actual = testSearchConditionEmployee.getIdDepartment(); + + assertEquals(expected, actual); + + } + + @Test + void getIdDepartment_正常系_IdDepartmentの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getIdDepartment(); + Integer actual = nullSearchConditionEmployee.getIdDepartment(); + + assertEquals(expected, actual); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/model/EmployeeTest.java b/src/test/java/com/example/rhizome/app/domain/model/EmployeeTest.java new file mode 100644 index 0000000..5ef9400 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/model/EmployeeTest.java @@ -0,0 +1,172 @@ +package com.example.rhizome.app.domain.model; + +import com.example.rhizome.app.infra.record.EmployeeEnum; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class EmployeeTest { + + final static Employee employeeTest = new Employee( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ); + + final static Employee employeeNull = new Employee( + EmployeeEnum.NULL_EMPLOYEE.getIdEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getNmEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getKnEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getMailAddress(), + EmployeeEnum.NULL_EMPLOYEE.getPassword(), + EmployeeEnum.NULL_EMPLOYEE.getAdminAuth(), + EmployeeEnum.NULL_EMPLOYEE.getIdDepartment() + ); + + @Nested + static class getIdEmployeeTest { + @Test + void getIdEmployee_正常系_IdEmployeeの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(); + Integer actual = employeeTest.getIdEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getIdEmployee_正常系_IdEmployeeの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getIdEmployee(); + Integer actual = employeeNull.getIdEmployee(); + + assertEquals(expected, actual); + + } + } + + @Nested + static class getNmEmployeeTest { + @Test + void getNmEmployee_正常系_NmEmployeeの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(); + String actual = employeeTest.getNmEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getNmEmployee_正常系_NmEmployeeの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getNmEmployee(); + String actual = employeeNull.getNmEmployee(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetKnEmployeeTest { + @Test + void getKnEmployee_正常系_KnEmployeeの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(); + String actual = employeeTest.getKnEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getKnEmployee_正常系_KnEmployeeの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getKnEmployee(); + String actual = employeeNull.getKnEmployee(); + + assertEquals(expected, actual); + } + } + + + @Nested + static class GetMailAddressTest { + @Test + void getMailAddress_正常系_MailAddressの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(); + String actual = employeeTest.getMailAddress(); + + assertEquals(expected, actual); + + } + + @Test + void getMailAddress_正常系_MailAddressの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getMailAddress(); + String actual = employeeNull.getMailAddress(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetPasswordTest { + @Test + void getPassword_正常系_Passwordの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getPassword(); + String actual = employeeTest.getPassword(); + + assertEquals(expected, actual); + + } + + @Test + void getPassword_正常系_Passwordの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getPassword(); + String actual = employeeNull.getPassword(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetAdminAuthTest { + @Test + void getAdminAuth_正常系_AdminAuthの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(); + Integer actual = employeeTest.getAdminAuth(); + + assertEquals(expected, actual); + + } + + @Test + void getAdminAuth_正常系_AdminAuthの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getAdminAuth(); + Integer actual = employeeNull.getAdminAuth(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetIdDepartmentTest { + @Test + void getIdDepartment_正常系_IdDepartmentの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment(); + Integer actual = employeeTest.getIdDepartment(); + + assertEquals(expected, actual); + + } + + @Test + void getIdDepartment_正常系_IdDepartmentの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getIdDepartment(); + Integer actual = employeeNull.getIdDepartment(); + + assertEquals(expected, actual); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/model/LoginInfoTest.java b/src/test/java/com/example/rhizome/app/domain/model/LoginInfoTest.java new file mode 100644 index 0000000..b63892f --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/model/LoginInfoTest.java @@ -0,0 +1,53 @@ +package com.example.rhizome.app.domain.model; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class LoginInfoTest { + + static LoginInfo testLoginInfo = new LoginInfo("aaa", "bbb"); + static LoginInfo nullLoginInfo = new LoginInfo(null, null); + + @Nested + static class GetMailAddressTest { + @Test + void getMailAddress_正常系_MailAddressの取得() { + String expected = "aaa"; + String actual = testLoginInfo.getMailAddress(); + + assertEquals(expected, actual); + + } + + @Test + void getMailAddress_正常系_MailAddressの取得結果がnull() { + String expected = null; + String actual = nullLoginInfo.getMailAddress(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetPasswordTest { + @Test + void getPassword_正常系_Passwordの取得() { + String expected = "bbb"; + String actual = testLoginInfo.getPassword(); + + assertEquals(expected, actual); + + } + + @Test + void getPassword_正常系_Passwordの取得結果がnull() { + String expected = null; + String actual = nullLoginInfo.getPassword(); + ; + + assertEquals(expected, actual); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/model/LoginUserTest.java b/src/test/java/com/example/rhizome/app/domain/model/LoginUserTest.java new file mode 100644 index 0000000..c53891b --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/model/LoginUserTest.java @@ -0,0 +1,196 @@ +package com.example.rhizome.app.domain.model; + +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class LoginUserTest { + + static LoginUser adminLoginUser = new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ); + + static LoginUser normalLoginUser = new LoginUser( + EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getNmEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getKnEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress(), + EmployeeEnum.NORMAL_EMPLOYEE.getPassword(), + EmployeeEnum.NORMAL_EMPLOYEE.getAdminAuth(), + EmployeeEnum.NORMAL_EMPLOYEE.getIdDepartment() + ); + + static LoginUser nullLoginUser = new LoginUser( + EmployeeEnum.NULL_EMPLOYEE.getIdEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getNmEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getKnEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getMailAddress(), + EmployeeEnum.NULL_EMPLOYEE.getPassword(), + EmployeeEnum.NULL_EMPLOYEE.getAdminAuth(), + EmployeeEnum.NULL_EMPLOYEE.getIdDepartment() + ); + + @Nested + static class getIdEmployeeTest { + @Test + void getIdEmployee_正常系_IdEmployeeの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(); + Integer actual = adminLoginUser.getIdEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getIdEmployee_正常系_IdEmployeeの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getIdEmployee(); + Integer actual = nullLoginUser.getIdEmployee(); + + assertEquals(expected, actual); + + } + } + + @Nested + static class getNmEmployeeTest { + @Test + void getNmEmployee_正常系_NmEmployeeの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(); + String actual = adminLoginUser.getNmEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getNmEmployee_正常系_NmEmployeeの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getNmEmployee(); + String actual = nullLoginUser.getNmEmployee(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetKnEmployeeTest { + @Test + void getKnEmployee_正常系_KnEmployeeの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(); + String actual = adminLoginUser.getKnEmployee(); + + assertEquals(expected, actual); + + } + + @Test + void getKnEmployee_正常系_KnEmployeeの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getKnEmployee(); + String actual = nullLoginUser.getKnEmployee(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetMailAddressTest { + @Test + void getMailAddress_正常系_MailAddressの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(); + String actual = adminLoginUser.getMailAddress(); + + assertEquals(expected, actual); + + } + + @Test + void getMailAddress_正常系_MailAddressの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getMailAddress(); + String actual = nullLoginUser.getMailAddress(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetPasswordTest { + @Test + void getPassword_正常系_Passwordの取得() { + String expected = EmployeeEnum.ADMIN_EMPLOYEE.getPassword(); + String actual = adminLoginUser.getPassword(); + + assertEquals(expected, actual); + + } + + @Test + void getPassword_正常系_Passwordの取得結果がnull() { + String expected = EmployeeEnum.NULL_EMPLOYEE.getPassword(); + String actual = nullLoginUser.getPassword(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetAdminAuthTest { + @Test + void getAdminAuth_正常系_AdminAuthの取得() { + Integer expected = EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(); + Integer actual = adminLoginUser.getAdminAuth(); + + assertEquals(expected, actual); + + } + + @Test + void getAdminAuth_正常系_AdminAuthの取得結果がnull() { + Integer expected = EmployeeEnum.NULL_EMPLOYEE.getAdminAuth(); + Integer actual = nullLoginUser.getAdminAuth(); + + assertEquals(expected, actual); + } + } + + @Nested + static class GetIdDepartmentTest { + @Test + void getIdDepartment_正常系_IdDepartmentの取得() { + Integer expected = DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(); + Integer actual = adminLoginUser.getIdDepartment(); + + assertEquals(expected, actual); + + } + + @Test + void getIdDepartment_正常系_IdDepartmentの取得結果がnull() { + Integer expected = DepartmentEnum.NULL_DEPARTMENT.getIdDepartment(); + Integer actual = nullLoginUser.getIdDepartment(); + + assertEquals(expected, actual); + } + } + + @Nested + static class IsAdminUserTest { + @Test + void isAdminUser_正常系_管理者である() { + assertTrue(adminLoginUser.isAdminUser()); + } + + @Test + void isAdminUser_正常系_一般である() { + assertFalse(normalLoginUser.isAdminUser()); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/service/impl/DeleteEmployeeTest.java b/src/test/java/com/example/rhizome/app/domain/service/impl/DeleteEmployeeTest.java new file mode 100644 index 0000000..5b8593d --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/service/impl/DeleteEmployeeTest.java @@ -0,0 +1,42 @@ +package com.example.rhizome.app.domain.service.impl; + + +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.infra.record.LoginUserEnum; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.ui.Model; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; + +@ExtendWith(MockitoExtension.class) +class DeleteEmployeeTest { + + @Mock + EmployeeRepository employeeRepository; + + @Mock + LoginUser loginUser; + + @Mock + Model model; + + @InjectMocks + DeleteEmployeeImpl deleteEmployeeImpl; + + @Nested + public class deleteExecTest { + @Test + public void deleteExec_正常系_アカウントの削除成功() { + doNothing().when(employeeRepository).deleteById(any()); + deleteEmployeeImpl.deleteEmployee(LoginUserEnum.NORMAL_LOGIN_USER.getIdEmployee()); + + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/service/impl/LoginImplTest.java b/src/test/java/com/example/rhizome/app/domain/service/impl/LoginImplTest.java new file mode 100644 index 0000000..8afcc76 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/service/impl/LoginImplTest.java @@ -0,0 +1,108 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.LoginInfo; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.infra.record.LoginUserEnum; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class LoginImplTest { + + @Mock + EmployeeRepository employeeRepository; + + @InjectMocks + LoginImpl login; + + @Nested + class doLoginTest { + @Test + void doLogin_正常系_ログイン者情報取得() { + when(employeeRepository.findByMailAddressAndPassword(anyString(), anyString())) + .thenReturn( + Optional.of( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ))); + + LoginUser actual = login.doLogin(new LoginInfo(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), EmployeeEnum.ADMIN_EMPLOYEE.getPassword())); + LoginUser expected = LoginUserEnum.ADMIN_LOGIN_USER.getLoginUserInstance(); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.getMailAddress()), + () -> assertEquals(expected.getPassword(), actual.getPassword()), + () -> assertEquals(expected.getAdminAuth(), actual.getAdminAuth()), + () -> assertEquals(expected.getIdDepartment(), actual.getIdDepartment()) + ); + + } + + @Test + void doLogin_正常系_ログイン者情報該当なし() { + when(employeeRepository.findByMailAddressAndPassword(anyString(), anyString())) + .thenReturn(Optional.empty()); + + + LoginUser actual = login.doLogin(new LoginInfo(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), EmployeeEnum.ADMIN_EMPLOYEE.getPassword())); + + assertAll( + () -> assertNull(actual.getIdEmployee()), + () -> assertNull(actual.getNmEmployee()), + () -> assertNull(actual.getKnEmployee()), + () -> assertNull(actual.getMailAddress()), + () -> assertNull(actual.getPassword()), + () -> assertNull(actual.getAdminAuth()), + () -> assertNull(actual.getIdDepartment()) + ); + + } + + + } + + @Nested + class canLoginTest { + @Test + void canLogin_正常系_ログイン可能() { + when(employeeRepository.findByMailAddressAndPassword(anyString(), anyString())) + .thenReturn( + Optional.of( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ))); + + boolean actual = login.canLogin(new LoginInfo(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), EmployeeEnum.ADMIN_EMPLOYEE.getPassword())); + + assertTrue(actual); + + } + + @Test + void canLogin_正常系_ログイン不可() { + when(employeeRepository.findByMailAddressAndPassword(anyString(), anyString())) + .thenReturn(Optional.empty()); + + boolean actual = login.canLogin(new LoginInfo(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), EmployeeEnum.ADMIN_EMPLOYEE.getPassword())); + + assertFalse(actual); + + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/service/impl/RegisterEmployeeImplTest.java b/src/test/java/com/example/rhizome/app/domain/service/impl/RegisterEmployeeImplTest.java new file mode 100644 index 0000000..5333489 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/service/impl/RegisterEmployeeImplTest.java @@ -0,0 +1,39 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class RegisterEmployeeImplTest { + + @InjectMocks + RegisterEmployeeImpl registerEmployee; + + @Mock + EmployeeRepository employeeRepository; + + @Nested + class registerEmployeeTest { + @Test + void registerEmployee() { + when(employeeRepository + .save(EmployeeEntity + .convertFrom(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()))) + .thenReturn((EmployeeEntity + .convertFrom(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()))); + + registerEmployee + .registerEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/service/impl/SearchConditionDepartmentImplTest.java b/src/test/java/com/example/rhizome/app/domain/service/impl/SearchConditionDepartmentImplTest.java new file mode 100644 index 0000000..67244db --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/service/impl/SearchConditionDepartmentImplTest.java @@ -0,0 +1,60 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.Department; +import com.example.rhizome.app.infra.entity.DepartmentEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.repository.DepartmentRepository; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class SearchConditionDepartmentImplTest { + + @InjectMocks + SearchDepartmentImpl searchDepartment; + + @Mock + DepartmentRepository departmentRepository; + + @Nested + class selectAllTest { + @Test + void selectAll_正常系_1件以上() { + Department department = DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance(); + DepartmentEntity departmentEntity = new DepartmentEntity(department.getIdDepartment(), department.getNmDepartment()); + + when(departmentRepository.findAll()) + .thenReturn(List.of(departmentEntity)); + + List actual = searchDepartment.selectAll(); + + assertAll( + () -> assertEquals(department.getIdDepartment(), actual.get(0).getIdDepartment()), + () -> assertEquals(department.getNmDepartment(), actual.get(0).getNmDepartment()) + ); + } + + @Test + void selectAll_正常系_0件() { + + when(departmentRepository.findAll()) + .thenReturn(List.of(new DepartmentEntity())); + + List actual = searchDepartment.selectAll(); + + assertAll( + () -> assertNull(actual.get(0).getIdDepartment()), + () -> assertNull(actual.get(0).getNmDepartment()) + ); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeImplTest.java b/src/test/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeImplTest.java new file mode 100644 index 0000000..7a10769 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeImplTest.java @@ -0,0 +1,163 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class SearchEmployeeImplTest { + + @InjectMocks + SearchEmployeeImpl searchEmployee; + + @Mock + EmployeeRepository employeeRepository; + + @Nested + class searchEmployeeTest { + @Test + void searchEmployee_正常系_1件以上() { + when(employeeRepository + .findByMailAddress(anyString())) + .thenReturn( + Optional.of( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ))); + + List actual = searchEmployee.searchEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()); + Employee expected = EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance(); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.get(0).getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.get(0).getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.get(0).getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.get(0).getMailAddress()), + () -> assertEquals(expected.getPassword(), actual.get(0).getPassword()), + () -> assertEquals(expected.getAdminAuth(), actual.get(0).getAdminAuth()), + () -> assertEquals(expected.getIdDepartment(), actual.get(0).getIdDepartment()) + ); + } + + @Test + void searchEmployee_正常系_0件() { + when(employeeRepository + .findByMailAddress(anyString())) + .thenReturn(Optional.empty()); + + List actual = searchEmployee.searchEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()); + + assertTrue(actual.isEmpty()); + } + } + + @Nested + class searchLoginUserTest { + @Test + void searchLoginUser_正常系_1件以上() { + + when(employeeRepository + .findByMailAddress(anyString())) + .thenReturn( + Optional.of( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ))); + + LoginUser actual = searchEmployee.searchLoginUser(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()); + Employee expected = EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance(); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.getMailAddress()), + () -> assertEquals(expected.getPassword(), actual.getPassword()), + () -> assertEquals(expected.getAdminAuth(), actual.getAdminAuth()), + () -> assertEquals(expected.getIdDepartment(), actual.getIdDepartment()) + ); + } + + @Test + void searchLoginUser_正常系_0件() { + when(employeeRepository + .findByMailAddress(anyString())) + .thenReturn(Optional.empty()); + + LoginUser actual = searchEmployee.searchLoginUser(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()); + + assertAll( + () -> assertNull(actual.getIdEmployee()), + () -> assertNull(actual.getNmEmployee()), + () -> assertNull(actual.getKnEmployee()), + () -> assertNull(actual.getMailAddress()), + () -> assertNull(actual.getPassword()), + () -> assertNull(actual.getAdminAuth()), + () -> assertNull(actual.getIdDepartment()) + ); + } + } + + + @Nested + class searchEmployeeByIdEmployeeTest { + @Test + void searchEmployeeByIdEmployee_正常系_該当あり() { + when(employeeRepository + .findByIdEmployee(any())) + .thenReturn( + Optional.of( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ))); + + Employee actual = searchEmployee.searchEmployeeByIdEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee()); + Employee expected = EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance(); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.getMailAddress()), + () -> assertEquals(expected.getPassword(), actual.getPassword()), + () -> assertEquals(expected.getAdminAuth(), actual.getAdminAuth()), + () -> assertEquals(expected.getIdDepartment(), actual.getIdDepartment()) + ); + } + + @Test + void searchEmployeeByIdEmployee_正常系_該当なし() { + when(employeeRepository + .findByIdEmployee(any())) + .thenReturn(Optional.empty()); + + Employee actual = searchEmployee.searchEmployeeByIdEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee()); + + assertAll( + () -> assertNull(actual.getIdEmployee()), + () -> assertNull(actual.getNmEmployee()), + () -> assertNull(actual.getKnEmployee()), + () -> assertNull(actual.getMailAddress()), + () -> assertNull(actual.getPassword()), + () -> assertNull(actual.getAdminAuth()), + () -> assertNull(actual.getIdDepartment()) + ); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeInfoImplTest.java b/src/test/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeInfoImplTest.java new file mode 100644 index 0000000..326c32f --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/service/impl/SearchEmployeeInfoImplTest.java @@ -0,0 +1,166 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.Department; +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.EmployeeInfo; +import com.example.rhizome.app.domain.model.SearchConditionEmployee; +import com.example.rhizome.app.infra.entity.DepartmentEntity; +import com.example.rhizome.app.infra.entity.EmployeeDepartmentEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.infra.repository.EmployeeInfoRepository; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.jpa.domain.Specification; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class SearchEmployeeInfoImplTest { + + @InjectMocks + SearchEmployeeInfoImpl searchEmployeeInfo; + + @Mock + EmployeeInfoRepository employeeInfoRepository; + + @Nested + class selectAllTest { + @Test + void selectAll_正常系_1件以上() { + Employee employee = EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance(); + Department department = DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance(); + + when(employeeInfoRepository.findAll()) + .thenReturn(List.of( + new EmployeeDepartmentEntity( + employee.getIdEmployee(), + employee.getNmEmployee(), + employee.getKnEmployee(), + employee.getMailAddress(), + employee.getPassword(), + employee.getAdminAuth(), + new DepartmentEntity(department.getIdDepartment(), department.getNmDepartment()) + ) + )); + + EmployeeInfo expected = new EmployeeInfo( + employee, + department + ); + + List actual = searchEmployeeInfo.selectAll(); + + assertAll( + () -> assertEquals(expected.getEmployee().getIdEmployee(), actual.get(0).getEmployee().getIdEmployee()), + () -> assertEquals(expected.getEmployee().getNmEmployee(), actual.get(0).getEmployee().getNmEmployee()), + () -> assertEquals(expected.getEmployee().getKnEmployee(), actual.get(0).getEmployee().getKnEmployee()), + () -> assertEquals(expected.getEmployee().getMailAddress(), actual.get(0).getEmployee().getMailAddress()), + () -> assertEquals(expected.getEmployee().getPassword(), actual.get(0).getEmployee().getPassword()), + () -> assertEquals(expected.getEmployee().getAdminAuth(), actual.get(0).getEmployee().getAdminAuth()), + () -> assertEquals(expected.getDepartment().getIdDepartment(), actual.get(0).getDepartment().getIdDepartment()), + () -> assertEquals(expected.getDepartment().getNmDepartment(), actual.get(0).getDepartment().getNmDepartment()) + ); + + } + + @Test + void selectAll_正常系_0件() { + Employee employee = EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance(); + Department department = DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance(); + + when(employeeInfoRepository.findAll()) + .thenReturn(List.of(new EmployeeDepartmentEntity())); + + EmployeeInfo expected = new EmployeeInfo( + employee, + department + ); + + List actual = searchEmployeeInfo.selectAll(); + + assertAll( + () -> assertNull(actual.get(0).getEmployee().getIdEmployee()), + () -> assertNull(actual.get(0).getEmployee().getNmEmployee()), + () -> assertNull(actual.get(0).getEmployee().getKnEmployee()), + () -> assertNull(actual.get(0).getEmployee().getMailAddress()), + () -> assertNull(actual.get(0).getEmployee().getPassword()), + () -> assertNull(actual.get(0).getEmployee().getAdminAuth()), + () -> assertNull(actual.get(0).getDepartment().getIdDepartment()), + () -> assertNull(actual.get(0).getDepartment().getNmDepartment()) + ); + + } + } + + @Nested + class searchByTest { + @Test + void searchBy_正常系_検索結果あり() { + when(employeeInfoRepository.findAll(any(Specification.class))) + .thenReturn(List.of(new EmployeeDepartmentEntity( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + new DepartmentEntity( + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(), + DepartmentEnum.TEST_DEPARTMENT.getNmDepartment() + ) + ))); + + EmployeeInfo expected = new EmployeeInfo( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance(), + DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance() + ); + + List actual = searchEmployeeInfo.searchBy( + new SearchConditionEmployee( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment() + ) + ); + + assertAll( + () -> assertEquals(expected.getEmployee().getIdEmployee(), actual.get(0).getEmployee().getIdEmployee()), + () -> assertEquals(expected.getEmployee().getNmEmployee(), actual.get(0).getEmployee().getNmEmployee()), + () -> assertEquals(expected.getEmployee().getKnEmployee(), actual.get(0).getEmployee().getKnEmployee()), + () -> assertEquals(expected.getEmployee().getMailAddress(), actual.get(0).getEmployee().getMailAddress()), + () -> assertEquals(expected.getEmployee().getPassword(), actual.get(0).getEmployee().getPassword()), + () -> assertEquals(expected.getEmployee().getAdminAuth(), actual.get(0).getEmployee().getAdminAuth()), + () -> assertEquals(expected.getDepartment().getIdDepartment(), actual.get(0).getDepartment().getIdDepartment()), + () -> assertEquals(expected.getDepartment().getNmDepartment(), actual.get(0).getDepartment().getNmDepartment()) + ); + } + + @Test + void searchBy_正常系_検索結果なし() { + when(employeeInfoRepository.findAll(any(Specification.class))) + .thenReturn(List.of()); + + assertTrue(searchEmployeeInfo.searchBy( + new SearchConditionEmployee( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment() + ) + ).isEmpty()); + + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/domain/service/impl/UpdateEmployeeImplTest.java b/src/test/java/com/example/rhizome/app/domain/service/impl/UpdateEmployeeImplTest.java new file mode 100644 index 0000000..fcba482 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/domain/service/impl/UpdateEmployeeImplTest.java @@ -0,0 +1,53 @@ +package com.example.rhizome.app.domain.service.impl; + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.infra.repository.EmployeeRepository; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class UpdateEmployeeImplTest { + @InjectMocks + UpdateEmployeeImpl updateEmployee; + + @Mock + EmployeeRepository employeeRepository; + + + @Nested + class updateEmployeeTest { + @Test + void updateEmployee_正常系_更新() { + when(employeeRepository.save(any())) + .thenReturn(null); + updateEmployee.updateEmployee(new Employee( + 1, + "test", + "test", + "test", + "test", + 1, + 1 + ), new Employee( + 1, + "test", + "test", + "test", + "test", + 1, + 1 + )); + assertTrue(true); + + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/infra/entity/DepartmentEntityTest.java b/src/test/java/com/example/rhizome/app/infra/entity/DepartmentEntityTest.java new file mode 100644 index 0000000..f3a4f66 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/infra/entity/DepartmentEntityTest.java @@ -0,0 +1,38 @@ +package com.example.rhizome.app.infra.entity; + +import com.example.rhizome.app.domain.model.Department; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ExtendWith(MockitoExtension.class) +class DepartmentEntityTest { + + DepartmentEntity expected; + + + @Nested + class createDepartmentListTest { + @Test + void createDepartmentList_正常系_変換() { + expected = new DepartmentEntity( + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(), + DepartmentEnum.TEST_DEPARTMENT.getNmDepartment() + ); + List actual = DepartmentEntity.createDepartmentList(List.of(expected)); + + assertAll( + () -> assertEquals(expected.getIdDepartment(), actual.get(0).getIdDepartment()), + () -> assertEquals(expected.getNmDepartment(), actual.get(0).getNmDepartment()) + ); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/infra/entity/EmployeeDepartmentEntityTest.java b/src/test/java/com/example/rhizome/app/infra/entity/EmployeeDepartmentEntityTest.java new file mode 100644 index 0000000..7819ea7 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/infra/entity/EmployeeDepartmentEntityTest.java @@ -0,0 +1,83 @@ +package com.example.rhizome.app.infra.entity; + +import com.example.rhizome.app.domain.model.EmployeeInfo; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ExtendWith(MockitoExtension.class) +class EmployeeDepartmentEntityTest { + + @Nested + class createEmployeeInfoTest { + @Test + void createEmployeeInfo_正常系() { + EmployeeInfo employeeInfo = EmployeeDepartmentEntity.createEmployeeInfo( + new EmployeeDepartmentEntity( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + new DepartmentEntity( + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(), + DepartmentEnum.TEST_DEPARTMENT.getNmDepartment() + ) + ) + ); + + assertAll( + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), employeeInfo.getEmployee().getIdEmployee()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), employeeInfo.getEmployee().getNmEmployee()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), employeeInfo.getEmployee().getKnEmployee()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), employeeInfo.getEmployee().getMailAddress()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), employeeInfo.getEmployee().getPassword()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), employeeInfo.getEmployee().getAdminAuth()), + () -> assertEquals(DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(), employeeInfo.getDepartment().getIdDepartment()), + () -> assertEquals(DepartmentEnum.TEST_DEPARTMENT.getNmDepartment(), employeeInfo.getDepartment().getNmDepartment()) + ); + + } + } + + @Nested + class createEmployeeInfoListTest { + @Test + void createEmployeeInfoList_正常系() { + EmployeeInfo employeeInfo = EmployeeDepartmentEntity.createEmployeeInfoList( + List.of(new EmployeeDepartmentEntity( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + new DepartmentEntity( + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(), + DepartmentEnum.TEST_DEPARTMENT.getNmDepartment() + ) + ))).get(0); + + assertAll( + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), employeeInfo.getEmployee().getIdEmployee()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), employeeInfo.getEmployee().getNmEmployee()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), employeeInfo.getEmployee().getKnEmployee()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), employeeInfo.getEmployee().getMailAddress()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), employeeInfo.getEmployee().getPassword()), + () -> assertEquals(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), employeeInfo.getEmployee().getAdminAuth()), + () -> assertEquals(DepartmentEnum.TEST_DEPARTMENT.getIdDepartment(), employeeInfo.getDepartment().getIdDepartment()), + () -> assertEquals(DepartmentEnum.TEST_DEPARTMENT.getNmDepartment(), employeeInfo.getDepartment().getNmDepartment()) + ); + + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/infra/entity/EmployeeEntityTest.java b/src/test/java/com/example/rhizome/app/infra/entity/EmployeeEntityTest.java new file mode 100644 index 0000000..d50a193 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/infra/entity/EmployeeEntityTest.java @@ -0,0 +1,149 @@ +package com.example.rhizome.app.infra.entity; + +import com.example.rhizome.app.domain.model.Employee; +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.model.SearchConditionEmployee; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@ExtendWith(MockitoExtension.class) +class EmployeeEntityTest { + + @Nested + class createEmployeeTest { + @Test + void createEmployee_正常系_変換() { + EmployeeEntity expected = new EmployeeEntity( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ); + Employee actual = EmployeeEntity.createEmployee( + expected + ); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.getMailAddress()), + () -> assertEquals(expected.getPassword(), actual.getPassword()), + () -> assertEquals(expected.getAdminAuth(), actual.getAdminAuth()), + () -> assertEquals(expected.getIdDepartment(), actual.getIdDepartment()) + ); + } + } + + @Nested + class createEmployeeListTest { + @Test + void createEmployeeList_正常系_変換() { + EmployeeEntity expected = new EmployeeEntity( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ); + List actual = EmployeeEntity.createEmployeeList(List.of(expected)); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.get(0).getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.get(0).getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.get(0).getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.get(0).getMailAddress()), + () -> assertEquals(expected.getPassword(), actual.get(0).getPassword()), + () -> assertEquals(expected.getAdminAuth(), actual.get(0).getAdminAuth()), + () -> assertEquals(expected.getIdDepartment(), actual.get(0).getIdDepartment()) + ); + } + } + + @Nested + class createLoginUserTest { + @Test + void createLoginUser_正常系_変換() { + EmployeeEntity expected = new EmployeeEntity( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ); + LoginUser actual = expected.createLoginUser(); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.getMailAddress()), + () -> assertEquals(expected.getPassword(), actual.getPassword()), + () -> assertEquals(expected.getAdminAuth(), actual.getAdminAuth()), + () -> assertEquals(expected.getIdDepartment(), actual.getIdDepartment()) + ); + } + } + + @Nested + class convertFromTest { + @Test + void convertFrom_正常系_変換_社員() { + Employee expected = new Employee( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ); + EmployeeEntity actual = EmployeeEntity.convertFrom(expected); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.getMailAddress()), + () -> assertEquals(expected.getPassword(), actual.getPassword()), + () -> assertEquals(expected.getAdminAuth(), actual.getAdminAuth()), + () -> assertEquals(expected.getIdDepartment(), actual.getIdDepartment()) + ); + } + + @Test + void convertFrom_正常系_変換_検索() { + SearchConditionEmployee expected = new SearchConditionEmployee( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ); + EmployeeEntity actual = EmployeeEntity.convertFrom(expected); + + assertAll( + () -> assertEquals(expected.getIdEmployee(), actual.getIdEmployee()), + () -> assertEquals(expected.getNmEmployee(), actual.getNmEmployee()), + () -> assertEquals(expected.getKnEmployee(), actual.getKnEmployee()), + () -> assertEquals(expected.getMailAddress(), actual.getMailAddress()), + () -> assertEquals(expected.getIdDepartment(), actual.getIdDepartment()) + ); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/infra/record/DepartmentEnum.java b/src/test/java/com/example/rhizome/app/infra/record/DepartmentEnum.java new file mode 100644 index 0000000..947b416 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/infra/record/DepartmentEnum.java @@ -0,0 +1,36 @@ +package com.example.rhizome.app.infra.record; + +import com.example.rhizome.app.domain.model.Department; + +public enum DepartmentEnum { + + TEST_DEPARTMENT(10000, "テスト部署"), + NULL_DEPARTMENT(null, null); + + /** + * 部署ID + */ + private final Integer idDepartment; + /** + * 部署名 + */ + private final String nmDepartment; + + DepartmentEnum(Integer idDepartment, String nmDepartment) { + this.idDepartment = idDepartment; + this.nmDepartment = nmDepartment; + } + + + public Integer getIdDepartment() { + return idDepartment; + } + + public String getNmDepartment() { + return nmDepartment; + } + + public Department getDepartmentInstance() { + return new Department(getIdDepartment(), getNmDepartment()); + } +} diff --git a/src/test/java/com/example/rhizome/app/infra/record/EmployeeEnum.java b/src/test/java/com/example/rhizome/app/infra/record/EmployeeEnum.java new file mode 100644 index 0000000..5139c21 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/infra/record/EmployeeEnum.java @@ -0,0 +1,111 @@ +package com.example.rhizome.app.infra.record; + + +import com.example.rhizome.app.domain.model.Employee; + +public enum EmployeeEnum { + + ADMIN_EMPLOYEE( + 90000, + "テスト太郎", + "テストタロウカナ", + "test@mail.com", + "password", + 1, + 10000), + NORMAL_EMPLOYEE( + 90001, + "テスト一般太郎", + "テストイッパンタロウカナ", + "test-normal@mail.com", + "password-normal", + 0, + 10000), + NULL_EMPLOYEE( + null, + null, + null, + null, + null, + null, + null); + + /** + * 社員ID + */ + private final Integer idEmployee; + /** + * 社員名 + */ + private final String nmEmployee; + /** + * 社員名カナ + */ + private final String knEmployee; + /** + * メールアドレス + */ + private final String mailAddress; + /** + * パスワード + */ + private final String password; + /** + * 管理者権限 + */ + private final Integer adminAuth; + /** + * 部署ID + */ + private final Integer idDepartment; + + EmployeeEnum(Integer idEmployee, String nmEmployee, String knEmployee, String mailAddress, String password, Integer adminAuth, Integer idDepartment) { + this.idEmployee = idEmployee; + this.nmEmployee = nmEmployee; + this.knEmployee = knEmployee; + this.mailAddress = mailAddress; + this.password = password; + this.adminAuth = adminAuth; + this.idDepartment = idDepartment; + } + + public Integer getIdEmployee() { + return idEmployee; + } + + public String getNmEmployee() { + return nmEmployee; + } + + public String getKnEmployee() { + return knEmployee; + } + + public String getMailAddress() { + return mailAddress; + } + + public String getPassword() { + return password; + } + + public Integer getAdminAuth() { + return adminAuth; + } + + public Integer getIdDepartment() { + return idDepartment; + } + + public Employee getEmployeeInstance() { + return new Employee( + getIdEmployee(), + getNmEmployee(), + getKnEmployee(), + getMailAddress(), + getPassword(), + getAdminAuth(), + getIdDepartment() + ); + } +} diff --git a/src/test/java/com/example/rhizome/app/infra/record/EmployeeSearchEnum.java b/src/test/java/com/example/rhizome/app/infra/record/EmployeeSearchEnum.java new file mode 100644 index 0000000..6ff68e1 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/infra/record/EmployeeSearchEnum.java @@ -0,0 +1,87 @@ +package com.example.rhizome.app.infra.record; + + +import com.example.rhizome.app.domain.model.SearchConditionEmployee; + +public enum EmployeeSearchEnum { + ADMIN_EMPLOYEE_SEARCH( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ), + NORMAL_EMPLOYEE_SEARCH( + EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getNmEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getKnEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress(), + EmployeeEnum.NORMAL_EMPLOYEE.getIdDepartment() + ), + NULL_EMPLOYEE_SEARCH( + EmployeeEnum.NULL_EMPLOYEE.getIdEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getNmEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getKnEmployee(), + EmployeeEnum.NULL_EMPLOYEE.getMailAddress(), + EmployeeEnum.NULL_EMPLOYEE.getIdDepartment() + ); + + /** + * 社員ID + */ + private final Integer idEmployee; + /** + * 社員名 + */ + private final String nmEmployee; + /** + * 社員名カナ + */ + private final String knEmployee; + /** + * メールアドレス + */ + private final String mailAddress; + /** + * 部署ID + */ + private final Integer idDepartment; + + EmployeeSearchEnum(Integer idEmployee, String nmEmployee, String knEmployee, String mailAddress, Integer idDepartment) { + this.idEmployee = idEmployee; + this.nmEmployee = nmEmployee; + this.knEmployee = knEmployee; + this.mailAddress = mailAddress; + this.idDepartment = idDepartment; + } + + public Integer getIdEmployee() { + return idEmployee; + } + + public String getNmEmployee() { + return nmEmployee; + } + + public String getKnEmployee() { + return knEmployee; + } + + public String getMailAddress() { + return mailAddress; + } + + public Integer getIdDepartment() { + return idDepartment; + } + + public SearchConditionEmployee getEmployeeSearchInstance() { + return new SearchConditionEmployee( + getIdEmployee(), + getNmEmployee(), + getKnEmployee(), + getMailAddress(), + getIdDepartment() + ); + } +} diff --git a/src/test/java/com/example/rhizome/app/infra/record/LoginUserEnum.java b/src/test/java/com/example/rhizome/app/infra/record/LoginUserEnum.java new file mode 100644 index 0000000..8d2c1f4 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/infra/record/LoginUserEnum.java @@ -0,0 +1,116 @@ +package com.example.rhizome.app.infra.record; + +import com.example.rhizome.app.domain.model.LoginUser; + +public enum LoginUserEnum { + + ADMIN_LOGIN_USER( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + ), + + NORMAL_LOGIN_USER( + EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getNmEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getKnEmployee(), + EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress(), + EmployeeEnum.NORMAL_EMPLOYEE.getPassword(), + EmployeeEnum.NORMAL_EMPLOYEE.getAdminAuth(), + EmployeeEnum.NORMAL_EMPLOYEE.getIdDepartment() + ); + + /** + * 社員ID + */ + private final Integer idEmployee; + /** + * 社員名 + */ + private final String nmEmployee; + /** + * 社員名カナ + */ + private final String knEmployee; + /** + * メールアドレス + */ + private final String mailAddress; + /** + * パスワード + */ + private final String password; + + /** + * 管理者権限 + */ + private final Integer adminAuth; + + /** + * 部署ID + */ + private final Integer idDepartment; + + LoginUserEnum( + Integer idEmployee, + String nmEmployee, + String knEmployee, + String mailAddress, + String password, + Integer adminAuth, + Integer idDepartment + ) { + this.idEmployee = idEmployee; + this.nmEmployee = nmEmployee; + this.knEmployee = knEmployee; + this.mailAddress = mailAddress; + this.password = password; + this.adminAuth = adminAuth; + this.idDepartment = idDepartment; + + } + + public Integer getIdEmployee() { + return idEmployee; + } + + public String getNmEmployee() { + return nmEmployee; + } + + public String getKnEmployee() { + return knEmployee; + } + + public String getMailAddress() { + return mailAddress; + } + + public String getPassword() { + return password; + } + + public Integer getAdminAuth() { + return adminAuth; + } + + public Integer getIdDepartment() { + return idDepartment; + } + + public LoginUser getLoginUserInstance() { + return new LoginUser( + getIdEmployee(), + getNmEmployee(), + getKnEmployee(), + getMailAddress(), + getPassword(), + getAdminAuth(), + getIdDepartment() + ); + } +} diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/DeleteEmployeeControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/DeleteEmployeeControllerTest.java new file mode 100644 index 0000000..3219679 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/DeleteEmployeeControllerTest.java @@ -0,0 +1,94 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.service.DeleteEmployee; +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import java.util.List; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class DeleteEmployeeControllerTest { + + @MockBean + DeleteEmployee deleteEmployee; + @MockBean + SearchDepartmentImpl searchDepartmentImpl; + @MockBean + Model model; + @Autowired + private MockMvc mockMvc; + + @Nested + class deleteEmployeeTest { + + @Test + void deleteEmployee_正常系_削除() throws Exception { + + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + doNothing().when(deleteEmployee).deleteEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee()); + when(searchDepartmentImpl.selectAll()).thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.DELETE_EMPLOYEE) + .session(session) + .param("idEmployee", "1")) + .andExpect(status().isOk()) + .andExpect(view().name("forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY)); + } + + @Test + void deleteEmployee_異常系_削除対象が操作者() throws Exception { + + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + doNothing().when(deleteEmployee).deleteEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee()); + when(searchDepartmentImpl.selectAll()).thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.DELETE_EMPLOYEE) + .session(session) + .param("idEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee().toString())) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name("forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY)); + } + + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/IndexControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/IndexControllerTest.java new file mode 100644 index 0000000..821fe8a --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/IndexControllerTest.java @@ -0,0 +1,53 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class IndexControllerTest { + + @MockBean + Model model; + @Autowired + private MockMvc mockMvc; + + @Nested + class indexTest { + + @Test + void index_正常系_ログイン画面へ遷移() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + mockMvc.perform(MockMvcRequestBuilders.get(TransitionTargetPageNameKeyword.INDEX_SLASH) + .session(session)) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.LOGIN_HTML)); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeConfirmControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeConfirmControllerTest.java new file mode 100644 index 0000000..7c941ce --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeConfirmControllerTest.java @@ -0,0 +1,177 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.domain.service.impl.SearchEmployeeImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import java.util.List; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class InsertEmployeeConfirmControllerTest { + + @MockBean + SearchEmployeeImpl searchEmployee; + @MockBean + SearchDepartmentImpl searchDepartment; + @MockBean + Model model; + @Autowired + private MockMvc mockMvc; + + @Nested + class insertEmployeeConfirmTest { + + @Test + void insertEmployeeConfirm_正常系_登録確認画面へ遷移() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress())) + .thenReturn(List.of()); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + mockMvc.perform(MockMvcRequestBuilders + .post(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_CONFIRM) + .session(session) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("passwordConfirm", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_CONFIRM_HTML)); + + } + + @Test + void insertEmployeeConfirm_異常系_登録情報に誤り() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress())) + .thenReturn(List.of()); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + mockMvc.perform(MockMvcRequestBuilders + .post(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_CONFIRM) + .session(session) + .param("nmEmployee", "") + .param("knEmployee", "") + .param("mailAddress", "") + .param("password", "") + .param("passwordConfirm", "") + .param("adminAuth", "") + .param("idDepartment", "")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML)); + + } + + @Test + void insertEmployeeConfirm_異常系_登録情報に誤り_パスワード不一致() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress())) + .thenReturn(List.of()); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + mockMvc.perform(MockMvcRequestBuilders + .post(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_CONFIRM) + .session(session) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("passwordConfirm", "password123") + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML)); + + } + + @Test + void insertEmployeeConfirm_異常系_登録情報に誤り_メールアドレス重複() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + mockMvc.perform(MockMvcRequestBuilders + .post(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_CONFIRM) + .session(session) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("passwordConfirm", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML)); + + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeControllerTest.java new file mode 100644 index 0000000..0825948 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeControllerTest.java @@ -0,0 +1,114 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.service.impl.RegisterEmployeeImpl; +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import java.util.List; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class InsertEmployeeControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + Model model; + + @MockBean + SearchDepartmentImpl searchDepartment; + + @MockBean + RegisterEmployeeImpl registerEmployee; + + + @Nested + class insertEmployeeTest { + @Test + void insertEmployee_正常系_登録結果画面へ遷移() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + doNothing().when(registerEmployee).registerEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE) + .session(session) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_RESULT_HTML)); + + } + + @Test + void insertEmployee_異常系_登録情報に誤り() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + doNothing().when(registerEmployee).registerEmployee(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE) + .session(session) + .param("nmEmployee", "") + .param("knEmployee", "") + .param("mailAddress", "") + .param("password", "") + .param("adminAuth", "") + .param("idDepartment", "")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML)); + } + + } + + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeInputControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeInputControllerTest.java new file mode 100644 index 0000000..b495c74 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/InsertEmployeeInputControllerTest.java @@ -0,0 +1,72 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import java.util.List; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class InsertEmployeeInputControllerTest { + + @MockBean + Model model; + @MockBean + SearchDepartmentImpl searchDepartment; + @Autowired + private MockMvc mockMvc; + + @Nested + class insertEmployeeInputTest { + + @Test + void insertEmployeeInput_正常系_登録画面へ遷移() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT) + .session(session) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.INSERT_EMPLOYEE_INPUT_HTML)); + + + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/LoginControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/LoginControllerTest.java new file mode 100644 index 0000000..b098585 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/LoginControllerTest.java @@ -0,0 +1,161 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.service.impl.LoginImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class LoginControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + LoginImpl login; + @MockBean + Model model; + + + @Nested + class loginTest { + + @Test + void login_正常系_ログイン画面へ遷移() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + + when(login.canLogin(any())).thenReturn(true); + + when(login.doLogin(any())) + .thenReturn(EmployeeEntity.convertFrom(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()).createLoginUser()); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.DO_LOGIN) + .session(session) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword())) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.MENU_HTML)); + + } + + @Test + void login_正常系_個人情報更新画面() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + + when(login.canLogin(any())).thenReturn(true); + + when(login.doLogin(any())) + .thenReturn(EmployeeEntity.convertFrom(EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance()).createLoginUser()); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.DO_LOGIN) + .session(session) + .param("mailAddress", EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.NORMAL_EMPLOYEE.getPassword())) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML)); + } + + @Test + void login_異常系_ログイン不可() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + + when(login.canLogin(any())).thenReturn(false); + + when(login.doLogin(any())) + .thenReturn(EmployeeEntity.convertFrom(EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance()).createLoginUser()); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.DO_LOGIN) + .session(session) + .param("mailAddress", EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.NORMAL_EMPLOYEE.getPassword())) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.LOGIN_HTML)); + } + + @Test + void login_異常系_パスワード誤り() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.DO_LOGIN) + .session(session) + .param("mailAddress", EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress()) + .param("password", "")) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.LOGIN_HTML)); + } + + @Test + void login_異常系_メールアドレス誤り() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.DO_LOGIN) + .session(session) + .param("mailAddress", "") + .param("password", EmployeeEnum.NORMAL_EMPLOYEE.getPassword())) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.LOGIN_HTML)); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/LogoutControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/LogoutControllerTest.java new file mode 100644 index 0000000..f770593 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/LogoutControllerTest.java @@ -0,0 +1,56 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class LogoutControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + Model model; + + + @Nested + class doLogoutTest { + + @Test + void doLogout_正常系_ログアウト() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.LOGOUT) + .session(session)) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.LOGIN_HTML)); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/MenuControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/MenuControllerTest.java new file mode 100644 index 0000000..d50f1fe --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/MenuControllerTest.java @@ -0,0 +1,49 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class MenuControllerTest { + + @Autowired + MockMvc mockMvc; + + @Nested + class showMenuTest { + + @Test + void showMenu_正常系_メニュー画面表示() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.SHOW_MENU) + .session(session)) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.MENU_HTML)); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/SelectEmployeeControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/SelectEmployeeControllerTest.java new file mode 100644 index 0000000..cfb44df --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/SelectEmployeeControllerTest.java @@ -0,0 +1,67 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.domain.service.impl.SearchEmployeeInfoImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import java.util.List; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class SelectEmployeeControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + Model model; + @MockBean + SearchDepartmentImpl searchDepartment; + @MockBean + SearchEmployeeInfoImpl searchEmployeeInfo; + + @Nested + class selectTest { + @Test + void select_正常系_社員検索画面表示() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO) + .session(session)) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_HTML)); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeControllerTest.java new file mode 100644 index 0000000..70a1fe5 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeControllerTest.java @@ -0,0 +1,105 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.model.EmployeeInfo; +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.domain.service.impl.SearchEmployeeInfoImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class UpdateEmployeeControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + Model model; + + @MockBean + SearchDepartmentImpl searchDepartment; + @MockBean + SearchEmployeeInfoImpl searchEmployeeInfo; + + @Nested + class showUpdateEmployeeTest { + @Test + void showUpdateEmployee_正常系_社員情報更新画面表示() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployeeInfo.searchBy(any())) + .thenReturn(List.of(new EmployeeInfo( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance(), + DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance() + ))); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.SHOW_UPDATE_EMPLOYEE) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee()))) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML)); + + } + + @Test + void showUpdateEmployee_異常系_更新対象のデータが存在しない() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployeeInfo.searchBy(any())) + .thenReturn(List.of()); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.SHOW_UPDATE_EMPLOYEE) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name("forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO)); + + } + + } + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeResultControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeResultControllerTest.java new file mode 100644 index 0000000..586f791 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/UpdateEmployeeResultControllerTest.java @@ -0,0 +1,532 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.service.impl.SearchDepartmentImpl; +import com.example.rhizome.app.domain.service.impl.SearchEmployeeImpl; +import com.example.rhizome.app.domain.service.impl.UpdateEmployeeImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.DepartmentEnum; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class EmployeeUpdateResultControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + Model model; + @MockBean + SearchDepartmentImpl searchDepartment; + @MockBean + SearchEmployeeImpl searchEmployee; + @MockBean + UpdateEmployeeImpl updateEmployee; + + @Nested + class employeeUpdateResultTest { + + @Test + void employeeUpdateResult_正常系_社員情報更新結果画面表示_メールアドレス同一人物_権限変更なし() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("passwordConfirm", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(view().name("forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY)); + + } + + @Test + void employeeUpdateResult_正常系_社員情報更新結果画面表示_メールアドレス同一人物_権限変更なし_パスワード更新なし() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", "") + .param("passwordConfirm", "") + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(view().name("forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY)); + + } + + @Test + void updateEmployeeResult_正常系_社員情報更新結果画面表示_メールアドレス同一人物_権限変更あり_パスワード更新なし_対象者は操作者ではない() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", "") + .param("passwordConfirm", "") + .param("adminAuth", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(view().name("forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY)); + + } + + @Test + void updateEmployeeResult_正常系_社員情報更新結果画面表示_メールアドレス重複無し_権限変更あり_パスワード更新なし_対象者は操作者ではない() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of()); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", "") + .param("passwordConfirm", "") + .param("adminAuth", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(view().name("forward:" + TransitionTargetPageNameKeyword.SELECT_EMPLOYEE_INFO_FORM_EMPTY)); + + } + + @Test + void updateEmployeeResult_異常系_パスワードが仕様を満たしていない1() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", "") + .param("passwordConfirm", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML)); + + } + + @Test + void updateEmployeeResult_異常系_パスワードが仕様を満たしていない2() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("passwordConfirm", "") + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML)); + + } + + @Test + void updateEmployeeResult_異常系_メールアドレス重複_権限変更なし() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.NORMAL_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("passwordConfirm", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML)); + + } + + @Test + void updateEmployeeResult_異常系_同一人物_操作者の権限変更あり() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("passwordConfirm", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML)); + + } + + @Test + void updateEmployeeResult_異常系_画面からのパラメータ異常() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", "") + .param("knEmployee", "") + .param("mailAddress", "") + .param("password", "") + .param("passwordConfirm", "") + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML)); + + } + + @Test + void updateEmployeeResult_異常系_更新前のデータが存在しない() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + when(searchDepartment.selectAll()) + .thenReturn(List.of(DepartmentEnum.TEST_DEPARTMENT.getDepartmentInstance())); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + when(searchEmployee.searchEmployeeByIdEmployee(any())) + .thenReturn(EmployeeEntity.createEmployee(new EmployeeEntity())); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + DepartmentEnum.TEST_DEPARTMENT.getIdDepartment())); + + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("passwordConfirm", EmployeeEnum.ADMIN_EMPLOYEE.getPassword()) + .param("adminAuth", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth())) + .param("idDepartment", String.valueOf(EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment()))) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_EMPLOYEE_INPUT_HTML)); + + } + + } + + +} \ No newline at end of file diff --git a/src/test/java/com/example/rhizome/app/presentation/controller/UpdatePersonalEmployeeResultControllerTest.java b/src/test/java/com/example/rhizome/app/presentation/controller/UpdatePersonalEmployeeResultControllerTest.java new file mode 100644 index 0000000..b34d999 --- /dev/null +++ b/src/test/java/com/example/rhizome/app/presentation/controller/UpdatePersonalEmployeeResultControllerTest.java @@ -0,0 +1,293 @@ +package com.example.rhizome.app.presentation.controller; + +import com.example.rhizome.app.domain.model.LoginUser; +import com.example.rhizome.app.domain.service.impl.SearchEmployeeImpl; +import com.example.rhizome.app.domain.service.impl.UpdateEmployeeImpl; +import com.example.rhizome.app.infra.entity.EmployeeEntity; +import com.example.rhizome.app.infra.record.EmployeeEnum; +import com.example.rhizome.app.presentation.controller.pageproperty.PageReturnAttributeKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.SessionKeyword; +import com.example.rhizome.app.presentation.controller.pageproperty.TransitionTargetPageNameKeyword; +import com.example.rhizome.app.presentation.form.LoginUserForm; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.ui.Model; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class UpdatePersonalEmployeeResultControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + Model model; + @MockBean + SearchEmployeeImpl searchEmployee; + @MockBean + UpdateEmployeeImpl updateEmployee; + + + @Nested + class personalEmployeeUpdateResultTest { + @Test + void personalEmployeeUpdateResult_正常系_個人情報更新結果画面表示_パスワードが両方あり_メールアドレス重複無し() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.PERSONAL_UPDATE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.NORMAL_EMPLOYEE.getPassword()) + .param("passwordConfirm", EmployeeEnum.NORMAL_EMPLOYEE.getPassword()) + ) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_PERSONAL_RESULT_HTML)); + } + + @Test + void personalEmployeeUpdateResult_正常系_個人情報更新結果画面表示_パスワードが両方無し_メールアドレス重複無し() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.PERSONAL_UPDATE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress()) + .param("password", "") + .param("passwordConfirm", "") + ) + .andExpect(status().isOk()) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_PERSONAL_RESULT_HTML)); + } + + @Test + void personalEmployeeUpdateResult_異常系_個人情報更新結果画面表示_パスワードが両方あり_メールアドレス重複有り() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of(EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance())); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.PERSONAL_UPDATE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress()) + .param("password", EmployeeEnum.NORMAL_EMPLOYEE.getPassword()) + .param("passwordConfirm", EmployeeEnum.NORMAL_EMPLOYEE.getPassword()) + ) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML)); + } + + @Test + void personalEmployeeUpdateResult_異常系_個人情報更新結果画面表示_パスワードが片方無し1_メールアドレス重複無し() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.PERSONAL_UPDATE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress()) + .param("password", "password") + .param("passwordConfirm", "") + ) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML)); + } + + @Test + void personalEmployeeUpdateResult_異常系_個人情報更新結果画面表示_パスワードが片方無し2_メールアドレス重複無し() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.PERSONAL_UPDATE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getNmEmployee()) + .param("knEmployee", EmployeeEnum.NORMAL_EMPLOYEE.getKnEmployee()) + .param("mailAddress", EmployeeEnum.NORMAL_EMPLOYEE.getMailAddress()) + .param("password", "") + .param("passwordConfirm", "password") + ) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML)); + } + + @Test + void personalEmployeeUpdateResult_異常系_個人情報更新結果画面表示_必須情報無し() throws Exception { + MockHttpSession session = new MockHttpSession(); + session.setAttribute( + SessionKeyword.LOGIN_USER, + LoginUserForm.convertFrom( + EmployeeEntity.convertFrom( + EmployeeEnum.ADMIN_EMPLOYEE.getEmployeeInstance() + ).createLoginUser() + )); + + when(searchEmployee.searchEmployee(any())) + .thenReturn(List.of()); + + doNothing().when(updateEmployee).updateEmployee(any(), any()); + + when(searchEmployee.searchLoginUser(any())) + .thenReturn(new LoginUser( + EmployeeEnum.ADMIN_EMPLOYEE.getIdEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getNmEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getKnEmployee(), + EmployeeEnum.ADMIN_EMPLOYEE.getMailAddress(), + EmployeeEnum.ADMIN_EMPLOYEE.getPassword(), + EmployeeEnum.ADMIN_EMPLOYEE.getAdminAuth(), + EmployeeEnum.ADMIN_EMPLOYEE.getIdDepartment() + )); + + mockMvc.perform(MockMvcRequestBuilders.post(TransitionTargetPageNameKeyword.PERSONAL_UPDATE_RESULT) + .session(session) + .param("idEmployee", String.valueOf(EmployeeEnum.NORMAL_EMPLOYEE.getIdEmployee())) + .param("nmEmployee", "") + .param("knEmployee", "") + .param("mailAddress", "") + .param("password", "") + .param("passwordConfirm", "") + ) + .andExpect(status().isOk()) + .andExpect(model().attributeExists(PageReturnAttributeKeyword.MESSAGE_ERROR)) + .andExpect(view().name(TransitionTargetPageNameKeyword.UPDATE_PERSONAL_EMPLOYEE_INPUT_HTML)); + } + } +} \ No newline at end of file diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties new file mode 100644 index 0000000..5fbf447 --- /dev/null +++ b/src/test/resources/application-test.properties @@ -0,0 +1,2 @@ +# \u30C6\u30B9\u30C8\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u7528\u306E\u30D7\u30ED\u30D1\u30C6\u30A3 +aop.enabled=false diff --git a/テスト仕様書/単体テスト仕様書.xlsx b/テスト仕様書/単体テスト仕様書.xlsx new file mode 100644 index 0000000..8c8f116 Binary files /dev/null and b/テスト仕様書/単体テスト仕様書.xlsx differ diff --git a/テスト仕様書/結合テスト仕様書.xlsx b/テスト仕様書/結合テスト仕様書.xlsx new file mode 100644 index 0000000..c34da12 Binary files /dev/null and b/テスト仕様書/結合テスト仕様書.xlsx differ diff --git a/ヒント.md b/ヒント.md new file mode 100644 index 0000000..8161433 --- /dev/null +++ b/ヒント.md @@ -0,0 +1,51 @@ +# Hint + +- Daoの代わりとなるRepositoryのインターフェースは既に実装済みなので既存の処理を参考に + 使い方を調べてみて下さい。 +- 既存のControllerクラスにはAOPを用いたアクセス権の制御が実装されています。 + 該当アノテーションは下記の通りです。 + ※ 該当アノテーションはコピペしないようにしてください。(正しく動作しなくなる可能性があります。 + - @PermissionCheck + - @SessionCheck + +## 第1段階 検索機能の追加 + +### 作業概要(厳密ではないため、あくまで指標として観て下さい) + +- 部署検索用HTMLに連動するControllerを作成する +- 画面とController間で使用する受け渡し用のFormを作成する +- 部署検索HTMLを新規で作成する + (既存のHTMLを参考に作成する事で Style.css がそのまま使えるが、可能であれば部署検索用に編集を加えると見た目も綺麗になるのでなお良しです) +- 部署検索用のサービスとの繋ぎ込みを行う +- メニューにボタンを追加し、検索画面に遷移するように編集 + (メニュー画面から部署検索画面用へ遷移する際に必要なJavaScriptは実装済みなので、 + Controllerに指定したURLに変更する等、自分の環境用に改修しつつそれを使ってください) + +## 第2段階 削除機能の追加 + +### 作業概要(厳密ではないため、あくまで指標として観て下さい) + +- 削除処理用のControllerを作成する +- 部署検索HTMLの検索結果各レコードに削除ボタンを追加する +- 部署削除用のサービスを作成する +- 削除用のサービスとRepository(Dao)を繋ぎ込みする + +## 第3段階 更新機能の追加 + +### 作業概要(厳密ではないため、あくまで指標として観て下さい) + +- 更新処理用のControllerを作成する +- 部署検索HTMLの検索結果各レコードに更新ボタンを追加する +- 部署更新用のサービスを作成する +- 更新用のサービスとRepository(Dao)を繋ぎ込みする + +## 第4段階 新規登録の追加 + +### 作業概要(厳密ではないため、あくまで指標として観て下さい) + +- 新規作成用のコントローラ(入力画面用・入力内容確認用・登録結果画面用)を作成する +- 新規登録用のHTML(入力画面用・入力内容確認用・登録結果画面用)を作成する + (メニュー画面から部署検索画面用へ遷移する際に必要なJavaScriptは実装済みなので、 + Controllerに指定したURLに変更する等、自分の環境用に改修しつつそれを使ってください) +- 新規登録用のサービスを作成する +- 新規登録用のサービスとRepository(Dao)を繋ぎ込みする diff --git a/設計書/start-db-ddl-dml.sql b/設計書/start-db-ddl-dml.sql new file mode 100644 index 0000000..fb243d7 --- /dev/null +++ b/設計書/start-db-ddl-dml.sql @@ -0,0 +1,50 @@ +-- DB ‚Æ User�쐬 Š֘A +-- •K—v‚ł ‚ê‚΃Rƒ�ƒ“ƒgŠO‚µ‚Ă­‚¾‚³‚¢ +-- CREATE DATABASE rezodb; +-- CREATE USER 'rezouser'@'localhost' IDENTIFIED BY 'Rezo_0000'; +-- GRANT ALL ON rezodb.* TO 'rezouser'@'localhost'; + +-- employeeƒe�[ƒuƒ‹‚̍쐬 +DROP TABLE IF EXISTS employee; +CREATE TABLE employee ( + id_employee INT AUTO_INCREMENT PRIMARY KEY + , nm_employee VARCHAR(50) NOT NULL + , kn_employee VARCHAR(50) NOT NULL + , mail_address VARCHAR(100) NOT NULL + , password VARCHAR(10) NOT NULL + , admin_auth INT NOT NULL + , id_department INT NOT NULL +) +AUTO_INCREMENT = 10000; + +-- •”��ƒe�[ƒuƒ‹‚̍쐬 +DROP TABLE IF EXISTS department; +CREATE TABLE department ( + id_department INT AUTO_INCREMENT PRIMARY KEY + , nm_department VARCHAR(10) NOT NULL +) +AUTO_INCREMENT = 10; + +-- ŽЈõƒe�[ƒuƒ‹‚̃f�[ƒ^ +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('ŽR“c—´–ç','ƒ„ƒ}ƒ_ƒ^ƒcƒ„','yamada@hoge.jp','aaa',1,10); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('�‚‹´�€','ƒ^ƒJƒnƒVƒWƒ…ƒ“','jtaka@hoge.jp','bbb',0,10); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('–ƒŽ}Žj–¾','ƒ}ƒGƒ_ƒtƒ~ƒAƒL','fmak@hoge.jp','ccc',0,11); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('Šیˏ͉î','ƒ}ƒ‹ƒgƒVƒ‡ƒEƒXƒP','marusyo@hoge.jp','ddd',0,12); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('ŽO‘','ƒ~ƒ„ƒPƒ^ƒPƒV','miya@hoge.jp','eee',0,13); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('Šۈä—I','ƒ}ƒ‹ƒCƒnƒ‹ƒJ','haru@hoge.jp','fff',0,13); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('—ÁŒ³���D','ƒXƒYƒ‚ƒgƒJƒIƒŠ','suzumoto@hoge.jp','ggg',0,13); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('—tŽR–«','ƒnƒ„ƒ}ƒ~ƒmƒ‹','mhayama@hoge.jp','hhh',0,14); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('�ì�ãŽ闢','ƒJƒ�ƒJƒ~ƒAƒJƒŠ','kawakami@hoge.jp','iii',0,14); +INSERT INTO employee (nm_employee, kn_employee, mail_address, password, admin_auth, id_department) VALUES ('�™ˆ䔣','ƒXƒMƒCƒnƒWƒ�','sugi@hoge.jp','jjj',0,15); + +-- •”��ƒe�[ƒuƒ‹‚̃f�[ƒ^ +INSERT INTO department (nm_department) VALUES ('–ðˆõ'); +INSERT INTO department (nm_department) VALUES ('�lŽ–�E‘�–±•”'); +INSERT INTO department (nm_department) VALUES ('Œo—�•”'); +INSERT INTO department (nm_department) VALUES ('ƒVƒXƒeƒ€ŠJ”­Ž–‹ƕ”'); +INSERT INTO department (nm_department) VALUES ('‹³ˆ玖‹ƕ”'); +INSERT INTO department (nm_department) VALUES ('‰c‹Ɗé‰敔'); + + +-- AUTO_INCREMENT’l‚ðƒŠƒZƒbƒg +ALTER TABLE `employee` auto_increment = 10000; diff --git a/設計書/【一般ユーザ】個人情報更新機能-詳細設計書.xlsx b/設計書/【一般ユーザ】個人情報更新機能-詳細設計書.xlsx new file mode 100644 index 0000000..858c6be Binary files /dev/null and b/設計書/【一般ユーザ】個人情報更新機能-詳細設計書.xlsx differ diff --git a/設計書/【共通】ログイン機能-詳細設計書.xlsx b/設計書/【共通】ログイン機能-詳細設計書.xlsx new file mode 100644 index 0000000..1c8d907 Binary files /dev/null and b/設計書/【共通】ログイン機能-詳細設計書.xlsx differ diff --git a/設計書/【管理者】メニュー機能-詳細設計書.xlsx b/設計書/【管理者】メニュー機能-詳細設計書.xlsx new file mode 100644 index 0000000..b4e8a40 Binary files /dev/null and b/設計書/【管理者】メニュー機能-詳細設計書.xlsx differ diff --git a/設計書/【管理者】社員情報検索更新削除機能-詳細設計書.xlsx b/設計書/【管理者】社員情報検索更新削除機能-詳細設計書.xlsx new file mode 100644 index 0000000..b63e8a7 Binary files /dev/null and b/設計書/【管理者】社員情報検索更新削除機能-詳細設計書.xlsx differ diff --git a/設計書/【管理者】社員情報登録機能-詳細設計書.xlsx b/設計書/【管理者】社員情報登録機能-詳細設計書.xlsx new file mode 100644 index 0000000..58672cc Binary files /dev/null and b/設計書/【管理者】社員情報登録機能-詳細設計書.xlsx differ diff --git a/設計書/【管理者】部署情報検索更新削除機能-詳細設計書.xlsx b/設計書/【管理者】部署情報検索更新削除機能-詳細設計書.xlsx new file mode 100644 index 0000000..e613b8f Binary files /dev/null and b/設計書/【管理者】部署情報検索更新削除機能-詳細設計書.xlsx differ diff --git a/設計書/【管理者】部署情報登録機能-詳細設計書.xlsx b/設計書/【管理者】部署情報登録機能-詳細設計書.xlsx new file mode 100644 index 0000000..8e331b5 Binary files /dev/null and b/設計書/【管理者】部署情報登録機能-詳細設計書.xlsx differ diff --git a/設計書/テーブル定義書.xlsm b/設計書/テーブル定義書.xlsm new file mode 100644 index 0000000..8859e31 Binary files /dev/null and b/設計書/テーブル定義書.xlsm differ diff --git a/設計書/基本設計書.xlsx b/設計書/基本設計書.xlsx new file mode 100644 index 0000000..1a921a7 Binary files /dev/null and b/設計書/基本設計書.xlsx differ