December 08, 2012

Git project's version auto increment

If you have a project which is under Git control and you have some configuration file containing current project's version, then you may wish to automate the process of it's updating.

You need to setup a git hook to do this. In general, any executable file can be a hook, but commonly it's a bash-script. The only requirement is to set a proper name for your hook, because it's execution time depends on it: before commit, after commit and so on. I suppose that the best way to update project's version is to do an automated commit after your manual commit is successfully done. The reason is you may have another hooks which can run some tests or check something before commit. If they will fail, there will be no reason to update current version. This seems to be quite logical.

So, we decided to update project's version after only after successful commit. To do this we need to create a hook with "post-commit" name specified. As you know, project's root directory contains ".git" subdirectory. The onle thing you need to install post-commit hook is to place it to ".git/hooks" directory. It can already contain some hooks samples. So, hook's path will look like:

/path/to/my/repo/.git/hooks/post-commit

If your project has submodules and you want to specify the hook for some of them, then path will look like:

/path/to/my/repo/.git/modules/MySubModule/hooks/post-commit

Make sure you can execute your hook:

chmod +x post-commit

So, let's see an example hook:

#!/bin/sh

MESSAGE=$(git log -1 HEAD --pretty=format:%s)
PRO_PATH=`git rev-parse --show-toplevel`"/Commander/Commander.pro"

VER_TOCKEN="VERSION"
VER_STR=$(grep "^$VER_TOCKEN" $PRO_PATH | awk '{print $3}')

VER_MAJ=$(echo $VER_STR | awk -F. '{print $1}')
VER_MIN=$(echo $VER_STR | awk -F. '{print $2}')
VER_PAT=$(echo $VER_STR | awk -F. '{print $3}')

applyVersion()
{
  VER_STR=$VER_MAJ"."$VER_MIN"."$VER_PAT
  VER_LINE=$VER_TOCKEN" = "$VER_STR
  sed -i 's/^'"$VER_TOCKEN"'.*/'"$VER_LINE"'/' $PRO_PATH
  git add $PRO_PATH
  git commit -m "version update: "$VER_STR
}

onVMAJ()
{
  let VER_MAJ++
  VER_MIN=0
  VER_PAT=0
  applyVersion
}

onVMIN()
{
  let VER_MIN++
  VER_PAT=0
  applyVersion
}

onVPAT()
{
  let VER_PAT++
  applyVersion
}

case "$MESSAGE" in
  *vmaj++* ) onVMAJ;;
  *vmin++* ) onVMIN;;
  *vpat++* ) onVPAT;;
  * );;
esac

exit

You can find this script in Horus Commander's repository, which is a Horus System subproject. Horus Commander is a Qt project and you can find it's configuration file here.

  • "MESSAGE" contains your last commit's message.
  • "PRO_PATH" is an absolute path to "Commander.pro" file, where the version is specified as "VERSION = x.y.z". "x" is for major version (VER_MAJ), "y" is for minor version (VER_MIN) and "z" is for path version (VER_PAT). This is a Semantic Versioning model.
  • If MESSAGE contains "vmaj++" then major version increases. "vmin++" increases minor version and "vpat++" increases patch version.
  • Then new version is written to the configuration file and new commit is done.

Usage exapmles:

# Imagine that current version is "0.0.0"

# Increase version to "0.0.1"
git commit -m "some nasty bug was fixed. #vpat++"

# Increase version to "0.1.0"
git commit -m "some nice feature was provided. #vmin++"

# Increase version to "1.0.0"
git commit -m "new mega release came out. #vmaj++"

October 31, 2012

LPC1114 GPIO example

A couple of exmaples for LPCXpresso are shown below.

1
Writing data
int myPort, myPin;

myPort = PORT3;
myPin = 2;

GPIOSetDir(myPort, myPin, 1);   /** Pay attention for the 1 value */
GPIOSetValue(myPort, myPin, 1);
2
Reading data
int myPort, myPin;

myPort = PORT2;
myPin = 9;

GPIOSetDir(myPort, myPin, 0);  /** Pay attention for the 0 value */

if ((LPC_GPIO2->DATA & (1 << myPin)) == 0)
{
  // onMyPinActive();
}

