Initial commit
This commit is contained in:
234
.gitignore
vendored
Normal file
234
.gitignore
vendored
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/node,webstorm
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=node,webstorm
|
||||||
|
|
||||||
|
### Node ###
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional stylelint cache
|
||||||
|
.stylelintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
.env*.local
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Storybook build outputs
|
||||||
|
.out
|
||||||
|
.storybook-out
|
||||||
|
storybook-static
|
||||||
|
|
||||||
|
# rollup.js default build output
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# Temporary folders
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
|
||||||
|
### WebStorm ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### WebStorm Patch ###
|
||||||
|
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||||
|
|
||||||
|
# *.iml
|
||||||
|
# modules.xml
|
||||||
|
# .idea/misc.xml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||||
|
.idea/**/sonarlint/
|
||||||
|
|
||||||
|
# SonarQube Plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||||
|
.idea/**/sonarIssues.xml
|
||||||
|
|
||||||
|
# Markdown Navigator plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||||
|
.idea/**/markdown-navigator.xml
|
||||||
|
.idea/**/markdown-navigator-enh.xml
|
||||||
|
.idea/**/markdown-navigator/
|
||||||
|
|
||||||
|
# Cache file creation bug
|
||||||
|
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||||
|
.idea/$CACHE_FILE$
|
||||||
|
|
||||||
|
# CodeStream plugin
|
||||||
|
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||||
|
.idea/codestream.xml
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/node,webstorm
|
||||||
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
6
.idea/jsLibraryMappings.xml
generated
Normal file
6
.idea/jsLibraryMappings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptLibraryMappings">
|
||||||
|
<includedPredefinedLibrary name="Node.js Core" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/wannistesvorbei.iml" filepath="$PROJECT_DIR$/.idea/wannistesvorbei.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
11
.idea/wannistesvorbei.iml
generated
Normal file
11
.idea/wannistesvorbei.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
4
.idea/watcherTasks.xml
generated
Normal file
4
.idea/watcherTasks.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectTasksOptions" suppressed-tasks="Pug/Jade" />
|
||||||
|
</project>
|
||||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM node:15-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY ./public /app/public
|
||||||
|
COPY ./src /app/src
|
||||||
|
COPY ./views /app/views
|
||||||
|
COPY ./package.json /app/package.json
|
||||||
|
COPY ./package-lock.json /app/package-lock.json
|
||||||
|
COPY ./tsconfig.json /app/tsconfig.json
|
||||||
|
|
||||||
|
RUN npm install && ./node_modules/.bin/tsc && rm -rf node_modules src tsconfig.json
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
RUN npm install --only=production && rm -rf package-lock.json
|
||||||
|
|
||||||
|
ENTRYPOINT npm start
|
||||||
|
EXPOSE 3000
|
||||||
2345
package-lock.json
generated
Normal file
2345
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
package.json
Normal file
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "wannistesvorbei",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"start": "node ./dist/index.js",
|
||||||
|
"dev": "tsc-watch --onSuccess \"node ./dist/index.js\""
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/express": "^4.17.11",
|
||||||
|
"@types/node": "^14.14.41",
|
||||||
|
"@types/node-fetch": "^2.5.10",
|
||||||
|
"@types/pug": "^2.0.4",
|
||||||
|
"tsc-watch": "^4.2.9",
|
||||||
|
"typescript": "^4.2.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"pug": "^3.0.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
public/homescreen.png
Normal file
BIN
public/homescreen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
15
public/manifest.json
Normal file
15
public/manifest.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "Wie lange noch?",
|
||||||
|
"short_name": "Corona-Uhr",
|
||||||
|
"lang": "de-DE",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"orientation": "any",
|
||||||
|
"theme_color": "#FD1D1D",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "homescreen.png",
|
||||||
|
"sizes": "172x172"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
14
public/script.js
Normal file
14
public/script.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
function onloaded() {
|
||||||
|
const elems = document.getElementsByClassName("big-number");
|
||||||
|
for (let i = 0; i < elems.length; i++) {
|
||||||
|
const elem = elems[i];
|
||||||
|
elem.innerText = parseInt(elem.dataset.value).toLocaleString();
|
||||||
|
}
|
||||||
|
const megaElems = document.getElementsByClassName("mega-date");
|
||||||
|
for (let i = 0; i < megaElems.length; i++) {
|
||||||
|
const elem = megaElems[i];
|
||||||
|
const date = new Date();
|
||||||
|
date.setTime(elem.dataset.value);
|
||||||
|
elem.innerText = date.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' });
|
||||||
|
}
|
||||||
|
}
|
||||||
78
public/style.css
Normal file
78
public/style.css
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
html {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Lato', sans-serif;
|
||||||
|
color: white;
|
||||||
|
background: rgb(131,58,180);
|
||||||
|
background: linear-gradient(11deg, rgba(131,58,180,1) 0%, rgba(253,29,29,1) 50%, rgb(255,171,13) 100%);
|
||||||
|
margin: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index {
|
||||||
|
font-size: 30pt;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.index p {
|
||||||
|
line-height: 40pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-number {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #41ffc3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mega-date {
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 50pt;
|
||||||
|
margin-top: 8rem;
|
||||||
|
margin-bottom: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin-top {
|
||||||
|
margin-top: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, a:visited {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #41ffc3;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1:not(:first-child) {
|
||||||
|
margin-top: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2:not(:first-child) {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3:not(:first-child) {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@media (max-width:600px) {
|
||||||
|
.index {
|
||||||
|
font-size: 20pt;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:400px) {
|
||||||
|
.index p {
|
||||||
|
line-height: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/index.ts
Normal file
53
src/index.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import * as express from "express";
|
||||||
|
import fetch from "node-fetch";
|
||||||
|
import {slice} from "./utils";
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const data = {
|
||||||
|
dayCount: 500000,
|
||||||
|
firstVac: 1400000,
|
||||||
|
secondVac: 5000000,
|
||||||
|
finalDate: new Date()
|
||||||
|
};
|
||||||
|
|
||||||
|
(async function fetchData() {
|
||||||
|
const res = await fetch("https://impfdashboard.de/static/data/germany_vaccinations_timeseries_v2.tsv");
|
||||||
|
const html = await res.text();
|
||||||
|
const arrayOfLines = html.split(/[\r\n]+/);
|
||||||
|
let sumOfTodays = 0;
|
||||||
|
let countDays = 0;
|
||||||
|
for (const line of slice(arrayOfLines, arrayOfLines.length-8)) {
|
||||||
|
const arr = line.split(/\s+/);
|
||||||
|
if (arr.length < 10) continue;
|
||||||
|
if (!Number.isNaN(+(arr[2]))) {
|
||||||
|
sumOfTodays += +(arr[2]);
|
||||||
|
countDays++;
|
||||||
|
}
|
||||||
|
data.firstVac = +(arr[5]) || data.firstVac;
|
||||||
|
data.secondVac = +(arr[9]) || data.secondVac;
|
||||||
|
}
|
||||||
|
data.dayCount = sumOfTodays / countDays;
|
||||||
|
const daysLeft = (83703925*2 - data.firstVac - data.secondVac) / data.dayCount * 0.8;
|
||||||
|
const date = new Date();
|
||||||
|
date.setTime(date.getTime() + daysLeft * 24 * 60 * 60 * 1000);
|
||||||
|
data.finalDate = date;
|
||||||
|
setTimeout(fetchData, 1000*60*60);
|
||||||
|
})()
|
||||||
|
|
||||||
|
app.set('view engine', 'pug')
|
||||||
|
app.set('views', './views')
|
||||||
|
app.use("/public", express.static("./public"))
|
||||||
|
app.get("/", (req, res) => {
|
||||||
|
res.render("index", data);
|
||||||
|
})
|
||||||
|
app.get("/impressum", (req, res) => {
|
||||||
|
res.render("impressum");
|
||||||
|
})
|
||||||
|
|
||||||
|
const listener = app.listen(
|
||||||
|
3000,
|
||||||
|
() => {
|
||||||
|
const addr = listener.address();
|
||||||
|
console.log(`App listening on port ${typeof addr === "object" ? addr.port : addr}!`);
|
||||||
|
}
|
||||||
|
)
|
||||||
12
src/utils.ts
Normal file
12
src/utils.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function* slice(src, start, finish = src.length) {
|
||||||
|
let index = 0;
|
||||||
|
for (const value of src) {
|
||||||
|
if (index >= finish) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (index >= start) {
|
||||||
|
yield value;
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es6",
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "dist"
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
||||||
97
views/impressum.pug
Normal file
97
views/impressum.pug
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
extends layout.pug
|
||||||
|
|
||||||
|
block body
|
||||||
|
- const mail = 'web<span style="display: none;">REMOVE</span>{at<!-- hehehe -->}s<!-- hehehe -->eb<span style="display: none;">DEL<!-- hehehe -->ETE</span>se[dot]de'
|
||||||
|
.impressum
|
||||||
|
h1 Impressum
|
||||||
|
h2 Angaben gemäß § 5 TMG:
|
||||||
|
p
|
||||||
|
| Sebastian Seedorf
|
||||||
|
h3 Postanschrift:
|
||||||
|
p
|
||||||
|
| Charlottenburger Ufer 3a
|
||||||
|
br
|
||||||
|
| 10587 Berlin
|
||||||
|
br
|
||||||
|
h3 Kontakt:
|
||||||
|
p E-Mail: !{mail}
|
||||||
|
h2 Information gemäß § 36 VSBG
|
||||||
|
p Gemäß § 36 VSBG (Verbraucherstreitbeilegungsgesetz – Gesetz über die alternative Streitbeilegung in Verbrauchersachen) erklärt der Betreiber dieser Website:
|
||||||
|
p Wir sind weder bereit noch verpflichtet, an Streitbeilegungsverfahren vor einer Verbraucherschlichtungsstelle teilzunehmen.
|
||||||
|
p
|
||||||
|
em
|
||||||
|
| Das Impressum wurde mit dem
|
||||||
|
a(href='https://www.activemind.de/datenschutz/impressums-generator/') Impressums-Generator der activeMind AG
|
||||||
|
| erstellt.
|
||||||
|
|
||||||
|
h1 Datenschutzerklärung
|
||||||
|
p Verantwortlicher im Sinne der Datenschutzgesetze, insbesondere der EU-Datenschutzgrundverordnung (DSGVO), ist:
|
||||||
|
p
|
||||||
|
| Sebastian Seedorf
|
||||||
|
br
|
||||||
|
| !{mail}
|
||||||
|
h2 Ihre Betroffenenrechte
|
||||||
|
p Unter den angegebenen Kontaktdaten unseres Datenschutzbeauftragten können Sie jederzeit folgende Rechte ausüben:
|
||||||
|
ul
|
||||||
|
li Auskunft über Ihre bei uns gespeicherten Daten und deren Verarbeitung (Art. 15 DSGVO),
|
||||||
|
li Berichtigung unrichtiger personenbezogener Daten (Art. 16 DSGVO),
|
||||||
|
li Löschung Ihrer bei uns gespeicherten Daten (Art. 17 DSGVO),
|
||||||
|
li Einschränkung der Datenverarbeitung, sofern wir Ihre Daten aufgrund gesetzlicher Pflichten noch nicht löschen dürfen (Art. 18 DSGVO),
|
||||||
|
li Widerspruch gegen die Verarbeitung Ihrer Daten bei uns (Art. 21 DSGVO) und
|
||||||
|
li Datenübertragbarkeit, sofern Sie in die Datenverarbeitung eingewilligt haben oder einen Vertrag mit uns abgeschlossen haben (Art. 20 DSGVO).
|
||||||
|
p Sofern Sie uns eine Einwilligung erteilt haben, können Sie diese jederzeit mit Wirkung für die Zukunft widerrufen.
|
||||||
|
p Sie können sich jederzeit mit einer Beschwerde an eine Aufsichtsbehörde wenden, z. B. an die zuständige Aufsichtsbehörde des Bundeslands Ihres Wohnsitzes oder an die für uns als verantwortliche Stelle zuständige Behörde.
|
||||||
|
p Eine Liste der Aufsichtsbehörden (für den nichtöffentlichen Bereich) mit Anschrift finden Sie unter:
|
||||||
|
a(href='https://www.bfdi.bund.de/DE/Infothek/Anschriften_Links/anschriften_links-node.html' target='_blank' rel='nofollow noopener')
|
||||||
|
| https://www.bfdi.bund.de/DE/Infothek/Anschriften_Links/anschriften_links-node.html
|
||||||
|
| .
|
||||||
|
h2 Erfassung allgemeiner Informationen beim Besuch unserer Website
|
||||||
|
h3 Art und Zweck der Verarbeitung:
|
||||||
|
p Wenn Sie auf unsere Website zugreifen, d.h., wenn Sie sich nicht registrieren oder anderweitig Informationen übermitteln, werden automatisch Informationen allgemeiner Natur erfasst. Diese Informationen (Server-Logfiles) beinhalten etwa die Art des Webbrowsers, das verwendete Betriebssystem, den Domainnamen Ihres Internet-Service-Providers, Ihre IP-Adresse und ähnliches.
|
||||||
|
p Sie werden insbesondere zu folgenden Zwecken verarbeitet:
|
||||||
|
ul
|
||||||
|
li Sicherstellung eines problemlosen Verbindungsaufbaus der Website,
|
||||||
|
li Sicherstellung einer reibungslosen Nutzung unserer Website,
|
||||||
|
li Auswertung der Systemsicherheit und -stabilität sowie
|
||||||
|
li zur Optimierung unserer Website.
|
||||||
|
p Wir verwenden Ihre Daten nicht, um Rückschlüsse auf Ihre Person zu ziehen. Informationen dieser Art werden von uns ggfs. anonymisiert statistisch ausgewertet, um unseren Internetauftritt und die dahinterstehende Technik zu optimieren.
|
||||||
|
h3 Rechtsgrundlage und berechtigtes Interesse:
|
||||||
|
p Die Verarbeitung erfolgt gemäß Art. 6 Abs. 1 lit. f DSGVO auf Basis unseres berechtigten Interesses an der Verbesserung der Stabilität und Funktionalität unserer Website.
|
||||||
|
h3 Empfänger:
|
||||||
|
p Empfänger der Daten sind ggf. technische Dienstleister, die für den Betrieb und die Wartung unserer Webseite als Auftragsverarbeiter tätig werden.
|
||||||
|
h3 Speicherdauer:
|
||||||
|
p Die Daten werden gelöscht, sobald diese für den Zweck der Erhebung nicht mehr erforderlich sind. Dies ist für die Daten, die der Bereitstellung der Website dienen, grundsätzlich der Fall, wenn die jeweilige Sitzung beendet ist.
|
||||||
|
p
|
||||||
|
h3 Bereitstellung vorgeschrieben oder erforderlich:
|
||||||
|
p Die Bereitstellung der vorgenannten personenbezogenen Daten ist weder gesetzlich noch vertraglich vorgeschrieben. Ohne die IP-Adresse ist jedoch der Dienst und die Funktionsfähigkeit unserer Website nicht gewährleistet. Zudem können einzelne Dienste und Services nicht verfügbar oder eingeschränkt sein. Aus diesem Grund ist ein Widerspruch ausgeschlossen.
|
||||||
|
h2 Verwendung von Scriptbibliotheken (Google Webfonts)
|
||||||
|
p Um unsere Inhalte browserübergreifend korrekt und grafisch ansprechend darzustellen, verwenden wir auf dieser Website „Google Web Fonts“ der Google LLC (1600 Amphitheatre Parkway, Mountain View, CA 94043, USA; nachfolgend „Google“) zur Darstellung von Schriften.
|
||||||
|
p
|
||||||
|
| Weitere Informationen zu Google Web Fonts finden Sie unter
|
||||||
|
a(href='https://developers.google.com/fonts/faq' rel='noopener nofollow' target='_blank') https://developers.google.com/fonts/faq
|
||||||
|
| und in der Datenschutzerklärung von Google:
|
||||||
|
a(href='https://www.google.com/policies/privacy/' rel='noopener nofollow' target='_blank') https://www.google.com/policies/privacy/
|
||||||
|
| .
|
||||||
|
h2 SSL-Verschlüsselung
|
||||||
|
p
|
||||||
|
| Um die Sicherheit Ihrer Daten bei der Übertragung zu schützen, verwenden wir dem aktuellen Stand der Technik entsprechende Verschlüsselungsverfahren (z. B. SSL) über HTTPS.
|
||||||
|
hr
|
||||||
|
h2 Information über Ihr Widerspruchsrecht nach Art. 21 DSGVO
|
||||||
|
h3 Einzelfallbezogenes Widerspruchsrecht
|
||||||
|
p Sie haben das Recht, aus Gründen, die sich aus Ihrer besonderen Situation ergeben, jederzeit gegen die Verarbeitung Sie betreffender personenbezogener Daten, die aufgrund Art. 6 Abs. 1 lit. f DSGVO (Datenverarbeitung auf der Grundlage einer Interessenabwägung) erfolgt, Widerspruch einzulegen; dies gilt auch für ein auf diese Bestimmung gestütztes Profiling im Sinne von Art. 4 Nr. 4 DSGVO.
|
||||||
|
p Legen Sie Widerspruch ein, werden wir Ihre personenbezogenen Daten nicht mehr verarbeiten, es sei denn, wir können zwingende schutzwürdige Gründe für die Verarbeitung nachweisen, die Ihre Interessen, Rechte und Freiheiten überwiegen, oder die Verarbeitung dient der Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen.
|
||||||
|
h3 Empfänger eines Widerspruchs
|
||||||
|
p
|
||||||
|
| Sebastian Seedorf
|
||||||
|
br
|
||||||
|
| !{mail}
|
||||||
|
hr
|
||||||
|
h2 Änderung unserer Datenschutzbestimmungen
|
||||||
|
p Wir behalten uns vor, diese Datenschutzerklärung anzupassen, damit sie stets den aktuellen rechtlichen Anforderungen entspricht oder um Änderungen unserer Leistungen in der Datenschutzerklärung umzusetzen, z.B. bei der Einführung neuer Services. Für Ihren erneuten Besuch gilt dann die neue Datenschutzerklärung.
|
||||||
|
h2 Fragen an den Datenschutzbeauftragten
|
||||||
|
p Wenn Sie Fragen zum Datenschutz haben, schreiben Sie uns bitte eine E-Mail oder wenden Sie sich direkt an die für den Datenschutz verantwortliche Person in unserer Organisation:
|
||||||
|
p
|
||||||
|
em
|
||||||
|
| Die Datenschutzerklärung wurde mithilfe der activeMind AG erstellt, den Experten für
|
||||||
|
a(href='https://www.activemind.de/datenschutz/datenschutzbeauftragter/' target='_blank' rel='noopener') externe Datenschutzbeauftragte
|
||||||
|
| (Version #2020-09-30).
|
||||||
21
views/index.pug
Normal file
21
views/index.pug
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
extends layout.pug
|
||||||
|
|
||||||
|
block body
|
||||||
|
.index
|
||||||
|
p
|
||||||
|
| Aktuell werden täglich  
|
||||||
|
span.big-number(data-value=Math.floor(dayCount)) #{Math.floor(dayCount)}
|
||||||
|
| Impfungen durchgeführt.  
|
||||||
|
span.big-number(data-value=firstVac) #{firstVac}
|
||||||
|
| haben bisher mindestens eine Impfung erhalten, davon  
|
||||||
|
span.big-number(data-value=secondVac) #{secondVac}
|
||||||
|
| schon die zweite Impfung.
|
||||||
|
p
|
||||||
|
| Wenn das so weiter geht, dann haben 80% am
|
||||||
|
p.mega-date(data-value=finalDate.getTime()) #{finalDate.toLocaleDateString(locale, { year: 'numeric', month: 'numeric', day: 'numeric' })}
|
||||||
|
p
|
||||||
|
| zwei Impfungen erhalten.
|
||||||
|
p.footer.margin-top Quelle:  
|
||||||
|
a(href="https://impfdashboard.de/") Offizelle Datensätze tagesaktuell bereitgestellt durch das RKI und das BMG
|
||||||
|
p.footer Quelle:  
|
||||||
|
a(href="/impressum") Impressum & Datenschutzerklärung
|
||||||
34
views/layout.pug
Normal file
34
views/layout.pug
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
doctype html
|
||||||
|
html(lang='de')
|
||||||
|
head
|
||||||
|
title Wann ist es vorbei?
|
||||||
|
meta(name='title' content='Wann ist es vorbei?')
|
||||||
|
meta(name='description' content='Wann sind endlich genug Leute geimpft? Wann kehrt endlich wieder Normalität ein?')
|
||||||
|
meta(name='keywords' content='Corona, Impfung, Datum, RKI, AstraZeneca, Normalität')
|
||||||
|
meta(name='robots' content='index, follow')
|
||||||
|
meta(http-equiv='Content-Type' content='text/html; charset=utf-8')
|
||||||
|
meta(name='language' content='German')
|
||||||
|
meta(name='revisit-after' content='7 days')
|
||||||
|
meta(name='author' content='Sebastian Seedorf')
|
||||||
|
|
||||||
|
// Webapp
|
||||||
|
link(rel='manifest' href='/public/manifest.json')
|
||||||
|
meta(name='mobile-web-app-capable' content='yes')
|
||||||
|
meta(name='apple-mobile-web-app-capable' content='yes')
|
||||||
|
meta(name='application-name' content='Corona-Uhr')
|
||||||
|
meta(name='apple-mobile-web-app-title' content='Corona-Uhr')
|
||||||
|
meta(name='theme-color' content='#FD1D1D')
|
||||||
|
meta(name='msapplication-navbutton-color' content='#FD1D1D')
|
||||||
|
meta(name='apple-mobile-web-app-status-bar-style' content='black-translucent')
|
||||||
|
meta(name='msapplication-starturl' content='/')
|
||||||
|
meta(name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no')
|
||||||
|
link(rel='icon' sizes='172x172' href='/public/homescreen.png')
|
||||||
|
link(rel='apple-touch-icon' sizes='172x172' href='/public/homescreen.png')
|
||||||
|
|
||||||
|
block scripts
|
||||||
|
script(src="/public/script.js")
|
||||||
|
link(rel="preconnect", href="https://fonts.gstatic.com")
|
||||||
|
link(rel="stylesheet", href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,900;1,400;1,900&display=swap")
|
||||||
|
link(rel="stylesheet", href="/public/style.css")
|
||||||
|
body(onload="onloaded()")
|
||||||
|
block body
|
||||||
Reference in New Issue
Block a user