tag:blogger.com,1999:blog-61697786546766230032024-02-20T18:13:29.003-08:00Pielmeier im WonderlandMarkus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.comBlogger14125tag:blogger.com,1999:blog-6169778654676623003.post-38161938907865087062013-10-17T12:42:00.000-07:002013-10-17T12:42:59.194-07:00Pielmeier => Peröbner<p>Pielmeier becomes Peröbner... and there goes my blog :)<p>
<p>Follow me on my new <a href="http://ma300k.tumblr.com/">ma300k tumblr blog</a>. Cu there!</p>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-20609642161037980762012-07-08T05:30:00.001-07:002012-07-08T05:34:20.840-07:00Installing Apps2SD for HTC Desire<h2>Introduction</h2>
<p>The <a target="_blank" href="http://www.htc.com/de/help/htc-desire/">HTC Desire mobile phone</a> is one of the best android phones on the market. Unfortunately it lacks internal memory. That’s why installing apps from <a target="_blank" href="https://play.google.com/store/apps">Google play</a> can be a pain. If you use big or many apps there’s just not enough internal memory for them all. Some apps support moving them to the SD card.... but many don’t. Especially the big ones like <a target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.maps&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5nb29nbGUuYW5kcm9pZC5hcHBzLm1hcHMiXQ..">Google Maps</a>, <a target="_blank" href="https://play.google.com/store/apps/details?id=com.facebook.katana&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5mYWNlYm9vay5rYXRhbmEiXQ..">Facebook</a> and <a target="_blank" href="https://play.google.com/store/apps/details?id=com.android.chrome&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5hbmRyb2lkLmNocm9tZSJd">Google Chrome for Android</a>. End of the story... no!</p>
<p>If your Desire is rooted there are tools to move even apps like Google Maps, Facebook and Chrome to the SD card. One of these tools is <a target="_blank" href="https://www.facebook.com/pages/Darktremor-Apps2SD/127051514027383">Apps2SD</a>. And here’s my journey which shows how to set up Apps2SD on an HTC Desire.</p>
<h2>Preconditions: Sandvold ICS for Desire</h2>
<p>Before you can install Apps2SD make sure you have installed <a target="_blank" href="http://www.sandvold.as/">ICS for HTC Desire</a>. I’ve walked through this howto using v0.15.0.1. I also expect you have installed the <a target="_blank" href="http://revolutionary.io/">Revolutionary Boot Loader</a>.</p>
<p>Also make sure you’ve backed up all your data. This includes the following:</p>
<ul>
<li>Your whole SD card’s content... we’re going to format it later.</li>
<li>All your apps on the phone, app settings, device settings, etc... we’re going to reset all these later too. I recommend you to sync all your settings, contacts into the Google cloud.</li>
</ul>
<p>Now say “If something goes wrong it’s my own fault because I didn’t backup all my data” (This also applies for incorrect descriptions in this guide).</p>
<h2>Format the SD card</h2>
<p>Normally there’s only one VFAT partition on your SD card. In order to swap apps from the phone’s internal memory to the SD card you need an ext partition on the SD card.</p>
<p>Revolutionary can format the SD card accordingly for you. To do so <a target="_blank" href="http://wiki.cyanogenmod.com/wiki/Howto:_Using_the_Recovery#Booting_into_the_Recovery">boot your phone into recovery mode</a> and choose ‘advanced’ -> ‘Partition SD Card’. This will create two partitions on your SD card. One ext partition for the apps + other stuff and one VFAT partition for your photos, music, etc. You have to decide about the size of the two partitions!</p>
<p>My setup was the following. I’ve got a 4GB SD card. I’m using 2GB for ext and 2GB for VFAT. <a target="_blank" href="http://code.google.com/p/android-roms/wiki/A2SD">Some people recommend not using more than 2GB for the ext partition</a>. I had no problems using 2GB.</p>
<p>‘Partition SD Card’ will also ask you about the size of your swap partition. 0M is enough.</p>
<p>Finally reboot your phone.</p>
<h2>Get Apps2SD onto SD card</h2>
<p>Now you have to download Apps2SD and put it onto the SD card. In my case the most recent Apps2SD version was 2.7.5.3 Beta 04 but it didn’t work for me. Using v2.7.5.3 Beta 04 made my device freeze on boot which is not cool. So I’ve used v2.7.5.2-1.
Now download <a target="_blank" href="http://www.darktremor.info/files/a2sd/dtapps2sd-2.7.5.2-1-signed.zip">dtapps2sd-2.7.5.2-1-signed.zip</a> and copy it onto the SD card’s VFAT partition. You can do this by connecting your Desire as a mass storage device to your PC.</p>
<h2>Set Up Apps2SD</h2>
<p>First you have to boot into recovery again. Now choose ‘install zip from sdcard’ -> ‘choose zip from sdcard’ -> ‘dtapps2sd-2.7.5.2-1-signed.zip’ and install Apps2SD. Reboot your phone again.</p>
<p>When back in android launch the ‘Terminal Emulator’ app. We need to set up Apps2SD. Type the following into the shell:</p>
<code><pre>$ su
$ a2sd reinstall
</pre></code>
<p>This will move your installed and all future apps onto the ext partition on the SD card. Apps2SD will reboot after it’s done.</p>
<p>We should also move the dalvik-cache onto the SD card. Otherwise there will be space for a few new apps but not many. To move the dalvic-cache onto the SD card launch the ‘Terminal Emulator’ app again and type the following:</p>
<code><pre>$ su
$ a2sd cachesd
</pre></code>
<p>This time a2sd will not reboot... now you might think: I’m done. Unfortunately not... maybe you have noticed that your hardware ‘home button’ is no longer working... more on this in the next chapter.</p>
<h2>Resetting to factory defaults</h2>
<p>The broken ‘home button’ <a target="_blank" href="http://forum.xda-developers.com/showthread.php?t=1713973">can be fixed with a little factory reset</a>. You can reset your device below ‘Settings’ -> ‘Backup & reset’ -> ‘Factory data reset’.</p>
<h2>Your Done</h2>
<p>Have some cake!</p>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com1tag:blogger.com,1999:blog-6169778654676623003.post-106839120373891862012-04-15T04:11:00.003-07:002012-04-15T04:14:48.601-07:00setVisible for jQuery<p>I really wonder why jQuery has no <code>setVisible(...)</code> function?!? Here's mine:</p>
<code><pre>(function($){
$.fn.setVisible = function(visible){
if(visible === true){
this.show();
}
else{
this.hide();
}
};
}(jQuery));
</pre></code>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com4tag:blogger.com,1999:blog-6169778654676623003.post-41069524505058639792011-10-02T08:21:00.001-07:002011-10-02T08:36:07.454-07:00CSS3 LED icons<p>Here they are... pure CSS3 LED icons:</p>
<style>
.led {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 6px;
}
.led.yellow {
background-color: #ffff00;
background-image: radial-gradient(50% -5%, circle closest-side, #ffffee, #ffff00 110%);
background-image: -webkit-radial-gradient(50% -5%, circle, #ffffee, #ffff00 110%);
background-image: -moz-radial-gradient(50% -5%, circle, #ffffee, #ffff00 110%);
box-shadow: 0px 0px 3px #ffff00;
}
.led.green {
background-color: #00ff00;
background-image: radial-gradient(50% -5%, circle closest-side, #eeffee, #00ff00 110%);
background-image: -webkit-radial-gradient(50% -5%, circle, #eeffee, #00ff00 110%);
background-image: -moz-radial-gradient(50% -5%, circle, #eeffee, #00ff00 110%);
box-shadow: 0px 0px 3px #00ff00;
}
.led.red {
background-color: #ff0000;
background-image: radial-gradient(50% -5%, circle closest-side, #ffeeee, #ff0000 110%);
background-image: -webkit-radial-gradient(50% -5%, circle, #ffeeee, #ff0000 110%);
background-image: -moz-radial-gradient(50% -5%, circle, #ffeeee, #ff0000 110%);
box-shadow: 0px 0px 3px #ff0000;
}
</style>
<p><span class="led green"></span> <span class="led yellow"></span> <span class="led red"></span></p>
<p>You may have to upgrade your browser if the LEDs aren't very shiny. In the meanwhile you can check out the source:</p>
<code><pre>.led {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 6px;
}
.led.yellow {
background-color: #ffff00;
background-image: radial-gradient(50% -5%, circle closest-side, #ffffee, #ffff00 110%);
background-image: -webkit-radial-gradient(50% -5%, circle, #ffffee, #ffff00 110%);
background-image: -moz-radial-gradient(50% -5%, circle, #ffffee, #ffff00 110%);
box-shadow: 0px 0px 3px #ffff00;
}
.led.green {
background-color: #00ff00;
background-image: radial-gradient(50% -5%, circle closest-side, #eeffee, #00ff00 110%);
background-image: -webkit-radial-gradient(50% -5%, circle, #eeffee, #00ff00 110%);
background-image: -moz-radial-gradient(50% -5%, circle, #eeffee, #00ff00 110%);
box-shadow: 0px 0px 3px #00ff00;
}
.led.red {
background-color: #ff0000;
background-image: radial-gradient(50% -5%, circle closest-side, #ffeeee, #ff0000 110%);
background-image: -webkit-radial-gradient(50% -5%, circle, #ffeeee, #ff0000 110%);
background-image: -moz-radial-gradient(50% -5%, circle, #ffeeee, #ff0000 110%);
box-shadow: 0px 0px 3px #ff0000;
}
</pre></code>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-5132561888815925422011-04-20T22:56:00.000-07:002011-04-25T08:26:41.438-07:00Deobfuscating java projects<p>Lately I've been digging into <a href="http://minecraft.net">minecraft</a>. Normally digging into minecraft means something like this:
<p><a href="http://www.flickr.com/photos/52735684@N02/5628251031/sizes/l/in/pool-1586306@N25/"><img src="http://farm6.static.flickr.com/5023/5628251031_c11427d5f6_m.jpg" width="240" height="135" /></a></p>
<p>I was rather digging into something like this:</p>
<p><code><pre>/* */ import java.io.DataInputStream;
/* */ import java.io.DataOutputStream;
/* */
/* */ public class a extends gc
/* */ {
/* */ public int a;
/* */ public int b;
/* */ public int c;
/* */
/* */ public void a(DataInputStream paramDataInputStream)
/* */ {
/* 21 */ this.a = paramDataInputStream.readInt();
/* 22 */ this.b = paramDataInputStream.readInt();
/* 23 */ this.c = paramDataInputStream.readByte();
/* */ }
/* */
/* */ public void a(DataOutputStream paramDataOutputStream) {
/* 27 */ paramDataOutputStream.writeInt(this.a);
/* 28 */ paramDataOutputStream.writeInt(this.b);
/* 29 */ paramDataOutputStream.writeByte(this.c);
/* */ }
</code></pre></p>
<p>Obfuscated java code :-(</p>
<h2>What is obfuscated code?</h2>
<p>By <a href="http://en.wikipedia.org/wiki/Obfuscated_code">obfuscating</a> your java classes you want to prevent others from taking your source, modify it and release it again under another brand. There are tools which automatically obfuscate your code. These tools normally do the following things:</p>
<ul>
<li>Put all artifacts (classes, interfaces, ...) into the default package</li>
<li>Rename all artifacts and members to something generic like 'a'</li>
</ul>
<p>These changes make it very hard for humans to understand the meaning of some code. But there are a few things that can't be changed that easily during obfuscation:</p>
<ul>
<li>Access modifiers</li>
<li>Types</li>
<li>Signatures in general</li>
<li>Import statements</li>
</ul>
<h2>What has all this to do with minecraft?</h2>
<p><a href="http://mojang.com/">mojang</a> is obfuscating it's minecraft releases so nobody can steal their code. Unfortunately this makes it very hard for developers to extend minecraft due to the lack of APIs within minecraft. So the community helped itself and created <a href="http://bukkit.org/">bukkit</a>. bukkit is an API for minecraft. bukkit is so important just because of the minecraft obfuscation. With every minecraft release (major or minor) the signatures of all classes change. bukkit is the abstraction layer for the obfuscation changes.</p>
<p>But this means a lot of work for the bukkit developers [<a href="#deobscurify_java_1">1</a>]. They need to revert the minecraft obfuscation for every minecraft release manually.</p>
<h2>The plan</h2>
<p>Now there is a chance to make undoing the obfuscation more easily. But it will only work when the following conditions are met:</p>
<ul>
<li>You got the deobfuscated source of a former version</li>
<li>The software is implemented iterative. So only relative small amounts of the code change during two versions.</li>
</ul>
<p>With these assumptions you can statistically try to match artifacts from the old source with artifacts from the new obfuscated source. You just need to compare the things that don't change during obfuscation. Theres a big chance that the two artifacts with the most equality are actually the same artifact. This allows you to transfer the artifact's name and package from the old source into the new source.</p>
<h2>The project</h2>
<p>I like the idea of automatically deobfuscate java code. So I've hacked something and released it on github. <a href="https://github.com/marook/java-deobscurify">java-deobscurify</a> tries to find matching artifacts in the clear text and obfuscated source. java-deobscurify is still a work in progress. Let's say pre alpha... but I hope it will produce reasonable output in the near future.</p>
<h2>References</h2>
<ol>
<li><a name="deobscurify_java_1" href="http://forums.bukkit.org/threads/when-will-bukkit-be-updated-for-minecraft-1-5.13701/">When will Bukkit be updated for Minecraft 1.5?</a></li>
</ol>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-81934092578378616382011-03-30T12:13:00.001-07:002011-03-30T12:17:44.657-07:00Another minecraft rendering<p>Another minecraft povray rendering got finished. For more details see my former blog post <a href="http://pielmeier.blogspot.com/2011/03/rendering-minecraft-worlds-with-povray.html">Rendering minecraft worlds with povray</a>:</p>
<p><a href="http://www.flickr.com/photos/59696509@N07/5575037936/sizes/l/in/photostream/"><img src="http://farm6.static.flickr.com/5011/5575037936_d16c83c9b6_m.jpg"/></a></p>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-24556843766250127812011-03-21T10:50:00.001-07:002011-03-21T10:59:46.338-07:00Rendering minecraft worlds with povray<p>Lately I've been playing with the <a href="http://www.minecraft.net/">minecraft</a> savegames. There's not much documentation about the savegame format [<a href="#rendering_minecraft_w_povray_1">1</a>] [<a href="#rendering_minecraft_w_povray_2">2</a>]. But I've managed to export some blocks and render them with <a href="http://www.povray.org/">povray</a>. Here are the results:</p>
<p><a href="http://www.flickr.com/photos/59696509@N07/5546984743/sizes/l/in/photostream/"><img src="http://farm6.static.flickr.com/5053/5546984743_8b2181d73b_m.jpg" /></a></p>
<h2>References</h2>
<ol>
<li><a name="rendering_minecraft_w_povray_1" href="http://pastebin.com/jvZ1yhAd">RegionFileCache.java</a></li>
<li><a name="rendering_minecraft_w_povray_2" href="http://pastebin.com/niWTqLvk">RegionFile.java</a></li>
</ol>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com3tag:blogger.com,1999:blog-6169778654676623003.post-61969333314274977122011-02-19T04:44:00.001-08:002011-02-19T04:45:04.670-08:00Headless HTML page rendering with phantomjs<h2>What is phantomjs?</h2>
<p>phantomjs is a headless browser which can render HTML pages into images. It uses a Webkit rendering engine. That's cool because the generated page images aren't missing any dynamically loaded javascript stuff. Event flash movies are shown as expected.</p>
<h2>Building phantomjs</h2>
<p>The <a href="http://code.google.com/p/phantomjs/">phantomjs homepage</a> contains some very useful hints about getting and <a href="http://code.google.com/p/phantomjs/wiki/BuildInstructions">building phantomjs</a>. Read the comments at the end of the build instructions page if something doesn't work out for you. There are many useful hints.</p>
<h2>Rendering my first page</h2>
<p>phantomjs is controlled using javascript commands. You can launch your phantomjs javascript files from the commandline:</p>
<p><code><pre>$ phantomjs myScript.js</pre></code></p>
<p>phantomjs calls your script every time after a page is loaded. To react in different ways on different pages you have to track your current "state". You can persist your script's state in the var <code>phantom.state</code>. phantomjs restores the value of <code>phantom.state</code> even after another page is loaded. Other javascript variables disappear after loading a new page. Initially the state is empty.</p>
<p>To load a page call <code>phantom.open(url)</code>. phantomjs will load the page below the specified URL and execute your script after the page's DOM is loaded.</p>
<p>The (in my opinion) coolest function is <code>phantom.render(path)</code>. phantomjs will save a "screenshot" of your current page to the specified path on your hard drive. The path's file extension defines the image file format. Your viewport's size can be defined by setting <code>phantom.viewportSize</code>.</p>
<p>After you're done with your phantom things you have to call <code>phantom.exit(returnCode)</code> to quit. The returnCode is passed as status to the parent process.</p>
<p>Now putting all that functions together in a script gives us the following:</p>
<p><code><pre>if(phantom.state.length === 0){
phantom.state = '0_home';
phantom.open('http://www.mini.de');
}
else if(phantom.state === '0_home'){
phantom.viewportSize = {width: 800, height: 600};
phantom.sleep(2000);
phantom.render('home.png');
phantom.exit(0);
}
</pre></code></p>
<p>The result after executing the script is a screenshot of <a href="http://www.mini.de">www.mini.de</a> in a file named 'home.png'. The image will show the main stage with a flash movie and a footer with three dynamically loaded HTML fragments. You can see the result below:</p>
<p><a href="http://www.flickr.com/photos/59696509@N07/5457844933/sizes/l/in/photostream/"><img src="http://farm6.static.flickr.com/5060/5457844933_1718c30e13_m_d.jpg"/></a></p>
<h2>Clicking links</h2>
<p>"Clicking links" like a humanoid user is simulated by firing mouse click events. The following listing defines the <code>clickElement(id)</code> function which can be used to "click" elements. This allows us to execute simple page flows.</p>
<p><code><pre><b>function clickElement(id){
var a = document.getElementById(id);
var e = document.createEvent('MouseEvents');
e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
a.dispatchEvent(e);
}
if(phantom.state.length !== 0){
// save screenshot for every page / state
phantom.viewportSize = {width: 800, height: 600};
phantom.sleep(2000);
phantom.render('screen_' + phantom.state + '.png');
}</b>
if(phantom.state.length === 0){
phantom.state = '0_home';
phantom.open('http://www.mini.de');
}
else if(phantom.state === '0_home'){
phantom.state = '1_config';
<b>clickElement('quicklink_id1');</b>
}
else if(phantom.state === '1_config'){
phantom.exit();
}
</pre></code></p>
<p>The script will load the URL <a href="http://www.mini.de">http://www.mini.de</a> which is the home page. After loading the home page the element with the ID 'quicklink_id1' will be target of a click event. The element with the ID 'quicklink_id1' should be the 'MINI KONFIGURATOR' link in the footer.</p>
<h2>Asserting stuff</h2>
<p>Within phantomjs scripts you can access you page's DOM, the global javascript variables and global javascript functions. This enables us to do some kind of unit testing.</p>
<p>I'm extending the listing once more:</p>
<p><code><pre>function clickElement(id){ ... }
<b>function fail(msg){
console.log(msg);
phantom.exit(1);
}
function assert(condition, msg){
if(condition){
return;
}
fail(msg);
}</b>
if(phantom.state.length !== 0){
phantom.viewportSize = {width: 800, height: 600};
phantom.sleep(2000);
phantom.render('screen_' + phantom.state + '.png');
}
if(phantom.state.length === 0){
phantom.state = '0_home';
phantom.open('http://www.mini.de');
}
else if(phantom.state === '0_home'){
phantom.state = '1_config';
clickElement('quicklink_id1');
}
else if(phantom.state === '1_config'){
<b>assert(document.getElementById('cake'), 'I am missing the cake!');</b>
phantom.exit();
}
</pre></code></p>
<p>Check this out: phantomjs returns a status code of 1 when the assertion fails. This can be used to do some custom post processing in the shell:</p>
<p><code><pre>$ phantomjs myScript.js && echo 'Test successful' || echo 'Test failed'</pre></code></p>
<h2>Further information</h2>
<p>For further information see the following pages. They are sorted by what I think is important.
<ul>
<li><a href="http://code.google.com/p/phantomjs/wiki/Interface">phantomjs javascript API</a></li>
<li><a href="http://phantomjs.googlecode.com">phantomjs homepage</a></li>
</ul>
</p>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com6tag:blogger.com,1999:blog-6169778654676623003.post-90393824991794053182010-09-03T05:18:00.000-07:002010-09-03T05:50:09.663-07:00experimental freebase integration in tagfs<p>Today I made a little experiment using <a href="http://github.com/marook/tagfs/">tagfs</a> and <a href="http://www.freebase.com/">freebase</a>. Freebase is a big database with structured data which contains around 12 million entities [<a href="#experimental_freebase_integration_in_tagf_ref1">1</a>]. These entities are used to describe subjects from the real world. Like movies, persons, places, ... So freebase is perfectly applicable for enriching your own data.</p>
<p>I will show this by an example. I've got some movies on my hard drive which I enjoy watching. One of them is the movie <a href="http://www.imdb.com/title/tt1071804/">Ink</a>. I store these movies in a movie directory. Every movie gets it's own subdirectory below the movies directory. So the movie Ink is stored on my hard drive below <code>/movies/Ink/Ink.avi</code>. This enables me to tag my movies for tagfs. My tag file for Ink looks like this:</p>
<p><code><pre>My Personal Rating: 8 stars
_freebase: type: /film/film, name: Ink, initial_release_date: None
</pre></code></p>
<p>In my experiment I extended tagfs to fetch taggings from freebase. tagfs reads the <code>_freebase</code> value for each item / movie and executes it as a query to freebase. The <a href='http://api.freebase.com/api/service/mqlread?query={"query":{"type":"/film/film","name":"Ink","initial_release_date":[]}}'>query</a> delivers a result like this:</p>
<p><code><pre>{
"code": "/api/status/ok",
"result": {
"initial_release_date": [
"2009-11-10"
],
"name": "Ink",
"type": "/film/film"
},
"status": "200 OK",
"transaction_id": "cache;cache03.p01.sjc1:8101;2010-09-03T12:38:45Z;0028"
}</pre></code></p>
<p>tagfs applies the fields <code>initial_release_date</code>, <code>name</code> and <code>type</code> as further taggings. So exporting the tagfs meta data as CSV looks like this:</p>
<p><code><pre>"name";"name";"type";"initial_release_date";"Titel"
"Ink";"Ink";"_film_film";"2009-11-10";"Ink"
</pre></code></p>
<p>Now I can filter my movies with tagfs using the meta data from the huge freebase community. I've release the experimental freebase integration in tagfs below the <a href="http://github.com/marook/tagfs/tree/freebase">freebase branch</a>.</p>
<h2>References</h2>
<ul>
<li><a id="experimental_freebase_integration_in_tagf_ref1">[1]</a> <a href="http://wiki.freebase.com/wiki/What_is_Freebase%3F">What is Freebase?</a></li>
</ul>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-23629417959903618492010-08-16T12:09:00.000-07:002010-08-16T12:42:12.981-07:00using a file system for my bank account<h1>the goal - organize your shared payments</h1>
<p>I'm sharing a flat with my girl friend. So we regularly shop things, that we are equally paying. Sometimes it's a little hard to track the many shared payments. Especially if you use cash, your giro account and visa.</p>
<h1>the idea - use a directory</h1>
<p>To track all your payments you need to organize all payments in one place. Normally this can't be your giro account as your bank doesen't care about your cash payments. So my approach is to gather my payment data on my computer. Fortunately my bank supports a <a href="http://en.wikipedia.org/wiki/Comma-separated_values">CVS</a> export of my giro and visa transactions. So I can easily export the account data in a computer processable format.</p>
<h2>the database is a directory</h2>
<p>As database for my payments I use a plain old directory on my file system. The directory contains a subdirectory for every transaction I made. No matter whether it was on my bank accounts or cash. For the transaction directory names I use the simple syntax: <code><date> - <description></code></p>
<p>Examples for the transaction directory names would be:
<ul>
<li><code>2010-08-12 - ice cream in park</code></li>
<li><code>2010-08-14 - GIRO PAYMENT at MY GROCERIES SHOP</code></li>
<li><code>2010-08-14 - VISA PAYMENT at furniture.example.com</code></li>
</ul>
</p>
<p>Each of the transaction directories is tagged with the transaction details. The taggings are applied in a text file within the transaction directory. The tagging file <code>2010-08-14 - GIRO PAYMENT at MY GROCERIES SHOP/.tag</code> i.e. has the following content:</p>
<p>
<code>
date: 2010-08-14 <br/>
account: visa <br/>
amount EUR: 120.00 <br/>
description: old table
</code>
</p>
<p>The tag files for the giro and visa transactions are created by a <a href="http://www.python.org/">python</a> script I wrote. The python script creates a transaction directory for every row in my bank's CSV exports. The columns from the CSV files are applied as taggings in the tag file. The python script does a little more magic, like merging already existing entries. But that's another story.<br/>
The transaction directories for cash payments are created manually by me. But the taggings contain basically the same data. The only difference is that the account field is tagged with cash.</p>
<p>I introduce a new tagging to separate my payments from the payments I share with my girl friend. My tagging for shared payments is:</p>
<p>
<code>
share: true
</code>
</p>
<h2>export filtered CSV with tagfs</h2>
<p>Now that I've collected my transactions and added meta data like the 'share' tagging, I need to filter the transactions. I use <a href="http://github.com/marook/tagfs/">tagfs</a> to filter the various transactions, contexts (like 'data', 'account', ...) and taggings. tagfs is mounted as a virtual file system beside the transactions directory. Mounting the above example with tagfs will show me a directory like this:</p>
<p><img width="342" height="134" src="http://www.bughome.de/img/tag_dir_listing.png" /></p>
<p>The tagfs root directory contains various subdirectories. The subdirectories represent filters for the tagfs items aka. my transaction directories. Filtering transactions takes place by entering directories. Enter the <code>share/true/</code> directory to see all transactions with a share flag. <code>share/true/account/giro</code> will show you all shared transactions which occurred via your giro account.</p>
<p>Now I create a CSV export which contains all shared transactions. To do so I open the CSV file <code>share/true/.export/export.csv</code>. The CSV file contains all matching transactions as rows. The columns represent the different taggings:
<table border="1">
<tr>
<th>name</th>
<th>date</th>
<th>account</th>
<th>amount EUR</th>
<th>description</th>
<th>share</th>
</tr>
<tr>
<td>2010-08-12 - ice cream in park</td>
<td>2010-08-12</td>
<td>cash</td>
<td>1.00</td>
<td> </td>
<td>true</td>
</tr>
<tr>
<td>2010-08-14 - GIRO PAYMENT at MY GROCERIES SHOP</td>
<td>2010-08-14</td>
<td>giro</td>
<td>32.53</td>
<td>just food</td>
<td>true</td>
</tr>
</table>
</p>
<p>I open this CSV table in <a href="http://www.openoffice.org/">OpenOffice.org</a> and calculate the sum in the 'amount EUR' column. That's real magic... isn't it?!?</p>
<h2>adding multi dimensional spice</h2>
<p>OK... I truly admit... the magic hasen't happend yet. What I just did was just some filter with a sum calculation. I could have used a simple excel sheet for that. Excel is a fine tool as long as you use structured data. Our transactions are structured data. Every transactions consists of a limited amount of fields with well defined values. To leave this limited view of the world you have to think of subjects instead of transactions in your bank account. A subject can be anything! A transactions can be a subject as good as a directory with my holiday pictures can be a subject (I borrowed this very abstract view of subjects from the <a href="http://en.wikipedia.org/wiki/Resource_Description_Framework">resource description framework</a> and the <a href="http://en.wikipedia.org/wiki/Triplestore">tripplestore concept</a>). Now I can tag my transactions and my holiday pictures with <code>holiday: india 2009</code>. This allows me various filters:</p>
<p>
<ul>
<li><code>holiday/india 2009</code> shows everything related to my india vacation in 2009. No matter whether it's a transaction on my visa account or my holiday pictures.</li>
<li><code>holiday/india 2009/account/visa/.export/export.csv</code> lets me calculate all my visa expenses during the holiday.</li>
</ul>
</p>
<h1>(my) conclusion</h1>
<p>As I think, an excel sheet or a relational database system gives you one view to your data. Viewing your data in a table like structure is good for analyzing items. These items need to be comparable in a specific way. But storing data is different to viewing data. When storing data you need the flexibility to adjust your storage to new kind of entries in your database. Relational database systems do this via tables. Storing data in tables will higher the risk for many conversions and complex table joins.</p>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-80340078749487314912010-07-21T03:04:00.000-07:002010-07-21T03:09:53.529-07:00android API source JAR<h1>Howto</h1>
<p>A few days ago I installed the <a href="http://developer.android.com/sdk/index.html">android SDK</a> and the <a href="http://developer.android.com/sdk/eclipse-adt.html">ADT plugin for eclipse</a>. When I started playing with the android API I was a little disappointed. I was missing the source attachment for the android.jar which contains the android API. I was searching the web for the android sources jar and found a guide how to create an android sources jar [<a href="#1">1</a>].</p>
<p>I've adapted the sources howto and created my own android sources jar for android platform 7 aka android 2.1. You can download it here:
<a href="http://www.bughome.de/android/platforms/android-7/android-src.jar" target="_blank">http://www.bughome.de/android/platforms/android-7/android-src.jar</a>
</p>
<p>I'm pretty sure that the android-src.jar is missing some sources, because the source jar is smaller than the binary jar. Comment me if you find the missing sources.</p>
<h1>References</h1>
<ol>
<li><a name="1" href="http://androidforums.com/android-developers/1045-source-code-android-jar.html">http://androidforums.com/android-developers/1045-source-code-android-jar.html</a></li>
</ol>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-63270533629129067592010-07-09T00:21:00.000-07:002010-07-09T01:14:04.203-07:00implementing a new eclipse remote control command<h1>Introduction</h1>
<p><a href="http://github.com/marook/eclipse-remote-control">eclipse remote control</a> is an eclipse plugin which allows to execute remote commands within eclipse. Right now it's pretty limited to a very few number of commands. Currently you can open a file and launch a build command. Launching commands is done via the java client application.</p>
<h1>Implement a command</h1>
<p>To create a new command you have to implement a few classes within eclipse remote control. So you have to check out the eclipse remote control source from the <a href="http://github.com">github</a> repository: <a href="git://github.com/marook/eclipse-remote-control.git">git://github.com/marook/eclipse-remote-control.git</a></p>
<p>Implementing a new command requires the following steps:
<ol>
<li>Implement a communication class. This class contains the data which is sent from the eclipse remote control client to the eclipse remote control plugin in the eclipse IDE.</li>
<li>Extend the eclipse remote control. You need to parse the client's command line arguments and create an instance of your communication class.</li>
<li>Implement a command runner. The command runner contains the actual work which is performed when the command is executed within eclipse.</li>
</ol>
</p>
<h2>Implement communication class</h2>
<p>The communication classes are located in the <code>com.github.marook.eclipse_remote_control.command</code> project. Add a new java class to the <code>com.github.marook.eclipse_remote_control.command.command</code> package. Your new command class must implement the abstract <code>Command</code> java class from the same package.</p>
<p>The communication class must set a unique ID. This ID is used to identifiy commands in the eclipse remote control plugin. The unique ID is passed to the <code>Command</code> constructor.</p>
<p>The communication class contains all the information which is sent from the eclipse remote control client to the eclipse remote control plugin. So the communication class needs to contain fields for all transfered information. Also you have to add getter and setter methods for all the fields.</p>
<p>All communication classes implement the <a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/io/Serializable.html"><code>Serializable</code></a> interface. Make sure your command class and the command class's fields implement the <code>Serializeable</code> requirements.</p>
<h2>Extend eclipse remote control client</h2>
<p>The client is implemented in the <code>com.github.marook.eclipse_remote_control.client</code> project. The client creates command classes from command line arguments and sends it to the eclipse remote control plugin. To create and send your command class you have to add the parse and send code to the <code>com.github.marook.eclipse_remote_control.client.Client</code> class's <code>main</code> method. The following listing is an example of the parse and send code for the open file command:</p>
<p><code><pre>if("open_file".equals(command)){
if(args.length < 2){
printUsage(System.err);
System.exit(1);
return;
}
final OpenFileCommand cmd = new OpenFileCommand();
cmd.setFileName(args[1]);
fireCommand(cmd);
}
</pre></code></p>
<h2>Implement command runner</h2>
<p>Here comes the actual work. You have to implement a command runner which executes the command within the eclipse instance. All command runners are implemented within the <code>com.github.marook.eclipse_remote_control.run</code> project. Create a new command runner class in the <code>com.github.marook.eclipse_remote_control.run.runner.impl.simple.atom</code> package. All command runnerst must implement the <code>ICommandRunner</code> interface from the same project. For your convenience you should use the <code>AbstractAtomCommandRunner</code> superclass for your command.</p>
<p>The commands's work is implemented in the command runner's <code>internalExecute(...)</code> method. This method is specified by the <code>ICommandRunner</code> interface.</p>
<p>At last you must register the command runner in the <code>SimpleCommandRunner</code> class. Add a <code>putAtomRunner</code> method call to the static block in the <code>SimpleCommandRunner</code> class. Right now this static block contains only two registrations:</p>
<p><code><pre>static {
putAtomRunner(new OpenFileCommandRunner());
putAtomRunner(new ExternalToolsCommandRunner());
}
</pre></code></p>
<p>Basically that's all you need to do for a new command. If you need more information check out the eclipse remote control source code. Read the source from the existing commands. I think this will be the best for getting started.</p>Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-4919450186598172242009-10-18T12:54:00.000-07:002009-10-22T06:55:28.920-07:00xtext for recipesYesterday I was at my parent's place. The weather wasen't very well so we enjoyed one of my mother's delicious dishes for dinner. At that time my mother and my girl friend started to exchange recipes and I started to think about writing a cookbook. It's more like a male cookbook... that's why I think the following aspects should matter the most for my book:
<ul>
<li>You should get a fast overview about the dish</li>
<li>More headwords than prose</li>
</ul>
I thik both of these aspects can be reached by using a diagram notation. My diagram should be some kind of <a href="http://en.wikipedia.org/wiki/Sequence_diagram" target="_blank">UML sequence diagram</a> which looks like a <a href="http://en.wikipedia.org/wiki/Flowchart" target="_blank">UML flowchart diagram</a>. Recipes should have a defined start state and multiple operations which can occure in parallel.
As I am more one of the text guys I prefere a textual notation for the recipies. The diagram should be generated from the textual recipe notation. The idea is a <a href="http://en.wikipedia.org/wiki/TeX" target="_blank">TeX</a> approach: Define your document in a specialized language, then render the document.
As cooking is much like executing a Makefile :-) there should be many subtasks which depend on each other. Dependencies are very easy for humans to express and dependencies are enough for the recipe generator to determine which tasks can be executed in parallel.
So last but not least here is my recipe language draft. I mixed the concepts from above with some meta information about the ingredients, cooking duration, etc.
<pre>
measure Prise {
}
measure Gramm {
}
measure Liter {
}
measure Blaetter {
}
ingredient Wasser;
ingredient Salz;
ingredient Nudeln;
ingredient Tomatenmark;
ingredient Basilikum;
recipe Tomatennudeln {
step WasserKochen {
title "Wasser zum kochen bringen";
ingredient 0.5 Liter Wasser;
duration 10 minutes;
}
step WasserSalzen {
title "Wasser salzen";
ingredient 1 Prise Salz;
duration 10 seconds;
}
step NudelnInWasser {
title "Nudeln weichkochen";
depends WasserKochen;
depends WasserSalzen;
ingredient 200 Gramm Nudeln;
duration 5 minutes;
}
step NudelnAbgiessen {
title "Nudeln abgiessen"
depends NudelnInWasser
duration 30 seconds;
}
step TomatenmarkErhitzen {
title "Tomatenmark wuerzen und erhitzen"
depends NudelnAbgiessen;
ingredient 10 Blaetter Basilikum;
duration 2 minutes;
}
step AllesVerruehren {
title "Nudeln und Tomatensosse verruehren"
depends NudelnAbgiessen;
depends TomatenmarkErhitzen;
duration 30 seconds;
}
}
</pre>
Hopefully I will get some time soon to implement a prototype using <a href="http://de.wikipedia.org/wiki/Xtext" target="_blank">TMF Xtext</a>.Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0tag:blogger.com,1999:blog-6169778654676623003.post-54970802899049868662009-08-11T06:35:00.000-07:002009-08-11T06:37:21.028-07:00Wally sagt: "Der Tüchtige hält immer möglichst viele SVN-Locks."Markus Pielmeierhttp://www.blogger.com/profile/08272959254915942027noreply@blogger.com0