tag:blogger.com,1999:blog-72503482531473452072024-03-05T18:26:35.077+02:00STDOUT.puts self.projectsRandom tech stuff I've been doingMikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.comBlogger34125tag:blogger.com,1999:blog-7250348253147345207.post-3368463130666330422011-06-29T04:04:00.001+03:002011-06-29T04:12:46.118+03:00Jasmine Guard for CoffeeScript rocks on Rails 3<p>
CoffeeScript sure is interesting and I had a very positive experience trying it with <a href="http://pivotal.github.com/jasmine/">Jasmine</a> BDD testing kit. With <a href="https://github.com/guard/guard">Guard</a> autocompiling the .js files, it becomes a charm on Rails 3.
</p>
<p>
<iframe src="http://player.vimeo.com/video/16761133?title=0&byline=0&portrait=0" width="400" height="225" frameborder="0"></iframe><p><a href="http://vimeo.com/16761133">Jasmine BDD in CoffeeScript</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
</p>
<p>
<a href="http://pivotallabs.com/users/mgehard/blog/articles/1683-using-jasmine-to-test-coffeescript-in-a-rails-3-1-app">This setup guide from pivotallabs.com</a> coupled with this <a href="http://gist.github.com/673967">updated gist</a> you will have the infrastructure set up in no time. Any change to the CoffeeScript source or spec files should trigger the Guard to recompile the JavaScript.
</p>
<p>
To compile "bare" js see <a href="http://code-ningja.posterous.com/pure-coffeescript-with-guard">this tip</a> to add <span class="code"> :bare => true </span> to your Guardfile.
</p>
<div>
Start guard and jasmine servers and browse to localhost:8888 to run the test suite.
<div class="code">
$ guard<br>
$ rake jasmine
</div>
</div>
<p>
<a href="http://www.visibiz.com/blog/kris-molendyke/code/flavored-coffee-test-driving-client-side-development-jasmine-coffeescript">Here is a good example</a> of writing a CoffeeScript spec. More spec examples will eventually sprout up, undeniably. And naturally, the <a href="https://github.com/pivotal/jasmine/wiki">Jasmine wiki</a> is a good source of information.
</p>
<div>
Here's one example:
<span class="code">timer.coffee</span>
<pre class="prettyprint">
class Timer
constructor: (@timer_json) ->
@start_date = new Date(@timer_json.start_date)
@end_date = new Date(@timer_json.end_date)
[@start_hours, @start_minutes] = @timer_json.start_at.split(":")
[@end_hours, @end_minutes] = @timer_json.end_at.split(":")
</pre>
And the corresponding test:
<span class="code">timer_spec.coffee</span>
<pre class="prettyprint">
describe 'timer-parser', ->
timer_data = {
start_date: "2011/06/20", end_date: "2011/06/25",
start_at: "12:00", end_at: "04:04"
}
it 'should parse properly', ->
timer_json = JSON.parse JSON.stringify timer_data
timer = new Timer(timer_json)
expect(timer.start_date).toEqual new Date "2011/06/20"
expect(timer.end_date).toEqual new Date "2011/06/25"
expect(timer.start_hours).toEqual "12"
expect(timer.start_minutes).toEqual "00"
expect(timer.end_hours).toEqual "04"
expect(timer.end_minutes).toEqual "04"
</pre>
</div>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-3078050557382593492011-06-01T17:37:00.000+03:002011-06-01T17:38:20.406+03:00Writing JavaScript in 2011 - catching up with the latest trends<p>
JavaScript has definitely bloomed during the last few years. I do remember the first time I heard of JavaScript in the late 90s - I wrote a small script that showed a random image (out of a static array) on a static HTML page that I tested in Netscape and IE5-or-so. Today people run JavaScript in top- and mid-range mobile devices, on their web browsers, on servers, on the <a href="http://live.gnome.org/Gjs/">Gnome3 desktop</a>.
</p>
<p>
JavaScript is the only language for <a href="http://addyosmani.com/blog/tools-for-jquery-application-architecture-the-printable-chart/">building an application</a> for all major "smart" <a href="http://arandomurl.com/2011/03/16/coding-for-the-mobile-web.html">mobile devices</a> from within a singular codebase. That, already, interests me enough to give a closer look on some modern JavaScript tools - and write my observations about them.
</p>
<p>
Foremost, <a href="http://msdn.microsoft.com/en-us/scriptjunkie/gg655487.aspx">testing JavaScript</a> was something I had completely neglected before. If I was to write serious applications using JavaScript, I'd absolutely needed a way to write unit tests. Secondly, I wanted to have a look at CoffeeScript, which has had a lot of positive attention lately.
</p>
<p>
I started out by digging into the recent archives of <a href="http://javascriptweekly.com/">JavaScriptWeekly newsletter</a>. Out of a good number of testing tools, I selected to try out JsTestDriver. It is compact, requiring only a single jar file and a configuration file. The jar contains a small web server that is ran on the source code directory, and exposes a specific url that should be opened in the browsers that will run the JavaScript code to be tested. Cool! If you consider to try out JsTestDriver yourself, I recommend you checkout their SVN repository and compile the jar yourself - the jar file given in the example is outdated and does not contain all the features that the guides may refer to - for example, mocking a piece of HTML that the JavaScript modifies.
</p>
<p>
Mocking AJAX was out of my scope at this stage, for that you may find <a href="http://enterprisejquery.com/2010/07/mock-your-ajax-requests-with-mockjax-for-rapid-development/">this article</a> to be helpful.
</p>
<p>
For learning to use JsTestDriver, I chose to write a simple slideshow application that uses CSS3 transformations to change the pictures. The required JavaScript for this seemed simple enough, and I wanted to learn some new CSS tricks as well. ;) So, this is "bébé", written in a few days using jQuery-powered CoffeeScript. I started out by getting the basics of CoffeeScript, having it to load the images onto the page, and then wrote tests to see the pictures were actually loaded. Testing the user interface seems to be very difficult, due to differences in how different browsers behave under JsTestDriver. I set the picture position to <i>absolute</i>, since elsehow I could not get the CSS transition to appear smooth (and have the image to disappear without hiding it with JavaScript). CoffeeScript is pretty amazing, and works really well with jQuery. :)
</p>
<p>
<iframe src="http://lamikae.github.com/bebe-coffee-testdriver/" width="600px" height="640px" style="margin: 0 auto"></iframe>
</p>
<p>
The code for this, along with the JsTestDriver tests, can be found on <a href="https://github.com/lamikae/bebe-coffee-testdriver">Github</a>. This seems to work reasonably well in Firefox 4, Chrome, Opera 11, Safari (and Mobile Safari on iOS) and Android browsers. Firefox 3 behaves correctly, it just doesn't show the transition effect. IE fails miserably, never showing anything except the first image. :/
</p>
<p>
Here are some nice pointers to related articles:
<ul>
<li>
<a href="http://blog.ssokolow.com/archives/2011/05/07/a-python-programmers-first-impression-of-coffeescript/">
A Python programmer’s first impression of CoffeeScript</a>
</li>
<li>
<a href="http://github.com/akitaonrails/CoffeeScript-Demonstration/">
Small demonstration of coffeescript with jQuery UI in a Rails app</a>
</li>
<li>
<a href="http://www.re-cycledair.com/coffeescript-with-websql-and-jquery">
CoffeeScript with WebSQL and jQuery</a>
</li>
</li>
<li>
<a href="http://msdn.microsoft.com/en-us/scriptjunkie/ff452703.aspx">
jQuery Test-Driven Development</a>
</li>
<li>
<a href="http://msdn.microsoft.com/en-us/scriptjunkie/gg749824.aspx">
Automating JavaScript Testing with QUnit</a>
</li>
<li>
<a href="http://tinnedfruit.com/2011/03/03/testing-backbone-apps-with-jasmine-sinon.html">
Testing Backbone applications with Jasmine and Sinon</a>
</li>
</ul>
</p>
<p>
..and now for something different ..<br>
<a href="http://bellard.org/jslinux/">
PC emulator in the browser running Linux on JavaScript</a>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com1tag:blogger.com,1999:blog-7250348253147345207.post-24229890756763137002011-03-07T05:53:00.015+02:002011-05-25T16:07:38.496+03:00HTML5 native audio support comparison<style type="text/css">
#browserAudioComparison table {
background: white;
}
#browserAudioComparison th {
font-size: 1.2em;
padding: 0.5em;
}
#browserAudioComparison td {
text-align: center;
padding: 0.5em;
min-width: 50px;
}
#browserAudioComparison .bad {
background: #ff0033;
}
#browserAudioComparison .buggy {
background: #ff9933;
}
#browserAudioComparison .good {
background: #99ff66;
}
#browserAudioComparisonNotes ul {
list-style-type: none;
}
</style>
<p>
Here are the results of a quick test how various browsers on OS X 10.6 (and iPhone 3GS) play HTML5 <audio>.
</p>
<p><b>UPDATE 25.5.2011</b>: I updated the data and found that the audio support has become better in many browsers. I left in old data for comparison.
</p>
<table id="browserAudioComparison">
<th>Browser / OS
</th>
<th>mp3
</th>
<th>wav
</th>
<th>ogg
</th>
<tr>
<td>Android 2.2
</td>
<td class="bad">X
</td>
<td class="bad">X
</td>
<td class="bad">X
</td>
</tr>
<tr>
<td>Chrome 9.0.597
</td>
<td class="good">ok
</td>
<td class="buggy">X<sup>1</sup>
</td>
<td class="good">ok
</td>
</tr>
<tr>
<td>Chrome 11
</td>
<td class="good">ok
</td>
<td class="buggy">X<sup>1</sup>
</td>
<td class="good">ok
</td>
</tr>
<tr>
<td>Firefox 3.6.13
</td>
<td class="bad">X
</td>
<td class="good">ok
</td>
<td class="bad">X<sup>2</sup>
</td>
</tr>
<tr>
<td>Firefox 4.0.1
</td>
<td class="bad">X
</td>
<td class="good">ok
</td>
<td class="good">ok
</td>
</tr>
<tr>
<td>iOS 4.2
</td>
<td class="good">ok
</td>
<td class="bad">X
</td>
<td class="bad">X
</td>
</tr>
<tr>
<td>Opera 11.1
</td>
<td class="bad">X
</td>
<td class="good">ok<sup>3</sup>
</td>
<td class="good">ok
</td>
</tr>
<tr>
<td>Safari 5.0.3
</td>
<td class="good">ok
</td>
<td class="bad">X
</td>
<td class="bad">X
</td>
</tr>
<tr>
<td>Safari 5.0.5
</td>
<td class="good">ok
</td>
<td class="good">ok<sup>3</sup>
</td>
<td class="bad">X
</td>
</tr>
</table>
<div id="browserAudioComparisonNotes">
<ul>
<li><sup>1</sup> plays, but is buggy
</li>
<li><sup>2</sup> hangs on load
</li>
<li><sup>3</sup> is able to seek!
</li>
</ul>
</div>
<p>
Likewise with <video>, there is a need to encode to many formats to support all browsers. I have no data of IE9. Unfortunately Android 2.2 cannot play any audio type at all! This is supposed to be fixed in Android 2.3. <a href="http://www.brianhadaway.com/html5-audio-support-on-android-devices/">See this link for more information on HTML5 audio on Android.</a> Also, Opera 11.1 could play ogg files, but I noticed that when they were encoded in higher bitrates, the playback stopped in the middle of the track, systematically. This seems to be fixed in Opera 11.11. Chrome buggyness on wav files appears upon seeking- the play stops and cannot be started again without reloading the page.
</p>
<p>
The tests were conducted by creating a very simple HTML5 document with this content:
<pre>
<!DOCTYPE html>
<html>
mp3: <audio src="test.mp3" controls></audio>
wav: <audio src="test.wav" controls></audio>
ogg: <audio src="02.ogg" controls></audio>
</html>
</pre>
The files were hosted (locally) from the same directory as the html document by ad-hoc Python web server:
<pre >
python -m SimpleHTTPServer
</pre>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-29236654487304916822011-02-27T03:04:00.084+02:002011-03-14T21:52:10.683+02:00Audio CD mastering with open source tools<style type="text/css">
h2 {
margin-top: 1em;
}
span.code {
margin: 0 0.2em;
color: #3322aa;
}
</style>
<p>
You want to burn an audio CD from a bunch of audio files from various sources, not direct CD rips? You can use open source tools to check the properties of the tracks and prepare them properly to avoid potential pitfalls and ensure a better listening experience.
</p>
<p>
The tools used in this memo:
<ul>
<li><a href="http://developer.berlios.de/projects/cuetools/">cuetools</a></li>
<li><a href="http://www.mega-nerd.com/libsndfile/">libsndfile</a></li>
<li><a href="http://normalize.nongnu.org/">normalize-audio</a></li>
<li><a href="http://www.etree.org/shnutils/shntool/">shntool</a></li>
<li><a href="http://sox.sourceforge.net/">SoX</a></li>
<li><a href="http://wavbreaker.sourceforge.net/">wavbreaker</a></li>
</ul>
<p>
Some of these do have overlapping functionality. With the exception of <span class="code">wavbreaker</span> (needs ALSA/OSS), all of them are available on both OS X and Linux.
</p>
<p>
Installation on Ubuntu:
<pre class="code">
$ sudo apt-get install sndfile-programs sox normalize-audio wavbreaker shntool cuetools
</pre>
Please note that the following changes to wav files are <b>destructive</b> so be sure to operate on copies of the originals.
</p>
<h2>
Normalize
</h2>
<p>
Check if the tracks need normalization.
</p>
<pre class="code">
$ sndfile-info *.wav | egrep 'File|Signal Max'
</pre>
<pre>
File : 01.wav
Signal Max : 16462 (-5.98 dB)
File : 02.wav
Signal Max : 19946 (-4.31 dB)
File : 03.wav
Signal Max : 24188 (-2.64 dB)
File : 04.wav
Signal Max : 12092 (-8.66 dB)
File : 05-06.wav
Signal Max : 16781 (-5.81 dB)
File : 07.wav
Signal Max : 32768 (0.00 dB)
File : 08-09.wav
Signal Max : 27442 (-1.54 dB)
</pre>
<p>
So there is one with a really loud peak (07.wav) and a few bit quieter tracks.
This is what <span class="code">normalize-audio</span> suggests to do (gain column):
</p>
<pre class="code">
$ normalize-audio -n *.wav
</pre>
<pre>
level peak gain
-12,6922dBFS -5,9791dBFS 0,6922dB 01.wav
-14,3614dBFS -4,3119dBFS 2,3614dB 02.wav
-15,2635dBFS -2,6370dBFS 3,2635dB 03.wav
-22,4749dBFS -8,6588dBFS 10,4749dB 04.wav
-15,9599dBFS -5,8126dBFS 3,9599dB 05-06.wav
-13,3062dBFS 0,0000dBFS 1,3062dB 07.wav
-13,3358dBFS -1,5407dBFS 1,3358dB 08-09.wav
</pre>
<p>
To go with <a href="http://www.laputan.org/selfish/selfish.html#WorksOutOfTheBox">automatic settings</a>:
</p>
<pre class="code">
$ normalize-audio *.wav
</pre>
<pre>
Applying adjustment of 0,69dB to 01.wav...
Applying adjustment of 2,36dB to 02.wav...
Applying adjustment of 3,26dB to 03.wav...
Applying adjustment of 10,47dB to 04.wav...
Applying adjustment of 3,96dB to 05-06.wav...
Applying adjustment of 1,31dB to 07.wav...
Applying adjustment of 1,34dB to 08-09.wav...
</pre>
<p>
I really didn't like what this did to track 04.wav, so I reverted it back from the backups and adjusted a smaller gain manually:
</p>
<pre class="code">
$ normalize-audio -g 2,5dB 04.wav
</pre>
<pre>
Applying adjustment of 2,500000dB...
04.wav 100% done, ETA 00:00:00 (batch 100% done, ETA 00:00:00)
</pre>
<p>
See <span class="code">normalize-audio --help</span> for more controls. Normalization does not adjust signal-to-noise ratio, but trust your ears and speakers when adjusting volume. The desired peak level is within range -1,0 .. -6,0 dB. See <a href="http://en.wikipedia.org/wiki/Audio_normalization">Wikipedia</a>.
</p>
<h2>
Resample to Red Book CD standard
</h2>
<p>
Convert the tracks to CD audio format (stereo, 16 bit, 44100 Hz).
First check their current sample rate:
</p>
<pre class="code">
$ sndfile-info *.wav | egrep 'File| Channels| Sample Rate| Bit Width'
</pre>
<pre>
File : 01.wav
Channels : 2
Sample Rate : 48000
Bit Width : 16
File : 02.wav
Channels : 2
Sample Rate : 48000
Bit Width : 16
File : 03.wav
Channels : 2
Sample Rate : 48000
Bit Width : 16
File : 04.wav
Channels : 2
Sample Rate : 44100
Bit Width : 16
File : 05-06.wav
Channels : 2
Sample Rate : 48000
Bit Width : 16
File : 07.wav
Channels : 2
Sample Rate : 44100
Bit Width : 16
File : 08-09.wav
Channels : 2
Sample Rate : 44100
Bit Width : 16
</pre>
<p>
Here I have a bunch of files in incompatible sampling rate. <span class="code">SoX</span> can do many things to audio files, including resampling.
</p>
<pre class="code">
$ sox inputfile.wav -r 44100 -b 16 -c 2 outputfile.wav
</pre>
<p>
I converted the 48 kHz files with this ad-hoc loop:
</p>
<pre class="code">
$ IFS=$'\n' ;\
for f in $(\
sndfile-info *.wav |\
egrep 'File|^Sample Rate' |\
grep -B 1 48000 |\
awk -F' : ' /File/{'print $2'}); do \
sox "${f}" -r 44100 -b 16 -c 2 "${f}-44k1.wav" && rm -f "${f}" ; done
</pre>
<h2>
Eliminate sector boundary errors (SBE)
</h2>
<p>
To make sure there won't be any clicks between tracks, when the audio is continuous over a track change segue, you need to ensure the proper length of each track. On disc, tracks begin at full sectors, and a single sector length is 1/75 sec. If the wav of previous track is just slightly too short, the cd burner will insert some silence where audio is missing, to fill out the sector. This is enough to cause an annoying click in some cd players.
</p>
<p>
<span class="code">shntool</span> is a great tool for extracting information and manipulating audio files. I will not give an example here, but see the output from <span class="code">shntool info *.wav</span> to examine the properties of your wave files.
</p>
<p>
Examine the output of the <span class="code">shntool len</span> command to discover problems:
<pre class="code">
$ shntool len *.wav
</pre>
<pre>
length expanded size cdr WAVE problems fmt ratio filename
3:43.65 39490508 B -b- -- ----- wav 1.0000 01.wav-44k1.wav
5:40.02 59979756 B -b- -- ----- wav 1.0000 02.wav-44k1.wav
4:26.66 47076708 B -b- -- ----- wav 1.0000 03.wav-44k1.wav
2:22.08 25067660 B --- -- ----- wav 1.0000 04.wav
5:53.48 62382468 B -b- -- ----- wav 1.0000 05-06.wav-44k1.wav
4:36.65 48838628 B -b- -- ----- wav 1.0000 07.wav
7:39.68 81128396 B -b- -- ----- wav 1.0000 08-09.wav
34:23.22 363964124 B 1.0000 (7 files)
</pre>
The <span class="code">b</span> in the cdr column indicates a SBE. The hyphen indicates that everything is OK.
</p>
<p>
I wrote a small script called <span class="code"><a href="https://github.com/lamikae/sbeok/blob/
/bin/sbeok">sbeok</a></span> to check wav for SBEs. You can either use the script or <span class="code">shntool</span>.
</p>
<pre class="code">
$ sbeok *.wav
</pre>
<pre>
01.wav-44k1.wav: FAILED, missing 1968 bytes
02.wav-44k1.wav: FAILED, missing 992 bytes
03.wav-44k1.wav: FAILED, missing 968 bytes
04.wav: OK
05-06.wav-44k1.wav: FAILED, missing 2024 bytes
07.wav: FAILED, missing 696 bytes
08-09.wav: FAILED, missing 1536 bytes
</pre>
<p>
Seems all but track 04.wav has improper length and a small amount of silence would be added to the end of these tracks while burning the cd. Additionally, there are two files: 05-06.wav and 08-09.wav that need to be cut and they have music during the segue.
</p>
<p>
The brute force approach to recalculate sector boundaries is to merge all wavs into one and manually insert the track markers. This has the benefit that you don't need to cut tracks in previous steps of your workflow, but to leave it until last.
</p>
<p>
Merge all tracks together with <span class="code">shnjoin</span>.
<pre class="code">
$ shnjoin *.wav
</pre>
<pre>
Joining [01.wav-44k1.wav] (3:43.65) --> [joined.wav] (34:23.22) : 100% OK
Joining [02.wav-44k1.wav] (5:40.02) --> [joined.wav] (34:23.22) : 100% OK
Joining [03.wav-44k1.wav] (4:26.66) --> [joined.wav] (34:23.22) : 100% OK
Joining [04.wav] (2:22.08) --> [joined.wav] (34:23.22) : 100% OK
Joining [05-06.wav-44k1.wav] (5:53.48) --> [joined.wav] (34:23.22) : 100% OK
Joining [07.wav] (4:36.65) --> [joined.wav] (34:23.22) : 100% OK
Joining [08-09.wav] (7:39.68) --> [joined.wav] (34:23.22) : 100% OK
Post-padded output file with 1128 zero-bytes.
</pre>
</p>
<p>
Use <span class="code">wavbreaker</span> to set track split markers.
<pre class="code">
$ wavbreaker joined.wav
</pre>
<p>
This opens up a friendly GUI to insert your track marks. Seek to proper position in the topmost waveform view, and adjust the exact cut point from the second-to-top view. Click "Add" to enter a marker .. the interface is very easy to use. You could split the tracks from within <span class="code">wavbreaker</span>, but once you have the marker file, it is possible to script the whole process. "Export to TOC" into file <span class="code">master.toc</span> and exit the program.
</p>
<p style="float: none; overflow: auto;">
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIo-bt7ZD9dl3Z-NQHSWTei8te9uCERZWbmCSOXJ7DQC6unG7GMcmd1bNnHDCeqjSSINFjiE-jhxL8LCi6r1-fKh0OM-hdrSTilqenjwkiCElBOSm2k6mRRIIy2a-rHNbbOUAtqtQm7prT/s1600/wb+joined.png"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 265px; height: 320px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIo-bt7ZD9dl3Z-NQHSWTei8te9uCERZWbmCSOXJ7DQC6unG7GMcmd1bNnHDCeqjSSINFjiE-jhxL8LCi6r1-fKh0OM-hdrSTilqenjwkiCElBOSm2k6mRRIIy2a-rHNbbOUAtqtQm7prT/s320/wb+joined.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5584023596287782386" /></a>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimI09OtFzyzqJr8Kp7aFyvVSyNkZX43Ga1__gDiMphm7YvRXtnbP_83HK8ag3N1hGQGqWSUjVwaeAQ4UOfFKd7F96nlD2MqglJ3kux4t56lG2qLX8ns1756TSeN4iT1EFJrGRcFtL1tnzx/s1600/wb+toc+export.png"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 264px; height: 320px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimI09OtFzyzqJr8Kp7aFyvVSyNkZX43Ga1__gDiMphm7YvRXtnbP_83HK8ag3N1hGQGqWSUjVwaeAQ4UOfFKd7F96nlD2MqglJ3kux4t56lG2qLX8ns1756TSeN4iT1EFJrGRcFtL1tnzx/s320/wb+toc+export.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5584023785270856898" /></a>
</p>
<p>
Use <span class="code">shnsplit</span> with <span class="code">cuebreakpoints</span> to split the files based on the TOC. Write the master CD cast to directory "master":
<pre class="code">
$ mkdir master
$ cuebreakpoints -i toc master.toc | shnsplit -t %n -d master joined.wav
</pre>
<pre>
Splitting [joined.wav] (34:23.22) --> [master/01.wav] (3:44.44) : 100% OK
Splitting [joined.wav] (34:23.22) --> [master/02.wav] (5:40.54) : 100% OK
Splitting [joined.wav] (34:23.22) --> [master/03.wav] (4:25.48) : 100% OK
Splitting [joined.wav] (34:23.22) --> [master/04.wav] (2:23.67) : 100% OK
Splitting [joined.wav] (34:23.22) --> [master/05.wav] (3:23.38) : 100% OK
Splitting [joined.wav] (34:23.22) --> [master/06.wav] (2:28.05) : 100% OK
Splitting [joined.wav] (34:23.22) --> [master/07.wav] (4:36.48) : 100% OK
Splitting [joined.wav] (34:23.22) --> [master/08.wav] (1:18.24) : 100% OK
Splitting [joined.wav] (34:23.22) --> [master/09.wav] (6:21.69) : 100% OK
</pre>
</p>
<p>
How about those sector sizes now?
</p>
<pre class="code">
$ sbeok master/*.wav
</pre>
<pre>
master/01.wav: OK
master/02.wav: OK
master/03.wav: OK
master/04.wav: OK
master/05.wav: OK
master/06.wav: OK
master/07.wav: OK
master/08.wav: OK
master/09.wav: OK
</pre>
<pre class="code">
$ shntool len master/*.wav
</pre>
<pre>
length expanded size cdr WAVE problems fmt ratio filename
3:44.44 39617132 B --- -- ----- wav 1.0000 master/01.wav
5:40.22 60027788 B --- -- ----- wav 1.0000 master/02.wav
4:26.05 46934204 B --- -- ----- wav 1.0000 master/03.wav
2:23.67 25382828 B --- -- ----- wav 1.0000 master/04.wav
3:21.15 35491724 B --- -- ----- wav 1.0000 master/05.wav
2:30.28 26525900 B --- -- ----- wav 1.0000 master/06.wav
4:36.48 48799340 B --- -- ----- wav 1.0000 master/07.wav
1:18.24 13815692 B --- -- ----- wav 1.0000 master/08.wav
6:21.69 67370732 B --- -- ----- wav 1.0000 master/09.wav
34:23.22 363965340 B 1.0000 (9 files)
</pre>
<p>
Looks good. How are the volume levels?
<pre>
File : master/01.wav
Signal Max : 22620 (-3.22 dB)
File : master/02.wav
Signal Max : 28166 (-1.31 dB)
File : master/03.wav
Signal Max : 29384 (-0.95 dB)
File : master/04.wav
Signal Max : 16501 (-5.96 dB)
File : master/05.wav
Signal Max : 26729 (-1.77 dB)
File : master/06.wav
Signal Max : 20980 (-3.87 dB)
File : master/07.wav
Signal Max : 29205 (-1.00 dB)
File : master/08.wav
Signal Max : 17139 (-5.63 dB)
File : master/09.wav
Signal Max : 27442 (-1.54 dB)
</pre>
All of them are within acceptable range, and the volume is perceived to be sensible acroll the tracks during playback. The perceived volume depends on the dynamic range of the audio - along with the equipment and the listener self as well.
<h2>
Burn to CD
</h2>
<p>
Since you're already on the command line, on Linux you can use <span class="code">cdrecord</span> to burn the CD.
</p>
<pre class="code">
$ cdrecord -v speed=1 dev=0,0,0 -dao -audio master/*.wav
</pre>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-70982186062424572792011-01-29T22:26:00.021+02:002011-02-14T18:34:17.678+02:00Recipe of request-response over AMQP with Python and Java<p>
This is a recipe to setup synchronized messaging over AMQP. The <a href="https://github.com/lamikae/amqpbus-recipe/zipball/master">recipe source zip file</a> contains an implementation of a Python backend broker. Along comes example Python and Java clients that send messages over AMQP to the running broker(s). The broker load can be balanced over to several processes. RabbitMQ can automagically balance the incoming requests to multiple consumers. This setup has been deployed successfully, achieving decent performance (we have benchmarked only the private implementation, our throughput is approx. 30 msgs/sec. with three backend processes).
</p>
<p>
Good presentations on concurrent messaging and AMQP are available from:
<ul>
<li><a href="http://www.rabbitmq.com/resources/erlang-exchange-talk-final/ex.html">http://www.rabbitmq.com/resources/erlang-exchange-talk-final/ex.html</a></li>
<li><a href="http://www.igvita.com/2009/04/06/henry-ford-event-driven-architecture/">http://www.igvita.com/2009/04/06/henry-ford-event-driven-architecture/</a></li>
<li><a href="http://kallistec.com/2009/05/15/basic-topic-publishing-with-amqp/">http://kallistec.com/2009/05/15/basic-topic-publishing-with-amqp/</a></li>
<li><a href="http://hopper.squarespace.com/blog/2008/10/6/multithreading-amqp-clients.html">http://hopper.squarespace.com/blog/2008/10/6/multithreading-amqp-clients.html</a></li>
<li><a href="http://www.slideshare.net/old_sound/interoperability-with-rabbitmq">http://www.slideshare.net/old_sound/interoperability-with-rabbitmq</a></li>
</ul>
</p>
<p>
AMQP can be used as a message bus between various system components in different languages maintained by different teams.
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGRm2GY_HtWVNwxuwbv58CTGF56Lc5pkK_y0Cl9u9bNq3XXXlUfAt-3AI8RvzPsnEutjmhd2PEuFHufdOBhbfLAT6bs92eAiYgDWbwZGdj6bPUdiI34MGrUbcVafvMsBxVjy8GpF0ah9uM/s1600/the-rabbitmq-universe.png" border="0" />
</p>
<p>
Here are the bare bones of this recipe:
<ul>
<li>create a unique identifier (qid) for the request</li>
<li>create a new consumer and bind it to a temporary response queue</li>
<li>publish the message into the durable request queue</li>
<li>wait for the response on the response queue</li>
<li>close response channel</li>
</ul>
Topic exchange is the only exchange type that honors routing keys, which are essential for pairing request and response together, using the unique identifier in routing key.
</p>
<p>
Unzip the recipe (or clone the <a href="https://github.com/lamikae/amqpbus-recipe">recipe repository</a> from GitHub).
Install RabbitMQ (default settings are ok), and install Python modules 'amqplib' and 'carrot' (plus 'jsonrpclib' for the tests).
</p>
<p>
Launch the RabbitMQ server.
<pre class="prettyprint">
sudo rabbitmq-server
</pre>
</p>
<p>
Start the example backend broker:
<pre class="prettyprint">
cd py-src
python example_broker.py
</pre>
This will launch a daemon that listens for messages on a specific AMQP channel.
A "request" is a thin JSON wrapper. If the request includes a request id (qid),
the daemon will return the current time over the AMQP. If the request is not identified,
the time will be printed instead.
</p>
<p>
Run the example requests in Python and Java, while the example_broker is running:
<pre class="prettyprint">
cd py-src
python example_request.py
</pre>
Output:
<pre class="code">
Response from AMQP:
{u'msg': u'Sat Jan 29 20:43:36 2011'}
</pre>
Run the same requests from Java:
<pre class="prettyprint">
cd java-src
java -cp .:build:lib/json.jar:lib/rabbitmq-client-1.8.1.jar:lib/commons-logging.jar:lib/commons-io.jar \
example.ExampleRequest
</pre>
Output:
<pre class="code">
29.1.2011 21:11:01 recipe.amqpbus.AMQPRequestResponseImpl newConnection
INFO: ExampleBroker connected to RabbitMQ @ 127.0.0.1:5672/
29.1.2011 21:11:01 recipe.amqpbus.AMQPPublisher send
INFO: publishing query to ExampleBroker_req with binding key: example.request
{"q":{"q":"hello AMQP backend, I am Java"}}
-----------------------------------------
29.1.2011 21:11:01 recipe.amqpbus.AMQPPublisher send
INFO: publishing query to ExampleBroker_req with binding key: example.request.q538
{"q":{"q":"time can you get me please?"},"qid":"q538"}
29.1.2011 21:11:01 recipe.amqpbus.AMQPConsumer receive
INFO: amq.gen-dyK/PZQn/brNl9jTR/tlAg== received message:
{"msg": "Sat Jan 29 21:11:01 2011"}
Response from AMQP: {"msg":"Sat Jan 29 21:11:01 2011"}
</pre>
</p>
<p>
The example_broker output should print the events when it receives the requests:
Output:
<pre class="code">
consumer received message:
{'exchange': u'TestExchange',
'consumer_tag': u'__main__.ExampleBroker-e7175ec0-cd1f-4d2e-973b-1eeb42d4071d',
'routing_key': u'example.request.*',
'redelivered': False,
'delivery_tag': 2,
'channel': <amqplib.client_0_8.channel.Channel object at 0x1007bbad0>}
-------------------
received request 355:
what time is it?
-------------------
response to TestExchange with routing_key: example.response.355, message:
{"msg": "Sat Jan 29 20:47:59 2011"}
using channel_id: 3
Channel open
Closed channel #3
</pre>
</p>
<p>
You should be able to pick up the ingredients and integrate them to your codebase as you see fit.
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-6356326458558472112010-12-05T04:12:00.030+02:002010-12-27T00:06:59.465+02:00Hybrid Qt applications with PySide and Django<p>
This article describes some thoughts and experiments on developing applications targeted for mobile systems, especially MeeGo. I am trying to imagine a secure and agile way to write applications that are robust yet elegant.
</p>
<p>
About the author – I have worked with Ruby on Rails, Django and Qt. I think that web run-time technologies (HTML5, JavaScript and CSS3 – called WRT in this article) can provide a flexible way to build user interfaces. Many developers are familiar with these technologies, and maximizing WRT percentage in the codebase has potential to better portability for devices from different manufacturers. Personally to me MeeGo is the most interesting mobile operating system target. I am trying not to completely forget about business models, but then again, I have a <i>software libre</i> bias.
</p>
<p>
I have experimented of "hybridizing" Qt with Django. <a href="http://www.pyside.org/">PySide</a> provides Qt bindings for Python in LGPL licensing. Django is a CMS-oriented web framework written also in Python. Using Python instead of C++ has a drawback in runtime efficiency, but in some cases developer productivity and codebase maintainability is more important. Python has become one of my favourite languages.
</p>
<p>
This approach interests me because an application from the same codebase can be deployed both on desktop and on (a Nokia) mobile device. Alternatively a desktop/server Django application could serve plain WRT components also for non-Qt clients (but I can't comment how Apple would respond to this sort of application for the App Store). Android Market - well - they probably would not have a problem with it. That's all I have to say about marketing and business politics.
</p>
<p>
Nokia N900 is a fabulous platform for prototyping, on which I wrote an experimental application for controlling a TV set within the local area network (LAN). Figure 1 displays an event cycle in which the whole application is self-contained on the mobile device.
</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3dtXGnsq6GGzK6jO-H7fXNkZOHKszMZ_K9wCN3vMiRrPljpQfQWUcCIfrhEP2VWMdG_D9aJr_4fKQ1v-YznkAba48BvtY_9yMeOnqwH9Ak4sAAnBHwwr3XdsEuASWX6zY0eUD8Wgn1vrQ/s1600/qthybrid+fig2.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="347" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3dtXGnsq6GGzK6jO-H7fXNkZOHKszMZ_K9wCN3vMiRrPljpQfQWUcCIfrhEP2VWMdG_D9aJr_4fKQ1v-YznkAba48BvtY_9yMeOnqwH9Ak4sAAnBHwwr3XdsEuASWX6zY0eUD8Wgn1vrQ/s400/qthybrid+fig2.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Fig 1. The software components on N900</td></tr>
</tbody></table>
<p>
Not depicted in figure 1 for clarity, the Python process contains an implementation of a finite-state machine. User actions are sent as events to the backend process handling logical states, while the WRT defines slots that update the UI.
</p>
<p>
This approach is reminescent of <a href="http://en.wikipedia.org/wiki/Cloud_computing">cloud computing</a>, but with an important difference in that the data that moves between the server an the mobile device would not be stored on servers the user does not have control over. The data would never pass to the ISP either. Consider a Windows PC with a media repository was running PySide/Django in the LAN, and an iPhone owner could control the media stream onto a MeeGo TV set? Switch Windows for Linux and iPhone for a MeeGo device and it still would work without a heavy rewrite of the codebase. The PC would serve an ad-hoc "cloud" that could be operated from the hand-held device, acting as a remote controller. That is the core of this vision.
</p>
<p>
It makes sense to browse local data (from the PC) and "stream" it onto the mobile device. You wouldn't carry the precious data around in your phone, but it still would be reachable from home over a secure network connection. This is a data privacy issue. Photos are a good example. A major concern in any networked application is security and I've foolishly ignored many gaping secury holes in this prototype. As for my defense I can only say I am experimenting the feasibility and hardware performance so far.
</p>
<div style="margin-bottom: 0cm;"><span style="font-style: normal;"> </span> </div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzQ2waeh8ejhq-h77OHKpo3sevJJ1knXjEy7-8IRrqNlTwOSUqs7rxbVC91-01MwSMwU6T4z-_BaCNWpl_rmPL57kMV69YJz1dfqpnUDar0fRWS8MiL6yRMliCIGTDKtSGdrXL31Dyvi_D/s1600/meego+everywhere.png" style="margin-left: auto; margin-right: auto;"><img border="0" height="187" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzQ2waeh8ejhq-h77OHKpo3sevJJ1knXjEy7-8IRrqNlTwOSUqs7rxbVC91-01MwSMwU6T4z-_BaCNWpl_rmPL57kMV69YJz1dfqpnUDar0fRWS8MiL6yRMliCIGTDKtSGdrXL31Dyvi_D/s320/meego+everywhere.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Fig 2. Cloud computing within the LAN with MeeGo</td></tr>
</tbody></table><style type="text/css">
p { margin-bottom: 0.21cm; }
</style> <br />
<p>
The prototype application I've written (called MxManager) is a remote controller for Maximum T-8000 personal video recorder (PVR) that runs on embedded Linux. Its prorietary firmware provides a simple HTTP interface that mimics the physical remote controller. This prototype uses that API to set recordings from the EPG and play recordings on the TV. Here is a screenshot of the application (on MacBook desktop) and a blurry video of it running on N900.
</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5VQZnNqzQuT6fdKYbJrPdNdiXBFDDexxiIwbLcKsTlHi-LGvVzbZGZ860xhSvcWo5vLoH2f_Sf9ytVrZ_ZpBns0OLcQEYSCsTykn2JfY5QdXiv8ubp50vCl_d4H-QdXwa0PESoNvQQLf6/s1600/qthybrid+on+mac.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5VQZnNqzQuT6fdKYbJrPdNdiXBFDDexxiIwbLcKsTlHi-LGvVzbZGZ860xhSvcWo5vLoH2f_Sf9ytVrZ_ZpBns0OLcQEYSCsTykn2JfY5QdXiv8ubp50vCl_d4H-QdXwa0PESoNvQQLf6/s640/qthybrid+on+mac.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Fig 3. MxManager UI</td></tr>
</tbody></table><br />
<div style="margin-bottom: 0cm;"><div style="text-align: center;"><br />
<iframe frameborder="0" height="300" src="http://player.vimeo.com/video/17479936" width="400"></iframe></div><div style="text-align: center;"><a href="http://vimeo.com/17479936">Qt hybrid on N900</a> on <a href="http://vimeo.com/">Vimeo</a>. <i>Sorry about the quality. It was shot up close, I guess I would have needed to strap on a macro lens.</i></div></div><br />
<style type="text/css">
p { margin-bottom: 0.21cm; }
</style> <br />
<div style="margin-bottom: 0cm;">The screen and remote control UI are individual QWebView elements and their content is composed by Django views. Events from the UI are triggered in JavaScript and events back from PySide are <a href="http://gitorious.org/maximum-pvr/mxmanager/blobs/master/mxlib/pyside/mxsignaler.py">injected as JavaScript function calls</a> into the page. PySide is running a finite-state machine (<a href="http://gitorious.org/maximum-pvr/mxmanager/blobs/master/mxlib/pyside/mxpuppeteer.py">using QStateMachine</a>) that holds the internal state of the application. Changes in UI are triggered by state change events. I wrote about this in more detail in a <a href="http://blogger-mikael.blogspot.com/2010/09/mxcontroller-preview.html">past blog post</a>. The <a href="http://gitorious.org/maximum-pvr/mxmanager">source code</a> is released under the BSD, so you are welcome to have a look and give an opinion. </div><div style="margin-bottom: 0cm;"><br />
</div><div style="margin-bottom: 1em;">Initial experiments with QML appeared subjectively much faster, nearing smooth animation along the button press, but in the past I had a problem in sending signals into QML. <a href="http://developer.qt.nokia.com/wiki/Updating_QML_content_from_Python_threads">This seems to have been fixed</a> in PySide 1.0.0. This is a solid direction to experiment - perhaps Django could be used to compose QML for the QDeclarativeView..<br />
<br />
Another video of the application in action with the TV set! </div><div style="margin-bottom: 0cm;"><div style="text-align: center;"><br />
<iframe frameborder="0" height="300" src="http://player.vimeo.com/video/17480937" width="400"></iframe></div><div style="text-align: center;"><a href="http://vimeo.com/17480937">Qthybrid and Maximum T-8000</a> on <a href="http://vimeo.com/">Vimeo</a>.</div></div><br />
<div style="margin-bottom: 0cm;">While building the web stack on well-proven frameworks, security issues still need to be considered carefully. Web sockets would be better designed for such eventing purpose than Ajax, with a better security model. I do repeat, this is <b>not</b> production-ready code.
</div>
<div style="margin-bottom: 0cm;">If the mobile phone supported QtMobility, it could be possible to use mobile accelerometer and orientation to control playback. Turn the phone upside down to pause, for example. The next video (by <a href="http://www.youtube.com/user/perlinet">perlinet</a>, not me) portrays using QtMobility API in PySide with QML.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><object height="385" width="480"><param name="movie" value="http://www.youtube.com/v/DpVpSZSOcGM?fs=1&hl=fi_FI"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/DpVpSZSOcGM?fs=1&hl=fi_FI" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object></div><br />
PySide is great technology and it's inclusion to MeeGo opens up many ways for developers to bring their applications to the platform. There are definite points to focus on this basis:<br />
<ul><li>security implications</li>
<li>web sockets</li>
<li>QML </li>
<li>QtMobility experimentation</li>
</ul>Especially intriguing for me would be to hook up digiKam database into a desktop-based Django app for browsing photos on a mobile device / tablet computer.<br />
<br />
</div>
<p>
What's unique here is the merging of the Qt and web frameworks to operate within the same OS process, which makes it easier to separate the presentation and business logic.
Personally I feel this technology seems feasible, and perhaps I will continue to investigate it further in 2011. There are web services that operate on a similar business model, and maybe open source software is following the trend.
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com1tag:blogger.com,1999:blog-7250348253147345207.post-62415818744565905932010-11-19T18:06:00.044+02:002010-11-21T19:31:47.658+02:00Recipe: handling database communication breakdown in Rails and Django<p>
This recipe is for users who manually handle persistent (shared) database connection, with Oracle, although it's probably easy to adapt for other database backends with small adjustments. I needed to implement this both in Ruby (Rails' ActiveRecord) and Python (django.db) daemons, both working in the same setting. I thought the solution was elegant enough to be cleaned up into a recipe.
</p>
<p>
Automated database connection pooling for Python (nor Ruby) is not supported with Oracle 10g. Only 11g introduced Database Resident Connection Pooling (DRCP). It probably makes this recipe redundant for Python users with 11g. Oracle has official support for <a href="http://www.oracle.com/technetwork/articles/dsl/python-091105.html">using Python with Oracle Database 11g</a>, using the <a href="http://cx-oracle.sourceforge.net/">cx_Oracle</a> driver. I'm not sure but I think Oracle doesn't have any form of official support for Ruby, but the de-facto <a href="http://ruby-oci8.rubyforge.org/en/">ruby-oci8</a> driver works well with ActiveRecord.
</p>
<p>
Without automated connection pooling you have two decent options. Either open and close a new connection for each request, or save open connections into shared memory. The latter has obvious performance benefits if the expected request rate is high, but exposes a number of other problems this recipe aims to address. A connection can abruptly terminate because of e.g. a network glitch or maintenance downtime, and the sysadmins deploying your software will be happier having to deal with less services to reboot.
</p>
<p>
The handler should catch exceptions only related to network or database resource failures, whereas in other cases (SQL typo?) the original exception should not be reacted upon. Figuring out the proper <a href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14219/toc.htm">ORA error codes</a> to use was an exciting task, I hope I got them right ;). Those guys at Oracle sure love to make things easy. Since I use a regular expression to match the error message string, a multitude of errors can be matched with a single rule. Fortunately, all errors dealing with <i>Transparent Network Substrate</i> are marked by prefix "TNS". In my tests most errors were indeed caught with the single "<code class="prettyprint">ORA-.....: TNS</code>" regexp.
</p>
<p>
Python and Ruby have much in common, both could let me write this very expressively with about the same LOC. There is one small detail I'd like to bring up. These two expressions both compare the codes listed with the exception (error message in variable "message"), and return true if the message matches to one of the given ORA error codes.
</p>
<p>
<span class="file">Python</span>
<pre class="prettyprint lang-py">
# Example message="ORA-03113: end-of-file on communication channel"
any(filter(lambda oracode: re.search('ORA-'+oracode,message), re.split(' *\n *| +(?=\d)',"""
.....: TNS
01000 01001 01014 01033 01034 01037 01089 01090
011.. 015.. 016..
031..
28547
30678
""")[1:-1]))
</pre>
<span class="file">Ruby</span>
<pre class="prettyprint lang-rb">
# Example message="ORA-01034: ORACLE not available"
%w{ .....:\ TNS
01000 01001 01014 01033 01034 01037 01089 01090
011.. 015.. 016..
031..
28547
30678
}.select {|oracode| message[/ORA-#{oracode}/]}.any?
</pre>
Especially take notice of Ruby's <code class="prettyprint">%w{multiline string}</code> versus Python's <code class="prettyprint">re.split(' *\n *| +(?=\d)',"""multiline string""")[1:-1]</code>. This just for the sake of the visual appearance of input data on the screen. Ruby makes it easier to write aesthetic code. Perhaps Python has an idiom for this, though, it just didn't pass my mind.
</p>
<p>
<span class="file">example_oci_exception_handler.py</span>
<pre class="prettyprint lang-py">
# -*- coding: utf-8 -*-
"""
You may use this file under the terms of the BSD license as follows:
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of copyright holder.
"""
import re
import sys
from time import sleep
from myapp.settings import settings # your django settings module
from django.core.management import setup_environ
setup_environ(settings)
import cx_Oracle
from django.db import connection
from django.db.utils import DatabaseError
from logging import getLogger
log = getLogger(__name__)
class ExampleOCIExceptionHandler():
"""Recipe for handling lost Oracle database connection.
Depends on Django ORM, and that proper settings.py exist and is initialized properly.
Selects the network and connection errors, waits until the server is reachable again,
and calls the method again during upon which the exception happened.
This is very useful if the connection, for some reason, is shared between requests.
Oracle 10g does not support connection pooling with cx_Oracle.
"""
@staticmethod
def dispatch(message_data):
"""Processes request.
In case of database connection failure, the waitForOCIConnection() loop is called
and connection should be re-established. In case of other Oracle errors,
the error is raised again.
"""
try:
# do some database operations...
except (cx_Oracle.Error, DatabaseError):
"""
Catch lost database connection.
Handles all TNS errors:
ORA-xxxxx: TNS errors
And all errors from these ranges:
ORA-011xx: Database file errors
ORA-015xx: Execution errors
ORA-016xx: Execution errors
ORA-031xx: communication errors
Along with these specific errors:
ORA-01000: maximum open cursors exceeded
ORA-01001: invalid cursor
ORA-01014: ORACLE shutdown in progress
ORA-01033: ORACLE initialization or shutdown in progress
ORA-01034: ORACLE not available
ORA-01037: cannot allocate sort work area cursor; too many cursors
ORA-01089: immediate shutdown in progress - no operations are permitted
ORA-01090: shutdown in progress - connection is not permitted
ORA-28547: connection to server failed, probable Oracle Net admin error
ORA-30678: too many open connections
"""
msg = str(sys.exc_info()[1]).rstrip()
# is the error about broken connection?
if any(filter(lambda oracode: re.search('ORA-'+oracode,msg), re.split(' *\n *| +(?=\d)',"""
.....: TNS
01000 01001 01014 01033 01034 01037 01089 01090
011.. 015.. 016..
031..
28547
30678
""")[1:-1]) # ignore outermost items as they are empty strings
):
log.error(msg)
ExampleOCIExceptionHandler.waitForOCIConnection()
# enter recursion and call this method again..
sleep(2)
return ExampleOCIExceptionHandler.dispatch(message_data)
else:
log.debug(msg)
log.debug("Error seems to be not about lost connection, raising again ..")
raise
@staticmethod
def waitForOCIConnection(time_to_wait=60):
"""Creates a new database connection, loops until one is established."""
# nullify the connection first, since it can't discover that the socket is gone
connection.connection = None
while not connection._valid_connection():
try:
log.info("Attempt to establish OCI connection to %s ..." % [
settings.DATABASES['default']['NAME']])
# in django parlance, calling _cursor() opens the database connection
cursor = connection._cursor()
sleep(2)
return connection._valid_connection()
except (cx_Oracle.Error, DatabaseError):
exctype, message = sys.exc_info()[:2]
log.error(str(message).rstrip())
log.info("Retrying OCI connection in %i seconds" % time_to_wait)
sleep(time_to_wait)
return ExampleOCIExceptionHandler.waitForOCIConnection(time_to_wait)
</pre>
<span class="file">example_oci_exception_handler.rb</span>
<pre class="prettyprint lang-rb">
# encoding: utf-8
=begin
You may use this file under the terms of the BSD license as follows:
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of copyright holder.
=end
require 'rubygems'
require 'active_record'
# Recipe for handling lost Oracle database connection with ActiveRecord.
#
# Depends on RAILS_ROOT and RAILS_ENV variables to be set and RAILS_ROOT/config/database.yml file to exist.
#
# Selects the network and connection errors, waits until the server is reachable again,
# and calls the method again during upon which the exception happened.
#
# This is very useful if the connection, for some reason, is shared between requests.
class ExampleOCIExceptionHandler
# Processes request.
#
# In case of database connection failure, the waitForOCIConnection() loop is called
# and connection should be re-established. In case of other Oracle errors,
# the error is raised again.
def self.dispatch(message_data)
begin
# do some database operations...
# Catch lost database connection.
#
# Handles all TNS errors:
# ORA-xxxxx: TNS errors
#
# And all errors from these ranges:
# ORA-011xx: Database file errors
# ORA-015xx: Execution errors
# ORA-016xx: Execution errors
# ORA-031xx: communication errors
#
# Along with these specific errors:
# ORA-01000: maximum open cursors exceeded
# ORA-01001: invalid cursor
# ORA-01014: ORACLE shutdown in progress
# ORA-01033: ORACLE initialization or shutdown in progress
# ORA-01034: ORACLE not available
# ORA-01037: cannot allocate sort work area cursor; too many cursors
# ORA-01089: immediate shutdown in progress - no operations are permitted
# ORA-01090: shutdown in progress - connection is not permitted
# ORA-28547: connection to server failed, probable Oracle Net admin error
# ORA-30678: too many open connections
#
rescue OCIError, ActiveRecord::StatementInvalid
msg = $!.message
# is the error about broken connection?
if %w{
.....: TNS
01000 01001 01014 01033 01034 01037 01089 01090
011.. 015.. 016..
031..
28547
30678
}.select{|oracode| msg[/ORA-#{oracode}/]}.any?
logger.error msg
waitForOCIConnection()
# enter recursion and call this method again..
return dispatch(message_data)
else
logger.debug msg
logger.debug("Error seems to be not about lost connection, raising again ..")
raise $!
end
end
end
# Attempts to establish database connection.
# Loops until ActiveRecord is connected.
#
# Set time_to_wait in seconds.
def self.waitForOCIConnection(time_to_wait=60)
begin
database_configuration = YAML.load_file(File.join(RAILS_ROOT,"config","database.yml"))
ActiveRecord::Base.configurations = database_configuration
logger.info(
"Attempt to establish OCI connection to %s ..." % database_configuration[RAILS_ENV]['database'])
ActiveRecord::Base.establish_connection(database_configuration[RAILS_ENV])
ActiveRecord::Base.connection # essential to open connection
return ActiveRecord::Base.connected?
rescue OCIError, ActiveRecord::StatementInvalid
logger.error($!.message)
logger.info("Retrying OCI connection in %i seconds" % time_to_wait)
sleep time_to_wait
return waitForOCIConnection(time_to_wait)
end
end
end
</pre>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-61007874112397232122010-10-15T21:32:00.057+03:002010-11-19T16:45:52.254+02:00Interacting with legacy Oracle database in Python<p>
I needed to use an Oracle database in Python. It all went rather smoothly with the <a href="http://www.oracle.com/technetwork/articles/dsl/python-091105.html">guides</a>, <a href="http://cx-oracle.sourceforge.net/BUILD.txt">hints</a> and <a href="http://blog.doughellmann.com/2007/12/using-raw-sql-in-django.html">examples</a>, but I was missing a walkthrough. This memo is about setting up Oracle with Python and how to use legacy database with Django. Better yet, use <a href="http://docs.djangoproject.com/en/dev/topics/db/models/">Django Models</a> without any of the HTTP functionality.
</p>
<p style="overflow: auto;">
<a href="http://oreilly.com/catalog/9780596158118">
<img style="float: left; cursor:pointer; cursor:hand;width: 180px; height: 236px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2Zg5qvmLKJwHDI4tyYC8b21dmXyv5l6hf99UhQ2nP5DC5Ewh-0N0glZqreR3SHlx59zXsMukaXnVGdOXhK0dEzs3B_R7ECoQMt0-JISCfziA2ejqSjbf4dcxs-8MySIkkT0K8B1iMfWSc/s320/oreilly-python2.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5528389894784196258" /></a>
<a href="http://oreilly.com/catalog/9780596000189">
<img style="float: left; cursor:pointer; cursor:hand;width: 180px; height: 236px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidis83tHOkyPR-MEN3scyMmxlSwnEeIHYrbo3b66vf7dKHEnzmKUUz5W9CtPuB4uPYphqaChi77ewEcymGZ9_mWj1IaKLfpsg8wevuBz9k_Bxgt8_6nnxsmfJtlJqJi2T8T2FxtN1tHq2o/s320/oreilly-oracle.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5528387745082915602" /></a>
</p>
<p style="clear:both;">
Oracle more or less has official support for <a href="http://cx-oracle.sourceforge.net/">cx_Oracle</a>, and it was fairly easy to set up. cx_Oracle needs Oracle headers to compile. From the <a href="http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html">Oracle download site</a> get, according to your OS and arch, <span style="font-style:italic;">instantclient-basic</span>, <span style="font-style:italic;">instantclient-sqlplus</span> and <span style="font-style:italic;">instantclient-sdk</span>. The Oracle download site requires registration.
</p>
<p>
Select a working path and extract the Instant Client packages.
<div class="code">
$ cd /opt<br />
$ unzip ~/Downloads/instantclient-basic-10.2.0.4.0-macosx-x64.zip <br />
$ unzip ~/Downloads/instantclient-sdk-10.2.0.4.0-macosx-x64.zip <br />
$ unzip ~/Downloads/instantclient-sqlplus-10.2.0.4.0-macosx-x64.zip
</div>
</p>
<p>
It is necessary to set the environment variables <span style="font-style:italic;">ORACLE_HOME</span>, <span style="font-style:italic;">LD_LIBRARY_PATH</span> and <span style="font-style:italic;">DYLD_LIBRARY_PATH</span>. Put these into a convenient file and update the environment.
</p>
<p>
<span class="file">~/.oraenv</span>
<pre class="prettyprint">
export ORACLE_HOME=/opt/instantclient_10_2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME
export DYLD_LIBRARY_PATH=$ORACLE_HOME
</pre>
</p>
<p>
On OS X, you need to create one symlink for the build to succeed:
<div class="code">
$ cd /opt/instantclient_10_2/<br />
$ ln -s libclntsh.dylib.10.1 libclntsh.dylib
</div>
</p>
<p>
Now you are ready to build and install the cx_Oracle driver.
<div class="code">
$ cd /opt<br />
$ tar xzf ~/Downloads/cx_Oracle-5.0.4.tar.gz <br />
$ cd cx_Oracle-5.0.4<br />
$ source ~/.oraenv # load environment<br />
$ python setup.py build<br />
$ python setup.py install
</div>
</p>
<p>
Assuming the database is already running somewhere, enter the connection parameters to this python script and test the connection:
</p>
<p>
<span class="file">test_connection.py</span>
<pre class="prettyprint lang-py">
# -*- coding: utf-8 -*-
import cx_Oracle
connection = cx_Oracle.connect(
"user",
"pass",
"127.0.0.1:1524/some.oraservice"
)
cursor = connection.cursor()
cursor.execute("select * from v$version")
for column_1 in cursor:
print "Values:", column_1
</pre>
You should see something like this:
<div class="code">
$ python test_connection.py <br />
</div>
<div class="quote">
Values: ('Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi',)<br />
Values: ('PL/SQL Release 10.2.0.4.0 - Production',)<br />
Values: ('CORE\t10.2.0.4.0\tProduction',)<br />
Values: ('TNS for Linux: Version 10.2.0.4.0 - Production',)<br />
Values: ('NLSRTL Version 10.2.0.4.0 - Production',)
</div>
BUT if you get:
<blockquote><i>cx_Oracle.DatabaseError: ORA-12737: Instant Client Light: unsupported server character set WE8ISO8859P15</i>
</blockquote>
You took the BASICLITE package!!! Go back to download the proper package and start from the beginning.
</p>
<p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRK6MHVoqJBWtIRZ8SG6SCannGqaCakSnweBoQnhs8oKY_EHqxc9GQmgLkNL6x0iT9dE3Psd5iI7Od-NJ4nwOXuf63iZnt5kqMFlaFQAzIcx04_brN8XSwggdwA73I7LphannLwxEZAYZp/s1600/django.jpg"><img style="float:none; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 160px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRK6MHVoqJBWtIRZ8SG6SCannGqaCakSnweBoQnhs8oKY_EHqxc9GQmgLkNL6x0iT9dE3Psd5iI7Od-NJ4nwOXuf63iZnt5kqMFlaFQAzIcx04_brN8XSwggdwA73I7LphannLwxEZAYZp/s320/django.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5528348875867664690" /></a>
</p>
<p>
Python can connect to the database with cx_Oracle, and Django models offer a clean way to make use of that connection. If you happen to have schema read privileges to the database, Django can generate <span class="file">models.py</span> from it. Now, this is pretty nice feature when it comes to interacting with legacy database, as we shall see.
</p>
<p>
<span class="file">myapp/settings.py</span>
<pre class="prettyprint lang-py">
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': '127.0.0.1:1524/some.oraservice',
'USER': 'user',
'PASSWORD': 'pass',
}
}
</pre>
</p>
<p>
<span class="file">myapp/manage.py</span>
<pre class="prettyprint lang-py">
from django.core.management import execute_manager
import settings
if __name__ == "__main__":
execute_manager(settings)
</pre>
</p>
<p>
The database SQL shell is useful to have and to test the connection.
You can get greeted with the friendly SQL*Plus console by command <i>dbshell</i>:
<div class="code">
$ source ~/.oraenv # remember environment!<br />
$ python myapp/manage.py dbshell<br />
</div>
<div class="quote">
SQL*Plus: Release 10.2.0.4.0 - Production on Fri Oct 15 12:56:05 2010<br />
<br />
Copyright (c) 1982, 2007, Oracle. All Rights Reserved.<br />
<br />
<br />
Connected to:<br />
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production<br />
With the Partitioning, OLAP, Data Mining and Real Application Testing options<br />
<br />
SQL>
</div>
</p>
<p>
Then you are ready to inspect the schema and generate the Python classes:
<div class="code">
$ python myapp/manage.py inspectdb > myapp/models.py
</div>
Check the new file and assign "primary_key=True" to a column you choose, for each table you need.
</p>
<p>
Say your legacy db has a table called OraAbbOy1001 you need to manipulate.
You may have a start script <span class="file">bin/start.py</span> (as you don't run this with <span class="file">django-manage</span>) in which you setup Django and do whatever you do to init your program. In <span class="file">myapp/logic.py</span> you import the models and operate with the database.
</p>
<p>
<span class="file">bin/start.py</span>
<pre class="prettyprint lang-py">
# -*- coding: utf-8 -*-
import myapp.settings
from django.core.management import setup_environ
setup_environ(myapp.settings)
# before do something else,
# the three lines above here is your first operation.
</pre>
You can then operate on the models by finding or creating instances (selecting and inserting rows) through the ORM. It is also possible to mix in raw SQL, like in this example. I had trouble figuring out how to set a custom sequence name (legacy value) so I opted to select it manually.
</p>
<p>
<span class="file">myapp/logic.py</span>
<!--
<script src="http://gist.github.com/629007.js?file=gistfile1.py"></script>
-->
<pre class="prettyprint lang-py">
# -*- coding: utf-8 -*-
import time
from django.db import models, connection
from myapp.models import OraAbbOy1001
id = # comes somewhere
try:
user = OraAbbOy1001.objects.get(id=id)
except OraAbbOy1001.DoesNotExist:
# select nextval from ID sequence
seq_name = 'q1001user'
cursor = connection.cursor()
cursor.execute("SELECT %s.NEXTVAL FROM DUAL" % seq_name)
userid = cursor.fetchone()[0]
# create new user
user = OraAbbOy1001.objects.create(
id=userid,
name='Vic Video',
create_date=time.strftime('%Y-%m-%d',time.localtime()),
)
log.info("OraAbbOy1001 user id %i (%s) created" % (
user.id,
user.name
)
)
</pre>
</p>
<p>
<a href="http://www.sqlalchemy.org/">SQLAlchemy</a> looks very interesting. If you need to have more control over the queries, look up for it.
<div>
<a href="http://oreilly.com/catalog/9780596516147">
<img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 180px; height: 236px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJDMXkP9LRh4IQxkyPSoNjDO7foLUMy4VSUNvxMjHWWWtia46lYUxNORw2vwgJm61zQ3IMZuLQdfk5S4Opd9WQznYCsSmk_s12989x_oraBjAYWszWoVkJTq8FTpMiSEdUkTm5iv0P_ITV/s320/oreilly-sqlalchemy.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5528655427834758850" /></a>
</div>
<div style="color: gray; font-style: italic; clear: both; font-size: 0.9em; margin-bottom: 0.2em;">
BTW, I'm not affiliated with O'Reilly, I just like the illustrations. They do have many good books.
</div>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-20642022707860740992010-09-11T00:15:00.013+03:002010-10-05T12:36:11.463+03:00QML signals on PySide<p>
I studied QML with signal-slot communication across to Python a bit.<br />
If you are looking for examples in source code, see
<ul>
<li>
<a href="http://gitorious.org/pyside-example-qml-signalslot/qml-signalslot/trees/master">gitorious.org/pyside-example-qml-signalslot/qml-signalslot</a>
</li>
<li>
<a href="http://gitorious.org/maximum-pvr/mxmanager/trees/master">gitorious.org/maximum-pvr/mxmanager</a>
</li>
</ul>
The latter one use PySide but not QML, and has a preview video elsewhere in this blog. Here are my earlier experiments.
</p>
<p>
This video shows a very small application, consisting of two files - <span class="file"><a href="http://gitorious.org/pyside-example-qml-signalslot/qml-signalslot/blobs/master/webview.qml">webview.qml</a></span> and <span class="file"><a href="http://gitorious.org/pyside-example-qml-signalslot/qml-signalslot/blobs/master/webview-qml.py">webview-qml.py</a></span>.<br />
The first three signals originate from QML and Python opens up a QMessageBox to display them, along by printing to stdout. The third signal will emit a fourth signal from Python to QML, with an url as a parameter, and the url will open inside a WebView.
</p>
<p>
<iframe src="http://player.vimeo.com/video/14862855" width="400" height="300" frameborder="0"></iframe>
</p>
<p>
This app evolves the idea a bit further. <span style="font-style:italic;">The HTML5 canvas demos seen in the video are not by me, they are from the web.</span> There is a state machine working behind the scenes.
</p>
<p>
<p>
<iframe src="http://player.vimeo.com/video/14926884" width="400" height="285" frameborder="0"></iframe>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com6tag:blogger.com,1999:blog-7250348253147345207.post-19739581154875322582010-09-10T10:36:00.026+03:002010-12-06T16:03:46.333+02:00Compiling PySide on OS X<p>
Binary packages of PySide are available from <a href="http://developer.qt.nokia.com/wiki/PySideBinariesMacOSX">developer.qt.nokia.com/wiki/PySideBinariesMacOSX</a>. You only need to compile it yourself if you have explicit reason to.
</p>
<p>
However, if for any reason you would like to compile it yourself, read on. First of all, <a href="http://qt.nokia.com/downloads/">download Qt SDK</a>. After it has been installed you can use this <a href="http://qt.gitorious.org/~lamikae/pyside/lamikae-pyside-packaging/trees/master/osx">Makefile</a> script to download, compile and package PySide from git master.
<div class="code">
$ git clone git://gitorious.org/~lamikae/pyside/lamikae-pyside-packaging.git<br />
$ cd lamikae-pyside-packaging/osx/<br />
$ make package
</div>
</p>
<p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhyGIM17tw7pPLIpWjJJDu9NggNLD2X2tPLQOG47XkI4SK3wE_RTl0oKVhHDGD_n9C6iC2781NcSNUzFipBQ80ZIAi6cU6p1On7mvj1rLjK99yB5qUPcHT2ipILQhMw6sfQQXpw0AuuIuQ/s1600/xkcd+compiling.png"><img style="float:none; margin:0 0 10px 2em;cursor:pointer; cursor:hand;width: 320px; height: 279px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhyGIM17tw7pPLIpWjJJDu9NggNLD2X2tPLQOG47XkI4SK3wE_RTl0oKVhHDGD_n9C6iC2781NcSNUzFipBQ80ZIAi6cU6p1On7mvj1rLjK99yB5qUPcHT2ipILQhMw6sfQQXpw0AuuIuQ/s320/xkcd+compiling.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5514894680375168722" /></a>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdks4l40WePlobPOYLdRVmZ9_2JvC9nk1hi9IcSkKXLA6egDX66RoIqYhdt_4VooAhzehz_lJ0wVElLT7GAzEfyvK-0MXGJSNMo39sZbifN3DcyrstIgNS4jc7LoGYwvnImghIGRRss2jz/s1600/pyside+compiling+qml.png"><img style="float:left; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 129px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdks4l40WePlobPOYLdRVmZ9_2JvC9nk1hi9IcSkKXLA6egDX66RoIqYhdt_4VooAhzehz_lJ0wVElLT7GAzEfyvK-0MXGJSNMo39sZbifN3DcyrstIgNS4jc7LoGYwvnImghIGRRss2jz/s320/pyside+compiling+qml.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5514898400307766882" /></a>
</p>
<p style="clear: both;">
Maybe after an hour or more you should have a .pkg file, which has PySide dynamically linked to Qt installed from official dmg.<br />
Install it with the command:
<div class="code">
$ sudo installer -pkg pyside-<version>.pkg -target "/"
</div>
See if it works (if there is no error, it does =) and try out some of the official <a href="http://qt.gitorious.org/pyside/pyside-examples">PySide examples</a>.
<div class="code">
$ python -c "from PySide import QtCore"
</div>
You can inspect the package contents by
<div class="code">
$ xar -xf pyside-<version>.pkg Bom && lsbom package.pkg/Bom
</div>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com2tag:blogger.com,1999:blog-7250348253147345207.post-90177391951418060972010-05-12T21:10:00.008+03:002010-05-13T01:07:02.460+03:00Gource animation of Rails-portlet development<a href="http://code.google.com/p/gource/">Gource</a> is a fabulous program that can visualize common version control repository history. This is the development of Rails-portlet for the last few years, in a few seconds.
<p>
<object width="400" height="300"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=11694038&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=11694038&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"></embed></object>
</p>
I had to write a small Python script that parses logs from Git submodules. The script is at <a href="http://gist.github.com/398626">Gist</a> and may be freely used.
<p>
<script src="http://gist.github.com/398626.js?file=gource-submodules.py"></script>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-34076933702707878962010-04-15T23:32:00.012+03:002010-04-18T02:15:54.328+03:00Testing JavaScript & XHR with Python<p>
I am working on a library for Django - which I'll describe later - and for building this project I need to test the behavior of XHR on the HTML page. That is, I have a page, inject some JavaScript (that may do a request on the server), and see how it changes the document. The Django application the library is designed for creates some parts of the original page and processes some parts of the server-side XHR.
</p>
<p>
Python is great for this. I've mentioned already in this blog <a href="/search/label/qt">how I like Qt4</a>, and it proves to be very useful again. I could not get PySide running on OS X just yet, so I opted for PyQt4.
</p>
<p>
Four tests; four evenings working with them – each having an intricate problem to solve ;) Two tests work on the local document, the other two connect to the <a href="http://github.com/lamikae/caterpillar/tree/master/portlet_test_bench/">Portlet test bench</a>, running on localhost. These tests trigger onclick submit actions from the XHR test page, simulating a user clicking a button.
</p>
<p>
This way it is possible to test the effect of JavaScript injection onto <em>any</em> web page in the wild. At least the WebKit response.. Firefox could be tested by using <a href="http://packages.debian.org/sid/python-gtkmozembed">python-gtkmozembed</a>. QWebKit also has methods for binding Python variables to the page (it is possible for JavaScript to trigger a Python callback function) and render an image snapshot of the page.
</p>
<p>
If you wish to run the tests, <a href="http://gist.github.com/gists/367610/download">download</a> the file, start up the Rails server with the test bench and run
<div class="code">
$ python xhr_tests.py
</div>
</p>
<script src="http://gist.github.com/367610.js?file=xhr_tests.py"></script>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-60720198764101034092010-04-05T17:46:00.027+03:002010-04-07T17:26:03.273+03:00Comparison of Web Proxy Portlet, Portletbridge and html2jsr286<p>
There are at least three different JSR 168 / 286 portlet projects that have a similar target: to allow custom web apps and arbitrary web content be accessible in portlets.
<ul>
<li><a href="http://www.ja-sig.org/wiki/display/PLT/WebProxy">Web Proxy Portlet</a> (<a href="https://www.ja-sig.org/svn/portlets/WebproxyPortlet/trunk/">source</a>)</li>
<li><a href="http://www.portletbridge.org/">portletbridge</a> (<a href="http://sourceforge.net/projects/portletbridge/">source</a>)</li>
<li><a href="http://github.com/lamikae/html2jsr286">html2jsr286</a> in Rails-portlet</li>
</ul>
I am the author of "Rails-portlet" and it's alive - I just updated the <a href="http://rails-portlet.rubyforge.org/doc/defaultsetup.html">setup guide</a>. It all started when I needed to develop a webapp for Liferay, and I wanted to do it with Rails. html2jsr286 is not an indication of the NIH syndrome, I just now learned of their existance. I inspected their source code, and this is a quick run-down of their features and pondering of future direction.
</p>
<p>
These are the common features in all three projects:
<ul>
<li>
Getting content from a downstream site
</li><li>
Proxying of remote resources (e.g. images, Flash etc.)
</li><li>
Regular expression defining which URL's are in the portlet and which should be regular links
</li><li>
Rewriting CSS urls
</li><li>
Moving Javascript and CSS links out of the head
</li>
<li>
Session cookie support
</li>
</ul>
All three have the same shortcoming concerning Ajax: the urls are not being rewritten so that XHR from the browser is not catched by the portlet.
</p>
<p>
WebProxyPortlet is being developed mainly for uPortal, and
<div class="quote">
..it provides mechanisms for connecting to and rendering HTML with options for clipping, maintaining session information, handling cookies. Proxied content is rendered within the portlet window. Web Proxy Portlet is often used to incorporate web content or applications that are built and run in non-Java environments allowing a site flexibility for integrating with many different technologies.
</div>
</p>
<p>
Sources of portletbridge
<div class="code">
$ mkdir portletbridge<br />
$ cd portletbridge/<br />
$ cvs -z3 -d:pserver:anonymous@portletbridge.cvs.sourceforge.net:/cvsroot/portletbridge co -P .
</div>
Sources of WebProxyPortlet
<div class="code">
$ svn co https://www.ja-sig.org/svn/portlets/WebproxyPortlet/trunk/ WebproxyPortlet
</div>
Sources of html2jsr286
<div class="code">
$ git clone git@github.com:lamikae/html2jsr286.git
</div>
</p>
<p>
My impression after a while looking through the sources is that WebProxyPortlet is the most advanced, and has a number of nice features, especially in ways of user authentication and portlet configuration through the user interface.
</p>
<p>
Considering code cohesion and the number of Java classes: WebProxyPortlet has 58, Portletbridge 51 and html2jsr286 only 10 Java source files. Here are links to their main view methods:
<br />
<br />
<span class="code">
void renderContent(final RenderRequest request, final RenderResponse response)
</span> in <a href="https://www.ja-sig.org/svn/portlets/WebproxyPortlet/trunk/src/main/java/edu/wisc/my/webproxy/portlet/WebProxyPortlet.java">WebProxyPortlet.java</a>
<br />
<span class="code">
void doView(final RenderRequest request, final RenderResponse response)
</span> in <a href="http://portletbridge.cvs.sourceforge.net/viewvc/portletbridge/portletbridge-ng/portletbridge-core/src/main/java/org/portletbridge/portlet/BridgeViewPortlet.java?revision=1.4&view=markup">BridgeViewPortlet.java</a>
<br />
<span class="code">
void render(RenderRequest request, RenderResponse response)
</span> in <a href="http://github.com/lamikae/html2jsr286/blob/master/WEB-INF/src/Rails286Portlet.java">Rails286Portlet.java</a>
</p>
<p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-cykO4UYtN2PlPRO9gK0A8xIeldPTykrh9Sf_y8cElu9j5OynHLGIME1JxAdU5ItCiFT4OtDVAXEHb9kizKbtpeaO2lS2S4PCK549S75e9zn5qP6uLMTvLUQ-O_DClC2ir5f2YRjG8L4m/s1600/WebProxyPortlet+tests.png"><img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 154px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-cykO4UYtN2PlPRO9gK0A8xIeldPTykrh9Sf_y8cElu9j5OynHLGIME1JxAdU5ItCiFT4OtDVAXEHb9kizKbtpeaO2lS2S4PCK549S75e9zn5qP6uLMTvLUQ-O_DClC2ir5f2YRjG8L4m/s320/WebProxyPortlet+tests.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5456668814917694434" /></a>
WebProxyPortlet works in JSR 168 containers and supports a variety of authentication techniques, handles caching, has pluggable Java classes for custom request filtering and page processing. On top of this is uses a whole lot of JavaBeans and JSPs that make the portlet configurable from the GUI in the portlet config mode. I am not sure how much runtime overhead this accouts to, and how useful it is to let users select the HTML parser the portlet is going to use. Page processing is implemented by chaining up SAX filters.
<br /><br />
Some criticism must be given; there are virtually <b>no unit tests</b> and there seems to be some code repetition and lots of "boilerplate" code (which is quite difficult to neutralize in Java) and somehow it just hurts me that the renderContent() method is 374 lines long. It could use some refactoring.
</p>
<p>
Portletbridge seems to have stalled active development some years ago, but there seems to be some recent code cleanup in progress, according to CVS logs.. It probably is doing what it's supposed to, feature-wise it seems to be close on par with html2jsr286, and it runs on JSR 168 portals. Page processing is done by XSLT, a feature that I really like.
</p>
<p>
html2jsr286 and Rails-portlet are strong in that they offer a toolchain for a Rails developer to get quickly into deployment with as much automation as possible. The other two projects look like they are more tuned to serve the portal administrator instead of the development team. The Rails-portlet project tools can also work without Rails, but then the deployment gets more encumbered, requiring more dirty work with Java and XML. Rails-portlet is targeting for web app developers who want to keep a healthy distance to the J2EE stack and "get things done" quickly.
<br /><br />
html2jsr286 passes the Liferay UID in request headers, with a unique authentication mechanism. It can also handle Liferay GID – feature that is missing from the other two portlets. It is, however, restricted for JSR 286 portals, as it makes use of portlet filters, which were introduced only in JSR 286. The rationale behind this is to improve code coherence (there are no technical reasons that would demand using filters). JSR 286 container will, however, be needed for the <a href="http://wiki.oasis-open.org/wsrp/XMLPortletRequest_Proposal">XMLPortletRequest</a> feature. The portlet is being used on at least two production sites, and in practise is doing fairly well. Page processing is done by HTML Parser, which does a decent job but has <a href="http://github.com/lamikae/html2jsr286/blob/master/Bugs.txt">shortcomings</a> that I would like to address with XSLT, and this is what Portletbridges is doing.
</p>
<p>
Nonetheless, I am considering a rational move to leverage WebProxyPortlet in Rails-portlet, and it seems that the first step is to get it running on Liferay and uPortal, hosting the <a href="http://github.com/lamikae/caterpillar/tree/master/portlet_test_bench/">portlet test bench</a>.
</p>
<p>
Next big step would be to work on Ajax support, by carrying out ideas from these posts to implement XMLPortletRequest.
<ul>
<li>
<a href="http://www.subbu.org/blog/2007/01/xmlportletrequest-part-1-background">http://www.subbu.org/blog/2007/01/xmlportletrequest-part-1-background</a>
</li>
<li>
<a href="http://www.subbu.org/blog/2007/01/xmlportletrequest-part-2-wrapping-xmlhttprequest">http://www.subbu.org/blog/2007/01/xmlportletrequest-part-2-wrapping-xmlhttprequest</a>
</li>
<li>
<a href="http://www.subbu.org/blog/2007/08/update-on-jsr-286-and-ajax">http://www.subbu.org/blog/2007/08/update-on-jsr-286-and-ajax</a>
</li>
<li>
<a href="http://blogs.sun.com/deepakg/entry/xmlportletrequest_in_portlet_container_2">http://blogs.sun.com/deepakg/entry/xmlportletrequest_in_portlet_container_2</a>
</li>
</ul>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com15tag:blogger.com,1999:blog-7250348253147345207.post-77138236761120011392010-04-04T11:17:00.005+03:002010-04-04T11:28:50.704+03:00Flash problems after upgrading from Hardy to LucidI upgraded Ubuntu 8.04 (Hardy Heron) to 10.04 (Lucid Lynx) a few days ago. While it is still in "RC" stage, the graphical update-manager already offered me the upgrade. Which I did.
I had to resolve to an ugly fix after the upgrade to get the proprietary Adobe Flash working. No matter what <em>apt-get</em> command I entered, there was this error message:
<blockquote><span style="font-family: courier new;">
Package is in a very bad inconsistent state - you should reinstall it before attempting a removal.
</span></blockquote>
There were a few others too who had similar problems on Ubuntu forums and <a href="http://ubuntuforums.org/showthread.php?t=1333876&page=4">this solution</a> finally worked for me: remove all occurances of "<em>flashplugin-installer</em>" and "<em>flashplugin-nonfree</em>" from <em>/var/lib/dpkg/status</em>.Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-88752033649657767172010-03-30T20:38:00.012+03:002010-11-20T00:02:36.036+02:00Mobile SDKs<p>
I met a nice guy who has a web page that presents an award-winning grill he's designed. He briefly mentioned the <a href="http://mestarigrilli.com/">site</a> that runs entirely on Flash and I offered to upgrade it for HTML, CSS and Javascript. I wanted to learn some <a href="http://www.css3.info/">CSS3</a> and <a href="http://mootools.net/">MooTools</a> on a real-world problem. The design consists of a menu, a large image and a caption. Images are switched either by timing or by user clicking next/back buttons, complete with fade out and fade in. As it came together I tested it on Firefox, Chrome, Opera, Arora, Safari, Konqueror and IEs 6-8. I decided to try out the popular mobile SDKs as well then. Namely, Nokia Maemo 5, Google Android and Apple iPhone. This is an overview and a quick, superficial evaluation of the mobile developer toolkits.
</p>
<p>
My aim was not to work on any platform-specific code, but to test out how these devices would display the page and the image transitions. I very much appreciate the ease of installation, good documentation and in general getting to the point very quickly with a minimum amount of hassle. Happy developers make better software. Even better when they needn't to fight with the toolchain. :)
</p>
<p>
Maemo 5 was the first one I picked since being Debian-based it seems to be the most open platform. I remember briefly using a Nokia N770 in 2006 and apparently Nokia thinks it's a product line worth upgrading by N810 and now N900 released in 2009. Unfortunately even with the backing of Nokia and several years of development, the documentation is not quite as organized as I'd like it to be, with all respect. From the main <a href="http://maemo.org/development/">Maemo.org developer page</a>, it takes five clicks through a Nokia site on another host, back to Maemo wiki, and to the <a href="http://wiki.maemo.org/Documentation/Maemo5_Final_Installation">cryptic installation notes</a> that remind me of Gentoo manuals. Choosing those five clicks wasn't quite trivial either.
</p>
<p>
Thankfully some fellow Maemo developers kindly guided me to <a href="http://tablets-dev.nokia.com/maemo-dev-env-downloads.php">a hidden Nokia page</a> hosting a prepared Ubuntu virtual image with the SDK and the rest of the tools. Apparently even hosted at nokia.com this is an unofficial image. I let the 1.7 GB image to download overnight and launched it in VirtualBox the next morning without a hitch. It brought up the Ubuntu desktop, with no assistance or an emulator icon around. Here be dragons indeed.. Spells and incantations will apparently be needed. Now, somewhere in the middle of the installation spellbook it says "Xephyr" needs to be started:
</p>
<blockquote><span style="font-family: courier new;">
$ Xephyr :2 -host-cursor -screen 800x480x16 -dpi 96 -ac -kb &
</span></blockquote>
<p>
Mm-hm. This launches up an empty, gray X window. Now, the commands to start the "scratchbox environment" and inside it, the Maemo startup script:
</p>
<blockquote><span style="font-family: courier new;">
$ setxkbmap fi<br />
$ /scratchbox/login<br />
> export DISPLAY=:2<br />
> af-sb-init.sh start
</span></blockquote>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJhBuCH2dYDwE56CcVtlcq_joTMICX8XsRqqHZcP1sN5YKET7U-VGoi-gGVQ5I1ti4lYfCXB3_5B6Cn3wlU7tX7tfDzw9VR59FcYbe9_pYmAgrUXZG-QO3_q1H_Tw6RtUA8FK-PJNJlnR2/s1600/getting+maemo+to+run.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 261px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJhBuCH2dYDwE56CcVtlcq_joTMICX8XsRqqHZcP1sN5YKET7U-VGoi-gGVQ5I1ti4lYfCXB3_5B6Cn3wlU7tX7tfDzw9VR59FcYbe9_pYmAgrUXZG-QO3_q1H_Tw6RtUA8FK-PJNJlnR2/s320/getting+maemo+to+run.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5454483324861594402" /></a>
<p>
Success! I still think I shouldn't need to know any of this, but it is running with a fair amount of work. Unfortunately none of the apps were installed and the virtual device seemed quite empty – all there was this Application Manager:
</p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpoGoNlA4AxNS5yCG0iwn0u9jpsBWh_zhWXGUqXuE9AulRdNhCQBsd-FPmsfDlJu9g-ry34OKT8MVZ7YKnQNaO4o3AMPVa3RFunKRcaSJPgIGXP8CCMDxdc2di54PgJ0AhSCmVsyn0-ofi/s1600/maemo+app+manager.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 261px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpoGoNlA4AxNS5yCG0iwn0u9jpsBWh_zhWXGUqXuE9AulRdNhCQBsd-FPmsfDlJu9g-ry34OKT8MVZ7YKnQNaO4o3AMPVa3RFunKRcaSJPgIGXP8CCMDxdc2di54PgJ0AhSCmVsyn0-ofi/s320/maemo+app+manager.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5454483597042582978" /></a>
<p>
Some extra packages need to be manually installed into the scratchbox environment:
</p>
<blockquote><span style="font-family: courier new;">
> apt-get install nokia-binaries nokia-apps
</span></blockquote>
<p>
Then I had the Maemo browser, which displayed the page correctly. Happiness!
</p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2U9iwJrbwZm_wkLn5IeakokAXsQT8cbDJMgPiN5_EnEdTlUP9XIuwPPCOYSOkiQNFgjqbLvMAnDhi7I_iv9Ai4lvNq9G137gY0DN1jMJEIkNN5hXMh8pogE-kaGDu1tvH0fDx8s5BXlmv/s1600/maemo+happiness.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 263px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2U9iwJrbwZm_wkLn5IeakokAXsQT8cbDJMgPiN5_EnEdTlUP9XIuwPPCOYSOkiQNFgjqbLvMAnDhi7I_iv9Ai4lvNq9G137gY0DN1jMJEIkNN5hXMh8pogE-kaGDu1tvH0fDx8s5BXlmv/s320/maemo+happiness.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5454483870564484546" /></a>
<p>
I wonder what Intel does to the SDK now after merging Moblin and Maemo to <a href="http://meego.com/">MeeGo</a>...
</p>
<p>
Next, testing Google Android. <a href="http://developer.android.com/sdk/index.html">The SDK</a> is a ~20 MB zip file that is a Java GUI which downloads the actual SDK. The size after downloading platforms v1.6 and v2.1 is 343 MB.
</p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkBgUgQd04cRd3no3yk3075Xbmcew6mtUNxNY3Nxkda63DJPA4Gz8Q2wC2dP3uZYsI2p3BVJJRBAtgLTpam-_bu-B98OAo7QkZZEQjhgkdRZZFAzkhzzxH_2llt0uHWF9xRzFbgoqKq8Pq/s1600/android+gui.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 186px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkBgUgQd04cRd3no3yk3075Xbmcew6mtUNxNY3Nxkda63DJPA4Gz8Q2wC2dP3uZYsI2p3BVJJRBAtgLTpam-_bu-B98OAo7QkZZEQjhgkdRZZFAzkhzzxH_2llt0uHWF9xRzFbgoqKq8Pq/s320/android+gui.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5454484237917327410" /></a>
<p>
Creating an Android virtual device was very easy with the GUI.
</p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh66hG9eV9UmvFaavKCGImIwMRIYEVo2UkEO6tt0cWSuwN3RPrTgVWgAVXhAV3TxDDKacPl5dCXcGSis0OVO47lnPTOYkH5ONCSclT2rRchBH0ivZXVhWOI5uhfzo0W1wwDMHnr1CZvyhCJ/s1600/android+virtual+device.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 229px; height: 320px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh66hG9eV9UmvFaavKCGImIwMRIYEVo2UkEO6tt0cWSuwN3RPrTgVWgAVXhAV3TxDDKacPl5dCXcGSis0OVO47lnPTOYkH5ONCSclT2rRchBH0ivZXVhWOI5uhfzo0W1wwDMHnr1CZvyhCJ/s320/android+virtual+device.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5454485004280294162" /></a>
<p>
And it renders correctly on version 2.1!
</p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1vc7XmqDk8I02KPuqyEdhv-2MrH-syUNTRz7Bqe5Z9_ANGAcHXMc0GsP3tks9E6Vfu2Z5J1b1Kx_IFg4bucCS9zguSy5jKWnn-fxj0JsIStNvfuUl4xNWQD5269qEQ7dMa55o9sTrXi7Y/s1600/android+2.1.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 230px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1vc7XmqDk8I02KPuqyEdhv-2MrH-syUNTRz7Bqe5Z9_ANGAcHXMc0GsP3tks9E6Vfu2Z5J1b1Kx_IFg4bucCS9zguSy5jKWnn-fxj0JsIStNvfuUl4xNWQD5269qEQ7dMa55o9sTrXi7Y/s320/android+2.1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5454485165140140050" /></a>
<p>
Finally, since I work on OS X, I can also try out the <a href="http://developer.apple.com/iphone/">iPhone SDK</a>. It required a registration and another overnight download of the whopping 2.8 GB package that comes with bundled Xcode. After downloading, QuickSilver finds the simulator quite nicely and it looks sleek.
</p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOJGh0I4MzW_tFANSSwwWX7MQ4grKHpX9QJZpHjhMZ8_TzZZW6QnzR302kaWRcpHaWBcwt3QN9r8pWNm_DSTks3aYP5Pfm4FdeCfB_NwctDhpjKMa2e9TOUWjMj8vg6VkMkWScvuHnj3ju/s1600/iPhone+simulator+QS.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 302px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOJGh0I4MzW_tFANSSwwWX7MQ4grKHpX9QJZpHjhMZ8_TzZZW6QnzR302kaWRcpHaWBcwt3QN9r8pWNm_DSTks3aYP5Pfm4FdeCfB_NwctDhpjKMa2e9TOUWjMj8vg6VkMkWScvuHnj3ju/s320/iPhone+simulator+QS.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5454485392987240162" /></a>
<p>
I have only a few times used a real iTouch device, but I see the appeal in their design. iPhone with its Safari browser can display my test page correctly.
</p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQFYWqXkHJAm7zQ1pijWn1EBgxkXPzXEszqK2MKVSFNTLgiNyRl6h6BCsP6SnGnGUXKsfLHSMTJgBVyBviae4Y3zNZcE-DulkMBFezs-_KqMoP9F5LlmZLwwhFKbHasN5bfKGz7AacsfFN/s1600/iPhone+grilli.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 172px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQFYWqXkHJAm7zQ1pijWn1EBgxkXPzXEszqK2MKVSFNTLgiNyRl6h6BCsP6SnGnGUXKsfLHSMTJgBVyBviae4Y3zNZcE-DulkMBFezs-_KqMoP9F5LlmZLwwhFKbHasN5bfKGz7AacsfFN/s320/iPhone+grilli.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5454485556456498946" /></a>
<p>
Overall, considering these mobile SDKs, Apple provides the most elegant solution, Google being in the middle ground and (now-depracated) Maemo the worst experience. While these being developer tools, the user is expected to have some technical knowledge. This is only a very superficial evaluation, just from the perspective of a web developer who wanted to test how his page renders on these platforms. Speaking of the devices, personally I cannot justify their price to their capabilities just yet, but it is nice to evaluate them by their SDKs. Maemo/MeeGo has the Debian sex appeal for the better and the worse. I feel that Nexus One won't be the first really big model even being technologically superior to the iPhone..
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-13194545307732648172010-03-18T18:19:00.008+02:002010-03-18T23:20:10.875+02:00Python Qt4 soup - quick way to cook up a cross-platform GUIA friend of mine asked me to do a very quick and dirty throwaway application that parses data off a standard HTML file into an Excel spreadsheet. I chose to do it in Python and spent about an hour to decide which backend libraries to use, and opted for <a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a> and <a href="https://secure.simplistix.co.uk/svn/xlwt/trunk/xlwt/doc/xlwt.html">xlwt</a> to do the hard work. The core app – one function to parse input and another function to create the Excel workbook – was written in under two hours. It was only running from the command line – so I cooked him up a GUI:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyDxQiGe1B_EFqg01KIKEflzlZUAK35DfN-4mJVCo7yVXtICI5FCWiYK4c5ls4Ih6z2OP67CGHBu-AbUDJUjRDPElnYp1cjs5HTkjBUHA4Q_4YTyHrsu4ptFmD6i9ScNxWNjjbTe3iXUwR/s1600-h/leaders_xls+osx.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyDxQiGe1B_EFqg01KIKEflzlZUAK35DfN-4mJVCo7yVXtICI5FCWiYK4c5ls4Ih6z2OP67CGHBu-AbUDJUjRDPElnYp1cjs5HTkjBUHA4Q_4YTyHrsu4ptFmD6i9ScNxWNjjbTe3iXUwR/s320/leaders_xls+osx.png" /></a></div><br />
This friend is a Windows user who dislikes Linux and Mac, and he needs a clean GUI that is dead simple to run and operate. After one sleepless night of furious hacking, he got one. In a Windows exe. Developed on OSX, also running under Linux. This is the power of Python combined with Qt4. The <a href="http://github.com/lamikae/qtpysoup">sources</a> are online for those interested to see the details. To emphasize the throwoff nature of the app, all labels are hard-coded to Finnish.<br />
<br />
I already had some experience on <a href="http://www.riverbankcomputing.co.uk/software/pyqt/intro">PyQt4</a>. If you're reading this and decide to look it up, do not pass <a href="http://www.pyside.org/">PySide</a> – it is a newer Python Qt4 bindings library endorsed by Nokia et al. Either one you choose, you can't pass QtDesigner, which is a nice tool to design the UI and comes bundled in the Qt developer packages. In this case all I did was to add a QTableView element with some margin for the tool and status bars.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIAaVFsUG-QanjnQ5Gpx2_t0kptqxDig-t_MOKgFA7ose6BAWQTFc_JzfeqnaKvbq1bro83MfmG0Nqg38BbmcK08LExbRsSiL_tNhAUhprMJsNC8wKeGTEhQb2P-KgdlesY9yfvr4hlVN8/s1600-h/QtDesigner+showcase.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIAaVFsUG-QanjnQ5Gpx2_t0kptqxDig-t_MOKgFA7ose6BAWQTFc_JzfeqnaKvbq1bro83MfmG0Nqg38BbmcK08LExbRsSiL_tNhAUhprMJsNC8wKeGTEhQb2P-KgdlesY9yfvr4hlVN8/s320/QtDesigner+showcase.png" /></a></div><br />
<br />
QtDesigner creates an .ui file (XML) that is translated to Python via pyuic4. With a text editor (XCode) I wrote a subclass of the UI model that extends it with a toolbar with two functions and a status bar for messages. Using file dialogs is easy. The most tricky bit is to make the data from the input file visible in the table view. PyQt4 handles that by a custom subclass of QAbstractTableModel with specific methods the Qt4 API will call to update the table contents.<br />
<br />
Quite simple until you get to signals, slots and threading, and it doesn't hurt too much to write and maintain. Overall, about 120 lines of code for the UI, 50 lines for the core.<br />
<br />
Now all is left is to test and package it for Windows for my friend to run. I've gotten over my worst fear and loathing of Windows, but I still have a very uneasy feeling every time I boot the OS, even in VirtualBox. Text editor and the console are my friends, and cmd.exe does not quite meet my standards, even on Windows 7. Perhaps I'll look up <a href="http://www.jpsoft.com/tccledes.htm">TCC</a>, but honestly I'd expect a better act on behalf of Microsoft. I had a better time with <a href="http://en.wikipedia.org/wiki/4DOS">4DOS</a> 20 years ago running on MS-DOS 5. Oh, don't even get me started on "edit.com"..<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPMYH7GaSiJklFGxX-4iKAQEqghT-iVbYIYUG60Mh5-TbcsKDmsnh6QGPsUdGTnTumVG_V7jxCPpYcBomkUvXwp-HW6HCIgSVNDrbl6DC0iO83nRCEgwl8IYGuHuWo5oobryjN9JBx28jq/s1600-h/edit.com+vs+vim.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPMYH7GaSiJklFGxX-4iKAQEqghT-iVbYIYUG60Mh5-TbcsKDmsnh6QGPsUdGTnTumVG_V7jxCPpYcBomkUvXwp-HW6HCIgSVNDrbl6DC0iO83nRCEgwl8IYGuHuWo5oobryjN9JBx28jq/s320/edit.com+vs+vim.png" /></a></div><br />
<div style="text-align: center;"><span style="font-size: x-small;"><i> Si si, I'm a terminal snob.</i></span></div><br />
Seems that <a href="http://www.py2exe.org/">py2exe</a> is just what I need. It installed fine via easy_install into XP. Their wiki houses the information how to construct the setup.py for py2exe to build it. Mainly, name of the main script for the executable and which libraries to bundle. It creates a whole number of files, totalling 26 MB. I was unable to generate a single executable file, but this does the trick.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh057UTIL4_z0avsj7edwgjNlfz_QHZSD6ouJ9n23WbljSVy542bV6m-_893nWTYeE7PiDst6_6CfNjcGs_NKC5CCxPH3nmGnE6gVwi26LblJiv36Rza9Bdf3oqke527H1gOQT3EdkXR-fd/s1600-h/win32+run.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh057UTIL4_z0avsj7edwgjNlfz_QHZSD6ouJ9n23WbljSVy542bV6m-_893nWTYeE7PiDst6_6CfNjcGs_NKC5CCxPH3nmGnE6gVwi26LblJiv36Rza9Bdf3oqke527H1gOQT3EdkXR-fd/s320/win32+run.png" /> </a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-3925755862867700192010-02-14T11:20:00.007+02:002010-03-13T08:40:39.769+02:00Introduction to Haskell and Erlang<p>I am reading <a href="http://oreilly.com/catalog/9780596515171">Masterminds of Programming</a>, by O'Reilly. It is a very good book I will get back to in other posts. Reading up on the thoughts of Haskell core language developers made me very interested in the language and functional programming in general. Haskell and Erlang are functional languages, so it takes a while to get into the mindset but seems like it's all worth the while. </p><p>I looked up some Haskell resources: <a href="http://www.haskell.org/haskellwiki/Haskell_in_5_steps">http://www.haskell.org/haskellwiki/Haskell_in_5_steps</a> </p><p>Then I saw the Haskell "Hello World" <blockquote><span style="font-family: courier new;"> Prelude> "Hello, World!"<br />
"Hello, World!" </span></blockquote>And immediately fell in love. Is there a simpler way to say "Hello, World!"? </p><p>This Haskell hacking video is also a great source of inspiration :) </p><p><object width="425" height="344" style="float: none;"><param name="movie" value="http://www.youtube.com/v/Cw4xtmMMbXc&hl=en_US&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/Cw4xtmMMbXc&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object> </p><p>There is also a nice guidebook called <a href="http://learnyouahaskell.com/">Learn You a Haskell for Great Good!</a> with cutesy pictures and writing that takes you by the hand. Very nice. Reminds me of the <a href="http://mislav.uniqpath.com/poignant-guide/book/">Poignant Guide to Ruby</a>. :) Erlang has got another one named <a href="http://learnyousomeerlang.com/">Learn You Some Erlang for Great Good!</a>, and you can't go wrong with one that has got a bearded squid on the cover =D </p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio2t_jH76xlr7B9I-9k4xuLL7TKUqw_0OHKQX_eNmKZ3ZBx6Gf6DoG_ebJUXIRoAzMjiFwzab9ycicGk6rSYhQH_L6q6R-WhypfjMkOz0wDd33WuSFlaLFwEzHh3x5KvWAEMIZCHvftTDt/s1600-h/Erlang+squid.png"><img style="float:none; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 185px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio2t_jH76xlr7B9I-9k4xuLL7TKUqw_0OHKQX_eNmKZ3ZBx6Gf6DoG_ebJUXIRoAzMjiFwzab9ycicGk6rSYhQH_L6q6R-WhypfjMkOz0wDd33WuSFlaLFwEzHh3x5KvWAEMIZCHvftTDt/s320/Erlang+squid.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5437790242753943122" /></a> <p>Erlang indeed looks to be a very nice language. This is an example from the book: </p><blockquote><span style="font-family: courier new;"> 1> Weather = [<br />
{toronto, rain},<br />
{montreal, storms},<br />
{london, fog},<br />
{paris, sun},<br />
{boston, fog},<br />
{vancouver, snow}].<br />
<br />
2> <b>FoggyPlaces = [X || {X, fog} <- Weather].</b><br />
[london,boston] </span></blockquote><p>In fact this is even more compact syntax than in Ruby. Erlang atoms behave much in the same way as Ruby symbols. In which the equivalent would be something like: </p><blockquote><span style="font-family: courier new;"> >> weather = [<br />
{'Toronto' => :rain},<br />
{'Montreal' => :storms},<br />
{'London' => :fog},<br />
{'Paris' => :sun},<br />
{'Boston' => :fog},<br />
{'Vancouver' => :snow}]<br />
<br />
>> <b>foggy_places = weather.collect{|x| x.keys[0] if x.values[0]==:fog }.compact</b><br />
=> ["London", "Boston"] </span></blockquote>Or.. <blockquote><span style="font-family: courier new;"> >> <b>foggy_places = weather.select{|x| x.values[0]==:fog }.collect(&:keys).flatten</b><br />
=> ["London", "Boston"] </span></blockquote><p>Either case, I cannot think of a better way to say this in Ruby and Erlang has a cleaner way. </p><p><a href="http://armstrongonsoftware.blogspot.com/">Joe Armstrong</a> is one of the original Ericsson engineers who designed Erlang and wrote the first implementation. He describes <a href="http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html">using Erlang to feed data onto the page by web sockets</a>. I am completely astonished. I <em>need</em> dig deeper into this... </p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-39877176240770407472010-01-29T14:59:00.019+02:002010-03-13T08:38:59.727+02:00EJB to Ruby proxying and a little bit on programming languages<p>This essay goes quite technical at times but the presented idea is pretty simple. </p><p>Java and the J2EE stack seem to be used in large-scale enterprise web solutions. Ruby is an odd hippie programming language that is not so often met (yet!) in this enterprise world. <a href="http://rubyonrails.org/">Ruby on Rails</a> does not quite have the native equivalent in Java web development toolpack, and there never will be such. One key fundamental difference in Java and Ruby, is their measure of abstractness. Higher abstraction in some cases help to describe and solve the problem in just a few code blocks. Ruby lets you express ideas outside the micromanagement level - right from the beginning of your introduction to the language. </p><p><a href="http://jruby.org/">JRuby</a> helps to break a major technical barrier, making possible to leverage the massive amount of Java libraries that now can be used through the Ruby interpreter. This is a description of a real world scenario where Ruby expression describes and solves the problem quite beautifully. </p><p>To understand what is happening next you need to know that an EJB is an <a href="http://java.sun.com/products/ejb/">Enterprise Java Bean</a>. You can imagine that the Bean is an exporter in Brazil. The Java transaction layer <a href="http://java.sun.com/javase/technologies/core/basic/rmi/index.jsp">RemoteMethodInvocation</a> is built on top TCP/IP infrastructure. Regular citizen Java clients need to contact their national supplier. </p><p>It is quite a bureaucratic process. It takes some knowledge of Java to understand how each object should behave. EJB3 makes this a bit easier but to efficiently use the developer tools will take a long time to learn. This is an example of the Java enterprise business model where you develop on elaborate IDEs and large companies have lots of people doing object-oriented chunks of code. After having that much Java your dreams will become XML configurable for a while.. </p><p>Ruby has a similar technique, <a href="http://segment7.net/projects/ruby/drb/">DRb - Distributed Ruby</a>. It is built into the Ruby core language. It provides a way to share data objects over the wire. As we will see, it takes only a few lines, perfectly writable even from the vi editor. </p><p><img src="http://github.com/lamikae/ejb-dispatcher/raw/master/wiki/ejbridge.png"
style="max-width: 80%;"
/> </p><p>Now, let's inspect the supply chain. <pre>bean_context =
{
'java.naming.factory.initial' => 'com.evermind.server.rmi.RMIInitialContextFactory',
'java.naming.security.principal' => security_principal,
'java.naming.security.credentials' => security_credentials,
'java.naming.provider.url' => provider_url
}
</pre>This is the Brazil Bean exporter who has the brew I like. His contact is found by jndi_name from the @context. Home represents my national office who will be creating me this @stub guy who actually does the delivery of my order. <pre>@context = InitialContext.new(bean_context)
@home = @context.lookup(jndi_name)
@stub = @home.create
</pre>EJB home is an object that implements the create() method for requesting the remote EJB and returning the stub object that acts as the EJB interface. It acts a bit like a database table model. </p><p>Let's say we want to know more of the company.. <pre>@stub.companyID
=> "430146"
@stub.companyName
=> "Brazil Bean Provider"
</pre>Mmmh. So let's make an order.. <pre>@order = @stub.createOrder(uid,"Coffea arabica, 1 kg sample")
=> #<#<Class:01x47042c25>:0x62ee558f @java_object=BBPServices stateless session>
</pre>Ah! It returned an object! One important aspect of the dynamic nature of Ruby (and thus JRuby) is that the callable methods need not be specified beforehand. The method call to the Ruby object is dispatched to the EJB, the return value as well and if possible, JRuby casts it to Ruby native. <pre>@order.items
=> ["Coffea arabica, 1 kg sample"]
</pre>This could be usable in Rails, but the architecture should allow dynamic translation of method calls so that the solution would have the most leverage and also to stay clean out of implementation details. Ruby has the sort of inner beauty that is capable of this. </p><p><a href="http://www.thirdbit.net/articles/2007/08/01/10-things-you-should-know-about-method_missing/">method_missing()</a> is a powerful Ruby kernel method, which has its counterpart in Python and Lisp, possibly other dynamic languages are growing into that direction too. Unless you are not familiar with method_missing(), I will explain it so that when Ruby calls a method on the EjbObject's instance (there is this @stub), and the Ruby object does not find the method, it calls method_missing, and here the call is redirected to the @stub, alas the EJB interface and along the network over TCP/IP. In other words, Ruby does not care what kind of EJB it gets. </p><p>This is the core of EjbObject class: <pre>class EjbObject
def context_environment
{
'java.naming.factory.initial' => 'com.evermind.server.rmi.RMIInitialContextFactory',
'java.naming.security.principal' => security_principal,
'java.naming.security.credentials' => security_credentials,
'java.naming.provider.url' => provider_url
}
end
def initialize
@context = InitialContext.new(context_environment)
@home = @context.lookup(jndi_name)
@stub = @home.create
end
def method_missing(method, *args, &block)
@stub.send(method, *args, &block)
end
end
</pre>EjbObject is used by subclassing it: <pre>class MyEJB < EjbObject
set_provider_url 'rmi://....'
end
</pre>
</p><p>And so, this essentially is the JRuby engine in ejb2rb. The solution wouldn't be complete without the Rails counterpart, ActiveEJB. Conceptually DRb and RMI are very similar.
</p><p>Ok - even if the code didn't speak to you, think it this way - now JRuby can talk to the remote Java beans, call their methods, and use the return values as other objects that have methods. Some object classes are mapped directly to corresponding Ruby classes, such as Strings, Arrays and Fixnums. The Java-cast beatnik flower child JRuby can talk enterprise jargon. The EJBDispatcher::Instance enables him to open a channel to one EJB for other Ruby VMs that are equally valuable as Ruby implementations but have not developed their Java-fu.
</p><p>This is how the EJB stub object is shared for DRb clients (the thread is started later by Hydra):
<pre>module EJBDispatcher
class Instance
self.config = {
'hostname' => 'localhost',
'port' => '9876',
'class' => 'MyEJB'
}
def initialize
@uri = "druby://%s:%s" % [config['hostname'],config['port']]
DRb.start_service(@uri, Kernel.const_get(config['class']).new)
return DRb.thread
end
end
end
</pre>What happens on the Ruby end?
<pre>module ActiveEJB
class Entity < DRb::DRbObject
def initialize
uri = 'druby://%s:%i' % [drb_server,drb_port]
super(nil,uri)
end
end
end
</pre>
ActiveEJB::Entity is used by subclassing it:
<pre>class MyEJB < ActiveEJB::Entity
include Singleton
set_drb_server 'localhost'
set_drb_port '9876'
end
</pre>
</p><p>So, in the end, you can use this in native MRI Ruby Rails:
<pre>profile = MyEJB.getUserProfile(@username, "PDS")
contacts = MyEJB2.getCountryContacts(profile.getAddress().getCountry())
contacts.each do |contact|
...
end
</pre>Or something .. usually more or less involving enterprise business logic.. The actual implementation can handle multiple concurrent EJB instances.
</p><p>But, in the end, if we look at the power and sheer expressfulness of Ruby, I think this is a fine example of it working to solve a real world problem. The <a href="http://github.com/lamikae/ejb-dispatcher">source code</a> is available to help rubyists with the leverage this technology may give them trying to survive under the serviance of J2EE.
</p><p>Oh, yes, the order:
<pre>@order.delivery.weight
=> 1.108
BrewerEJB.makeCoffee(
@order.delivery,
:espresso,
:milk => true,
:sugar => false)
</pre></p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-17060377090273071482010-01-23T20:41:00.035+02:002010-03-13T08:50:29.249+02:00Mathematical discourse on the web<style type="text/css">
p.capture {
overflow:auto;
width: 90%;
min-width: 500px;
}
</style> Consider explaining mathematics on the web for someone. The tools to use are quite nifty. Algebra needs distinguishable symbols, geometry some other control methods. Even simple formulas are not so simple: <ul><li><a href="http://terrytao.wordpress.com/2009/10/29/displaying-mathematics-on-the-web/">http://terrytao.wordpress.com/2009/10/29/displaying-mathematics-on-the-web/</a></li>
<li><a href="http://terrytao.wordpress.com/2009/11/04/displaying-maths-online-ii/">http://terrytao.wordpress.com/2009/11/04/displaying-maths-online-ii/</a></li>
</ul>I have a friend who recommended I should try to mix MathFlow with webMathematica and offered me a developer platform. This post is not so much as on the display of formulas as it is about my personal experience of mathematical expression on the web. Mathematica feels like a nice language. I had help for learning it from an experienced notebook / jsp writer, another friend. With his teaching I could quickly learn the essentials constructs of Mathematica's functional style to do simple experimentation and mix it in jsp. WebMathematica3 is a Java servlet package with the necessary backend kernel connectivity and a taglib for the developer. Worked out-of-the-box on OSX – Linux server requires 1 extra step for Xvnc. The taglib is quite usable, with three basic types of components: <ul><li> strings or graphics from the kernel (as small blips in building the UI)</li>
<li> <a href="http://library.wolfram.com/webMathematica/Mathematics/ConstantCurvature.jsp">Java applet for Graphics3D</a></li>
<li> <a href="http://library.wolfram.com/webMathematica/Manipulate/Bragg.jsp">Flash applet for Manipulate</a></li>
</ul>Manipulate is not quite as swift as it is in native Mathematica. The image does not follow the slider before the click is released. The network and server would be stressed for serving many concurrent users.. <p class="capture"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0NTsnSQBFCcowVqW01bcjFUpUg7GJ3l3Ty4xJKVTaShKSOvdGL7gIJSS-lf8OQd32f06QYtFJwDSsnFT2JkFeViChFOuXWJerjr3PUxznc_dx_Z5QoGLxe5h7lSHJaoQwbYnZuXjPlGhn/s1600-h/MathFlowLinux.png"><img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 320px; height: 200px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0NTsnSQBFCcowVqW01bcjFUpUg7GJ3l3Ty4xJKVTaShKSOvdGL7gIJSS-lf8OQd32f06QYtFJwDSsnFT2JkFeViChFOuXWJerjr3PUxznc_dx_Z5QoGLxe5h7lSHJaoQwbYnZuXjPlGhn/s320/MathFlowLinux.png" alt="" id="BLOGGER_PHOTO_ID_5430028167902625074" border="0" /></a> <a href="http://www.dessci.com/en/products/mathflow/">MathFlow</a> is an input mechanism to essentially decrease the learning curve to input mathematical notation into the web. It is a Java applet that seems to work on all major OSes given that the moon is in correct orientation and system Java has not crucially changed. Icedtea6 Java plugin on Ubuntu worked too. MathFlow is proprietary software, this was an evaluation license. To be able to test it on a private server so that clients other than localhost can see it, was possible by recompiling the jar with a custom evaluation license. I could not find any open source alternatives, and this software seems capable of doing the job right now. Ideally, modern-day alternative could be written in JavaScript.. maybe compatible with <a href="http://www.mathjax.org/?page_id=13">MathJax</a>.. </p>The output formula is in MathML, and it can be captured to webMathematica input, in JavaScript, using for example the MooTools toolkit to do an XHR and update the page: </p><pre style="font-family:courier new;">var mml = document.SampleSimpleEditorApplet.getMathML();
params = 'fun='+URLescape(mml);
var req = new Request.HTML({
method: 'post',
url: '_action.jsp?'+params,
encoding: 'iso8859-15',
onRequest: function() {},
update: $('div.output'),
onComplete: function(response) {}
}).send();
</pre>This would send the contents of the editor applet to _action.jsp in request parameter <span style="font-style: italic;">fun</span>, and the XHR would update the page. This _action.jsp in webMathematica could.. <pre face="courier new"><%@ page contentType="text/xml"%>
<%@ taglib uri="http://www.wolfram.com/msp" prefix="msp" %>
<msp:evaluate>
MSPFormat[
MSPToExpression[$$fun],
TraditionalForm
]
</msp:evaluate>
</pre>.. generate an image of the formula in traditional mathematical notation. Notice the <span style="font-style: italic;">$$fun</span> variable, which is parsed by the webMathematica backend. In case where the formula has variables, it is possible to parse it in the "delayed" form: <pre face="courier new">SetDelayed[
f[x_],
Evaluate[
MSPToExpression[
$$fun,
MathMLForm
]
]
];
</pre>Or plot it, notice the use of MSPBlock .. <pre face="courier new">MSPBlock[
{$fun},
MSPShow[
Plot[
$fun,
{x, -2*Pi, 2*Pi},
ImageSize->{600,500}
]]]
</pre><p class="capture"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuyj6SbJkl0vkDMNLpcpaaZ7rFwtj9WYX48P3EK0-DYbu5tTmDbY0Ob102pVrzvo4kRsR_N4RgGaiD8Cq74sID3dcoXx1QWr1Z_0Zg8sUGO_1JeQ2XLpWM2CZ02AhQT_ww-9wA5FYh1GR9/s1600-h/MathFlow+input+to+webMathematica3.png"><img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 320px; height: 165px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuyj6SbJkl0vkDMNLpcpaaZ7rFwtj9WYX48P3EK0-DYbu5tTmDbY0Ob102pVrzvo4kRsR_N4RgGaiD8Cq74sID3dcoXx1QWr1Z_0Zg8sUGO_1JeQ2XLpWM2CZ02AhQT_ww-9wA5FYh1GR9/s320/MathFlow+input+to+webMathematica3.png" alt="" id="BLOGGER_PHOTO_ID_5430010283888816658" border="0" /></a> So you can build all sorts of elaborate user interfaces on top of these building blocks. This is just an example of plotting the user input formula. He shouldn't need to learn LaTeX or any other new notation to input the mathematics into the computer. </p><p class="capture"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwEDRJPJGjxLtkdKhY982z4lzRXw2R7P5WguFkyE7-9rRPl-tz366MXdONr0GfeGa6ZHFRrcF3Fp-BHfi-49i9DadeNelXMC70EYqKRd5_OkryeLxgar_EW-OpT7wjMXqLu_9MLUk-fMwo/s1600-h/workbench-talo.png"><img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 320px; height: 200px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwEDRJPJGjxLtkdKhY982z4lzRXw2R7P5WguFkyE7-9rRPl-tz366MXdONr0GfeGa6ZHFRrcF3Fp-BHfi-49i9DadeNelXMC70EYqKRd5_OkryeLxgar_EW-OpT7wjMXqLu_9MLUk-fMwo/s320/workbench-talo.png" alt="" id="BLOGGER_PHOTO_ID_5430013915970022914" border="0" /></a>The mathematica magician can work with the Wolfram Workbench to write Mathematica code, and still work in a familiar notebook environment. </p>The web developer has a similar view to produce the 3D applet, where the MSPLive3D module creates the HTML code for the Java applet. <pre style="font-family: courier new;">Needs["Talo3D`"];
...
MSPLive3D[
Graphics3D[
{
RGBColor[0, 0, 1],
Thickness[0.005],
Map[Line, house]
},
Boxed -> False
]
]
</pre><p class="capture"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaIyC6BoU_bHx12CZxkfpYm2bYt5J7vvgxHZCAytFSy5OpQGSgVTqI3hLxkCAHpT9Trd2WDxBjZPoET8gwUv_dCqFwLk_STJZTJKlpCLlFkl5No9dJuw2aGva4wEdvWMhW0a16i5OP8cX6/s1600-h/live3d-safari.png"><img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 320px; height: 245px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaIyC6BoU_bHx12CZxkfpYm2bYt5J7vvgxHZCAytFSy5OpQGSgVTqI3hLxkCAHpT9Trd2WDxBjZPoET8gwUv_dCqFwLk_STJZTJKlpCLlFkl5No9dJuw2aGva4wEdvWMhW0a16i5OP8cX6/s320/live3d-safari.png" alt="" id="BLOGGER_PHOTO_ID_5430016521192167218" border="0" /></a> This is LiveGraphics3D generated by webMathematica3 on Safari. The house is rotatible. =) The original .nb was cc'd to me by Jyrki Kajala a few years ago. Quite recently he taught me about Mathematica packages, and .m files, and how the notebook can load the package. The package can now be subjected to functional testing and also included to webMathematica JSP. The tools have a certain good feel of dynamicity. Some issues, here and there, but it would be very interesting to build various use scenarios .. </p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-89085192525067731342009-12-28T12:10:00.006+02:002010-03-14T10:53:50.287+02:00EtherPad and co-ment<p>I was sitting in a train for a few hours, with the source code of <a href="http://etherpad.com/">EtherPad</a> (Apache License 2.0) and <a href="http://www.co-ment.net/">co-ment</a> (GNU Affero GPL 3) on my MacBook. I had just done the initial checkout before the trip - I was very excited to look how these two open source code editors work. EtherPad was just being <a href="http://etherpad.com/ep/blog/posts/google-acquires-appjet">acquired by Google</a>, apparantly to get more professional people to work on the Wave. Real-time collaborative editing seems to be the new paradigm for web user interfaces. </p><p>Both projects, naturally, use JavaScript for transacting with the DOM. EtherPad handles page updates with Comet techniques. Neither come with verbose description of their inner workings, but the EtherPad authors have written a nice post (in the source code repository) that reveals the essential magic ingredient: </p><span style="font-style: italic;"></span><blockquote><span style="font-style: italic;">"The crazy idea here, which seems to have originated with Dutch programmer Marijn</span> <span style="font-style: italic;">Haverbeke, is to take advantage of a browser feature called "design</span> <span style="font-style: italic;">mode" (or "content editable"), a mode which allows the user to</span> <span style="font-style: italic;">directly edit an HTML document. This feature has quietly been added</span> <span style="font-style: italic;">to all major browsers over time. In fact, it's what GMail uses to let</span> <span style="font-style: italic;">users compose rich-text e-mail. The advantages of basing an editor on</span> <span style="font-style: italic;">a design-mode buffer are that such a buffer has a full DOM (document</span> <span style="font-style: italic;">model), which allows arbitrary styling and swapping of parts of the</span> <span style="font-style: italic;">document, and that native editing operations (selection, copy/paste)</span> <span style="font-style: italic;">are mapped by the browser onto operations on the DOM.</span></blockquote><blockquote>... </blockquote><blockquote style="font-style: italic;">The key is to treat the DOM as a hugely complicated I/O device between you and the browser, and carefully make rules to constrain it. The plus side is that once you've systematically beat design mode into submission, you can have an unmatched degree of scalability and nativity." </blockquote>The server-side is handled by Scala, Java and JavaScript. Huh? <blockquote style="font-style: italic;">"This enabled us to be more productive by writing all of EtherPad in the same language, and shuttle data between the client, server, and database all using JavaScript objects." </blockquote>The data persistance model is not very conventional either: <blockquote style="font-style: italic;">"EtherPad stores all its data in the AppJet Database, which automatically scales and caches itself in memory as necessary. This makes it fast to implement EtherPad features, fast to change storage models, and fast to serve requests in production."</blockquote>The code looks very professional and clean, albeit difficult to grok to develop new features. As an interesting note, the included documents describe the changeset to look something like: <blockquote>Z:5g>1|5=2p=v*4*5+1$x </blockquote><blockquote style="font-style: italic;">"This changeset, together with the pool, represents inserting a bold letter "x" into the middle of a line."</blockquote>This is achieved by JavaScript: <pre>function handleUserChanges() {
...
var userChangesData = editor.prepareUserChangeset();
if (userChangesData.changeset) {
lastCommitTime = t;
state = "COMMITTING";
stateMessage = {type:"USER_CHANGES", baseRev:rev,
changeset:userChangesData.changeset,
apool: userChangesData.apool };
stateMessageSocketId = socketId;
sendMessage(stateMessage);
sentMessage = true;
callbacks.onInternalAction("commitPerformed");
}
...
}
</pre>...and the changeset can be traced back to function "compose()": <pre>Changeset.compose = function(cs1, cs2, pool) {
var unpacked1 = Changeset.unpack(cs1);
var unpacked2 = Changeset.unpack(cs2);
...
var bankAssem = Changeset.stringAssembler();
var newOps = Changeset.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function(op1, op2, opOut) {
var op1code = op1.opcode;
var op2code = op2.opcode;
if (op1code == '+' && op2code == '-') {
bankIter1.skip(Math.min(op1.chars, op2.chars));
}
Changeset._slicerZipperFunc(op1, op2, opOut, pool);
if (opOut.opcode == '+') {
if (op2code == '+') {
bankAssem.append(bankIter2.take(opOut.chars));
}
else {
bankAssem.append(bankIter1.take(opOut.chars));
}
}
});
return Changeset.pack(len1, len3, newOps, bankAssem.toString());
};
</pre><p>So overall, EtherPad looks very promising, but difficult to tailor for specific needs. </p><p>Co-ment, in the other hand, is a simpler solution. <span style="font-style: italic;">"co-ment® makes it possible for you to write or upload your own texts, submit them for comments and process the comments.</span>" </p><p>It also uses JavaScript on client-side and Python with Django on the server. The magic is not as advanced; it uses a DOM manipulation API (Beautiful Soup), and happily ignores standard design patterns by mixing views and request/response mechanism control structures with inline SQL. In other words: it is written with more traditional technology, but in a way that makes it difficult to maintain. </p><p>The source codes of either project are definitely beneficial to read and learn from. Unfortunately the lack of architectural documentation makes this a tedious task. </p><p>UPDATE: <a href="http://lwn.net/Articles/367879/">LWN comments on EtherPad</a> </p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-83479816597067242392009-11-17T18:26:00.012+02:002010-03-18T23:19:44.033+02:00Recent advances in WWW technologies and the new generation of user interfaces<p>Many new technologies for the web have emerged during the year 2009. Google Wave, HTML5 and the increasing importance of JavaScript are the driving on the internet, but the mobile device is a growing market where Qt and Android look to provide the best SDKs for iPhone competition. JavaScript engines have been making significant improvements in performance, and V8 makes the Chrome browser <a href="http://www.chromeexperiments.com/">a playground of innovation</a>. </p><p> I have been silently learning Python with PyQt4 that along with QtDesigner make a good combination of tools for cross-platform GUI development. PyQt4 on the other hand did not agree on new licensing with Nokia, and now there is a new Python Qt4 library emerging: <a href="http://www.pyside.org/">PySide</a>. PySide is an important effort and Python -the language- is looking very promising for a number of reasons. </p><p> This exciting iframe below presents <a href="http://www.chromeexperiments.com/detail/your-world-of-text/">Your World of Text</a>, a co-editor which is a prime example of what is possible with modern technology, but this is just a sneak preview of the possibilities that are opening up for developers. Not just on the web but also on the desktop. This demo is produced by Andrew Badr using jQuery, a few lines of custom JavaScript and <a href="http://www.djangoproject.com/">Django</a>, the Python framework. </p><p> <iframe src="http://www.yourworldoftext.com/chromeexperiments" height="300px" width="300px">&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;Your browser does not support iframes.&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;/p&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt;br&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;</iframe> </p><p><i> In 10 years we may have an Ajax X-server. </i> </p><p> The <a href="http://www.youtube.com/watch?v=3ykZYKCK7AM&feature=PlayList&p=9835D9A0057300B5&playnext=1&playnext_from=PL&index=1">Google Wave videos</a> (check also the playlist) are also inspiring. Google Wave provides a same kind of technology as the demo above, but the codebase is not the same. </p><p> The "Wave" that Google presented is under the hood essentially an XML document. The <a href="http://www.waveprotocol.org/">Google Wave Federation Protocol</a> defines the operational transformation layer for sharing the document and mitigating live updates between all wave providers. This works not unlike Git, and all geeks agree how fabulous Git is. As an analogue, Wave provides to non-techie fellow humans (communicate, share) what Git does for code hackers (code, share). Just in a very cool way that code hackers too can appreciate. The protocol is open to contributions by the broader community with the goal to continue to improve how humans share information, together. Even across language barriers! </p><p> So in the very near future, we can have live co-editing in multimedia documents with indesign publication / forking / remixing mechanism. The environment, then .. will it be only the web? </p><p> The trio: HTML5, CSS3 and JavaScript, has matured and provides a solid base for new generation of dynamic user interfaces. The <a href="http://www.chromeexperiments.com/detail/chiptunecom-gui/">Amiga Workbench Emulator</a> is a showcase of JavaScript UI and <a href="http://labs.trolltech.com/blogs/wp-content/uploads/2009/11/demo.html">Qt Labs demonstrates the power of HTML5+CSS3</a> that only works on WebKit browsers (Safari, Konqueror, Chrome). There is no particular Javascript code that switches the items, everything is done by CSS. </p><p> Any defences for the plain old desktop apps? Other than terminals, text/video/etc editors, games, mission-critical tasks, CPU/GPU-intensive 3D apps, ... Oh yes. I for one find it somehow silly to overload a web browser with all of this. One of the reasons why web apps got widly popular at some stage is that they are not locked into one physical computer and that the user can change from operating system to another. Reality hits back in the form of browser inconsistencies and especially by the well-known fact that <a href="http://en.wikipedia.org/wiki/Template:Msieshare1">the single most used browser</a> is <a href="http://mashable.com/2009/07/16/ie6-must-die/">completely incapacitated by todays standards</a> (IE6 - 23,4% of all browsers in October 2009). </p><p> When I started using QtDesigner and Python I was fairly delighted how well they work together. Nice IDE to design the GUI and the UI widgets can be imported and instantiated in my Python code. <i>This is a win for the <span style="font-weight: bold;">Qt</span> app.</i> Qt implements the concept of signals and slots, which provide a way to connect asynchronous events (signal) to call a method (slot). For a web app, this would be possible with JavaScript XHR, but there is no "API", since this concept is a bit foreign in the web world. <i>This is a win for the <span style="font-weight: bold;">Qt</span> app.</i> The layout of a QFrame is very rigid, unlike HTML+CSS which can be extremely fluid. <i>This is a win for the <span style="font-weight: bold;">web</span> app.</i> It also is quite sensible to use accessor objects for inserting data onto a table, but I have to say it feels a bit silly to write 10-20 lines of boilerblate code instead of just iterating over an array and setting a few CSS classes to ones liking? <i>This is a win for the <span style="font-weight: bold;">web</span> app. </i><b>Σ: Qt </b><span class="Unicode">≘</span><b> web = 2</b>. Both have unique strengths. </p><p> Indeed, the web hosts many exotic UIs without overall consistency, whereas the desktop look and feel is pretty much standard with a limited set of widgets, uniform in appearance and function across all applications. That is user-friendly. In some sense it is nice to provide the administrator a single install file and the user an icon on the desktop (or Dock) to click on to access the application. A desktop application may also have access to the hardware and external devices such as USB cameras. An everyday internet browser, enhanced for secure anonymous browsing, should never have these privileges. </p><p> <a href="https://mozillalabs.com/prism/">Mozilla Prism</a> is a small independent browser window and it already is my favourite way to read GMail and Facebook, but the full potential of desktop integration is not used. Prism uses the Gecko engine, whereas Qt4 provides a <a href="http://doc.trolltech.com/main-snapshot/qtwebkit.html">QtWebKit module</a> that is capable of loading and rendering web pages with the help of the <a href="http://webkit.org/">WebKit browser engine</a>. </p><p> I will continue in part #2 on my ideas how desktop and web technologies could build on top of each other's strengths. </p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-67776377603858712612009-11-15T14:05:00.007+02:002010-03-13T08:41:53.855+02:00Chrome Experiments paint the canvas with the future<p>This is one of my favourites from the <a href="http://www.chromeexperiments.com/">Chrome Experiments</a>. <a href="http://deanm.github.com/pre3d/colorscube.html">Colorscube</a> by Dean McNamee. Best run on the Chrome browser. </p><p>It reminds me of the movie Cube. In this demo you can't actually zoom into the cube, but the controls make possible to rotate the cube on the canvas element. </p><p>The user interface on this demo, for example, show the power of HTML5 and modern JavaScript technologies. The user experience in the Chrome Experiments is good also on modern touchpads. </p><p>This will open up new technologies for developers also on the desktop - and today the most promising tech looks to be Qt. The desktop is a tremendous playground, not just the browser where <a href="http://www.codemeit.com/reviews/chrome-vs-ie-javascript-engine-performance-comparison.html">the drag is one de-facto breed of browsers</a>. </p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-80676575862203117452009-07-09T16:10:00.010+03:002010-03-13T08:42:08.416+02:00Oracle 10g on Ubuntu 9.04 x86_64I installed <a href="http://www.oracle.com/technology/software/products/database/xe/htdocs/102xelinsoft.html">Oracle 10g</a> for testing a particular piece of code. My development environment is: <pre>$ uname -om ; lsb_release -a|grep ^De
x86_64 GNU/Linux
Description: Ubuntu 9.04
</pre>and before installing I read some horror stories of people trying to run Oracle on Debian and/or x86_64. These were old posts, so I went on to try it out. In the end I had no hitches and it just works. :) After downloading the deb package, I installed some core libraries <a href="http://halisway.blogspot.com/2006/10/oracle-10gr2-on-ubuntu-610-amd64.html">someone recommended</a>. I have no idea if all of these are required (why gcc/make when this is a binary package?) but for the reference, this is what I installed before the oracle deb. BTW, that blog has good tuning tips. <pre>sudo apt-get install gcc libaio1 lesstif2 lesstif2-dev make libc6 libc6-i386 libc6-dev-i386 libstdc++5 lib32stdc++6 lib32z1 ia32-libs
</pre>Oracle was a breeze to install: <pre>$ dpkg -i --force-architecture oracle-xe-universal_10.2.0.1-1.0_i386.deb
dpkg - warning, overriding problem because --force enabled:
package architecture (i386) does not match system (amd64)
(Reading database ... 234278 files and directories currently installed.)
Unpacking oracle-xe-universal (from oracle-xe-universal_10.2.0.1-1.0_i386.deb) ...
Setting up oracle-xe-universal (10.2.0.1-1.0) ...
update-rc.d: warning: /etc/init.d/oracle-xe missing LSB information
update-rc.d: see <http://wiki.debian.org/LSBInitScripts>
Executing Post-install steps...
-e You must run '/etc/init.d/oracle-xe configure' as the root user to configure the database.
$ /etc/init.d/oracle-xe configure
Oracle Database 10g Express Edition Configuration
-------------------------------------------------
This will configure on-boot properties of Oracle Database 10g Express
Edition. The following questions will determine whether the database should
be starting upon system boot, the ports it will use, and the passwords that
will be used for database accounts. Press <enter> to accept the defaults.
Ctrl-C will abort.
Specify the HTTP port that will be used for Oracle Application Express [8080]:8888
Specify a port that will be used for the database listener [1521]:
Specify a password to be used for database accounts. Note that the same
password will be used for SYS and SYSTEM. Oracle recommends the use of
different passwords for each database account. This can be done after
initial configuration:
Confirm the password:
Do you want Oracle Database 10g Express Edition to be started on boot (y/n) [y]:
Starting Oracle Net Listener...Done
Configuring Database...Done
Starting Oracle Database 10g Express Edition Instance...Done
Installation Completed Successfully.
To access the Database Home Page go to "http://127.0.0.1:8888/apex"
</pre>Apex works so I am happy, but how about a command line console? Ah, there's <a href="http://www.orafaq.com/wiki/SQL*Plus">SQL*Plus</a>. I needed to set up some environment variables (note the unorthodox install location of the binary), which I based on the packaged shell script "/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/oracle_env.sh" I put this in /etc/environment: <pre>export ORACLE_HOME="/usr/lib/oracle/xe/app/oracle/product/10.2.0/server"
PATH="${PATH}:${ORACLE_HOME}/bin"
export ORACLE_SID=XE
</pre>Testing the admin account, and checking the platform. Oracle is running in 32-bit mode, while the platform is 64-bit. <pre>$ sqlplus SYS AS SYSDBA
SQL*Plus: Release 10.2.0.1.0 - Production on Thu Jul 9 15:10:54 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Enter password:
Connected to:
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production
SQL> select platform_name from v$database;
PLATFORM_NAME
--------------------------------------------------------------------------------
Linux IA (32-bit)
</pre>The SQL*Plus help files need to be manually loaded: <pre>cd /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/sqlplus/admin/help
sqlplus SYS AS SYSDBA @helpdrop.sql
sqlplus SYS AS SYSDBA @hlpbld.sql helpus.sql
</pre>In conclusion, I was happy to get it running without running a virtual Centos server. =)Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-86464598639326025362009-05-07T20:52:00.004+03:002010-03-13T08:43:43.467+02:00.vimrc + Python indentationI had two separate projects (vcpynet-client and MXManager) which belong together. MXManager is a GUI in PyQt4 for vcpynet-client (which is now renamed to mx-download). That is worth another post. I needed to re-indent the two codes to have the same indentation style. In Ruby I tend to use 2 spaces. In Python it feels a bit more natural to use 4 spaces. These files used both styles which is ok as long as the indentation is strict in each separate file. Re-indenting in Vim should be simple. I defined these in my .vimrc: <pre>set tabstop=4
set softtabstop=4
set shiftwidth=4
set shiftround
set expandtab
set autoindent
set paste
</pre>Vim re-indents the file in normal mode by ”gg=G”. Whoops, didn't work on my files. Guess I need to be more strict. I break some lines in a bit unorthodox fashion but Python 2.5 seems to accept it. Vim doesn't. Sed accomplised it, so for the record: <pre>sed -i 's/\ \ /\ \ \ \ /g'
</pre>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0tag:blogger.com,1999:blog-7250348253147345207.post-88479403817529541072009-05-04T20:08:00.006+03:002011-03-16T21:32:52.978+02:00NSLU2 + UTF8 ♥<p>
<a href="http://en.wikipedia.org/wiki/NSLU2">NSLU2</a> aka ”slug” is a small consumer-grade embedded ARM device. It is not very fast but quite handy and completely silent. It consumes only ~5 W with an USB flash drive attached. However the Debian image I use does not come with all the needed locales but it's easy to generate them.
</p>
<p>
Include whatever locales you like to <span class="code">/etc/locale.gen</span> and generate them:
<pre>
# locale-gen
Generating locales (this might take a while)...
en_GB.ISO-8859-1... done
en_GB.ISO-8859-15... done
en_GB.UTF-8... done
...
Generation complete.
</pre>
The next step is to configure the proper keyboard layout.
<pre>
# apt-get install console-data console-tools debconf
# dpkg-reconfigure console-data
</pre>
Finally, define the default system-wide locale:
<pre>
# echo 'LC_ALL="en_GB.UTF-8"' > /etc/default/locale
</pre>
</p>Mikaelhttp://www.blogger.com/profile/01685744853091442806noreply@blogger.com0