Recently, I became an Android phone user (Samsung Galaxy S, to be more precise) and one of the first quests I had to take was to transfer contacts from my old phone (Nokia 6300) to the new one. Unfortunatelly, I haven't found any complete guide on the net, so I decided to combine a number of found solutions and provide an ultimate one.
The easiest way of importing contacts into an Android phone is to import them to your Google account. To be honest, I don't find that satisfying - I would like to have my old contacts on my phone and my phone only.
Long story short, these are the steps that worked for me:
1. Install Nokia PC Suite and connect your phone to it. Then, go to Contacts and in the Nokia Communication Centre window select them all and choose File -> Export in order to save contacts info into a CSV file.
2.Open the CSV file in any text editor and find all occurences of ';' (semicolon) replacing them with ',' (comma). Yes, I know it doesn't seem right, but unfortunately the CSV to VCF conversion tool we are going to use later doesn't handle semicolons.
3. Open the CSV to vCard conversion tool and paste the content of the CVS file. Follow to the step 3 and copy all the content (it's a vCard now) and save it as a .vcf file.
4. Open the VCF file in any text editor and do two things:
- replace all occurences of quotation mark (") with an empty string (i.e. remove all quotation marks from the file) - without this you will have really ugly contact display and I don't even think that phone numbers would be working
- replace all occurences of 'FN: ' with 'FN:' (i.e. remove trailing whitespaces after the 'FN:' string) - without this you will have a space before every contact that has a 'Name' field set
5. Install an application that allows .vcf contact import - for me it was Samsung Kies, which has a nice option of importing contacts to your phone, not your Google account.
And that's it! After some time I was able to use my old Nokia contacts on my brand new Android phone. I hope you'll find this short guide useful :-).
Importing contacts from Nokia to Android phone
Comparing Strings
Nothing much, really, but I recently noticed that when you need to compare two Strings in Java, when one of them is constant, instead of
stringVariable != null && stringVariable.equals("someConstantString")you can simply do
"someConstantString".equals(stringVariable)
, which does all the magic at once.
Adding reCAPTCHA
Lately I've been receiving comments from bots on my personal blog. Because this blog is written by me from scratch (PHP & Smarty), I thought about adding some anti-bot protection, like CAPTCHA, to comment submit form.
CAPTCHA, according to wikipedia, stands for Completely Automated Public Turing test to tell Computers and Humans Apart. I'm sure every single one of you've seen something similar on many web pages.
But reCAPTCHA, currently owned by Google (surprised?), is something more than just another CAPTCHA. It uses this protection to build the biggest electronic library in the world internet. How? The idea is ingenious, yet simple - the user receives two words to copy: one of these words is known to the machine (computer, server...), the other one is a misshapen word, which was impossible for OCR software to recognize. ReCAPTCHA assumes, that if a user fills in the known word correctly, the other one is correct as well. The not-known word is sent to more than one (say, ten) users and if sufficiently often people recognize the word as the same one, it is believed that it's the correct option.
ReCAPTCHA provides really neat tutorial for PHP, well, quickstart guide, to be more precise. Instructions are really simple. Long story short, you just have to:
- Download reCAPCTHA library, unzip and include it in a proper PHP script file
require_once('path/to/the/lib/recaptchalib.php'); - Sign up for an API key - you'll recieve two keys: private and public. It's a good practise to store them in some constants, like:
$RECAPTCHA_PUBLIC_KEY = 'YOUR_RECAPTCHA_PUBLIC_KEY';
$RECAPTCHA_PRIVATE_KEY = 'YOUR_RECAPTCHA_PRIVATE_KEY'; - To recieve HTML with reCAPTCHA form, simply call
echo recaptcha_get_html($RECAPTCHA_PUBLIC_KEY);
I've got to change some CSS to match my blog layout (change margins of proper CSS classes), but it was really easy and quick - as always, firebug and it's Inspect was extremely helpful ;-). - Last thing to do is check validity of CAPTCHA, which is simply done by
$resp = recaptcha_check_answer(
$RECAPTCHA_PRIVATE_KEY,
$_SERVER['REMOTE_ADDR'],
$_POST['recaptcha_challenge_field'],
$_POST['recaptcha_response_field']
);
if(!$resp->is_valid) {
$errors[] = 'Bad captcha, try again.';
$valid = false;
}
It just proves the fact that in the nearest future Google will eat everything, including our souls... The doom is coming!
Box and Whisker script
Recently, I had to generate some box-and-whisker plots to present results of my work on my master thesis. Some google search revealed that there are no complete solutions to fully fit my expectations and needs. My colleague, Stefan, presented a solution on his blog, but that script still wasn't what I was looking for.
I wanted to have a script that, naturally, will present a set of results of an experiment. Stefan used quartiles and median, I liked standard deviation and average values more. Moreover, I wanted a script to be configurable at least by passing a path to a directory, where files with results are situated.
And that's how my funky-fresh-and-supercool-Ruby-script was born. Let me guide you through, as I think, most interesting parts of it. If you only need to se the whole script, you should scroll this post down, where you'll find a link to download it :-).
I decided that I'll allow the user to pass two arguments - first is the directory (explained earlier) and second one is optional and it's a filename pattern (if it's not present, default is "*.txt"). Script simply chooses only these files from given directory, which match the specified filename pattern. Thanks to the Ruby's magic, it's done simply as that:
# changing directory to givenWell, I know that Process.exit! may not be the nicest way to exit a script, but it works like a charm ;-).
Dir.chdir(directory)
# finding
files = Dir.glob(filename_pattern)
if files.length == 0
puts 'There are no files matching specified filename pattern'
Process.exit!
end
...
files.each do |file|
...
end
Result files that this script process have to be in a specific format:
iteration_number valuefor every line. For example:
1 234.6and so on.
2 324.3
3 4.55
My algorithm generates results in an untypical way - the result files may not have same number of lines - that's why I perform a check of number of lines of every file and getting a minimum number from them - that way we're sure that every iteration has the same number of values to process.
Next, script calculates the values: mean, standard deviation and keeps global minimum and maximum of results, to be used and explained later.
Two interesting things here:
1) because of using
Dir.chdir(directory)earlier, we're still inside this directory, so invoking
output_file = File.new('output.dat', 'w')will result in creating a file inside this directory.2) thanks to Drew Olson's "5 things you can do with a Ruby array in one line" I came up with these lines:
sum = tab.inject { |s, item| s + item }for summing up the array andvariance = ((tab.map { |item| (item - average) ** 2 }).inject { |s, item| s + item }) / file_counterfor computing variance. Nice, huh? :)I decided to print out the last two values: average and standard deviation. I needed them to compare my algorithm's best results for different parameters. Nevertheless - comment them out or just delete if you don't need them.
Now, to create a nice plot (I needed logarithmic scale for the lowest, latest values), I wrote a simple piece of code to find a range of two numbers being powers of ten closest to the given value. Ok, not so obvious, I know, but I think this code explains what I did:
first_bigger = 10.0As you can see, if global minimum is, for example, 0.5, this code produces a range of (0.1, 1) and if global minimum is 45 - it gives (10, 100). Currently, I'm only using the first_smaller value, but first_bigger may also be useful for modifications, so I leave it there.
first_smaller = 1.0
while !(first_bigger > global_minimum && first_smaller < global_minimum)
if global_minimum > first_bigger
first_bigger *= 10.0
first_smaller *= 10.0
else
first_bigger /= 10.0
first_smaller /= 10.0
end
end
Finally, producing the gnuplot script file which inside looks like that:
set terminal png size 1280,1024Of course, #{value} are replaced with proper values. For explanation of all these enigmatic gnuplot options (maybe except output image resolution ;-)) I have to send you to the gnuplot documentation page.
set output "output.png"
set boxwidth 0.2 absolute
set yrange [ #{first_smaller} : #{global_maximum.ceil} ]
set xrange [ 0 : #{min_lines + 10} ]
set log y
plot 'output.dat' every 5 using 1:3:2:6:5 with candlesticks lt 3 lw 2 notitle whiskerbars, '' using 1:4:4:4:4 with candlesticks lt -1 lw 2 notitle
And that's it! Script assumes that the user has RW rights to the given directory, so be sure you set them. It produces two files: output.dat and gnuplot_script. The format of first of them is:
iteration_number minimum_value average-standard_deviation standard_deviation average+standard_deviation maximumfor every line.
To make gnuplot create outpug.png file with the plot, simply go to the directory you've passed to the script and type
?> gnuplot gnuplot_scriptYou can download this script from here - whatever you want to do with it - you can. The only thing I ask for is some adnotation from where you got it.
Voila! :)
Getting started
Some time ago I thought that having a technological blog is something to make fun of. Today, I'm starting my own, which kinda gives me creeps.
I'm beggining to be one of you, corporate employees, who realizes that the only way to be over average is to tell the world that the work that one's doing is so freakin' special to post its results on a blog.
But seriously, I don't mean all of that. Lately, I've begun to have a feeling that some of the things I do may be interesting enough to share with others, possibly even help. That's why Negative Latency has been born.
I hope it will be fun to read. Wish me luck!