Posts mit dem Label Programmierung werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Programmierung werden angezeigt. Alle Posts anzeigen

Donnerstag, 23. Januar 2025

Lernen - Informatik Grundlagen

Freies Material für den für Informatikunterricht (Codierung, Präsentationen über Hardware und Netzwerke, Grundkurs Informatik) findet sich auf der Website cpothmann.de von Christian Pothmann. Dies ist eine gute Ergänzung zum Thema Netzwerkgrundlagen - Lernen mit der kostenlosen Simulationssoftware "Filius".


Das Material steht unter der Lizenz CC BY-NC-SA 4.0 und orientiert sich an den Lehrplänen für Nordrhein-Westfalen.


Dies bietet einen guten Einstieg in die Themen Textverarbeitung, Scratch, Codierung, Präsentationen über Hardware und Netzwerke, Einführung in die OOP mit Java und mehr.

Sonntag, 6. November 2022

OpenStreetMap - Anstatt Google Maps in Android-Apps verwenden

Mit Hilfe der Bibliothek osmdroid können Entwicklern, auf OpenStreetMap-Karten in Android-Apps ähnlich komfortabel zuzugreifen wie auf Google-Maps-Karten. Durch Integration der Bibliothek OSMBonusPack ist sogar Routing und Geocoding möglich. Für den Einsatz auf Webseiten empfehle ich meinen Beitrag "Webseite mit interaktiver Karte ohne Google Maps? Leaflet.js".

Integration von osmdroid und OSMBonusPack

dependencies {
...
    implementation 'org.osmdroid:osmdroid-android:6.1.14'
    implementation 'com.github.MKergall:osmbonuspack:6.9.0'
}

Ein gutes Beispiel Projekt findet sich in der c't 23/2022 S. 138 oder unter https://gitlab.com/andreaslinke/lastlocation/-/tree/main/ .

Sonntag, 28. August 2022

Markdown - Basic Formatierungsinformationen

Viele Systeme verstehen mittlerweile Markdown, in diesem Beitrag gebe ich eine kleine Einführung für die die weit verbreitete Auszeichnungssprache. Der Vorteil, Texte im Markdown Format (.md) sind einfach zu schreiben und auch im reinen Quelltext sehr gut lesbar.


Mittlerweile verstehen alle möglichen Systeme die Sprache, siehe hierzu auch https://www.markdownguide.org/tools/. Mit Hilfe von Markdown Viewern, kann man diese in fast allen Browsern betrachten. Siehe z.B. https://simov.github.io => Markdown Viewer. 

John Grubers ursprüngliche Markdown-Spezifikation und GitHubs Markdown-Variante sind ein sehr guter Einstieg in das Thema. 

Editor: https://github.com/KDE/ghostwriter

Beispiel:

# ToDo Liste

- Einkaufen im Supermarkt
- [ ] Milch
- [x] Butter
- [ ] Zucker
- ~~Einkaufen beim Metzger~~
- [Blog] Artikel lesen

[Blog]: https://www.shemel.de

# Überschrift

## Unterüberschrift

*kursiv* und **fett**

