11 kwietnia 2012

Uruchamianie aplikacji w przeglądarce...

...czyli rejestrowanie własnego protokołu URL

Kilka razy podchodziłem do tego problemu. A to kombinowałem z zakręconym JavaScriptem (bezskutecznie), a to z pluginem do Firefoxa (z powodzeniem). Aż trafiłem na artykuł o rejestrowaniu własnych protokołów, tak jak wbudowany http://

Aby przeglądarka rozpoznawała wywołanie typu winbox:192.168.88.1;admin;admin; należy ten protokół zarejestrować w systemie.
Osobiście potrzebowałem kilku takich protokołów, przygotowałem mały zestaw skrypt+aplikacja aby ten proces zautomatyzować.

Plik konfiguracyjny url_launcher.config:
(Nazwa pliku jest ważna, na sztywno wpisana w aplikacji url_launcher.exe)

winbox;c:\bin\winbox.exe
putty;C:\BIN\putty.exe
quake;d:\games\Quake III Arena\quake3.exe

Pierwsza pozycja to nazwa protokołu, druga pozycja (oddzielona średnikiem) to ścieżka do pliku wykonywalnego obsługującego nasz protokół. Odpowiednie wpisy do rejestru wykonuje poniższy skrypt, wpisy są uzależnione od wpisów w pliku konfiguracyjnym.

Skrypt url_launcher.cmd
@echo off
set URL_LAUNCHER_PATH=%~dp0
set URL_LAUNCHER_PATH=%URL_LAUNCHER_PATH:\=\\%

echo Windows Registry Editor Version 5.00 > url_launcher.temp.reg
FOR /F "eol= tokens=1,2 delims=;" %%I in (url_launcher.config) do (
 (
 echo [HKEY_CLASSES_ROOT\%%I]
 echo @="Winbox URI"
 echo "URL Protocol"=""
 echo [HKEY_CLASSES_ROOT\%%I\DefaultIcon]
 echo @="\"%%J\",0"
 echo [HKEY_CLASSES_ROOT\%%I\shell]
 echo @="open"
 echo [HKEY_CLASSES_ROOT\%%I\shell\open]
 echo [HKEY_CLASSES_ROOT\%%I\shell\open\command]
 echo @="\"%URL_LAUNCHER_PATH%url_launcher.exe\" \"%%1\""
 ) >> url_launcher.temp.reg
)
regedit /s url_launcher.temp.reg
del url_launcher.temp.reg

Do tego wszystkiego, potrzebny jest mały programik, który obrobi dane wejściowe i wywoła nam aplikację docelową url_launcher.exe

Wracając do naszego protokołu winbox:192.168.88.1;admin;admin, po wpisaniu go w pasku adresu przeglądarki i uruchomieniu, zostanie uruchomiony program z parametrami c:\bin\winbox.exe 192.168.88.1 admin admin. Analogicznie z putty:8.8.8.8;-l;root zostanie uruchomiony c:\bin\putty.exe 8.8.8.8 -l root

Aby wszystko zadziałało bezproblemowo, wszystkie pliki powinny znajdować się w tym samym katalogu.

I na zakończenie: to rozwiązanie jest uniwersalne, działa w każdej przeglądarce.

5 kwietnia 2012

Speedtest.net Mini - automatyczna aktualizacja

Czasami zdarzało się, że wchodząc na mój własny speedtest okazywało się, że jest nieaktualny... czasami taki nieaktualny wisiał ponad miesiąc...
Napisałem więc prościusieńki skrypt w BASHu który robi to za mnie
#!/bin/bash

cd <pełna_ścieżka_do_katalogu_z_twoim_speedtest.net_mini>
if ! wget -N http://c.speedtest.net/mini/mini.zip 2>&1 | grep -q "not retrieving";then
    unzip -o mini.zip
fi
Uruchamiamy co jakiś czas z crona i zapominamy o pilnowaniu i aktualizowaniu naszego Speedtest.net Mini.

