Initial commit.
This commit is contained in:
commit
6c22c168a7
19 changed files with 695 additions and 0 deletions
2
.editorconfig
Normal file
2
.editorconfig
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[*]
|
||||||
|
insert_final_newline=true
|
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# batch files are specific to windows and always crlf
|
||||||
|
*.bat eol=crlf
|
84
.gitignore
vendored
Normal file
84
.gitignore
vendored
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
|
||||||
|
__pycache__
|
||||||
|
.classpath
|
||||||
|
.DS_Store
|
||||||
|
.gradle
|
||||||
|
.history
|
||||||
|
.kobalt
|
||||||
|
.mtj.tmp/
|
||||||
|
.mvn/timing.properties
|
||||||
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
.nb-gradle
|
||||||
|
.project
|
||||||
|
.scannerwork
|
||||||
|
.settings
|
||||||
|
*.class
|
||||||
|
*.code-workspace
|
||||||
|
*.ctxt
|
||||||
|
*.iws
|
||||||
|
*.log
|
||||||
|
*.nar
|
||||||
|
*.rar
|
||||||
|
*.sublime-*
|
||||||
|
*.tar.gz
|
||||||
|
*.zip
|
||||||
|
/**/.idea_modules/
|
||||||
|
/**/.idea/**/caches/build_file_checksums.ser
|
||||||
|
/**/.idea/**/contentModel.xml
|
||||||
|
/**/.idea/**/dataSources.ids
|
||||||
|
/**/.idea/**/dataSources.local.xml
|
||||||
|
/**/.idea/**/dataSources/
|
||||||
|
/**/.idea/**/dbnavigator.xml
|
||||||
|
/**/.idea/**/dictionaries
|
||||||
|
/**/.idea/**/dynamic.xml
|
||||||
|
/**/.idea/**/gradle.xml
|
||||||
|
/**/.idea/**/httpRequests
|
||||||
|
/**/.idea/**/libraries
|
||||||
|
/**/.idea/**/mongoSettings.xml
|
||||||
|
/**/.idea/**/replstate.xml
|
||||||
|
/**/.idea/**/shelf
|
||||||
|
/**/.idea/**/shelf/
|
||||||
|
/**/.idea/**/sqlDataSources.xml
|
||||||
|
/**/.idea/**/tasks.xml
|
||||||
|
/**/.idea/**/uiDesigner.xml
|
||||||
|
/**/.idea/**/usage.statistics.xml
|
||||||
|
/**/.idea/**/workspace.xml
|
||||||
|
/**/.idea/$CACHE_FILE$
|
||||||
|
/**/.idea/$PRODUCT_WORKSPACE_FILE$
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
bin/
|
||||||
|
build/
|
||||||
|
cmake-build-*/
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics-build.properties
|
||||||
|
crashlytics.properties
|
||||||
|
dependency-reduced-pom.xml
|
||||||
|
deploy/
|
||||||
|
dist/
|
||||||
|
ehthumbs.db
|
||||||
|
fabric.properties
|
||||||
|
gen/
|
||||||
|
gradle.properties
|
||||||
|
hs_err_pid*
|
||||||
|
kobaltBuild
|
||||||
|
kobaltw*-test
|
||||||
|
lib/kotlin*
|
||||||
|
libs/
|
||||||
|
local.properties
|
||||||
|
out/
|
||||||
|
pom.xml.next
|
||||||
|
pom.xml.releaseBackup
|
||||||
|
pom.xml.tag
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
proguard-project.txt
|
||||||
|
project.properties
|
||||||
|
release.properties
|
||||||
|
target/
|
||||||
|
test-output
|
||||||
|
Thumbs.db
|
||||||
|
venv
|
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
|
@ -0,0 +1 @@
|
||||||
|
readingtime
|
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<bytecodeTargetLevel target="14" />
|
||||||
|
</component>
|
||||||
|
</project>
|
36
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
36
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="TOP_LEVEL_CLASS_OPTIONS">
|
||||||
|
<value>
|
||||||
|
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||||
|
<option name="REQUIRED_TAGS" value="" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="INNER_CLASS_OPTIONS">
|
||||||
|
<value>
|
||||||
|
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||||
|
<option name="REQUIRED_TAGS" value="" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="METHOD_OPTIONS">
|
||||||
|
<value>
|
||||||
|
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||||
|
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="FIELD_OPTIONS">
|
||||||
|
<value>
|
||||||
|
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||||
|
<option name="REQUIRED_TAGS" value="" />
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="IGNORE_DEPRECATED" value="false" />
|
||||||
|
<option name="IGNORE_JAVADOC_PERIOD" value="true" />
|
||||||
|
<option name="IGNORE_DUPLICATED_THROWS" value="false" />
|
||||||
|
<option name="IGNORE_POINT_TO_ITSELF" value="false" />
|
||||||
|
<option name="myAdditionalJavadocTags" value="created" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
20
.idea/jarRepositories.xml
generated
Normal file
20
.idea/jarRepositories.xml
generated
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RemoteRepositoriesConfiguration">
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="central" />
|
||||||
|
<option name="name" value="Maven Central repository" />
|
||||||
|
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="jboss.community" />
|
||||||
|
<option name="name" value="JBoss Community repository" />
|
||||||
|
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="BintrayJCenter" />
|
||||||
|
<option name="name" value="BintrayJCenter" />
|
||||||
|
<option name="url" value="https://jcenter.bintray.com/" />
|
||||||
|
</remote-repository>
|
||||||
|
</component>
|
||||||
|
</project>
|
5
.idea/misc.xml
generated
Normal file
5
.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_14" default="true" project-jdk-name="14" project-jdk-type="JavaSDK" />
|
||||||
|
</project>
|
18
build.gradle.kts
Normal file
18
build.gradle.kts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
plugins {
|
||||||
|
id("org.jetbrains.kotlin.jvm") version "1.3.72"
|
||||||
|
`java-library`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
|
||||||
|
implementation("org.jsoup:jsoup:1.13.1")
|
||||||
|
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
|
||||||
|
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
185
gradlew
vendored
Normal file
185
gradlew
vendored
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2015 the original author or authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
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
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=`expr $i + 1`
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
0) set -- ;;
|
||||||
|
1) set -- "$args0" ;;
|
||||||
|
2) set -- "$args0" "$args1" ;;
|
||||||
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
104
gradlew.bat
vendored
Normal file
104
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
10
settings.gradle.kts
Normal file
10
settings.gradle.kts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* This file was generated by the Gradle 'init' task.
|
||||||
|
*
|
||||||
|
* The settings file is used to specify which projects to include in your build.
|
||||||
|
*
|
||||||
|
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||||
|
* in the user manual at https://docs.gradle.org/6.5.1/userguide/multi_project_builds.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
rootProject.name = "readingtime"
|
68
src/main/kotlin/net/thauvin/erik/readingtime/ReadingTime.kt
Normal file
68
src/main/kotlin/net/thauvin/erik/readingtime/ReadingTime.kt
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package net.thauvin.erik.readingtime
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import java.math.RoundingMode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the reading time of the given [text].
|
||||||
|
*
|
||||||
|
* Calculation based on this [Medium's Post](https://blog.medium.com/read-time-and-you-bc2048ab620c)
|
||||||
|
*/
|
||||||
|
class ReadingTime(
|
||||||
|
var text: String,
|
||||||
|
var wpm: Int = 275,
|
||||||
|
var postfix: String = "min read",
|
||||||
|
var plural: String = "min read",
|
||||||
|
var excludeImages: Boolean = false
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun wordCount(words: String): Int {
|
||||||
|
val s = Jsoup.parse(words).text().trim()
|
||||||
|
return if (s.isEmpty()) 0 else s.split("\\s+".toRegex()).size
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun imgCount(html: String): Int {
|
||||||
|
return "<img ".toRegex(RegexOption.IGNORE_CASE).findAll(html).count()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calcReadingTimeInSec(): Double {
|
||||||
|
var readingTime = 0.0
|
||||||
|
|
||||||
|
if (!excludeImages)
|
||||||
|
readingTime += calcImgReadingTime()
|
||||||
|
|
||||||
|
readingTime += wordCount(text) / (wpm / 60.0)
|
||||||
|
|
||||||
|
return readingTime
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calcReadingTime(): String {
|
||||||
|
val readingTime = BigDecimal((calcReadingTimeInSec() / 60)).setScale(0, RoundingMode.CEILING)
|
||||||
|
return if (readingTime.compareTo(BigDecimal.ONE) == 1) {
|
||||||
|
"$readingTime $plural".trim()
|
||||||
|
} else {
|
||||||
|
"$readingTime $postfix".trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calcImgReadingTime(): Int {
|
||||||
|
var imgTime = 0
|
||||||
|
val imgCount = imgCount(text)
|
||||||
|
|
||||||
|
var offset = 12
|
||||||
|
for (i in 1..imgCount) {
|
||||||
|
if (i > 10) {
|
||||||
|
imgTime += 3
|
||||||
|
} else {
|
||||||
|
imgTime += offset
|
||||||
|
offset--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return imgTime
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package net.thauvin.erik.readingtime
|
||||||
|
|
||||||
|
import net.thauvin.erik.readingtime.ReadingTime.Companion.imgCount
|
||||||
|
import net.thauvin.erik.readingtime.ReadingTime.Companion.wordCount
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class ReadingTimeTest {
|
||||||
|
private val rt = ReadingTime("This is a <b>test</b>.\nWith an image: <img src=\"#\">")
|
||||||
|
private val blogPost = File("src/test/resources/post.html").readText()
|
||||||
|
private val mediumPost = File("src/test/resources/medium.html").readText()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWordCount() {
|
||||||
|
assertEquals(0, wordCount(" "))
|
||||||
|
assertEquals(3, wordCount("one two three"))
|
||||||
|
assertEquals(2, wordCount(" one two "))
|
||||||
|
assertEquals(7, wordCount(rt.text))
|
||||||
|
assertEquals(210, wordCount(blogPost))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testImgCount() {
|
||||||
|
assertEquals(1, imgCount(rt.text))
|
||||||
|
assertEquals(4, imgCount(blogPost))
|
||||||
|
assertEquals(3, imgCount(mediumPost))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReadingTimeInSec() {
|
||||||
|
assertEquals((wordCount(rt.text) / (rt.wpm / 60.0)) + 12.0, rt.calcReadingTimeInSec())
|
||||||
|
rt.text = "<img src=\"#\"> <IMG src=\"#\">"
|
||||||
|
assertEquals(12.0 + 11.0, rt.calcReadingTimeInSec())
|
||||||
|
rt.text = blogPost
|
||||||
|
assertEquals((wordCount(rt.text) / (rt.wpm / 60.0)) + 12.0 + 11.0 + 10.0 + 9.0, rt.calcReadingTimeInSec())
|
||||||
|
rt.text = mediumPost
|
||||||
|
rt.wpm = 300
|
||||||
|
assertEquals(wordCount(rt.text) / (rt.wpm / 60.0) + 12.0 + 11.0 + 10.0, rt.calcReadingTimeInSec())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testReadingTime() {
|
||||||
|
rt.text = blogPost
|
||||||
|
assertEquals("2 min read", rt.calcReadingTime())
|
||||||
|
rt.plural = "mins read"
|
||||||
|
assertEquals("2 mins read", rt.calcReadingTime())
|
||||||
|
rt.text = mediumPost
|
||||||
|
rt.plural = ""
|
||||||
|
assertEquals("2", rt.calcReadingTime())
|
||||||
|
}
|
||||||
|
}
|
46
src/test/resources/medium.html
Normal file
46
src/test/resources/medium.html
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
Eons ago, a couple of Medium engineers got fed up. They were sick of having to scroll all the way down the page to see how long a story was. It was wearing out their trackpad, it was making their fingers sore, and they figured there must be a better way. So they sat down and devised a simple formula, and the Medium read time was born.</p>
|
||||||
|
<figure class="ij ik il im in io da db paragraph-image">
|
||||||
|
<div class="ip iq ir is ai">
|
||||||
|
<div class="da db ii">
|
||||||
|
<div class="iy r ir iz">
|
||||||
|
<div class="ja jb r">
|
||||||
|
<div class="it iu s t u iv ai br iw ix"><img alt="Image for post" class="s t u iv ai jc jd je"
|
||||||
|
src="https://miro.medium.com/max/60/1*wju0JzgNZVpPzZDgfchajg.png?q=20"
|
||||||
|
width="180" height="58"/></div>
|
||||||
|
<img alt="Image for post" class="it iu s t u iv ai jf" width="180" height="58"/>
|
||||||
|
<noscript><img alt="Image for post" class="s t u iv ai"
|
||||||
|
src="https://miro.medium.com/max/360/1*wju0JzgNZVpPzZDgfchajg.png" width="180"
|
||||||
|
height="58"/></noscript>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</figure>
|
||||||
|
<p id="8a5b" class="ht hu as hv b fa hw hx fd hy hz ia ib fi ic id fl ie if fo ig di ih">With the widespread
|
||||||
|
adoption of this feature across the internet, we decided to shed some light on exactly what goes in to our read time
|
||||||
|
calculation.</p>
|
||||||
|
<blockquote class="jg"><p id="13d1" class="jh ji as eh b jj jk jl jm jn jo ig aw">Read time is based on the average
|
||||||
|
reading speed of an adult (roughly 275 WPM). We take the total word count of a post and translate it into minutes.
|
||||||
|
Then, we add 12 seconds for each inline image. <strong class="be">Boom, read time.</strong></p></blockquote>
|
||||||
|
<p id="17fc" class="ht hu as hv b fa jp hx fd jq hz ia jr fi ic js fl ie jt fo ig di ih">Lately, we have seen more and
|
||||||
|
more long form stories containing a ton of images. With our release of <a
|
||||||
|
href="https://medium.com/the-story/introducing-image-grids-c592e5bc16d8" class="co he ju jv jw jx"
|
||||||
|
target="_blank" rel="noopener">image grids</a>, we expect even more of these types of essays.</p>
|
||||||
|
<p id="c072" class="ht hu as hv b fa hw hx fd hy hz ia ib fi ic id fl ie if fo ig di ih">Our original read time
|
||||||
|
calculation was geared toward “slow” images, like comics, where you would really want to sit down and invest in the
|
||||||
|
image. This resulted in articles with crazy big read times. For instance, this <a
|
||||||
|
href="https://medium.com/@dahul/inside-medium-94931f66eebd" class="co he ju jv jw jx" target="_blank"
|
||||||
|
rel="noopener">article</a> containing 140 images was clocking in at a whopping 87 minute read. So we amended
|
||||||
|
our read time calculation to count 12 seconds for the first image, 11 for the second, and minus an additional second
|
||||||
|
for each subsequent image. Any images after the tenth image are counted at three seconds.</p>
|
||||||
|
<p id="fbc9" class="ht hu as hv b fa hw hx fd hy hz ia ib fi ic id fl ie if fo ig di ih">You might see this change
|
||||||
|
reflected across the site. Keep in mind that our estimated read time is just that: <em class="jy">an estimation</em>.
|
||||||
|
You might finish a story faster or slower depending on various factors such as how many children or cats you have,
|
||||||
|
your caffeine/alcohol intake, or if you’re a time-traveler from the future and already read that story. We just want
|
||||||
|
to give you a ballpark figure so you can decide whether you have time to read one more story before the bus comes,
|
||||||
|
or if you should bookmark it for later.</p>
|
||||||
|
<p id="369b" class="ht hu as hv b fa hw hx fd hy hz ia ib fi ic id fl ie if fo ig di ih">We aren’t done with read time
|
||||||
|
yet. In the future, we’d like to tailor it to your reading speed, account for the <a
|
||||||
|
href="https://medium.com/@fchimero/this-should-only-take-a-minute-or-four-probably-e38bb7bf2adf"
|
||||||
|
class="co he ju jv jw jx" target="_blank" rel="noopener">complexity of an article</a>, and add support for
|
||||||
|
other languages. We’ll be sure to let you know about these changes as they happen.</p>
|
45
src/test/resources/post.html
Normal file
45
src/test/resources/post.html
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<h1>HTML Ipsum Presents</h1>
|
||||||
|
|
||||||
|
<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
|
||||||
|
|
||||||
|
<h2>Header Level 2</h2>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
|
||||||
|
<li>Aliquam tincidunt mauris eu risus.</li>
|
||||||
|
<li><img src="#"></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<blockquote><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.</p></blockquote>
|
||||||
|
|
||||||
|
<h3>Header Level 3</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
|
||||||
|
<li>Aliquam tincidunt mauris eu risus.</li>
|
||||||
|
<li><img src="#"></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Header Level 4</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
|
||||||
|
<li>Aliquam tincidunt mauris eu risus.</li>
|
||||||
|
<li><img src="#"></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Header Level 5</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
|
||||||
|
<li>Aliquam tincidunt mauris eu risus.</li>
|
||||||
|
<li><img src="#"></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<pre><code>
|
||||||
|
#header h1 a {
|
||||||
|
display: block;
|
||||||
|
width: 300px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
</code></pre>
|
Loading…
Add table
Add a link
Reference in a new issue