├── ImpfQuoten.js ├── LICENSE ├── README.md └── img ├── error.png ├── pic1.png ├── pic2.png ├── pic3.png ├── pic4.png ├── pic5.png ├── pic6.png ├── widget1.png └── widget2.png /ImpfQuoten.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: deep-green; icon-glyph: syringe; 4 | // 5 | // Script für https://scriptable.app 6 | // iOS Widget zur Anzeige der gegen COVID-19 geimpften Personenzahl. 7 | // Die Quote der Geimpften mit Bezug auf die Bevölkerung von Deutschland oder eines gewählten Bundeslands. 8 | // Zusätzlich werden die Zahlen mit einem Fortschrittsbalken visualisiert. 9 | // Konfiguriert als Widget Medium. Schaltet automatisch auch in den DarkMode. 10 | // 11 | // Script by MacSchierer, 03.05.2022, v2.3 12 | // Download der aktuellen Version hier: GitHub https://github.com/MacSchierer/ImpfQuote 13 | // https://fckaf.de/Bn0 14 | // 15 | // Verwendet die bereitgestellte Robert Koch-Institut COVID-19 API - von Marlon Lückert 16 | // https://api.corona-zahlen.org, https://github.com/marlon360/rki-covid-api 17 | 18 | // 19 | // Optionale Konfiguration 20 | // 21 | // Individuelle Farbstufen für die Impfquote: 22 | // Rot = Step1st < 25, Grün = Step2nd > 85, Dazwischen Orange, Ziel > 85 = "Herdenimmunität" 23 | const Step1st = 25 24 | const Step2nd = 85 25 | const StepFin = 100 26 | 27 | debug = false 28 | 29 | // 30 | // Ab hier nichts ändern 31 | // 32 | let APIurl = "https://api.corona-zahlen.org/vaccinations" 33 | let hasError = false 34 | let ErrorTxt = "" 35 | let RegionKey= "Deutschland" 36 | 37 | const BarWidth = 15 38 | const BarHeigth = 105 39 | 40 | let param = args.widgetParameter // Abfrage des Parameters vom Widget 41 | if (debug) {param = "de"} 42 | if (param != null && param.length > 0) { 43 | param = param.toUpperCase() 44 | if (setRegionKey(param) != false) { 45 | RegionKey = setRegionKey(param) 46 | RegionKey = param 47 | } 48 | else { 49 | hasError = true 50 | ErrorTxt += "Bundesland konnte nicht zugeordnet werden.\r\rBitte überprüfe den Parameter im Widget." 51 | } 52 | } 53 | 54 | try { 55 | AllItems = await loadItems(APIurl) 56 | } catch (e) { 57 | hasError = true 58 | ErrorTxt += "Das Widget konnte keine Daten abrufen." 59 | } 60 | 61 | try { 62 | if (RegionKey != "DE") { 63 | RegItems = AllItems.data.states[RegionKey] 64 | RegionName = RegItems.name 65 | } else { 66 | RegItems = AllItems.data 67 | RegionName = "Deutschland" 68 | } 69 | 70 | // Daten zuordnen 71 | Vacc1st = RegItems.vaccinated 72 | QuoteVacc1st = RegItems.quote*100 73 | DeltaVacc1st = RegItems.delta 74 | Vacc2nd = RegItems.secondVaccination.vaccinated 75 | QuoteVacc2nd = RegItems.secondVaccination.quote*100 76 | DeltaVacc2nd = RegItems.secondVaccination.delta 77 | Booster1st = RegItems.boosterVaccination.vaccinated 78 | QuoteBooster1st = RegItems.boosterVaccination.quote*100 79 | DeltaBooster1st = RegItems.boosterVaccination.delta 80 | Booster2nd = RegItems['2ndBoosterVaccination'].vaccinated 81 | QuoteBooster2nd = RegItems['2ndBoosterVaccination'].quote*100 82 | DeltaBooster2nd = RegItems['2ndBoosterVaccination'].delta 83 | 84 | if(debug){ 85 | log("Region: " + RegionName) 86 | log("Vacc1st: " + Vacc1st + ", " + QuoteVacc1st + ", " + DeltaVacc1st) 87 | log("Vacc2nd: " + Vacc2nd + ", " + QuoteVacc2nd + ", " + DeltaVacc2nd) 88 | log("Booster1st: " + Booster1st + ", " + QuoteBooster1st + ", " + DeltaBooster1st) 89 | log("Booster2nd: " + Booster2nd + ", " + QuoteBooster2nd + ", " + DeltaBooster2nd) 90 | log("Stand: " + AllItems.meta.lastCheckedForUpdate) 91 | } 92 | 93 | } catch (e) { 94 | hasError = true 95 | ErrorTxt += "Beim Verarbeiten der Daten ist ein Fehler aufgetreten.\r\r" 96 | ErrorTxt += "API: " + AllItems.message 97 | } 98 | 99 | // Fraben definieren 100 | WidgetBgColor = Color.dynamic(new Color("#fefefe"), new Color("#1e1e1e")) 101 | ContentBGColor = Color.dynamic(new Color("#efefef"), new Color("#444444")) 102 | MainTextColor = Color.dynamic(new Color("#000000"), new Color("#ffffff")) 103 | SubTextColor = Color.dynamic(new Color("#666666"), new Color("#aaaaaa")) 104 | TitelColor = MainTextColor 105 | BarTextColor1 = Color.dynamic(new Color("#ffffff"), new Color("#000000")) 106 | BarTextColor2 = Color.dynamic(new Color("#000000"), new Color("#ffffff")) 107 | 108 | // Ausgabe aufgelaufene Fehler oder Widget 109 | if (hasError == true) { 110 | let widget = errorWidget(ErrorTxt) 111 | Script.setWidget(widget) 112 | widget.presentMedium() 113 | Script.complete() 114 | } else { 115 | 116 | const widget = new ListWidget() 117 | widget.backgroundColor = WidgetBgColor 118 | widget.setPadding(15, 15, 15, 15) 119 | const Title = widget.addStack() 120 | let TitleText = Title.addText("COVID-19 Impfungen") 121 | TitleText.textColor = TitelColor 122 | TitleText.font = Font.boldSystemFont(12) 123 | TitleText.minimumScaleFactor = 0.5 124 | TitleText.lineLimit = 1 125 | Title.addSpacer() 126 | widget.borderWidth = 1 127 | widget.borderColor = MainTextColor 128 | let DateText = Title.addDate(new Date(AllItems.meta.lastCheckedForUpdate)) 129 | DateText.textColor = SubTextColor 130 | DateText.applyDateStyle() 131 | DateText.font = Font.boldSystemFont(8) 132 | const SubTitle = widget.addStack() 133 | let SubTitleText = SubTitle.addText(RegionName) 134 | SubTitleText.font = Font.systemFont(10) 135 | SubTitleText.textColor = SubTextColor 136 | SubTitleText.lineLimit = 1 137 | widget.addSpacer(2) 138 | 139 | const Content = widget.addStack() 140 | Content.setPadding(2,2,2,2) 141 | Content.layoutHorizontally() 142 | 143 | const Stack1 = Content.addStack() 144 | Stack1.layoutVertically() 145 | Stack1.backgroundColor = ContentBGColor 146 | Stack1.cornerRadius = 4 147 | Stack1.setPadding(4,4,4,4) 148 | const Stack1Head = Stack1.addStack() 149 | Stack1Head.addSpacer() 150 | let Title1stText = Stack1Head.addText("Vollständig") 151 | Title1stText.textColor = MainTextColor 152 | Title1stText.font = Font.boldSystemFont(14) 153 | Stack1Head.addSpacer() 154 | Stack1.addSpacer(4) 155 | const Stack1Vacc = Stack1.addStack() 156 | Stack1Vacc.addSpacer() 157 | let VaccFullText = Stack1Vacc.addText(Vacc2nd.toLocaleString('de-DE')) 158 | VaccFullText.textColor = MainTextColor 159 | VaccFullText.font = Font.boldSystemFont(14) 160 | Stack1Vacc.addSpacer() 161 | const Stack1Diff = Stack1.addStack() 162 | Stack1Diff.addSpacer() 163 | let DiffFullText = Stack1Diff.addText("+" + DeltaVacc2nd.toLocaleString('de-DE')) 164 | DiffFullText.textColor = SubTextColor 165 | DiffFullText.font = Font.systemFont(12) 166 | Stack1Diff.addSpacer() 167 | Stack1.addSpacer(4) 168 | const Stack1Percent = Stack1.addStack() 169 | Stack1Percent.layoutHorizontally() 170 | Stack1Percent.centerAlignContent() 171 | Stack1Percent.addSpacer() 172 | let QuoteFullText = Stack1Percent.addText((QuoteVacc2nd.toLocaleString('de-DE')).replace('.', ',')) 173 | QuoteFullText.textColor = MainTextColor 174 | QuoteFullText.font = Font.boldSystemFont(28) 175 | QuoteFullEin = Stack1Percent.addText("%") 176 | QuoteFullEin.textColor = SubTextColor 177 | QuoteFullEin.font = Font.systemFont(14) 178 | Stack1Percent.addSpacer() 179 | Stack1.addSpacer() 180 | Content.addSpacer() 181 | const BarContent1 = Content.addStack() 182 | BarContent1.layoutVertically() 183 | const progressBar1st = BarContent1.addImage(creatProgress(QuoteVacc2nd, QuoteVacc1st)) 184 | progressBar1st.cornerRadius = 4 185 | progressBar1st.imageSize = new Size(BarWidth, BarHeigth) 186 | 187 | Content.addSpacer() 188 | 189 | const BarContent2 = Content.addStack() 190 | BarContent2.layoutVertically() 191 | const progressBar2nd = BarContent2.addImage(creatProgress(QuoteBooster1st, QuoteBooster2nd)) 192 | progressBar2nd.cornerRadius = 4 193 | progressBar2nd.imageSize = new Size(BarWidth, BarHeigth) 194 | Content.addSpacer() 195 | const Stack2 = Content.addStack() 196 | Stack2.layoutVertically() 197 | Stack2.backgroundColor = ContentBGColor 198 | Stack2.cornerRadius = 4 199 | Stack2.setPadding(4,4,4,4) 200 | const Stack2Head = Stack2.addStack() 201 | Stack2Head.addSpacer() 202 | let Title2ndText = Stack2Head.addText("Auffrischung") 203 | Title2ndText.textColor = MainTextColor 204 | Title2ndText.font = Font.boldSystemFont(14) 205 | Stack2Head.addSpacer() 206 | Stack2.addSpacer(4) 207 | const Stack2Vacc = Stack2.addStack() 208 | Stack2Vacc.addSpacer() 209 | let VaccBoosterText = Stack2Vacc.addText(Booster1st.toLocaleString('de-DE')) 210 | VaccBoosterText.textColor = MainTextColor 211 | VaccBoosterText.font = Font.boldSystemFont(14) 212 | Stack2Vacc.addSpacer() 213 | const Stack2Diff = Stack2.addStack() 214 | Stack2Diff.addSpacer() 215 | let DiffBoosterText = Stack2Diff.addText("+" + DeltaBooster1st.toLocaleString('de-DE')) 216 | DiffBoosterText.textColor = SubTextColor 217 | DiffBoosterText.font = Font.systemFont(12) 218 | Stack2Diff.addSpacer() 219 | Stack2.addSpacer(4) 220 | const Stack2Percent = Stack2.addStack() 221 | Stack2Percent.layoutHorizontally() 222 | Stack2Percent.centerAlignContent() 223 | Stack2Percent.addSpacer() 224 | let QuoteBoosterText = Stack2Percent.addText((QuoteBooster1st.toLocaleString('de-DE')).replace('.', ',')) 225 | QuoteBoosterText.textColor = MainTextColor 226 | QuoteBoosterText.font = Font.boldSystemFont(28) 227 | QuoteBoosterEin = Stack2Percent.addText("%") 228 | QuoteBoosterEin.textColor = SubTextColor 229 | QuoteBoosterEin.font = Font.systemFont(14) 230 | Stack2Percent.addSpacer() 231 | Stack2.addSpacer() 232 | 233 | // Ausgabe 234 | if (!config.runsInWidget) { 235 | await widget.presentMedium() 236 | } else { 237 | Script.setWidget(widget) 238 | } 239 | Script.complete() 240 | } 241 | 242 | // 243 | // Error Widget 244 | // 245 | function errorWidget(reason){ 246 | let w = new ListWidget() 247 | w.setPadding(5,5,5,5) 248 | let myGradient = new LinearGradient() 249 | w.backgroundColor = new Color("#933") 250 | myGradient.colors = [new Color("#990000"), new Color("#ff0000")] 251 | myGradient.locations = [0.0,1] 252 | w.backgroundGradient = myGradient 253 | let title = w.addText("Fehler") 254 | title.centerAlignText() 255 | title.textColor = Color.white() 256 | title.font = Font.semiboldSystemFont(24) 257 | title.minimumScaleFactor = 0.5 258 | let reasonText = w.addText(reason) 259 | reasonText.centerAlignText() 260 | reasonText.textColor = Color.white() 261 | reasonText.font = Font.semiboldSystemFont(12) 262 | reasonText.minimumScaleFactor = 0.5 263 | return w 264 | } 265 | 266 | // 267 | // JSON holen 268 | // 269 | async function loadItems(APIurl) { 270 | let req = new Request(APIurl) 271 | let json = await req.loadJSON() 272 | return json 273 | } 274 | 275 | function creatProgress(BarValue1, BarValue2) { 276 | BarValue1 = Math.round(BarValue1) 277 | BarValue2 = Math.round(BarValue2) 278 | const context = new DrawContext() 279 | context.size = new Size(BarWidth, BarHeigth) 280 | context.opaque = false 281 | context.respectScreenScale = true 282 | // BG 283 | const path = new Path() 284 | path.addRoundedRect(new Rect(0, 0, BarWidth, BarHeigth),4,4) 285 | context.addPath(path) 286 | context.setFillColor(ContentBGColor) 287 | context.fillPath() 288 | // BarValue1 289 | if (BarValue1 < Step1st) {BarColor1 = new Color("#bb1e10")} 290 | if (BarValue2 < Step1st) {BarColor2 = new Color("#bb1e1075")} 291 | 292 | if (BarValue1 >= Step1st && BarValue1 < Step2nd) {BarColor1 = new Color("#f7b500")} 293 | else if (BarValue1 >= Step2nd) {BarColor1 = new Color("#00b347")} 294 | 295 | if (BarValue2 >= Step1st && BarValue2 < Step2nd) {BarColor2 = new Color("#f7b50075")} 296 | else if (BarValue2 >= Step2nd) {BarColor2 = new Color("#00b34775")} 297 | 298 | // BarValue2 299 | context.setFillColor(BarColor2) 300 | const path2 = new Path() 301 | const path2BarHeigth = (BarHeigth * (BarValue2 / StepFin) > BarHeigth) ? BarHeigth : BarHeigth * (BarValue2 / StepFin) 302 | path2.addRoundedRect(new Rect(0, BarHeigth, BarWidth, -path2BarHeigth),2,2) 303 | context.addPath(path2) 304 | context.fillPath() 305 | 306 | // BarValue1 307 | context.setFillColor(BarColor1) 308 | const path1 = new Path() 309 | const path1BarHeigth = (BarHeigth * (BarValue1 / StepFin) > BarHeigth) ? BarHeigth : BarHeigth * (BarValue1 / StepFin) 310 | path1.addRoundedRect(new Rect(0, BarHeigth, BarWidth, -path1BarHeigth),2,2) 311 | context.addPath(path1) 312 | context.fillPath() 313 | 314 | context.setFont(Font.boldSystemFont(8)) 315 | context.setTextAlignedCenter() 316 | if (BarValue1 < 90) { 317 | context.setTextColor(SubTextColor) 318 | context.drawTextInRect("%", new Rect(0, 3, BarWidth, BarHeigth)) 319 | } else { 320 | context.setTextColor(BarTextColor1) 321 | context.drawTextInRect("%", new Rect(0, BarHeigth-15, BarWidth, BarHeigth)) 322 | } 323 | if (BarValue1 < 10) { 324 | PosCorr = -10 325 | context.setTextColor(BarTextColor2) 326 | } 327 | else { 328 | PosCorr = 2 329 | context.setTextColor(BarTextColor1) 330 | } 331 | context.drawTextInRect(BarValue1.toString(), new Rect(0, BarHeigth-path1BarHeigth+PosCorr, BarWidth, path1BarHeigth-PosCorr)) 332 | return context.getImage() 333 | } 334 | 335 | // 336 | // Regionen und Widgetparameter 337 | // 338 | function setRegionKey(Region) { 339 | let Regions = { BW: "Baden-Württemberg", BY: "Bayern", BE: "Berlin", BB: "Brandenburg", HB: "Bremen", HH: "Hamburg", HE: "Hessen", MV: "Mecklenburg-Vorpommern", NI: "Niedersachsen", NW: "Nordrhein-Westfalen", RP: "Rheinland-Pfalz", SL: "Saarland", SN: "Sachsen", ST: "Sachsen-Anhalt", SH: "Schleswig-Holstein", TH: "Thüringen", DE: "Deutschland" }; 340 | if (Regions.hasOwnProperty(Region)) { 341 | result = Regions[Region] 342 | } else { 343 | result = false 344 | } 345 | return result 346 | } 347 | 348 | 349 | // End of Script 350 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 MacSchierer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ImpfQuoten, Ein Scriptable Widget 2 | Ein Scriptable Widget zur Anzeige der gegen COVID-19 geimpften Personenzahl. 3 | Die Quote der Geimpften mit Bezug auf die Bevölkerung von Deutschland oder eines gewählten Bundeslands.
4 | Zusätzlich werden die Zahlen mit einem Fortschrittsbalken visualisiert.