6 marca 2012

Clean Drive

Tak sobie przypomniałem o pewnej bardzo prostej komendzie, którą można czyścić dyski ze zbędnych śmieci (chodzi o zajęte sektory po usuniętych plikach). Bardzo przydatne przy tworzeniu obrazów dysków/partycji w systemach plików nie obsługiwanych przez Wasz program do archiwizacji (tryb 'sektor po sektorze'). A wszystko po to, aby zminimalizować rozmiar skompresowanego archiwum...
dd if=/dev/zero of=/0bits bs=20M;rm -f /0bits
dd if=/dev/zero of=/home/0bits bs=20M;rm -f /home/0bits
dd if=/dev/zero of=/var/0bits bs=20M;rm -f /var/0bits
dd if=/dev/zero of=/usr/0bits bs=20M;rm -f /usr/0bits
dd if=/dev/zero of=/tmp/0bits bs=20M;rm -f /tmp/0bits
Oczywiście parametry wywołań będą różnić się od ilości i miejsca montowań partycji.
Przy okazji zmierzymy prędkość zapisu na danej partycji :)

10 sierpnia 2011

Szablon XSL - słownie złotych

Przy okazji uruchamiania systemu generującego PDFy z fakturami, potrzebowałem czegoś, co zamieni kwoty przedstawione za pomocą liczb na odpowiadający im opis słowny. Tak powstał ten szablon XSL, gotowy do dołączenia w projektach.
Pierwowzorem był znaleziony w necie, pewien algorytm napisany w C#, który to w międzyczasie przerobiłem na Javascript (tego użyłem w innym projekcie związanym z PDF).
I tak oto powstał ten szbalon.
<xsl:template name="get-gr">
  <xsl:param name="amount"/>
  <xsl:variable name="a1" select="floor($amount)"/>
  <xsl:variable name="len" select="string-length($a1)"/>
  <xsl:variable name="a2" select="substring($a1,$len,1)"/>
  <xsl:choose>
    <xsl:when test="$a1 = 1"><xsl:value-of select="document('amount-in-words.xml')/amount-in-words/grosze[1]"/></xsl:when>
    <xsl:when test="$a2 > 1 and $a2 < 5"><xsl:value-of select="document('amount-in-words.xml')/amount-in-words/grosze[2]"/></xsl:when>
    <xsl:otherwise><xsl:value-of select="document('amount-in-words.xml')/amount-in-words/grosze[3]"/></xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="get-zl">
  <xsl:param name="amount"/>
  <xsl:variable name="a1" select="floor($amount)"/>
  <xsl:variable name="len" select="string-length($a1)"/>
  <xsl:variable name="a2" select="substring($a1,$len,1)"/>
  <xsl:choose>
    <xsl:when test="$a1 = 1"><xsl:value-of select="document('amount-in-words.xml')/amount-in-words/zlote[1]"/></xsl:when>
    <xsl:when test="$a2 > 1 and $a2 < 5"><xsl:value-of select="document('amount-in-words.xml')/amount-in-words/zlote[2]"/></xsl:when>
    <xsl:otherwise><xsl:value-of select="document('amount-in-words.xml')/amount-in-words/zlote[3]"/></xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="get-words">
  <xsl:param name="amount"/>
  <xsl:variable name="zl" select="floor($amount)"/>
  <xsl:variable name="len" select="string-length($zl)"/>
  <xsl:if test="$len > 6">
    <xsl:variable name="million2" select="substring($zl,$len -6,1)"/>
    <xsl:variable name="million">
        <xsl:if test="$len > 8"><xsl:value-of select="substring($zl,$len -8,1)"/></xsl:if>
        <xsl:if test="$len > 7"><xsl:value-of select="substring($zl,$len -7,1)"/></xsl:if>
        <xsl:value-of select="substring($zl,$len -6,1)"/>
    </xsl:variable>
    <xsl:if test="$million > 1">
      <xsl:call-template name="get-words">
        <xsl:with-param name="amount" select="$million"/>
      </xsl:call-template>
    </xsl:if>
    <xsl:choose>
      <xsl:when test="$million = 1">
        <xsl:value-of select="document('amount-in-words.xml')//millions[1]"/>
      </xsl:when>
      <xsl:when test="$million > 1 and $million < 5">
        <xsl:value-of select="document('amount-in-words.xml')//millions[2]"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="document('amount-in-words.xml')//millions[3]"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:if>

  <xsl:if test="$len > 3">
    <xsl:variable name="thousend2" select="substring($zl,$len -3,1)"/>
    <xsl:variable name="thousend">
      <xsl:if test="$len > 5"><xsl:value-of select="substring($zl,$len -5,1)"/></xsl:if>
      <xsl:if test="$len > 4"><xsl:value-of select="substring($zl,$len -4,1)"/></xsl:if>
      <xsl:value-of select="substring($zl,$len -3,1)"/>
    </xsl:variable>

    <xsl:if test="$thousend > 1">
      <xsl:call-template name="get-words">
        <xsl:with-param name="amount" select="$thousend"/>
      </xsl:call-template>
    </xsl:if>

    <xsl:choose>
      <xsl:when test="$thousend = 1">
        <xsl:value-of select="document('amount-in-words.xml')//thousends[1]"/>
      </xsl:when>
      <xsl:when test="$thousend2 > 1 and $thousend2 < 5">
        <xsl:value-of select="document('amount-in-words.xml')//thousends[2]"/>
      </xsl:when>
      <xsl:when test="$thousend = '000' and $len > 6">
        <xsl:text></xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="document('amount-in-words.xml')//thousends[3]"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:if>

  <xsl:if test="$len > 2">
    <xsl:if test="substring($zl,$len -2,1) != 0">
      <xsl:value-of select="document('amount-in-words.xml')//hundrets[substring($zl,$len -2,1) + 1]"/>
    </xsl:if>
  </xsl:if>

  <xsl:if test="$len > 0">
    <xsl:variable name="to99">
      <xsl:choose>
        <xsl:when test="$len = 1">
          <xsl:value-of select="substring($zl,$len,1)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="substring($zl,$len -1,2)"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$to99 < 20">
        <xsl:choose>
          <xsl:when test="substring($to99,1,1) = 0">
            <xsl:if test="substring($to99,2,1) != 0">
              <xsl:value-of select="document('amount-in-words.xml')//units[substring($to99,2,1) + 1]"/>
            </xsl:if>
          </xsl:when>
          <xsl:otherwise>
            <xsl:if test="$to99 != 0">
              <xsl:value-of select="document('amount-in-words.xml')//units[$to99 + 1]"/>
            </xsl:if>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="document('amount-in-words.xml')//tens[substring($to99,1,1)+1]"/>
        <xsl:if test="substring($to99,2,2) != 0">
          <xsl:value-of select="document('amount-in-words.xml')//units[substring($to99,2,2) + 1]"/>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:if>

  <xsl:if test="$zl = 0">
    <xsl:value-of select="document('amount-in-words.xml')//units[1]"/>
  </xsl:if>
