Hinweis: Wäre JavaScript aktiviert würde ein
Navigationsmenü am Seitenrand angezeigt.
Hinweis: Wäre JavaScript aktiviert würde ein
Navigationsmenü am Seitenrand angezeigt.
Schwarzer Bildschirm nur mit Cursor nach Upgrade auf OpenSuse Leap 15.4 (SDDM) und Reboot
Nach Wechsel in Console (z.B. mit Ctrl+Alt+F2) konnte ich die graphische Oberfläche starten mit einem simplen:
startx
Das hätte man dann aber nach jedem Booten machen müssen.
sudo pkcon update
Schlug bei mir zunächst fehl. Irgendeine RPM konnte nicht gefunden werden.
Nachdem ich ein offenbar nicht mehr existierendes Repo (GEO) via Yast deaktiviert hatte und obigen Befehl nochmals (diesmal erfolgreich) ausführen konnte, war das Problem dann behoben.
Schwarzer Bildschirm nur mit Cursor nach Upgrade auf OpenSuse Tumbleweed und SDDM und Bildschirm aus
Nach dem Upgrade auf OpenSuse Tumbleweed und auf den neuen Desktop-Manager SDDM konnte ich,
nachdem sich nach einigen Minuten Inaktivität, der Bildschirm ausgeschaltet hatte, das System nicht mehr entsperren.
Symptom: Schwarzer Bildschirm nur mir (beweglichem) Cursor.
Mit Ctrl+Alt+F1 (...F6) konnte man zwar in die Console umschalten, von dort half aber auch nur noch
systemctl restart sddm
Das ist aber natürlich unbefriedigend...
Der Hinweis den Benutzer
sddm
in die Gruppe
video aufzunehmen
brachte keine Verbesserung.
Lösung: Folgendes Verzeichnis löschen (oder zunächst mal sicherheitshalber nur umbenennen):
~/.cache
Nebenwirkungen: bei mir keine.
Möglicherweise bestand das Problem bereits seit einiger Zeit unter 13.2 mit kdm.
Damals aber nur sporadisch nach dem Aufwecken aus dem Suspend. Symptom ebenfalls schwarzer Bildschirm mit "lebendigem" Cursor.
Dafür konnte ich dann aber nichtmal mehr in ein TTY wechseln - es blieb also nur das harte Ausschalten.
Jetzt muss sich noch zeigen, ob das auch auf meinem Arbeitsrechner Abhilfe schafft.
Das System dort ist ein zum "Kubuntu" mutiertes Ubuntu, nachdem mir Unity zu sehr auf den Zeiger gegangen ist (ständig blieben Schatten
irgendwelcher Popup-Fenster als Geister zurück, Problem mit dem Scaling auf 4K-Screen, und und und).
Symptome dort: Nachdem der Bildschirm schlafen gegangen ist muss man plasmashell neu starten, da sonst alle Desktop Icons neu
sortiert sind und er das aktuelle Hintergrundbild "vergessen" hat. Außerdem vergisst leider auch SDDM (oder wer auch immer)
den Skalierungsfaktor fü den 4K-Bildschirm nach jedem Neustart (Trotzdem gefällt mir der SDDM deutlich besser als Unity oder Gnome)
killall plasmashell; plasmashell
OpenSuse 12.1 (KDE
Plasma-Desktop) und NVidia-Grafikkarte auf Laptop
"Optimus-Technologie"
- Da Optimus
(Umschaltung zwischen dem einfachen On-Board Grafik-Chip
und der NVidia-Karte) wohl noch nicht wirklich gut
unterstützt wird (das Linux-Äquivalent heißt dann
passenderweise "
Bumblebee "), musste ich zuerst im Bios fest auf die NVidia-Karte
umschalten (sonst hatte ich bei grafisch komplexeren
bzw. 3D-Anwendungen seltsame Effekte, wie z.B. bunte
hüpfende Pixel)
- Danach arbeitet der mitgelieferte Nouveau-Treiber
(offener Treiber für NVidia-Grafikkarten) eigentlich
ganz zufriedenstellend, aber bei bestimmten Anwendungen
gab es doch noch Probleme. Also habe ich in YAST unter Software →Software
Repositories die (zur OpenSuse-Version
passende) NVidia-Seite eingetragen, also bei mir:
http://download.nvidia.com/opensuse/12.1
Und dann über
Install/Remove Software und den Suchbegriff "nvidia" den
passenden Treiber angeklickt. Nun werden weitere
Komponenten (die mit diesem Filter ebenfalls sichtbar
sind) als abhängig mitselektiert. Hier muss man aber
aufpassen! Bei mir wurden teilweise die falschen
Komponenten ausgewählt. Eine der Komponenten endet auf
den Kernel-Flavour (bei mir "default"). Wenn hier (nur)
das falsche "Flavour" selektiert wird (z.B. "...desktop" oder "...pae") gibt es
einen Haufen Probleme (X-Windows startet nicht mehr,
Lösung s.u.). Die Kernel-Version (samt "Flavour") kann
man sich übrigens in einer Shell mit "uname -a" anzeigen
lassen. Die Kernel-Flavour-abhängigen Pakete kann man
aber alle parallel installieren- sinnvoll ist das aber
nur wenn man auch die entsprechenden Kernel-Flavours
(pae, desktop, default) dazu installiert hat.
- Nach einem Neustart lief dann tatsächlich der
NVidia-Treiber (über
My Computer, bzw. Konqueror mit der Url " sysinfo:/"
erkennbar), nur leider waren alle Schriften
(Fenstertitel, etc.) viel zu groß (noch häufiger kommen
aber wohl viel zu kleine Schriften vor). Um das zu
beheben geht man in
Configure Desktop (unter Favoriten) und dort
zu Application
Appearance und dort wiederum zu Fonts. Dort
aktiviert man DPI für
Schriften erzwingen (bei mir sieht die
Einstellung "96 DPI"
gut aus). Danach nochmaliger Neustart bzw. zumindest ab-
und wieder anmelden (reicht).
- Das letzte Problem: Wenn der Rechner in den
Ruhezustand (Sleep-Modus), oder auch nur in den
Screensaver ging funktionierte danach die
Helligkeitsregelung nicht mehr (weder über die
Funktionstasten, noch über den Schieberegeler, der
erscheint wenn man in der Task-Leiste auf
Battery-Monitor geht). Seit ich in /etc/X11/xorg.conf.d/50-device.conf
Folgendes eingetragen habe geht auch das:
Section "Device"
Identifier "Device0"
Driver "nvidia"
VendorName "NVIDIA Corporation"
Option "RegistryDwords" "EnableBrightnessControl=1"
EndSection
Achtung: Will man wieder auf nouveau umsteigen (z.B. weil
es fü ein Rolling-Release wie OpenSuse Tumbleweed ziemlich
umständlich ist den NVidia-Treiber zu installieren) muss das
unbedingt entfernt werden, sonst startet die grafische Oberfläche
nicht mehr!
In dieser Datei war vorher übrigens nur eine
auskommentierte Template-Device-Section eingetragen. Ob
das ein Fehler bei der Installation ist, oder immer so
ist, weiß ich leider nicht. Wichtig ist dabei in jedem
Fall das Attribut "EnableBrightnessControl=1".
Wenn, wie bei mir das Kind in den Brunnen gefallen ist
und die falschen Komponenten installiert wurden und
X-Windows daraufhin nicht mehr startet
(ich kann hier aber nur den Fall "Mein Kernel ist im
default-Flavour aber nur die desktop-Komponente wurde
installiert" aus eigener Erfahrung beschreiben):
- Mit etwas Verzögerung (in der offenbar erfolglos
versucht wird X zu starten) kommt ein Text-Modus
Login-Prompt.
- Dort als root
einloggen und YAST
starten.
- Alle NVidia-Komponenten deinstallieren (ziemlich
fummelig im Text-Modus), dabei aufpassen nicht den
Nouveau-Treiber zu deinstallieren, den man auch mit dem
Filter "nvidia" findet.
- Die Datei /etc/X11/xorg.config,
die fälschlicherweise angelegt wurde löschen, oder
sicherheitshalber besser nur umbenennen oder verschieben
(zumindest müsste wohl der NVidia-Treiber darin durch "nv" für den
Nouveau-Treiber ersetzt werden, was ich aber nicht
ausprobiert habe).
- Mit dem Befehl "reboot"
den Rechner neu starten (X sollte nun wieder laufen) und
die richtigen Treiber-Komponenten installieren (wie oben
beschrieben).
Bei mir klappte übrigens beim ersten Mal alles (die
richtigen Komponenten wurden automatisch ausgewählt und
installiert). Ich habe aber den NVidia-Treiber nochmal
deinstalliert (auch wieder via YAST), weil ich dachte doch
mit dem Nouveau-Treiber hinzukommen. Erst als ich den
NVidia-Treiber erneut auf demselben Weg installieren
wollte hatte ich o.g. Probleme...
Grafische
Oberfläche (X) startet nicht mehr nach Update von
OpenSuse (hier 12.1 auf 12.3) mit NVidia-Treiber
Nach dem Update von OpenSuse, in dem Fall von 12.1 auf 12.3
startet die grafische Oberfläche nicht mehr. Zumindest wenn
man im "Failsafe-Modus" startet sollte man sich im
Text-Modus anmelden können (mit Alt+F1 bzw. Alt+Ctrl+F1
müsste man in den Text-Modus kommen). Symptome:
- Zumindest beim Starten im Failsafe-Modus sieht man als
letzte Ausgabe:
"[OK] Reached target Graphical Interface"
- In der /var/log/Xorg.0.log findet man relativ
weit unten folgende Fehlermeldung:
"Failed to initialize NVIDIA kernel module"
Aus dem Text-Modus kann man nun
YaST starten. Es ist
wieder etwas fummelig, aber man muss versuchen die richtigen
NVidia-Pakete zu installieren und die falschen zu
deinstallieren. Ggf. muss man erst noch das richtige
Repository angeben. Für OpenSuse 12.3 also:
- ftp://download.nvidia.com/opensuse/12.3
Bei mir wurden die falschen Pakete ausgewählt. Auch ich
selbst habe, trotz vorhergehender Konsultation der
NVidia-Seite, erstmal noch die "falschen" Pakete gewählt -
jedenfalls funktionierten diese nicht. Auch das
Installieren mittels einer von der NVidia-Seite direkt
heruntergeladenen Run-Datei hat nicht funktioniert bzw.
keine Besserung gebracht. Erst als ich die gfxG02-Pakete
statt der gfxG03-Pakete gewählt habe funktioniert alles
wieder. Die Kernel-Flavour-abhängigen Pakete kann man
übrigens alle installieren, wenn man verschiedene
Kernel-Flavours (pae, desktop, default) parallel
installiert hat.
Internet-Explorer Tabs (Reiter, Registerkarten)
verschwunden (IE8 unter XP)
Dafür kann es wohl mehrere Ursachen geben. Bei mir war es
unter XP mit dem IE8 Folgendes: Ich hatte das Fenster zum
Öffnen des Windows-Themes geändert, das Theme dort geändert
(von Classic auf XP) und die Operation dann aber
abgebrochen. Danach waren die Tabs im IE verschwunden (den
Zusammenhang habe ich aber nur zufällig entdeckt).
Lösung: Das Fenster
erneut öffnen und aktuelles Theme wählen und bestätigen. IE
nochmal neu starten.
Die Google Bilder-Suche zeigt
nur noch die erste Seite an (Seamonkey)
...das kann daran liegen, dass man eingestellt hat, dass nur
noch Bilder vom Herkunftsserver geladen und angezeigt
werden. Die Einstellung ist beim (englischen) Seamonkey
unter "Privacy & Security" → "Images" zu finden und
heißt "Only load images that come from the originating
server". Das sollte in "Load all images" (zurück-)geändert
werden. Wenn es das nicht ist scheint es teilweise was zu
bringen die "Privaten Daten" zu löschen, allerdings brachte
das in meinem Fall natürlich nichts...
Prozess
"plugin-container" (Firefox / Seamonkey) erzeugt extrem
hohe CPU-Auslastung
Das in einschlägigen Foren oft vorgeschlagene Deaktivieren
des Prozesses (als URL "about:config" eingeben und dann nach
"dom.ipc.plugins" filtern) ist
keine gute
Idee. Bei mir stürzte danach dauernd der Browser ab, und
erzeugte zuvor selbst eine reichlich hohe Prozessorlast.
Nein, schuld ist der Flash-Player, denn um dessen Abstürze
abzufangen existiert der "plugin-container" eigentlich. Wer
auf Flash-verseuchte Seiten (damit aber auch die meisten
Filmchen) verzichten kann, der kann den Flash-Player
komplett deinstallieren. Danach wird der Prozess
"plugin-container" übrigens garnicht mehr gestartet.
Alternativ kann man mal eine andere (ältere/neuere)
Flash-Player-Version installieren oder die aktuelle einmal
de- und erneut installieren (z.B. unter Linux über den
jeweiligen Paketmanager). Bei mir hat das geholfen...
Nachtrag: inzwischen
dreht dafür unter Linux (OpenSuse 12.1) öfter mal der
XOrg-Prozess völlig durch (nahe 100% CPU-Auslastung). Wenn
ich den Browser schließe und wieder öffne beruhigt sich das
wieder. Eine bessere Lösung habe ich leider noch nicht
gefunden...
JAR via Batch-Datei aufrufen - oder wie vermeide ich den
Fehler "unable to access jarfile"
Folgendes Problem: Wenn man eine JAR (myJar.jar) aus einer
Batch-Datei (myBatch.bat) aufrufen will, die z.B. so
aussieht:
myBatch.bat:
java -jar myJar.jar
Wobei ich hier davon ausgehe, dass myBatch.bat und myJar.jar
im selben Verzeichnis liegen. Wenn man die Batch-Datei nun
diese über das Cmd-Fenster aufruft, während man sich in
einem anderen als dem Verzeichnis der Batch- und Jar-Datei
befinden, bekommt man in etwa folgende Fehlermeldung:
unable to access jarfile
myJar.jar
Das Problem lässt sich leicht beheben (auch wenn auf einigen
Seiten das Gegenteil behauptet wird), indem man die
myBatch.bat etwas umschreibt:
myBatch.bat:
java -jar %~0dp0/myJar.jar
%dp0 ergibt dabei den Pfad der Batch-Datei. Sinnvoll/nötig
ist ein Aufruf via Kommandozeile insbesondere dann, wenn man
beim Aufruf noch Parameter übergeben will, wie z.B. hier
myBatch.bat:
java -jar %~0dp0/myJar.jar %1 %2
Mehrere ausführbahre Klassen (also solche mit einer
main-Methode) in eine JAR packen und ausführen
Wo ich gerade bei JARs bin. Man kann quasi mehrere Programme
in eine Jar packen. Die lassen sich dann folgendermaßen
aufrufen:
java -cp myJar.jar
packageXY.subpackageAB.myMainClass1
java -cp myJar.jar packageXY.subpackageAB.myMainClass2
...
Wobei man dann bei der Erstellung der Jar (z.B. mit FatJar)
keine Main-Class angibt. Wenn die Programme dieselben
Basis-Klassen und Libraries benutzen (wie z.B. in meinem
"E3D" Paket) lässt sich damit enorm Speicherplatz sparen...
Adobe PDF (Distiller)
dreht Seiten (und ich will das nicht)
Aufgrund der teilweise Verwendung gedrehten Textes wurden
bei mir (alle) Seiten beim Ausdruck über Adobe-PDF gedreht,
was aber in diesem Fall grober Unfug war, da der Text an dem
sich offenbar orientiert wurde, ein um 90° gedrehter Text am
Seitenrand war. Lösen lässt sich das Problem so:
- Den Distiller selbst öffnen (z.B. im Eingabefeld des
Windows-7-Start-Menüs "distiller" eintippern, ansonsten
versteckt sich der Distiller z.B. hier: "C:\Program
Files (x86)\Adobe\Acrobat 10.0\Acrobat\acrodist.exe"
- Im Menü "Voreinstellungen" des Distillers "Adobe
PDF-Einstellungen bearbeiten..." auswählen
- Dort dann "Seiten automatisch drehen" auf "aus"
stellen
- Mit "ok" bestätigen (wenn man noch die
Standard-Einstellungen hatte wird man gefragt werden
unter welchem Namen man die geänderten Einstellungen
abspeichern möchte - so heißt dann auch das
Job-Settings-Profil)
- Beim Drucken über Adobe-PDF dann erst noch auf
"Eigenschaften" klicken
- Im Eigenschaftsfenster unter dem Reiter "Adobe
PDF-Einstellungen" dann für "Standardeinstellungen" das
eben angelegte Job-Settings-Profil wählen
- Eigenschaftsfenster wieder schließen und Drucken -
jetzt sollte es nicht mehr gedreht werden...
Start einer
Eclipse-Application (RCP) aus Eclipse heraus kommt es zu
folgendem Fehler: "Cannot load 32-bit SWT libraries on 64-bit JVM"
Ich musste aus bestimmten Gründen ein 32-Bit Eclipse (4.3 -
Kepler) auf einem 64-Bit Rechner (Windows-7) installieren.
Dazu sind diverse Java-Versionen (JREs/JDKs in den Versionen
1.6, 1.7, jeweils in 32- und 64-Bit) auf dem Rechner
installiert. Nun habe ich ein Tutorial zur RCP-Entwicklung
(Applikation, die auf dem Eclipse-Framework aufbaut)
angefangen (recht gut übrigens, soweit wie ich bisher
gekommen bin :-)):
http://www.vogella.com/articles/EclipseRCP/article.html
Erstes kleineres Problem (aber das nur am Rande): ich musste
die "offizielle" Update-Site für die E4-Erweiterungen
benutzen (wie die Seite zu erreichen ist, ist im o.g.
Tutorial beschrieben), sonst bekam ich Fehler beim Erstellen
der Beispiel-Appikation über den Wizard, dass irgendein
Editor nicht geöffnet werden könne.
Etwas länger beschäftigt hat mich dann das oben genannte
32-/64-Bit-Problem. Ich konnte in den Projekt-Properties
JREs/JDKs einstellen wie ich wollte, es kam beim Start der
Applikation immer der hier nochmal erwähnte Fehler:
"Cannot load 32-bit
SWT libraries on 64-bit JVM"
Die Lösung:
Man öffnet die .product-Datei. Dort geht man auf den Tab
"Launching" (die Tabs sind hier unten aufgelistet). Dort
stellt man das Execution-Environment ein - in meinem Fall
JavaSE-1.7. Nur verbarg sich dahinter eine
64-Bit-Java-Version. Also musste ich zusätzlich noch über
den Button "Environments" neben dem Auswahlfeld eine
32-Bit-Version als Default für JavaSE-1.7 wählen.
Was theoretisch auch geht:
man wählt in den Run-Configurations bzw. wahlweise auch den
Debug-Configurations (oben über das Run- bzw. Debug-Menü zu
erreichen) im Tab "Main" unter "Runtime JRE" eine
32-Bit-Java-Version aus.
Großes Aber:
Das funktioniert nur solange man das Programm über das
Run-Menü startet! Denn jedesmal wenn man den beschriebenen
und im Tutorial stark angeratenen Weg über die
.product-Datei geht, wird das wieder überschrieben :-( Daher
ist der obere Weg also deutlich vorzuziehen...
Zum
Feedback-Formular...
Eclipse-Plugin-Projekt zieht
falsches Plugin unter Plugin-Dependencies an
Ich habe zwei Plugin-Projekte erstellt in denen mehrere
identische Packages und Klassen enthalten sind. Allerdings
hat das eine Plugin einen erweiterten Umfang - d.h.
zusätzliche Packages und Klassen. Das ältere Plugin wollte
ich für ein anderes Projekt unverändert behalten, in einem
zweiten Projekt jedoch auf die neuere, erweiterte Version
umstellen. Leider weigerte sich Eclipse beharrlich, das alte
Plugin-Projekt zu "vergessen" - es blieb unter
"Plugin-Dependencies" im Package-Explorer sichtbar, obwohl
es weder im Manifest, noch in der .product-Datei aufgeführt
war. Ergebnis war, dass sich die Applikation (RCP) nicht
starten ließ, weil Klassen nicht gefunden wurden.
Ursache, war dass die hier über die Manifest-Datei
über die Dependencies die Packages referenziert wurden. Diese
Packages kommen aber in beiden Plugin-Projekten vor.
Lösung 1 (korrekt): Man sorgt dafür, dass die beiden
Plugin-Versionen auch tatsächlich unterschiedliche Versionen haben
(über deren Manifest-Dateien) und schränkt dann in der Manifest
des nutzenden Plugins die Versionen an den angegebenen Packages
im Manifest entsprechend ein (rechte Maustaste auf das Package
im Dependencies-Tab des Manifest-Editors → Properties).
Lösung 2 (auch gut): Man löscht die Package-Abhängigkeiten
und fügt stattdessen Abhängigkeiten zu dem Plugin (jeweils
dam in der richtigen Version ein), wobei diese dann unterschiedliche IDs
haben müssen (→ Manifest). Alternativ kann man auch bei den
Plugin-Abhängigkeiten die Versionen einschränken (s.o.)
Lösung 3 (Notlösung):
Hat man keinen Einfluss auf Id und Version des zu benutzenden
Plugins funktioniert zur Not auch das alte Plugin-Projekt kurz zu
schließen, ggf. ein "Clean" durchzuführen, die Applikation einmal
zu starten, um zu sehen ob alles funktioniert. Danach kann das alte
Plugin-Projekt wieder geöffnet werden. Eclipse sollte nun die Zuordnung
"gefressen" haben und beibehalten, solange man das eingebundene
Plugin-Projekt nicht mehr ändert. Muss man es ändern, taucht evtl.
Plötzlich wieder das falsche Plugin-Projekt in den Dependencies auf
(wenn man es ändern kann geht aber auch Lösung 1 oder 2).
Lösung 4 (immer möglich):
Man benutzt zwei verschiedene Workspaces.
Zum
Feedback-Formular...
In Java über alle Dateien in ineinander verschachtelten
Zip-Archiven (nested zip archives) iterieren
Die erste Frage, die sich mir beim Öffnen verschachtelter
ZIP-Archive ("Zip in Zip", "nested Zip") stellte, lautet: Wie
komme ich eigentlich an die ZipEntries einer inneren
Zip-Datei innerhalb einer anderen Zip-Datei - und das über beliebig
viele Verschachtelungsebenen?
Die Antwort ist eigentlich ganz einfach: An einem solchen
ZipEntry
aus einem
ZipInputStream zis1 angekommen, wird einfach ein
weiterer
ZipInputStream zis2 initialisiert:
ZipInputStream zis2 = new ZipInputStream(zis1).
Dies wird in der folgenden rekursiven Methode verwendet:
01
02
03
04
05
06
07void iterate (InputStream in)
08{
09 ZipInputStream zip = new ZipInputStream(in);
10 ZipEntry entry;
11 while ((entry = zip.getNextEntry()) != null) {
12 if (entry.isDirectory()) {
13
14
15
16 } else if (isZip(entry)) {
17
18
19 iterate(zip);
20 }
21 }
22}
Hier wird eine Methode
boolean isZip(ZipEntry) angenommen, die
z.B. aufgrund des Namens (
String ZipEntry.getName()) erkennt, ob
es sich um ein eingebettetes Zip-Archiv handelt.
Die zweite Frage lautet: Wie stelle ich fest, ob eine Datei
ein Zip-Archiv oder irgendein anderes Datei-Format ist, ohne
es anhand des Names (z.B. "*zip") zu bestimmen? Hierfür kann testweise ein neuer
ZipInputStream angelegt und versucht werden das erste
ZipEntry daraus zu lesen. Gelingt das, handelt es sich um
ein Zip-Archiv, sonst ist es ein anderes Dateiformat. Folgende Methode liefert
null falls es kein Zip-Archiv ist und sonst das (erste)
ZipEntry.
01
02
03
04
05
06ZipEntry getNextZipEntry (ZipInputStream zipStream) throws IOException
07{
08 try {
09 return (zipStream.getNextEntry());
10 } catch (ZipException exception) {
11 return (null);
12 }
13}
Diese Methode sollte nur verwendet werden, um das jeweils erste
ZipEntry
aus einem
ZipInputStream zu holen.
Die dritte Frage die daraufhin aber noch zu klären ist: Wie
verarbeite ich die Datei, wenn es kein Zip-Archiv ist,
obwohl
ZipInputStream.getNextEntry() bereits Bytes aus dem
InputStream lesen musste, um feststellen zu können, dass es
doch kein Zip-Archiv ist?
Hierfür schalten wir jeweils eine erweiterte Abwandlung der Java-Standardklasse
PushbackInputStream vor. Diese Klasse sieht so aus:
01
02
03
04
05
06class BufferingPushbackInputStream extends java.io.PushbackInputStream
07{
08
09 private boolean buffering = true;
10
11
12 private final List<byte[]> buffer;
13
14
15
16
17
18 public BufferingPushbackInputStream (InputStream in) {
19 this(in, 1024, 1);
20 }
21
22
23
24
25
26
27
28
29
30
31 public BufferingPushbackInputStream (InputStream in,
32 int byteBufferSize,
33 int readBufferSize)
34 {
35 super(in, byteBufferSize);
36 buffer = new ArrayList<byte[]>(readBufferSize);
37 }
38
39 @Override
40 public int read () throws IOException {
41 int b = super.read();
42 if (b != -1 && buffering) {
43 buffer.add(new byte[]{(byte)b});
44 }
45 return (b);
46 }
47
48 @Override
49 public int read (byte[] b) throws IOException {
50 return (read(b, 0, b.length));
51 }
52
53 @Override
54 public int read (byte[] b, int off, int len) throws IOException {
55 int s = super.read(b, off, len);
56 if (s > 0 && buffering) {
57 buffer.add(Arrays.copyOfRange(b, off, off + s));
58 }
59 return (s);
60 }
61
62 @Override
63 public synchronized void close () throws IOException { <== Trick (s.u.)
64
65
66
67
68
69 }
70
71
72 public void setBuffering (boolean buffering) {
73 this.buffering = buffering;
74 }
75
76
77 public void pushback () throws IOException {
78 for (byte[] b : buffer) unread(b);
79 buffer.clear();
80 }
81}
Diese Klasse erlaubt es uns, die zum Testen, ob es sich um ein Zip-Archiv handelt, ausgelesenen Bytes zu
speichern und ggf. zurückzuschreiben falls es sich um eine "normale" Datei handelt. Da es sich hier
um eine Wrapper-Klasse für einen anderen Stream handelt, unterbinden wir das Schließen des Streams
durch Überschreiben der Methode
close(). Das Schließen würde
nämlich alle übergeordneten Streams ebenfalls schließen und die Iteration mit einer Exception
abbrechen. Genau das passiert z.B. bei Verwendung der Methode
SAXBuilder.build(...)
zum Parsen einer XML-Datei.
Unter Verwendung der neuen Klasse
BufferingPushbackInputStream können
wir die oben gezeigte Methode
iterate(InputStream) folgendermaßen
abwandeln, so dass Zip-Archive nun automatisch erkannt werden:
01
02
03
04
05void iterate (InputStream inStream) throws IOException
06{
07
08 BufferingPushbackInputStream pushbackStream = new BufferingPushbackInputStream(inStream);
09 ZipInputStream zipStream = new ZipInputStream(pushbackStream);
10 ZipEntry entry = getNextZipEntry(zipStream);
11 if (entry != null) {
12 pushbackStream.setBuffering(false);
13 do {
14 if (entry.isDirectory()) {
15
16 } else {
17
18 iterate(zipStream);
19 }
20 } while ((entry = zipStream.getNextEntry()) != null);
21 } else {
22 pushbackStream.pushback();
23
24
25 }
26}
Initial aufgerufen wird diese Methode z.B. so:
01File file = new File("Archiv.zip");
02InputStream stream = new FileInputStream(file);
03try {
04 iterateStream(stream, file.getName());
05} finally {
06 stream.close(); <== Haupt-Stream schließen!
07}
Im Gegensatz zu den "Sub-Streams" ist hier natürlich wichtig sicherzustellen, dass der
FileInputStream
auch wieder geschlossen wird.
Das Ganze ließe sich z.B. noch derart erweitern, dass jeweils entschieden werden kann, ob ein eingebettetes Zip-Archiv
durchsucht werden soll oder nicht. Etwas komplizierter ist das Auslassen von "Verzeichnissen" in einem Zip, da die gezippten Dateien
im Prinzip in einer flachen Hierarchie abgelegt sind und lediglich immer den kompletten Pfad im Namen haben, anhand dessen dann die
Verzeichniszugehörigkeit erkannt werden muss. Dazu vielleicht ein anderes Mal mehr... stay tuned :-)
Zum
Feedback-Formular...
Seamonkey Debugger (Venkman) hängt wenn "Bei Exceptions stoppen" eingestellt wurde
Problem:
Der Javscript-Debugger hängt sich und den Seamonkey-Browser komplett auf, nachdem dort unter Debug → Auslöser bestätigen "Bei Exceptions stoppen" gewählt wurde.
Damit kann dann leider auch die Einstellung nicht mehr auf dem normalen Weg, über das Menü, rückgängig gemacht werden...
Lösung:
Config-Seite aufrufen:
about:config
und dort die folgende Eigenschaft suchen und ändern:
extensions.venkman.lastThrowMode "break" / "trace" → "ignore"
Update
Der Venkman-Editor wird zwar nach wie vor mit dem Seamonkey ausgeliefert, funktioniert aber nicht mehr, da die von ihm benutzte API deaktiviert wurde.
Es gibt mehrere Debugger die stattdessen installiert und benutzt werden können.
Ich nutze Firebug (der allerdings das Problem hat, dass das Menü-Item dauernd verschwindet; starten via F12 funktioniert aber unabhängig davon
(s.a.
https://bugzilla.mozilla.org/show_bug.cgi?id=1132983).
Firebug hat auch den großen Vorteil nur eine Seite zu debuggen (während Venkman bei zig geöffneten Tabs völlig versagte).
Zum
Feedback-Formular...
Eclipse-Projekt von Subversive auf Subclise umstellen (SVN)
Problem:
Irgendwie bekam ich die Projekte mit Subversive nicht korrekt eingebunden. Auschecken ging, aber danach konnte ich keine Synchronisation, kein Update, etc. durchführen. Fehlermeldung war immer diese:
407 Proxy Authentication Required
Offenbar hat es irgendwas mit dem Proxy zu tun hinter dem ich sitze. Dieser ist jedoch unter den Eclipse-Preferences (Menü Window → Preferences → Suche nach Proxy) korrekt eingestellt
("Active Provider" steht auf "Manual", Die Zeile fü "HTTP" ist korrekt angegeben).
"Kleine" Lösung:
Bevor man den Weg der Umstellung von Subversive auf Subclipse versucht, kann man mal dort in den Preferences die Zeile "SOCKS" selektieren und rechts auf den Button "Clear" klicken.
Offenbar hat das bei ähnlich gelagerten Problemen teilweise geholfen - bei mir aber nicht...
"Große" Lösung:
- Subclipse installieren, falls noch nicht installiert (Help → "Install New Software..." dort ggf. die Update-Site "http://subclipse.tigris.org/update_1.6.x" oder
"http://subclipse.tigris.org/update_1.8.x" (je nach SVN-Version) hinzufügen und Subclipse installieren.
- Projekte von Subversive trennen: Projekt(e) selektieren → rechte Maustaste → Team → Disconnect, Die SVN-Metadaten dabei nicht löschen!
- Projekte mit Subclipse connecten: Projekt(e) selektieren → rechte Maustaste → Team → Share Project...
(nicht "Share Projects...", das ist der Subversive Menüpunkt)
- Im sich dann öffnenden Fenster den Repository-Typ "SVN" wählen. Sehr wahrscheinlich gibt es dort gleich zwei Einträge, die beide "SVN" heißen und man muss den richtigen erwischen, sonst hat man wieder Subversion...
Bei mir war es bisher immer der obere, aber ich würde nicht versprechen wollen, dass das immer und für alle gilt.
Und dann das Projekt / die Projekte "connecten" (wobei man letztlich doch jedes Projekt einzeln "connecten" muss).
Bei mir funktionierte dann alles wie gewünscht.
Falls Subclipse noch weniger funktioniert kann man entsprechend wieder von Subclipse zu Subversive umziehen...
Zum
Feedback-Formular...
Neue Generator Functions in ECMAScript 6 (Javascript) zur sequenziellen Abarbeitung asynchroner (Callback-basierter) Tasks
Man findet im Netz so einiges, wo externe Libraries verwendet werden, die dann "Promises" oder ähnliche Konstrukte zur Verfügung stellen. Aber eher wenig, wo mal gezeigt wird, wie man mit Generator Functions direkt die Aufrufe asynchroner Funktionen vereinfachen und der "Callback-Hell" entfliehen kann.
Problematisch ist das mit dem "normalen" Ansatz der Callbacks insbesondere dann, wenn man verschachtelte asynchron laufende Funktionen hat:
- führe Funktion A aus
- führe Funktion B aus (aber erst nachdem A fertig ist)
Nachteil:
hier muss die Callback-Funktion die man A übergibt dann B aufrufen usw., was schnell unübersichtlich wird (u.a. wegen der tiefen Verschachtelung, wenn man alles "inline" schreibt) und das Fehlerhandling und auch das Sammeln von Ergebnissen kompliziert macht (Fehler/Ergebnisse müssen durch alle Aufrufe gefangen/gesammelt und nach oben durchgereicht werden).
Nachfolgend ein kleines Beispiel, wie man Callback-basierte asynchrone Funktionen über eine Generator Function serialisieren kann (läuft zumindest im FF und Seamonkey und wahrscheinlich auch in Chrome).
Der interessante "Trick" besteht eigentlich nur darin, dass die Callbackfunktion
resumer() die Methode
iterator.next() aufruft (Z.31), womit sichergestellt wird, dass die einzelnen Tasks nacheinander abgearbeitet werden...
Vorteil:
Man hat alles, was man in diversen Callbacks hätte machen müssen, gebündelt in der Generator Function (Aufruf der Tasks, Fehlerhandling, Ergebnisse sammeln) und es sieht dort nach "normalem" iterativem Programmieren aus.
01
02
03
04
05
06
07
08
09
10
11
12
13
14function serialize (callback, tasks)
15{
16
17
18
19
20 var iterator = undefined;
21 var generator = function*(tasks) {
22 var results = [];
23 var errors = [];
24
25
26
27 var resumer = function(result, error) {
28 if (error) {
29 iterator.throw(error);
30 } else {
31 iterator.next(result);
32 }
33 };
34
35
36
37 for (var i = 0; i < tasks.length; i++) {
38 var task = tasks[i];
39 task(resumer, results, errors);
40 try {
41
42
43
44 var result = yield (null);
45
46 results.push(result);
47 errors.push(undefined);
48
49 } catch (error) {
50
51
52 results.push(undefined);
53 errors.push(error);
54 }
55 }
56
57
58 callback(results, errors);
59 return;
60 };
61
62
63 iterator = generator(tasks);
64
65
66 iterator.next();
67}
68
69
70function async (callback, n) {
71 if (n == 23) {
72 document.body.innerHTML += " ERROR " + n + " is bad | ";
73 callback(undefined, new Error(n + " is bad!"));
74 } else if (n <= 0) {
75 document.body.innerHTML += " STOP | ";
76 callback("done", undefined);
77 } else {
78 console.log("N=" + n);
79 document.body.innerHTML += " " + n;
80 setTimeout(function(){ async(callback, n-1); }, 100);
81 }
82}
83
84
85
86
87
88
89
90
91
92function initGeneratorCallbackTest ()
93{
94 console.clear();
95
96
97 var tasks = [function(callback, results, errors){ async(callback, 10); },
98 function(callback, results, errors){ async(callback, 25); },
99 function(callback, results, errors){ async(callback, 20); },
100 function(callback, results, errors){ async(callback, 30); }];
101
102 serialize(function(results,errors){
103 console.log("FINISHED");
104 document.body.innerHTML += " FINISHED - RESULTS: [" + results + "], ERRORS: [" + errors + "]";
105 }, tasks);
106}
Anmerkungen dazu:
- Errorhandling wird über ein normales try/catch gemacht und das kann (wie hier) zentral an einer Stelle passieren. Man muss nur wissen, dass Fehler aus dem yield "geflogen" kommen.
- Hier wird ein sehr generischer Serialisierer gezeigt. Dafür müssen alle auszuführenden "Tasks" von außen gleich aussehen, was hier über Wrapper-Funktionen gewährleistet wird (Z.97-100). Natürlich kann man die Generator Function auch spezieller aufbauen, indem bestimmte asynchrone Aufgaben hart-kodiert nacheinander aufgerufen werden (getrennt durch jeweils ein yield) statt wie hier in einer For-Schleife über ein Array von Tasks zu iterieren.
- Im gezeigten Beispiel bekommen die Tasks zwar die Ergebnisse ihrer Vorgänger-Tasks, benötigen sie aber nicht wirklich. Sollte das der Fall sein und man keine einheitliche Schnittstelle (Parameter) dafür hat/hinbekommt (trotz Hilfe der Wrapper-Funktionen), wird man es nicht über eine ganz so generische serialize()-Funktion realisieren können.
- Die gesammelten Ergebnisse und Fehler werden hier wieder über einen Callback weitergeben. Wenn man das weiterdenkt, kann man damit auch eine "Callback-Hell" höherer Ordnung generieren :-) - man beachte, dass async() und serialize() sich nach außen sehr ähnlich darstellen - insbesondere auch hinsichtlich der Callback-Funktionen.
- Mit einer weniger generischen Generator-Function würde man die Ergebnisse dann einfach dort weiterverarbeiten, wo sie hier an die Callback-Funktion übergeben werden (Z.58)
Und hier eine dazu passende Mini-Html-Datei zum testen (obigen Sourcecode in Datei "GeneratorCallbackTest.js" kopieren und in dasselbe Verzeichnis legen, dann diese Html-Seite im Browser öffnen) :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<title>Javscript Generator Callback Test</title>
<script type="text/javascript" src="GeneratorCallbackTest.js"></script>
</head>
<body onload="initGeneratorCallbackTest();">
</body>
</html>
Und hier das Ganze zum direkt ausprobieren:
GeneratorCallbackTest.html
Nachtrag:
Für den hier gezeigten Fall funktioniert die nachfolgend gezeigte Variante von
serialize() (die ohne Generator-Functions auskommt) genauso
und ist dabei auch noch kürzer. Bei einem weniger generischen Ansatz würde der Ansatz mit den Generator-Functions eher einen Vorteil bringen.
01function serialize (callback, tasks)
02{
03 var i = 0;
04 var results = [];
05 var errors = [];
06 var resumer = function(res,err){
07 if (err) {
08 results.push(undefined);
09 errors.push(err);
10 } else {
11 results.push(res);
12 errors.push(undefined);
13 }
14 if (++i < tasks.length) {
15 tasks[i](resumer);
16 } else {
17 callback(results, errors);
18 }
19 }
20 tasks[0](resumer);
21}
Zum
Feedback-Formular...
Seamonkey findet keine Plugins mehr (u.a. Flashplayer)
Symptome:
- Seamonkey spielt keine Flash-Videos mehr ab.
- Achtung Youtube-Videos gehen trotzdem, weil die schon lange HTML5 verwenden (zumindest wenn kein Flashplayer verfügbar ist).
- Auf der Seite about:config werden keinerlei Plugins mehr angezeigt (stattdessen steht da "You don't have any add-ons of this type")
Diagnose:
Zunächst mal prüfen ob es am Profil liegt. Dazu im Menü Tools → "Switch Config..." auswählen. Dort auf ein anderes Profil wechseln (ggf. vorher ein neues anlegen, was auch aus diesem Dialog heraus möglich ist).
Lösung:
Wenn es am Profil liegt, besteht die Standardmethode darin alle Dateien "extensions.*" zu löschen (oder zu verschieben). Das hat bei mir allerdings nichts gebracht.
Bei mir lag es an der Datei
prefs.js, die ebenfalls im Profil-Verzeichnis liegt.
Was an dieser Datei genau defekt ist habe ich nicht herausgefunden, da ich eine Sicherungskopie hatte, von der ich die prefs.js herüberkopieren konnte.
Ohne Sicherungskopie, bliebe evtl. nur mit einer neuen prefs.js bzw. sogar einem ganz neuen Profil anzufangen, wobei man z.B. das Mail-Verzeichnis übernehmen kann.
Das Profil befindet sich übrigens normalerweise hier:
- Linux: /home/<username>/.mozilla/seamonkey
- Windows-7: C:\Users/<username>\AppData\Roaming\Mozilla\SeaMonkey
Zum
Feedback-Formular...
Kein Netzwerk nach dem Wecken aus dem Ruhe- bzw. Energiesparzustand (OpenSuse 13.2)
Schon lange verliert mein Laptop sporadisch das Netzwerk nachdem ich ihn aus dem Ruhe- bzw. Energiesparmodus wecke.
Seit dem Update auf OpenSuse 13.2 passiert das allerdings "zuverlässig" jedesmal.
Wenn WLAN vorher deaktiviert war (Hardwareschalter) lässt sich zumindest das WLAN noch einmal aktivieren.
Nach dem nächsten "Nickerchen" ist dann aber auch das weg.
Ich habe lange gesucht und diverse Hinweise gefunden, nur leider bei mir alle nicht funktionieren (entweder weil sie
keinen Effekt haben, oder weil die entspr. Kommandos auf meinem System nicht verfügbar sind.
Randbedingungen:
Bei mir läuft der NetworkManager (prüfbar z.B. mit "systemctl status NetworkManager" - auch als Nicht-root, also ohne "sudo").
System: OpenSuse 13.2 (KDE).
Lösung:
Neustart des NetworkManagers mit:
sudo systemctl restart NetworkManager
Um das nicht jedesmal von Hand machen zu müssen, kann man den Neustart des NetworkManagers
nach dem Wecken in ein systemd-Skript auslagern (die Datei als root neu anlegen):
/usr/lib/systemd/system/network-manager-resume.service
(in /etc/systemd/system/ ginge auch, /usr/lib/systemd/system/ sollte aber bevorzugt verwendet werden)
Dort folgenden Inhalt eintragen:
[Unit]
Description=Restart NetworkManager after suspend
After=suspend.target
[Service]
Type=oneshot
ExecStart=systemctl restart NetworkManager
[Install]
WantedBy=suspend.target
Und dann den neuen Service scharfschalten:
sudo systemctl enable network-manager-resume.service
Danach (spätestens aber nach dem nächsten Reboot) sollte das dann funktionieren...
WLANs nicht (de-)aktivierbar (Not authorized to control Networking)
In OpenSuse 13.2 (KDE) lässt sich über das Toolbar-Icon kein WLAN-Netzwerk aktivieren/deaktivieren.
Die Fehlermeldung lautet:
Not authorized to control Networking
Lösung:
Was bei half war die /etc/NetworkManager/NetworkManager.conf zu editieren.
Vorher:
[main]
plugins=ifcfg-suse,keyfile
Nachher:
[main]
plugins=ifcfg-suse,keyfile
[ifcfg-suse]
managed=true
(Hinweis: In einigen anderen Lösungsbeschreibungen im Internet ist "ifcfg-suse" durch "ifupdown"
ersetzt, da dort das Debian-Pendant verwendet wird)
Nach dem nächsten Reboot funktionierte das dann...
Den Benutzer weiteren Gruppen wie "network" oder "netdev" hinzuzufügen brachte nichts (schon weil es diese Gruppen bei mir nicht gibt).
Der vollständigkeit halber aber auch noch das Kommando dafür:
sudo usermod -G netdev -a