September 23, 2012

Firefox uses wrong file manager under KDE

If Firefox uses different from your KDE file manager, then there's a workaround for this. Just add the following to the
"~/.local/share/applications/mimeapps.list" file:
[Added Associations]
x-directory/normal=kde4-dolphin.desktop;kde4-kfmclient_dir.desktop;
inode/directory=kde4-dolphin.desktop;kde4-kfmclient_dir.desktop;kde4-gwenview.desktop;kde4-filelight.desktop;kde4-cervisia.desktop;

[Default Applications]
inode/directory=kde4-dolphin.desktop;kde4-kfmclient_dir.desktop;kde4-gwenview.desktop;kde4-filelight.desktop;kde4-cervisia.desktop;
x-directory/normal=kde4-dolphin.desktop;kde4-kfmclient_dir.desktop;
Create file/sections manually if they do not exist.
[Workaround source].

September 10, 2012

LPCXpresso IDE + libxul.so problem

If during LPCXpresso IDE startup you are getting this (or something else related to XULrunner):
# Problematic frame:
# C  [libxul.so+0xda3c0f]
then add the following option to your "lpcxpresso.ini" (/path/to/lpcxpresso_dir/lpcxpresso/lpcxpresso.ini):
-Dorg.eclipse.swt.browser.XULRunnerPath=/dev/null
Add that option to "lpcxpresso.ini". If you are running LPCXpresso IDE from command line, passing mentioned option as a command-line parameter may not work.

August 29, 2012

Setting max laptop backlight brightness

Make sure you have rc.local. If so, add the following to it:
path_backligth_base="/sys/class/backlight/"
file_current="brightness"
file_max="max_brightness"

path_acer_wmi=$path_backligth_base"acer-wmi/"
path_max_acer_wmi=$path_acer_wmi$file_max

if [[ -f $path_max_acer_wmi ]]; then
        cat $path_max_acer_wmi > $path_acer_wmi$file_current
else                                           
                                               
        path_acpi=$path_backligth_base"acpi_video0/"
        path_max_acpi=$path_acpi$file_max

        if [[ -f $path_max_acpi ]]; then
                cat $path_max_acpi > $path_acpi$file_current
        fi                                     
fi
As you can see the 1st if-statement is Acer-laptops specific and the 2nd is for general case. You may need to change "acer_wmi" to something else. Just look through the "backlight" directory to find your answer. It's possible you do not need the 1st check at all. It's just distributive-dependent trick.

July 29, 2012

Getting IP address of server stream socket of local process

    If you need to get IP address which is assigned to some socket created by local process, you can run following command for shell:
lsof -i | grep -m 1 process_name | awk '{print $9}' | awk -F: '{print $1}'
    Let's see how it works step by step.

1
Running
lsof -i
    gives the listing of all Internet and x.25 (HP-UX) network files.

2
Running
lsof -i | grep -m 1 process_name
    gives the listing 1 file specified for target process. For example, process name is "firefox". The result will be:
firefox  2287 oblalex   50u  IPv4 247178      0t0  TCP 192.168.1.33:56695->93.184.220.20:http (CLOSE_WAIT)
3
Running
lsof -i | grep -m 1 process_name | awk '{print $9}'
    gives source address and destination address with protocol name. In our example it will be:
192.168.1.33:56695->93.184.220.20:http
4
Finally, running
lsof -i | grep -m 1 process_name | awk '{print $9}' | awk -F: '{print $1}'
    gives the final result by splitting string with ":" separator and selecting source address:
192.168.1.33

July 12, 2012

MKV to MP4 via ffmpeg

    To convert from MKV to MP4 without compression make sure ffmpeg and x264 are installed. Then run:
ffmpeg -i input.mkv -strict experimental -vcodec libx264 output.mp4

June 16, 2012

Arch Linux: logging system in hangs up

    After installing 'kdebase' package on an Arch Linux having just minimalistic 'base' packages group, you may found that starting KDE hangs up and such message in '~/.xsession-errors' appears:
QDBusConnection: session D-Bus connection created before QCoreApplication.
Application may misbehave.
    It can appear even if you have DBus daemon installed. The solution is to install missing in dependencies DejaVu font running command:
sudo pacman -S ttf-dejavu

June 11, 2012

Hunspell ukrainian and russian dictionaries

1
Download dictionaries:
2
Move to a proper directory:
sudo mv ./hunspell-uk_UA/* /usr/share/hunspell/
sudo mv ./hunspell-ru_RU/* /usr/share/hunspell/
3
Change files' mod
cd /usr/share/hunspell/
sudo chmod 644 uk_UA.* ru_RU.*

June 03, 2012

Netbeans with KDE

1
Uniform Look for Qt and GTK Applications. I know, your linux distro may be not Arch Linux, but the plot is the same. Oxygen-gtk works very Ok. If you really don't get how to do that, just install oxygen-gtk, go to "System Settings->Lost and Found->GTK style":


Open "GTK style" setting dialog and select "oxygen-gtk":

2
Open your "netbeans.conf" file. It's located at "etc" subdirectory of your Netbeans' main directory. If your Netbeans' location is
~/netbeans-7.1/
then config file will be located at
~/netbeans-7.1/etc/netbeans.conf
3
Find "netbeans_default_options" variable.
4
Add this parameter
--laf com.sun.java.swing.plaf.gtk.GTKLookAndFeel
to the end of variable's declaration. Use space to separate it from other parameters.
5
Launch Netbeans and enjoy.

June 01, 2012

Install True Type Fonts on Linux

1
Navigate to the directory, where TTF fonts are placed.
2
Create a directory for fonts (if not exists):
# mkdir /usr/share/fonts/truetype
3
Move the font files to the new font directory:
# mv *.ttf /usr/share/fonts/truetype
4
Navigate to the font directory:
# cd /usr/share/fonts/truetype
5
Create fonts.scale and fonts.dir:
# mkfontscale && mkfontdir
# fc-cache

May 25, 2012

AVR firmware uploading tools

    Imagine you have an [AVR] microcontroller with bootloader inside. You have written some program for  AVR and you need to compile&upload it inside. How you can do that? Let's see how to do it on example of [ATmega64A] which is installed on a Tank device from [Open System].


0
Preparations
    For Windows:
1
Download CP210x USB to UART Bridge VCP Drivers from [here].
2
Get [avrdude] for windows. Visit this [page] to see avrdude's parameters.
3
Connect device to PC via USB.
4
Install bridge drivers. A new COM-device should appear in system. Remember it's name.
5
Reboot.
    For Linux:
1
Visit this [page] to see what you should do to install AVR-GCC toolchain.
2
Connect device to PC via USB.
3
Run 'lsusb' to see vendor's and product's IDs:
alexlaptop alex # lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 008 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 003: ID 064e:a103 Suyin Corp. Acer/HP Integrated Webcam [CN0314]
Bus 006 Device 002: ID 093a:2510 Pixart Imaging, Inc. Optical Mouse
Bus 003 Device 002: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x Composite Device
As you can see our device is on the last line. Vendor's ID is '10c4' and product's ID is 'ea60'. Lets remember them:
alexlaptop alex # idVendor=10c4
alexlaptop alex # idProduct=ea60
echo $idVendor:$idProduct
10c4:ea60
4
Now create new USB rule:
alexlaptop alex # echo "ATTRS{idVendor}==\"$idVendor\",  ATTRS{idProduct}==\"$idProduct\", MODE=\"0660\", GROUP=\"users\"" > /etc/udev/rules.d/usb_bridge.rules
alexlaptop alex # cat /etc/udev/rules.d/usb_bridge.rules
ATTRS{idVendor}=="10c4",  ATTRS{idProduct}=="ea60", MODE="0660", GROUP="users"
5
Update rules:
alexlaptop alex # udevadm control --reload-rules
6
Remember your device. For this run:
alexlaptop alex # find /dev/ -name "*usb*"
and then look for your device's name. As for me it was:
/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0

1
Atmel Studio
   Atmel for Atmel. Register for free [here] to download [Atmel Studio]. You'll get the download link right after email confirmation. Download size is above 700 MiB (too much? it's Visual Studio based, so what did you expect?). Installation includes studio itself, compilers/linkers and USB-drivers.
   Downloaded. Installed. Launched.

1
Click 'New Project...'
2
Select 'GCC C Executable Project'. Enter project's name and location.


3
Select 'ATmega64A' as target device. You can get datasheet just following the link at the right side.


4
Get your main file template automatically created.
/*
 * tank_test.c
 *
 * Created: 25.05.2012 13:08:47
 *  Author: alex
 */ 