</xsl:template>

<xsl:template name="amount-in-words">
  <xsl:param name="amount"/>
  <xsl:call-template name="get-words"><xsl:with-param name="amount" select="$amount"/></xsl:call-template>
  <xsl:call-template name="get-zl"><xsl:with-param name="amount" select="$amount"/></xsl:call-template>
  <xsl:call-template name="get-words"><xsl:with-param name="amount" select="round(($amount - floor($amount))*100)"/></xsl:call-template>
  <xsl:call-template name="get-gr"><xsl:with-param name="amount" select="round(($amount - floor($amount))*100)"/></xsl:call-template>
</xsl:template>
Powyższy fragment kody należy umieścić w dowolnym miejscu istniejącego szablonu. Dodatkowo w katalogu z szablonem, należy umieścić poniższy plik o nazwie amount-in-words.xml:
<?xml version="1.0" encoding="UTF-8"?>    
<amount-in-words>
<grosze>grosz </grosze>
<grosze>grosze </grosze>
<grosze>groszy </grosze>
<zlote>złoty </zlote>
<zlote>złote </zlote>
<zlote>złotych </zlote>
<units>zero </units>
<units>jeden </units>
<units>dwa </units>
<units>trzy </units>
<units>cztery </units>
<units>pięć </units>
<units>sześć </units>
<units>siedem </units>
<units>osiem </units>
<units>dziewięć </units>
<units>dziesięć </units>
<units>jedenaście </units>
<units>dwanaście </units>
<units>trzynaście </units>
<units>czternaście </units>
<units>piętnaście </units>
<units>szesnaście </units>
<units>siedemnaście </units>
<units>osiemnaście </units>
<units>dziewiętnaście </units>
<tens></tens>
<tens>dziesięć </tens>
<tens>dwadzieścia </tens>
<tens>trzydzieści </tens>
<tens>czterdzieści </tens>
<tens>pięćdziesiąt </tens>
<tens>sześćdziesiąt </tens>
<tens>siedemdziesiąt </tens>
<tens>osiemdziesiąt </tens>
<tens>dziewięćdziesiąt </tens>
<hundrets></hundrets>
<hundrets>sto </hundrets>
<hundrets>dwieście </hundrets>
<hundrets>trzysta </hundrets>
<hundrets>czterysta </hundrets>
<hundrets>pięćset </hundrets>
<hundrets>sześćset </hundrets>
<hundrets>siedemset </hundrets>
<hundrets>osiemset </hundrets>
<hundrets>dziewięćset </hundrets>
<thousends>tysiąc </thousends>
<thousends>tysiące </thousends>
<thousends>tysięcy </thousends>
<millions>milion </millions>
<millions>miliony </millions>
<millions>milionów </millions>
</amount-in-words>            
Wywołanie jest proste, polega na wstawieniu poniższego fragmentu w interesującym nas miejscu szblonu:
<xsl:call-template name="amount-in-words">
  <xsl:with-param name="amount" select="value"/>