5 |  

6 | Zahlen zu vollständig Geimpften und Auffrischimpfungen (Booster):
7 | - Anzahl der Geimpften
8 | - Differenz zum Vortag
9 | - Prozentsatz mit Bezug auf die Bevölkerung
10 | 11 | ## Verwendung 12 | 13 | * Download Scriptable App für iOS Geräte - https://scriptable.app 14 | * Download/Import der ImpfQuoten.js Datei nach iCloud/Scriptable 15 | * Auf dem Homescreen ein neues mittleres Scriptable Widget erstellen - Parameter für Bundesland optional
16 |  

17 | Das Skript ist aktuell für die mittlere Widgetgröße ausgelegt und wurde auf einem iPhone 12Pro, Xs getestet.
18 | Auf anderen Geräten oder Widgetgrößen kann es ggf. zu Abweichungen in der Darstellung kommen. 19 | 20 | ## Features 21 | 22 | * Quelle der Daten: Robert Koch-Institut COVID-19 API - von Marlon Lückert >> https://api.corona-zahlen.org 23 | * Über den Parameter des Widgets kann ein Bundesland vorgegben werden. Kürzel nach ISO 3166-2:DE 24 | * Wechselt gemäß der Geräteeinstellung automatisch in den Darkmode 25 | * Individuelle Farbstufen für die Impfquote: Rot = Step1st < 25, Grün = Step2nd > 85, Dazwischen Orange, Ziel > 85 = "Herdenimmunität" 26 | 27 | ## Kürzel für den Parameter des Widgets 28 | BW = Baden-Württemberg
29 | BY = Bayern
30 | BE = Berlin
31 | BB = Brandenburg
32 | HB = Bremen
33 | HH = Hamburg
34 | HE = Hessen
35 | MV = Mecklenburg-Vorpommern
36 | NI = Niedersachsen
37 | NW = Nordrhein-Westfalen
38 | RP = Rheinland-Pfalz
39 | SL = Saarland
40 | SN = Sachsen
41 | ST = Sachsen-Anhalt
42 | SH = Schleswig-Holstein
43 | TH = Thüringen
44 | DE = Deutschland 45 | 46 | 47 | ## Beispiele 48 |  