Link zu einer Webseite [shemel.de](https://www.shemel.de)

> Zitat

>> Unter-Zitat

* Liste
* Liste

1. Eins
2. Zwei

+ Punkt
  1. Unterpunkt

```javascript
alert('Hello World')
```

# Tabelle

| Spalte 1 | Spalte 2 | Spalte 3 |
| -------- | -------- | -------- |
| Zeile    | Zeile    | Zeile    |


Montag, 8. August 2022

Lasttest - k6 Open Source load testing tool

Bei einem Lasttest werden bei dem zu testenden System Lasten erzeugt. Hierbei wird das Ziel verfolgt zu sehen, ob die Apllikation oder das System diese Last bewältigen kann. So sollte eine Webseite mehreren Besuchern gleichzeitig in akzeptabler Zeit eine Antwort (response) schicken können.


Einen einfachen Einstieg in Lasttests bietet K6, siehe https://k6.io/open-source/ .

Mit dem folgenden Beispiel werden bis zu 1.000 VUs innerhalb 30 sec erstellt:

import http from 'k6/http';
import { sleep } from 'k6';

export const options = {
  stages: [
    { duration: '10s', target: 50 },
    { duration: '10s', target: 100 },
    { duration: '10s', target: 500 },
    { duration: '30s', target: 1000 },
    { duration: '10s', target: 500 },
    { duration: '15s', target: 0 },
  ],
};

export default function () {
 http.get('http://localhost:8080');
 //sleep(1);
}

Quelle: https://github.com/jamct/php-performance/blob/main/load.js

Viele weitere Beispiele und Tutorials finden sich hier https://k6.io/docs/examples/ .

Sonntag, 12. Juni 2022

Programmierung - Halbierungsmethode (Wurzelfindung) mit Excel und Python inkl. Struktogramm

Mi Hilfe des Halbierungsverfahren, kann man Sie sich z.B. einer Wurzel nähern. Siehe auch https://de.wikibrief.org/wiki/Root-finding_algorithms => "Halbierungsmethode". Auf dieser Basis habe ich ein Struktogramm erstellt und eine Umsetzung mit Excel und Python realisiert.


Struktogramm

Dies wurde mit Hilfe des Struktogrammeditor, ein Tool des Lehrstuhls für Didaktik der Informatik der TU Dresden, erstellt.


Excel

Umsetzung in Excel (Halbierungsverfahren_Wurzel.xlsx) mit Hilfe der folgenden Formeln.


Python

Programmierung in Python (Halbierungsmethode_Wurzel.py), online ausführbar über:

 

z=float(input("Zahl ? "))
l=float(input("Linke Grenze ? "))
r=float(input("Rechte Grenze ? "))
n=float(input("Durchläufe ? "))

i=1
while i<=n:
    m=(l+r)/2
    if m**2<z:
        l=m
    else:
        r=m
    print(i, l, r)
    i=i+1

 

Quelle: c't 12/2022 S. 156

Freitag, 3. Juni 2022

Python - Generierung von QR-Code Bildern

Mit Hilfe der Python QR-Code-Generierungsbibliothek "qrcode" kann man ganz einfach QR-Code-Bilder generieren. Es ist auch mit "Pillow" möglich einen QR-Code in ein anderes Bild einzubetten oder ein Bild in einen QR-Code einzubetten. In diesem Beitrag zeige ich einige Beispiele.

Python QR-Code Bild-Generator: qrcode

Der QR-Code ist ein zweidimensionaler Code, der aus quadratischen schwarzen und weißen Punkten (Zellen) besteht, siehe auch https://de.wikipedia.org/wiki/QR-Code.

Python hat eine eigene Bibliothek zum Generieren von QR-Code-Bildern, siehe auch https://github.com/lincolnloop/python-qrcode.

Die Standardinstallation erfolgt mit dem folgenden Befehl:
pip install qrcode[pil]

Wenn man einen einfachen QR-Code erstellen möchte, funktioniert dies mit dem folgenden Befehl:
qr "Test Blog shemel.de" > qrcode.png

Hinweis: Ein QR-Code enthält nur eine Zeichenfolge (String).

QR-Code Bild mit Python erstellen

import qrcode

img = qrcode.make('https://www.shemel.de')

print(type(img))
print(img.size)

img.save('/home/hemel/qrcode_hemel_1.png')

Sollte der Fehler "AttributeError: module 'qrcode' has no attribute 'make'" erscheinen, bitte als Dateinamen NICHT qrcode.py wählen. Siehe auch https://github.com/lincolnloop/python-qrcode/issues/185.

Man kann auch mit Hilfe der QRCode-Klasse Details verändern:

qr = qrcode.QRCode(
    version=12,
    error_correction=qrcode.constants.ERROR_CORRECT_H,
    box_size=2,
    border=8
)
qr.add_data('htttps://www.shemel.de')
qr.make()
img = qr.make_image(fill_color="yellow", back_color="#23dda0")
img.save('/home/hemel/qrcode_hemel_2.png')


QR-Code in ein Bild einbetten

Mit Hilfe von PilImage kann man Image-Objekte direkt in andere Bilder einfügen bzw. einbetten.

Anbei ein Beispiel zum Einfügen des QR-Codes in der unteren rechten Ecke.

import qrcode
from PIL import Image

img_bg = Image.open('/home/hemel/blog.png')

qr = qrcode.QRCode(box_size=2)
qr.add_data('
htttps://www.shemel.de')
qr.make()
img_qr = qr.make_image()

pos = (img_bg.size[0] - img_qr.size[0], img_bg.size[1] - img_qr.size[1])

img_bg.paste(img_qr, pos)
img_bg.save('/home/hemel/qrcode_hemel_3.png')


QR-Code zum Bezahlen benutzen

Siehe auch c't 9/2022 S. 8 https://www.heise.de/select/ct/2022/9/softlinks/yb26?wt_mc=pred.red.ct.ct092022.008.softlink.softlink und https://de.wikipedia.org/wiki/EPC-QR-Code.

import qrcode

vwz = "Rechnung 123456789"
iban = "DE02100500000054540402"
bic = "BELADEBE"
recipient = "Beispielfirma Musterdörfer"
amount = 55.25
filename = "epc_qr"

# The docs can be found here: https://pypi.org/project/qrcode/
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M)

qr.add_data("BCD\n")
qr.add_data("002\n")
qr.add_data("1\n")
qr.add_data("SCT\n")
qr.add_data(bic+"\n")
qr.add_data(recipient[0:69]+"\n")
qr.add_data(iban+"\n")
qr.add_data("EUR"+str(amount)+"\n")
qr.add_data("\n")
qr.add_data("\n")
qr.add_data(vwz[0:139]+"\n")
qr.make(fit=True)
img = qr.make_image()
img.save(filename+".png")


Sonntag, 16. Mai 2021

JavaScript - DOM-Manipulationen mittels purem JavaScript

Das Document Object Model (DOM) beschreibt die Spezifikation einer Programmierschnittstelle, hierbei werden HTML- oder XML-Dokumente als Baumstruktur darstellt. Dabei repräsentiert jeder Knoten ein Objekt, welches wiederum ein Teil eines Dokumentes (z.B. eine Webseite) repräsentiert. In dem Beitrag möchte ich kurz auf die Möglichkeiten der DOM-Manipulationen per purem JavaScript eingehen.

Das Document Object Model (DOM) wird vom World Wide Web Consortium (W3C) definiert.

DOM-Knotenbaum einer Webseite

Mitte der 1990er Jahre wurde die Skriptsprache JavaScript erfunden, die Browser boten aber nur rudimentäre Möglichkeiten um auf das HTML-Dokument zuzugreigen oder das DOM zu manipulieren.
Dies führte zu einer Verbreitung von Bibliotheken wie zum Beispiel jQuery.
Mittlerweile kann man aber immer öfter auf JavaScript-Bibliotheken, die Funktionen zur DOM-Navigation und -Manipulation zur Verfügung stellen, verzichten!

Die folgenden Webseiten unterstützen dabei, Probleme von Frontend-Developern in purem JavaScript (ohne jQuery) lösen zu können

Hierdurch ist es möglich Webseiten von überflüssigen Bibliotheken zu befreien.

Siehe nachfolgendes Beispiel:

// With jQuery
// Update the text of a .button
$(".button").text("New text");
// Read the text of a .button
$(".button").text(); // Returns "New text"

// Without jQuery

// Update the text of a .button
document.querySelector(".button").textContent = "New text";
// Read the text of a .button
document.querySelector(".button").textContent; // Returns "New text"


Quelle: https://tobiasahlin.com/blog/move-from-jquery-to-vanilla-javascript/#updating-the-dom

Samstag, 2. Januar 2021

Android - (App) APK Decompiler und Quellcode anzeigen

Mit Hilfe von einem APK Decompiler wie z.B. "jadx - Dex to Java decompiler" ist es möglich eine kompilierte Android App wieder zurück in den Source Code umzuwandeln. Dies ist oft der erste Schritt um im Quellcode sensible Informationen (z.B. Passwörter eines Admin-Accounts oder Zugangsdaten zu Datenbanken bzw. Schnittstellen) zu finden.

Des Weiteren ist es möglich die Funktionsweise bzw. Programmierung der jeweiligen App genauer nachvollziehen umso IT-Security Schwachstellen zu finden. 


Die APK (Android Package Kit) Datei der Android App wird benötigt

Um an die Datei zu kommen, gibt es verschieden Möglichkeiten:

  1. APK Datei vom Smartphone auf PC kopieren mit Hilfe von ADB, wie man die Android Debug Bridge installieren kann, hatte ich bereits in einem älteren Artikel ABD Installation Amazon Fire-Tablet - Spezialangebote (Werbung) entfernen beschrieben.
    • adb shell pm list packages (z.B. "com.example.appname")
    • adb shell pm path com.example.appname (Pfadnamen der App anzeigen)
    • adb pull /data/app/com.example.appname-2.apk D:\Downloads
  2. Installierte Apps im Total Commander anzeigen und auf die SD-Karte oder WebDAV kopieren.
  3. Mit Hilfe von Sideloading die Android-App aus einem anderen Marketplace herunterladen.

Update 05.06.2022

APK-Quellen im Internet:


Dekompilieren

Mit einem Dekompilier wandelt man den Bytecode (Maschinen- oder Objektcode) wieder lesbaren Quellcode in eine höhere Programmiersprache um. Dabei wird versucht, den Vorgang des Kompilierens umzukehren und den Quellcode wieder bestmöglich herzustellen.

Hinweis: Das Dekompilieren darf nicht mit dem Disassemblern verwechselt werden, denn die Assemblersprache ist nur eine andere Darstellung des kompilierten Maschinencodes!

Dekompilieren einer APK Datei mit jadx => JAVA

Update 05.06.2022

Die APK Datei wird mit Hilfe von jadx direkt in die entsprechenden Java-Dateien umgewandelt.

Download des aktuellen Release von github: https://github.com/skylot/jadx/releases/latest

Am einfachsten verwendet man "jadx" mit einer grafischen Benutzeroberfläche. Der Start erfolgt mit der Datei jadx-gui-1.2.0.exe . Anschließend wählt man im Fenster die APK Datei aus, welche dekompiliert werden soll.

Wurde die Datei ausgewählt, dekompiliert jadx sie und stellt auf der linken Seite der Anwendung alle Java-Pakete und -Dateien der APK aufgelistet bereit. Hinweis: Verwendet die App als native Code Basis Cordova, basiert die App selbst auf Javascript (der Quellcode befindet sich in dann unter Resources / Assets / www).

Jetzt ist es möglich nach sensiblen Informationen z.B. http(s)://, passw, key, user, rsa, aes, sslsocket und secret zu suchen.

Dekompilieren per Webseite

Zum Beispiel die Webseiten http://www.decompileandroid.com/ und http://www.javadecompilers.com/apk bieten das Dekompilieren als Online-Service an.

Mittwoch, 23. Dezember 2020

Deutscher Pressevertrieb - PDF Dateien mit Hilfe von PowerShell Script sichern

Die DPV bietet viele verschiedene Android Apps um sein digitales Abo auf dem Smartphone/Tablet lesen zu können. Leider gibt es keine direkte Möglichkeit ein komplettes PDF herunterzuladen. Mit Hilfe einem PowerShell Script und dem Beitrag Linux - PDF Dokumente zusammenfügen / Merge PDF files ist dies dennoch möglich.


Das nachfolgende Beispiel wurde mit der App von "Schöner Wohnen" erfolgreich getestet!

Der Download innerhalb der App wird im Speicher des Smartphones unter dem folgenden Ordner abgelegt:

  • storage/696E-E61B/Android/data/com.audiencemedia.app2928/files/content/2bfdd49d-d113-4b18-b9ab-e84abbc94789/3abcca1a-0f52-4f7b-86c7-06dea1a9f24a/2

 

Diesen Ordner am Besten mit TotalCommander suchen und auf den PC kopieren (zum Beispiel per WebDav Share).

Jetzt kann das folgende PowerShell Script verwendet werden: https://www.shemel.de/download/powershell/GetPdfFromDigitalEpaper.ps1
Hinweis: Der Paramter zum Donwload Ordner muss natürlich ggf. angepasst werden.

Zum Abschluss im Ordner "..\3abcca1a-0f52-4f7b-86c7-06dea1a9f24a\2\pdf" den Befehl pdfunite *.pdf 01-2021.pdf , aus dem Beitrag https://sebastianhemel.blogspot.com/2020/09/linux-pdf-dokumente-zusammenfugen-merge.html ausführen!

# (c) 2020 - Sebastian Hemel, www.shemel.de
# Get One PDF File from "SCHÖNER WOHNEN Digital E-Paper" - https://play.google.com/store/apps/details?id=com.audiencemedia.app2928
######################################################################################################################################################
# Note: You can find the download folder in the app directory
# storage/696E-E61B/Android/data/com.audiencemedia.app2928/files/content/2bfdd49d-d113-4b18-b9ab-e84abbc94789/3abcca1a-0f52-4f7b-86c7-06dea1a9f24a/2
######################################################################################################################################################

# Loop through files in a directory using PowerShell
$pathToFiles = 'D:\Downloads\Schöner Wohnen 01-2021\3abcca1a-0f52-4f7b-86c7-06dea1a9f24a\2\'
$copyPath = $pathToFiles + 'pdf\'
$scriptPath   = '.\*'
$pattern1 = "page-" # only get files like page-02_2eb264de-f649-4c11-8bee-eeef504aaf48.stxml
$fileNames = Get-ChildItem -Path $scriptPath -Recurse -Include *.stxml

# generate folder for pdfs
New-Item -Name „pdf“ -ItemType Directory -Path $pathToFiles

foreach ($file in $fileNames) {

    if ($file.name -match $pattern1){
        $filesInDirectory = $file.Basename + $file.Extension
        Write-Output $filesInDirectory

        [xml]$xml = Get-Content $pathToFiles$filesInDirectory
        #Write-Output $xml.stage.scene.pdf | Where-Object {$_.contentURL} | Select-Object id
        #Adding leading zeros to a file name
        $newFilename1 = "{0:d3}$($_.extension)" -f [int]$fileNames.IndexOf($file)
        $counter = 0
        
        #copy PDF-files and rename it
        # page-02_2eb264de-f649-4c11-8bee-eeef504aaf48.stxml
        # ==> 5009b369-ff27-4136-9cad-7424be6b0c8b.pdf ==> ./pdf/000-1.pdf
        # ==> d90b35dc-ce19-4e78-b944-87d9503f4850.pdf ==> ./pdf/000-2.pdf
        $xml.stage.scene.pdf | Where-Object {$_.contentURL} | Select-Object id | ForEach-Object {
            $fileName = $_.id
            $fileName = $pathToFiles + $fileName
            Write-Output 'Copy: '$fileName
            Copy-Item $fileName $copyPath$newFilename1'-'$((++$counter))'.pdf'
        }
    }
}


Montag, 24. August 2020

Fritz!Box - Anrufe per Python mit TR-064 und fritzconnection

Mit Hilfe von fritzconnection lassen sich Anrufe per TR-064 initiieren als auch beenden. Siehe auch https://avm.de/service/schnittstellen bzw. "AVM TR-064 – First Steps". Mit wenigen Zeilen Python-Quellcode kann man so z.B. auf Ereignisse bei einem Raspberry Pi reagieren.


Vorbereitung: Ein FRITZ!Box-Benutzerkonto erstellen

Siehe auch https://service.avm.de/help/de/FRITZ-Box-7590/018/hilfe_system_user_konzept.


Installation von fritzconnection (unter Python3)

Hinweis: Die hier gezeigte Lösung funktioniert nur mit Python3!
 
Package installer for Python (pip), wenn noch nicht vorhanden:
sudo apt-get install python3-pip

Damit die Python .whl files installiert werden können, müssen folgenden Packete vorhanden sein:
sudo apt-get install libxml2-dev libxslt-dev python-dev
Error: Please make sure the libxml2 and libxslt development packages are installed.

Installation von fritzconnection package via pip
sudo pip3 install fritzconnection
Hinweis: Da die Python .whl files (wheels) installiert werden müssen, dauert die Installation ca. 5-10min.

Script 

#!/usr/bin/python
from time import sleep
from fritzconnection import FritzConnection

fc = FritzConnection(
        address='192.168.1.1',
        user="ring",
        password="123456",
        )

print(fc)  # print router model informations
#fc.reconnect()  # get a new external ip from the provider

# call_action takes two required arguments: the service- and the action-name
# https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_voip-avm.pdf
fc.call_action("X_VoIP1","X_AVM-DE_DialNumber",
                arguments={"NewX_AVM-DE_PhoneNumber ": "**9"})
# **9 (Rundruf) Alle angeschlossenen Telefone klingeln
sleep(5)
# Disconnect the dialling process.
fc.call_action("X_VoIP1","X_AVM-DE_DialHangup")


Fehler die auftreten können:

fritzconnection.core.exceptions.FritzActionFailedError: UPnPError:
errorCode: 501
errorDescription: Action Failed


=> Bei der FRITZ!Box muss unter 'Telefonie/Telefonbuch/Wählhilfe' der Punkt 'Wählhilfe verwenden' ausgewählt werden. ErrorCode 501 erscheint beim Fehlen der Wählhilfe. 

fritzconnection.core.exceptions.FritzSecurityError: UPnPError:
errorCode: 606
errorDescription: Action Not Authorized

=> Der Benutzer der FRITZ!Box hat nicht die notwendigen Rechte einen Anruf zu tätigen.



Samstag, 11. Juli 2020

Reguläre Ausdrücke (RegExp) mit Grep - Beispiele

Reguläre Ausdrücke (regular expression oder RegExp) bzw. Zeichenketten, können als Filterkriterien in Textsuchen verwendet werden. Der Text wird dabei mit dem "Muster" des regulären Ausdrucks abgeglichen. Somit kann man etwas suchen und finden, auch dann wenn man nicht mehr die genaue Schreibweise kennt.


Unter Linux kann man Hilfe von grep Dateien nach bestimmten Textzeichen durchsuchen. Unter Windows wäre die Verwendung mit Hilfe von grepWin (Regular expression search and replace for Windows) oder Select-String möglich.

Eine einfache Suche ist mit dem folgenden Befehl möglich:
  • grep 'hemel' \ ~/*
Der Parameter -E von grep definiert einen Regulären Ausdruck und die runden Klammern als Sonderzeichen. Mit dem Parameter -i ignoriert grep zusätzlich Groß- und Kleinschreibung.
Der | Strich (Pipe) steht für ein logisches "oder", somit wird nach dem "h" nach "hemel" und "hamel" gesucht.
  • grep -E -i 'h(e|a)mel' \ ~/*
Möchte man nach mehreren Zeichen inkl. Umlauten suchen, muss man die Zeichengruppe [] inkl. dem Quantifer + verwenden. Jetzt wird nach einem oder mehreren Zeichen gesucht, die innerhalb der [] vorkommen.
  • grep -E -i 'h[\0-9A-F]+mel' \ ~/*

Weitere Beispiele

  • [he]+ "h", "e", "hh", "hheeh" usw.
  • [0-6]{2,5} zwei bis fünf Ziffern von 0-6 in Folge, z. B. "16" oder "23456", jedoch nicht "7", "0.1" oder "1bca2“
  • h.{0,2}mel beliebiges Zeichen, min 0mal, max 2mal vorkommen, z.B. hemel, haemel, hmel

Wichtige Zeichen

  • . einzelnes Zeichen
  • (..) Gruppe von Elementen
  • ..|.. Oder Verknüpfung
  • ^ findet den Anfang einer Zeile
  • $ findet das Ende einer Zeile

Wichtige Zeichengruppen

  • [eam] ein Zeichen "e", "a" oder "m"
  • [0-9A-F] ein großer beliebiger Buchstabe oder eine beliebige Ziffer
  • [A-Za-z0-9] ein beliebiger Buchstabe oder eine beliebige Ziffer

Vordefinierte Zeichenklassen

  • \d Ziffer [0-9]
  • \D keine Ziffer [^\d] bzw. [^0-9]
  • \w Buchstabe [a-zA-Z_0-9]
  • \W weder Buchstabe noch Zahl noch Unterstrich [^\w]
  • \s whitespace Leerzeichen und Steuerzeichen \f, \n, \r, \t und \v
  • \S kein whitespace

Quantifier

  • ? optional, kommt null- oder einmal vor {0,1}
  • * beliebig oft oder auch keinmalt {0,}
  • +  mindestens einmal oder auch mehrfach {1,}
  • {n} muss exakt n-mal vorkommen {n,n}
  • {n,m} muss mindestens n-mal und darf maximal m-mal vorkommen

Unter debuggex.com kann man die erstellte regular expression testen und verstehen.


Dienstag, 26. Mai 2020

Leaflet.js - draggable marker und Ausgabe der Koordinaten (lat, lng)

In dem Beitrag "Webseite mit interaktiver Karte ohne Google Maps? Leaflet.js" hatte ich beschrieben, wie man Leaflet.js auf seiner Webseite als gute Alternative zu Google Maps einbindet. 


In diesem Beispiel geht es darum einen "ziehbaren" Marker zu erstellen und die Koordinaten in zwei Feldern (lat, lng) anzuzeigen.


Es wird die Dragend-Methode für den Marker verwendet um lat und lng abzufangen:

<script type="text/javascript">
    function showMap() {
      
        var map = L.map('map_leaflet').setView([50.9033081, 9.5924615], 14);
        var my_divicon = L.divIcon({
            className: 'arrow_box'
        });
        var marker = L.marker([50.9033081, 9.5924615], {
            draggable:true
        });
        function addToTextBox(lt,ln){
            document.getElementById('lat').innerHTML = lt;
            document.getElementById('lng').innerHTML = ln;
          
        }
        marker.on('dragend', function(event){
            //alert('drag ended');
            var marker = event.target;
            var location = marker.getLatLng();
            var lat = location.lat;
            var lon = location.lng;
            addToTextBox(lat,lon);
            //alert(lat);
            //retrieved the position
          });
       
        // load a tile layer
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
            {
                attribution: 'Map data © OpenStreetMap and contributors CC-BY-SA',
                maxZoom: 18,
                minZoom: 9
            }).addTo(map);
          
        // initialize the map
        //var map = L.map('map_leaflet', { layers: osm, tap: false } );
        L.control.scale({imperial:false}).addTo(map); // metrisch

        marker.addTo(map);
    }
</script>



Samstag, 23. Mai 2020

JavaScript - Fetch API File Upload: Apache 403 Forbidden error SecFilterEngine

Für eine Erweiterung meiner Webcamseiten, benötigte ich ein Formular mit Bild-Upload-Funktion. Das Hochladen von Dateien ist eine der häufigsten Funktionen für eine Webanwendung. Ich verwende in meinem Beispiel KEINE der vielen JavaScript-Bibliotheken, sondern die Fetch-API (eine native JavaScript Funktion).


Als erstes benötigt man auf der Webseite ein HTML Formular mit einem Eingabeelement:

...
    <form action="xyz.php" name="melderForm" method="post" enctype="multipart/form-data">
...
        <input id="formMelderImage-file" class="form-control" type="file">
...
    </form>


Mit dem folgenden JavaScript Code wird ein Event-Listener hinzugefügt, wenn der Benutzer eine Datei auswählt. Mit der Methode fileUpload () wird ein Dateiobjekt als Eingabe empfangen und es mit fetch () auf den Server hochgeladen (inklusive einer Überprüfung des Dateityps (nur Bilder) und der Dateigröße (< 10MB).

<script>
    // Datei vom Formular
    const fileInput = document.getElementById('formMelderImage-file');

    // event listener
    fileInput.addEventListener('change', () => {
        fileUpload(fileInput.files[0]);
    });
   
    const fileUpload = (file) => {
        // Check des Dateityps
        if(!['image/jpeg', 'image/gif', 'image/png', 'image/svg+xml'].includes(file.type)) {
            console.log('Es sind nur Bilder erlaubt!');
            return;
        } else if(file.size > 10 * 1024 * 1024) { // Check der Groesse (< 10MB)
            console.log('Die Datei muss kleiner 10MB sein!');
            return;
        } else {
            // Datei zum FormData object hinzufügen
            const fd = new FormData();
            fd.append('formMelderImage-file', file);

            // `POST` request senden
            fetch('/upload/image', {
                method: 'POST',
                body: fd
            })
            // Abfangen von Fehlern
            .then(res => res.json())
            .then(json => console.log(json))
            .catch(err => console.error(err));
        }
    }
</script>

SyntaxError: "JSON.parse: unexpected character at line 1 column 1 of the JSON data" - 403 Forbidden


404- oder 403-Fehlern nach dem Senden eines Formulars können an der mod_security-Einstellung in Apache auf dem Server liegen. Das Apaches-Modul mod_security hat standardmäßig ein Upload-Limit von 60 KB, sodass bei jedem größeren Upload ein 403-Fehlercode ausgegeben wird.

Man kann versuchen diese zu deaktivieren, und folgendes zu der .htaccess-Datei hinzuzufügen, man wird aber vermutlich keinen Erfolg mehr haben (support for .htaccess files was discontinued in 2.x as it raised too many security issues https://stackoverflow.com/questions/19093542/how-to-disable-mod-security-and-mod-security2-in-htaccess/19196856#19196856)

<IfModule mod_security.c>
  SecFilterEngine Off
</IfModule>

Oder wenn man direkten Zugriff auf die Apache Einstellungen hat, geht dies auch direkt unter nano  /etc/httpd/conf.d/mod_security.conf .

<IfModule mod_security.c>

    # Turn the filtering engine On or Off
    SecFilterEngine Off

Samstag, 4. Januar 2020

Unit-Tets - Was ist automatisches Testen?

Der Zusatzaufwand für automatische Tests lohnt sich in der Regel schon nach wenigen Releases. Die Tests helfen den Entwicklern dabei Fehler im Voraus zu vermeiden und den Quellcode gut zu strukturieren.


Manuelles Testing

Das Testing von umgesetzten Anforderungen nimmt immer eine gewisse Menge Zeit in Anspruch. Oft werden hierbei Fehler übersehen um z.B. Zeit zu sparen oder es werden nicht alle Testfälle "durchgespielt".

Dieses "manuelle" Testing hat in der Regel weitere Releases zur Folge und der gesamte Test-Zyklus muss wiederholt werden. Dies kann dann für alle Beteiligten (Anforderer, Product Owner, Entwickler usw.) eine sehr stupide Tätigkeit werden. Hieraus ergibt sich die Empfehlung für die Einführung von automatischen Tests (Unit-Test).

Unit-Tests

Unit-Tests sind kleine Programme, welche die umgesetzten Anforderungen testen und prüfen, ob sie die Erwartungen der Anforderer erfüllen. Wichtig, jeder automatische Test sollte immer nur eine Eigenschaft einer Methode überprüfen (ein zu erwartender Output). Nichts desto trotz muss natürlich die jeweilige Methode vollständig (Verzweigungen, Sonderfälle usw.) getestet werden und so werden viele kleine Tests benötigt. Man spricht hierbei auch von vielen kleinen Einheiten (Units).
Die Tests müssen zusätzlich zu den Anforderungen programmiert werden, so fallen bei einer "testgetrieben Entwicklung / Test Driven Development" höhere Aufwände an. Das Verständnis dafür sollte vorher beim Auftraggeber eingeholt werden.

Idealerweise stehen die Testfälle vorab für die Entwickler zusätzlich zu den Anforderungen (in der Regel als User Story beschrieben) bereit. So besteht die Möglichkeit zuerst die Unit-Tests zu entwickeln und im Nachgang erfolgt die Umsetzung des eigentlichen Quellcodes für die Anforderungen. Dies hilft den Entwicklern den Quellcode besser zu strukturieren und intuitive Ideen für die Umsetzung zu entwickeln. Ein weiterer Vorteil ist, dass jede Implementierung (Eincheken/Commit) bereits auf Basis der Unit-Tests überprüft wird. So können einzelne Funktionen (Features) gezielt umgesetzt werden, ohne die komplette Umsetzung der Anforderungen in Gänze in einem Schritt entwickeln zu müssen.

Werden im Anschluss die umgesetzten Funktionen in ihrer gesamten Komplexität getestet, spricht man von Integrationstests.
Siehe hierzu auch meinen Beitrag vom März 2018 "Softwaretest bei agiler Entwicklung durch Testautomatisierung".

Fazit

Wurde das Projekt mit automatischen Tests ausgestattet, ist das Entwickeln effizienter und macht mehr Spaß!

So kann man zum Beispiel beim Refactoring schon sagen, welche Anpassungen am Quellcode notwendig sind, damit dieser korrekt funktioniert. Beim Einchecken einer Codeänderung in das Versionsverwaltungssystem werden die Tests gestartet und können den Commit z.B. automatisch zurückweisen (erstellen eines Issue), wenn diese fehlschlagen.

Gerade bei größeren Softwareentwicklungsprojekten zahlt sich der anfangs zusätzliche Aufwand im Nachgang wieder aus. Entwickler und Tester sparen mit jedem weiteren Release Zeit, das Refactoring wird optimiert und es treten zwangläufig weniger Fehler auf (im Vergleich zum manuellen Testing).

Dienstag, 17. September 2019

Online Visitenkarte mit GitHub Pages

Mit Hilfe von GitHub Pages ist es relativ schnell möglich eine online Visitenkarte oder auch einen Blog vollkommen kostenlos zu erstellen.


Alles was hierzu nötig ist, ist ein GitHub Account (in der kostenlosen Version):
 
Jetzt muss man ein Repository erstellen (z.B. mit dem Namen "card"):


Anschließend kann man das noch "leere" Repository aufrufen:

Jetzt kann man direkt eine neue Datei mit dem Namen "index.md" anlegen (https://github.com/shemel/card/new/master) und dort seine Informationen (Visitenkarte etc.) hinterlegen:

Hierbei handelt es sich dann um ein Markdown (vereinfachte Auszeichnungssprache): https://github.com/shemel/card/blob/master/index.md

Unter den Einstellungen (Settings) des Repository kann man unter dem Punkt "GitHub Pages" verschiedene Themes aussuchen:


Hier sollte man jetzt den "master branch" und ein passendes "Theme" auswählen. Das Theme selber wird in der "_config.yml" abgelegt:

Jetzt ist die Visitenkarte unter der folgenden URL abrufbar: https://shemel.github.io/card/


Montag, 2. September 2019

Webseite mit interaktiver Karte ohne Google Maps? Leaflet.js


Leaflet.js ist eine Open-Source-JavaScript-Bibliothek für interaktive Karten auf der eigenen Webseite.


Die JavaScript Bibliothek ist klein, einfach und flexibel und derzeit wahrscheinlich die beliebteste Open-Source-Mapping-Bibliothek. Gleichzeitig ist Leaflet.js auch eine gute Alternative zu Google Maps, da eine Verwendung nur noch nach Registrierung möglich ist und nur noch in einem geringen Umfang kostenlos ist.

Die Bibliothek ist kostenlos und frei nutzbar (2-Clause BSD License).
Desweiteren ist es möglich, dass die Karten vom eigenen Server ausgeliefert werden können, somit muss im Impressum bei der Datenschutzerklärung (DSGVO) nicht auf einen externen Service verwiesen werden.

Aktuelles Beispiel, wenn die Verwendung der Google Maps API ohne Registrierung erfolgt:


  • Are you using an API key?
  • Is billing enabled on your account?
  • Is the provided billing method no longer valid (for example an expired credit card)?
  • Is there an exceeded self-imposed daily limit on the API?
  • Does your API key have an IP addresses restriction?

Integration von Leaflet.js in die eigene Webseite:

  • Ordner entpacken und unter ../leaflet speichern
  • In der HTML-Datei ein div element mit einer id hinterlegen:
    • <div id="map_leaflet"></div>
  • Die CSS‐Datei und das Leaflet‐API‐Script einbinden:
    • <link rel="stylesheet" href="leaflet/leaflet.css" rel="stylesheet" />
    • <script src="leaflet/leaflet.js"></script>
  • Der Kartencontainer (mapid) muss eine definierte Höhe hat z.B. per CSS festlegen:
    • #map_leaflet{ height: 392px; } 
    • <div id="map_leaflet" style="width:800px; height:392px"></div>
  • Damit ein Layer anzeigt werden kann, muss der Kartenbereich (hier mit den Koordinaten) initalisiert werden:
    • var map = L.map('map_leaflet').setView([50.869333, 9.715948], 14);
  • Wie auch die Google Maps API benötigt die Leaflet API Kartenbilder (Tiles im .png oder .jpeg Format), diese werden je nach Zoomstufe schachbrettartig zu einer Karten zusammengesetzt:
    • https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png (Templatestring hinzufügen)
    • Servernummer = (s)
    • Zoomlevel = (z)
    • Koordinaten = (x,y)
    • Zoom Bereich und Copyright werden festgelegt
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
    attribution: 'Map data © OpenStreetMap and contributors CC-BY-SA',
    maxZoom: 18,
    minZoom: 9
}).addTo(map);
  • Metrischen Maßstab in der Karte einblenden:
    • L.control.scale({imperial:false}).addTo(map); // metrisch
  • Mit der Methode L.marker. kann man Orte auf der Karte markieren:
    • L.marker([50.869333, 9.715948]).addTo(map);


  • Mit bindPopup kann ein Popup hinterlegt werden und beim Aufrufen der Karte geöffnet werden:
    • L.marker([50.869333, 9.715948]).addTo(map).bindPopup("Bahnhofsmission Bad Hersfeld").openPopup();

Weitere Beispiele finden sich auch auf der Herstellerseite: https://leafletjs.com/examples.html

Anbei der komplette Quellcode:

<html>
    <head>
...
        <link rel="stylesheet" href="leaflet/leaflet.css" rel="stylesheet" />
...
        <script src="leaflet/leaflet.js"></script>
...
        <script type="text/javascript"> 
            function showMap() {           
                // initialize the map
                var map = L.map('map_leaflet').setView([50.869333, 9.715948], 14);
               
                // load a tile layer
                L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                    {
                        attribution: 'Map data © OpenStreetMap and contributors CC-BY-SA',
                        maxZoom: 18,
                        minZoom: 9
                    }).addTo(map);
               
                L.control.scale({imperial:false}).addTo(map); // metrisch
               
                //L.marker([50.869333, 9.715948]).addTo(map);
                L.marker([50.869333, 9.715948]).addTo(map).bindPopup("Bahnhofsmission Bad Hersfeld").openPopup();
            }
        </script>
    </head>
   
    <body onload="showMap()">
...
        <div id="map_leaflet" style="width:800px; height:392px"></div>
...
    </body>
</html>