</xsl:call-template>
Jak na razie, u mnie ma to status beta, jeśli ktoś znajdzie jakieś błędy, zaproponuje poprawki, zapraszam do dyskusji.

5 lipca 2011

cwRsync portable

Często używam rsync do robienia backupów albo do synchronizowania zawartości folderów na wielu serwerach. Ostatnio postanowiłem, że kupię sobie dysk przenośny o dużej pojemności i wrzucę tam wszystkie najważniejsze swoje rzeczy. Chciałem mieć możliwość robienia tego z dowolnego miejsca przez net, więc pomyślałem o rsync.

Wszystko chciałem uruchamiać pod Windows, na dowolnym kompie do którego się podepnę. Stworzyłem prostą strukturę katalogów w głównym folderze dysku:
\bin
\backup
Zawartość z katalogu bin z folderu instalacyjnego cwRsync wrzuciłem do katalogu bin na dysku przenośnym.

Dorzuciłem też plik cwrsync.cmd do głównego katalogu. Poniżej zawartość pliku:
@echo off
setlocal
set CWRSYNCHOME=%~d0\bin
set CYGWIN=nontsec
set HOME=%HOMEDRIVE%%HOMEPATH%
set PATH=%~d0\bin;%PATH%

cygpath -a backup > backup.d
set /p BACKUP= < backup.d
del backup.d

rsync -rtlv --compress user@host::moduł %BACKUP%/ < %~d0\plik_z_hasłem
Problem z rsync polegał na tym, że ścieżka docelowa musi być absolutną ścieżką w formacie cygwin, np.: /cygdrive/h/backup. Wszelkie próby z relatywną ścieżką zawodziły.
Wykorzystałem także możliwość prostej autoryzacji w rsync, jedynym sposobem przekazania hasła, było proste przekierowanie go z zewnętrznego pliku.