#include <avr/io.h>

int main(void)
{
    while(1)
    {
        //TODO:: Please write your application code 
    }
}
5
Set project configuration to 'Release' instead of 'Debug'. Click 'Build->Build Solution' or just press F7. After building you will get .elf and .hex files.
6
Upload .hex file to the device. To do that you need press "reset" button & run avrdude. Script must be running while the device is resetting. You can run this [bat-file]. It's content is shown below.
@echo off
rem Use avrdude as programming-software with the AVRProg compatible bootloader
rem Martin Thomas, 2006

rem Verfiy that the bootloader is configured with #define DEVTYPE DEVTYPE_ISP
rem since it seems that avrdude does not work with "Boot" device-types and needs
rem ISP device-types (at least in version 5.1 as in WinAVR 4/06)

set HEXFILE=tank_test.hex
set PROGRAMMER=avr109
set PORT=com3
set PART=m64

rem * disable safemode - bootloader can not "restore" fuses anyway
set DIS_SAVE=-u

avrdude %DIS_SAVE% -p %PART% -P %PORT% -c %PROGRAMMER% -v -U flash:w:%HEXFILE% 

pause
HEXFILE is a path to your previously compiled .hex-file.
PROGRAMMER is set to avr109 because [this] bootloader is used.
PORT is com3, it's virtual port installed earlier.
PART is m64 = ATmega64

After running script you should see lots of logs and this message at the end:
arvdude done. Thank you.
   So, your program was uploaded. In current example program does nothing, but nevertheless, congrats!
2
WinAVR
   WinAVR's [homepage].
3
CodeVisionAVR
   CodeVisionAVR's [homepage].
4
Code::Blocks
   You can search the web to see how to use [Code::Blocks] for AVR projects development. On
5
Eclipse AVR Plugin
1
Get [Eclipse] and launch it. Edition does not matter. I had 'Java EE' edition and it's OK.
2
Go to 'Help->Eclipse Market place...', type 'avr' and press 'enter' to find 'AVR Eclipse Plugin'.

3
Install plugin and restart Eclipse.
4
Create new project: 'File->New->Other...' (or just press Ctrl+N). Select 'C Project'.


Go next, set project's name and location. Select 'AVR Cross Target Application'.


Go next and next again. Select your target device and it's working frequency.


Click 'Finish'.
5
Create new or add existing C-source file. Let it be a program, which blinks 2 LEDs with periods of 1 and 2 seconds. Source file can be viewed [here].
6
Compile your program to get .hex-file.
7
Go to 'Project->Properties->AVR->AVRDude'.


8
In 'Programmer' tab click 'New...' near 'Programmer configuration'. Set configuration's name, select 'Atmel AppNote AVR109 Boot Loader' as programmer hardware, and path to your USB device:


Click 'Ok', 'Ok' to apply settings and close dialogues.
9
Upload your firmware to the device: press 'Reset' button on the device & click
'AVR->Upload Project to Target Device' (or just press 'Ctrl+Alt+U'). Remember: you must upload firmware while device is resetting.

May 24, 2012

XeLaTex application form example

    I've created an application form for 2nd phase of Olympiad for my university.       
   Source code can be downloaded from [here]. click [here] to get PDF, do not look via dropbox viewer. The result looks like:

May 22, 2012

XeLaTex unicode blank

   Here is a script to create a blank XeLaTex document with cyrillic letters support:
%&program=xelatex
%&encoding=UTF-8 Unicode

\documentclass[a4paper]{article}
\pagestyle{empty}

\usepackage{geometry}
\geometry{top=2cm}
\geometry{left=2cm}
\geometry{bottom=2cm}
\geometry{right=1cm}

\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{cmap}
\usepackage{fontspec}
\setmainfont{FreeSerif}