49 |  

50 | ## Bekannte Probleme 51 | 52 | * Fortschrittsbalken wechselt nicht direkt in das zugehörige Erscheinungsbild (hell/dunkel) 53 | * Tritt ein Fehler beim Datenabruf auf, wird eine Fehlermeldung angezeigt:
54 |

55 | 56 | ## Changelog 57 | * v2.3 Neue API >> Robert Koch-Institut COVID-19 API - von Marlon Lückert 58 | * v2.1 Fix %-Zeichen, Erstimpfungen werden im linken Fortschirttsbalken schattiert im Hintergrund dargestellt 59 | * v2.0 Anzeige: Impfquote vollständig geimpft, Impfquote Auffrischimpfung 60 | * v1.3 Impfquoten angepasst, API V2 - https://github.com/ThisIsBenny/rki-vaccination-data 61 | * v1.2 Kleine Korrekturen: Farben, Dezimaltrenner 62 | * v1.1 Anzeige der Erstimpfungen als kleines Widget 63 | * v1.0 Release GitHub 64 | 65 | ## Hinweis zur Quelle und Datenstand 66 | Verwendet die bereitgestellte Robert Koch-Institut COVID-19 API - von Marlon Lückert
67 | https://api.corona-zahlen.org, https://github.com/marlon360/rki-covid-api
68 | -------------------------------------------------------------------------------- /img/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/error.png -------------------------------------------------------------------------------- /img/pic1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/pic1.png -------------------------------------------------------------------------------- /img/pic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/pic2.png -------------------------------------------------------------------------------- /img/pic3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/pic3.png -------------------------------------------------------------------------------- /img/pic4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/pic4.png -------------------------------------------------------------------------------- /img/pic5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/pic5.png -------------------------------------------------------------------------------- /img/pic6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/pic6.png -------------------------------------------------------------------------------- /img/widget1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/widget1.png -------------------------------------------------------------------------------- /img/widget2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacSchierer/ImpfQuoten/fcdd3ea7df7c66a13453a50a6bdd81db5b8b0ca7/img/widget2.png --------------------------------------------------------------------------------