\begin{document}
\fontsize{14pt}{14pt}
\selectfont
\begin{center}
\textbf{\uppercase{I'm header. Я заголовок}\\
I'm subheader. Я подзаголовок
}
\end{center}
The quick brown fox jumps over the lazy dog.\\
Съешь ещё этих мягких французских булок, да выпей же чаю.
\end{document}
   The result is (click to enlarge):



Things to note:

    pagestyle is set to 'empty', so no header/footer will be displayed on page. By default footer contains page number.

    You can use documentclass to set font size in such way:
\documentclass[12pt, a4paper]{article}
    In this case you should keep in mind that class 'article' allows to use
10-12pt sizes only. To use another size you should set it with fontsize just after document's body beginning. Do not forget to apply it with selectfont.

    To make it possible to use fontspec package this script must be compiled with XeLaTex instead of LaTex.

    If you are using Texmaker, you can add a hotkey to compile with XeLaTex and run preview with Evince. To do this go to
User->User Comands->Edit User Comands
    then enter 'XeLaTex' (or whatever you like) as menu's title and enter next command:
xelatex -interaction=nonstopmode -synctex=-1 %.tex | evince %.pdf

    This will be looking something like below:

    Voila, you can compile and run preview with 'Alt+Shift+F1' hotkey (or another selected one).

April 24, 2012

Kiev Hackathon

    Last weekend I and three my mates took participation in [Kiev Hackathon], organized by Facebook. This event took place at [Hyatt Regency Kiev] on April 21-22.
    
    At the beginning of hackathon [Paul] has asked to raise a hand as an answer to a question: 'Who has a problem?'. No hands were raised. Then Paul said that when he asks this question in his class it comes that almost everyone has some kind of problem, something to change in everyday life. 
    
This seems to be very strange. Just think about it: people living in a country with high standard of living (such as the USA) have rather more problems than people living in a country where standard of living is more lower and pessimistic moods are dominating (such as Ukraine). I suppose, everyone just misunderstood the question, but nevertheless, it's a kind of paradoxical fact. 

   As about the event itself, it was great. Crazy night, awesome place, nice and positive people. By the way, the day the hackathon started was the same day I've returned from my 5-day trip to Odessa, where I have been taking participation in the 'Technical diagnosis of digital devices and software' olympiad. So, it seemed to me like a one crazy 6-day almost sleepless event. Maybe I'm self-masohism prone:).

   Despite, I'm trying to be aware of any kind of social networks, I'd like to thank Facebook and especially people, who organized hackathon for this great and positive event. It helped me to open my mind a little more once again.

    Try to find me on the picture below ;) .


April 03, 2012

Earth's chronology

   Every time I see the picture below I say "Damn!". And it's not because of it's a clock (it alludes the cycling of events, but we can't be sure of it).  It's because of time proportions.

    Taking into consideration the approximate age of humanity is 200.000 years and average lifespan is about 70 years, in terms of this 'clock' the average human lives just about 0.027 seconds.
   Just amazing. It took about 24⋅60 minutes to create and seems it will take less then 1 minute to destroy. Imagine a digital signal with setup-time of 1440 minutes and hold-time about 1 minute. It's 1:1440. Damn! What kind of logic is it?

March 29, 2012

GStreamer Audio Echo


   Examples of outputting audio stream from audio input with [GStreamer]  were created. C-language was used. Examples include demonstration of direct and over-network audio data transmission.
    See everything in my [repo]. More information in \readme\ section there.

March 18, 2012

DOU logo on facebook

   I don't know, how come the photo below was chosen as [DOU] logo [on facebook], but nevertheless I'm pleased to see my face on it. This photo was taken from hackathon in Lviv. You can read my report about this event [here].


March 07, 2012

Sharing tests in maven multi modules projects

   [Here] is an article which describes how to keep sources and tests in one maven project and to access them from another (sibling) project.
    Project structure example:
componentA
|
|-moduleA
|         /src/main/java
|         /src/main/resources
|         /src/test/java
|         /src/test/resources
|-moduleB
|         /src/main/java
|         /src/main/resources
|         /src/test/java
|         /src/test/resources

February 07, 2012

Gnome3 Login Wallpaper

    [Here] is a post about how to change Login wallpaper in Gnome3. {Arch Linux as an example}

February 01, 2012

Qt Audio Echo


    I've created a simple demo Qt multimedia application, which reads the audio input and writes  data to the audio output (QAudioInput and QAudioOutput are used). It can be tested using microphone and speakers/headphones.
     The source code of the application can be viewed in my repository [here].

January 23, 2012

ISE Simulator: Failed to compile one of the generated C code...

    When you have a clean installation of Xilinx ISE and you want to run ISim you can get an error which sounds like this:

ISE Simulator (ISim) - "FATAL_ERROR:Simulator:Fuse.cpp:217:1.95 - Failed to compile one of the generated C code..."

   One of the probable solutions can be found [here]. Turning on a verbose messaging probably will cause telling something like this:

libstdc++.so.6: version `GLIBCXX_3.4.14' not found

    It can be solved in the way described [here].
    By the way, gcc 4.4.* may be required (But it's not a rule).

January 19, 2012

Ugly Qt Application under root

    To change default qt settings for root-running application run qtconfig with root privileges. Something like this:

sudo qtconfig

    After that you can configure everithing as you wish.

January 17, 2012

IExplorer 6 under Wine

    Lets say you've already installed this things:
  • wine
  • winetricks
  • wine_gecko
    Now you want to install IE6. First of all, let winetrick do some work:

winetricks corefonts vcrun6 wsh56 gdiplus msls31 riched20 riched32 tahoma

    Maybe, some of packages are extra, but nothing bad will happen if you'll install them. One more package you will need is this:

winetricks msxml3

    Winetricks will show an URL aks to follow if to download msxml3.msi package and to save it to

~/.cache/winetricks/

    After that you can repeat installation via winetricks.
   Next thing you'll need to do is to copy some dll-libs to your wine environment. They are:
  • msctf.dll
  • msimtf.dll
  • uxtheme.dll
  • msvcrt.dll
    Originally they are placed here:

C:\WINDOWS\system32

    Or here:

C:\WINDOWS\system32\dllcache

    You need to copy them here:

~/.wine/drive_c/windows/system32/

    After counfigure your registy, placed  here:

~/.wine/user.reg

    Opet it in some text editor and find this section:

[Software\\Wine\\DllOverrides]

    There you can copy this content:

"browseui"="native, builtin"
"comctl32"="builtin"
"crypt32"="native, builtin"
"gdiplus"="native"
"hhctrl.ocx"="native, builtin"
"hlink"="native, builtin"
"iernonce"="native, builtin"
"iexplore.exe"="native, builtin"
"itircl"="native, builtin"
"itss"="native, builtin"
"jscript"="native, builtin"
"mlang"="native, builtin"
"mshtml"="native, builtin"
"msimtf"="native,builtin"
"msxml3"="native,builtin"
"riched20"="native,builtin"
"riched32"="native,builtin"
"secur32"="native, builtin"
"shdoclc"="native, builtin"
"shdocvw"="native, builtin"
"shlwapi"="native, builtin"
"url"="native, builtin"
"urlmon"="native, builtin"
"usp10"="native, builtin"
"uxtheme"="native,builtin"
"wininet"="builtin"
"wintrust"="native, builtin"

    You can do it using winecfg also. The result should be like this:


    Now IE can be installed:

winetricks ie6

    This command will download IE6 installator, prepare and launch it. The only thing you'll have to do is to click 'Next' during instalation process.
     The final result:


January 02, 2012

Tapestry: AttributeExpansionBinding@XXXX is read-only

   If a TapestryException appears and it says something like this:
Binding org.apache.tapestry5.internal.services.AttributeExpansionBinding@2c4f59 is read-only.
   then the solution can be in removing ${} from t:value property in problematic component. Something like change this:
<t:checkbox t:id="oneEmailPerUser" t:name="oneEmailPerUser" t:value="${config.oneEmailPerUser}"/>
   to this:
<t:checkbox t:id="oneEmailPerUser" t:name="oneEmailPerUser" t:value="config.oneEmailPerUser"/>
   That's made my day evening.