I recently saw a simple 2D animation that rendered in a red line how a plane moved over a map. This is what you might also know from Indiana Jones. I immediately had an idea on how to do this in Blender so I went ahead and did it. Here is the result:


(large).

How to achieve the effect

The idea is quite simple: To make the red path appear on the map we move it from behind the map to front of it. The trick is that the path isn't planar to the map but the front is "higher" than the end of the line. This way moving it through the map will make the red line appear at the start first and reveal more and more until the line reaches the end.

So first of all you need to create the background map for your animation. I used tiles from OpenStreetMap on 3x3 planes for this, but you can use whatever background you prefer. Afterwards you need to create the line the flight will take. I thought using a straight line is boring, so I went for a curve. I created a bezier curve to move along the way you want to animate. Make sure you create a 3D curve, because we need the Z-axis for our animation. Also make sure to set the curves "Twisting" to "Z-Up" which is necessary that the line is flat in relation to the map. Once you are satisfied with your path, you need to add a mesh to solidify the curve. Use a simple small plane for this, set its color to red and add two modifiers:

  • Array: This will convert the plane into a line. Adjust width and height until you are satisfied with your line.
  • Curve: This will make your line follow the curve.

The red material must not cast any shadows. If you are using cycles to render the animation I recommend creating the material as shown in Blenderartists thread Cycles: make object cast no shadow.

After you modeled your path (the mesh and the curve) move it behind you map. Afterwards insert a location keyframe (press "I" and select "Location") for both, go to your target frame (e.g. 90), move the line to the front and insert another location keyframe. Blender will now interpolate between the two points for you. Press "Alt+A" to see a preview of the animation. You might need to adjust the curve to make the animation look smooth (rotate some nodes, add some notes, etc.). Once satisfied go ahead and render the animation.

To create a GIF from the generated PNGs you can (as for most imaging automation tasks) use imagemagick: convert $(for a in 00*.png; do printf -- "-delay 10 %s " $a; done; ) result.gif

Feel free to play with the final blend file.

Verfasst von: egore911

I recently had a discussion with a friend of mine regarding the usefulness of Scrum. I've taken some helpful hints from the discussion on how a developer can feel used and misused by Scrum. Let's talk about a few of them, but let's start with some naked rules of Scrum first:

  1. The daily work of a developer is bound to the user stories of a sprint.
  2. Due to the nature of time only a limited amount of this resource can be spent during a sprint.
  3. The customer is expecting a result according to his wishes in the shortest time possible.

Theory: Scrum stops creativity

I can agree with this only partially. The truth is: The customer is setting the requirements and, most important, he pays for reaching them. That means: he is setting the direction where the project is heading, no matter how strange some requirements might appear to the developer. But of course that does not mean everyone should blindly follow a wrong direction. So what happens if a developer has a really good idea on how to improve the product? It's really simple: Take the input from your developers and take it to the customer. If the idea is really that good, he will agree on implementing it. From my point of view the creativity is not harmed by Scrum in any way. Everyone can still suggest ideas, but you should not go ahead an implement them without permission of the customer. Next to that: It's hard to plan when a developer might have that one brilliant idea.

Theory: There is no time to do things right

I can not agree with this at all. First of all it is really to find a proper definition of right. What is the right way to implement a search functionality? Performing a LIKE-search on a database column? Or use weighted search on a lucene index using a solr cluster? Both attempts have obvious advantages and disadvantages. A search using an index is likely to be more natural to the end user, but it might not even make a difference. And searching a small table with a couple of lines can perform really well, but what about millions of lines?

To me this boils down to one question: How good are my user stories? When a story is well defined (specifying the use cases, the amount of data and the likelihood of usage) it is easy to find the right solution. If it's not a developer might go for a technically interesting but expensive solution. If a story is well defined, the estimated development time will be large enough give the developer enough room to implement a solution properly. If it's not be prepared for bad code.

Theory: Implementations must be shortsighted

I partially agree with this. One of Scrums basic ideas is: "only implement what you really need". In most cases a developer will have to focus on a single feature/problem without having the complete spectrum of future requirements in mind. In most cases this results in solutions very specific to the given problem.

Theory: No time to undo mistakes of the past

I largely agree with this. When a developer is working on a new feature it commonly happens that he will go through a lot of existing code. And every code base has established concepts of doing things and these are accepted by the developers. But from time to time some concepts have proven to be bad and need to be reworked. But the customer will not be very happy when, after months and years of work, being presented a product that looks exactly the same as before. It's almost impossible to find a customer paying for this! So if your developers are completely used by the Scrum there is no time to fix the so called technical debt. In my experience it is good to stop the Scrum process from time to time to allow the developers to perform larger cleanups. Alternatively it also works to have a sprint without enough user stories to consume the whole time available.

Conculsion

I agree that a developer might feel controlled by the customer/product owner/scrum master and being less able to establish his own ideas. But in my experience that often boils down to improper usage of Scrum. Having good user stories and a bidirectional communication with all involved parties not only leads to better products, but most important to happier developers. When everyone involved in the Scrum process is fulfilling the required role, it can be an enjoyable development experience for all sides.

Verfasst von: egore911

I recently had to recover images from a 1 TB large drive. I used photorec to find the data on the drive which resulted in lots and lots of images within lots and lots images. How do you find the relevant images within that amount of data? For initial filtering I focused on a single criteria: image dimension. I wrote a little script to find all images, check their size, and symlink them to a folder sorting them by YEAR/MONTH/DAY. You can invoke them by calling

./findimages.sh /some/directory
. It will produce /some/directory/found with accoring subfolder for the date of the image. Note that you need the exiv2 binary to properly use this script.

#!/bin/sh

export LC_ALL=C
DIR='${1}'
TARGET_DIR='${DIR}/found/'

function symlink() {
	IMAGE="${1}"
	EXIV="${2}"
	IMAGE_DATE=$(echo "${EXIV}" | grep "Image timestamp" | sed -e "s/Image timestamp\s*:\s*//")
	DATE_FOLDER=$(echo ${IMAGE_DATE} | sed -e "s:\([0-9:]\+\) [0-9:]\+:\1:" | sed -e "s|:|/|g")
	mkdir -p "${TARGET_DIR}${DATE_FOLDER}"
	ln "${IMAGE}" "${TARGET_DIR}${DATE_FOLDER}"
	sync
}

COUNT=$(find ${DIR} -name '*.jpg' 2> /dev/null | wc -l)
CURRENT=1

for IMAGE in $(find ${DIR} -name '*.jpg' 2> /dev/null); do
	echo "${CURRENT}/${COUNT}"
	CURRENT=$((${CURRENT} + 1))
	EXIV="$(exiv2 ${IMAGE} 2> /dev/null)"
	IMAGE_SIZE=$(echo "${EXIV}" | grep "Image size" | sed -e "s/Image size\s*:\s*//")
	if [[ ${IMAGE_SIZE} =~ ^[0-9]+( )x( )[0-9]+.*$ ]]; then
		X=$(echo ${IMAGE_SIZE} | sed -e "s:\([0-9]\+\) x [0-9]\+:\1:")
		Y=$(echo ${IMAGE_SIZE} | sed -e "s:[0-9]\+ x \([0-9]\+\):\1:")
		if [ "$((${X} * ${Y}))" -gt "786432" ]; then
			symlink "${IMAGE}" "${EXIV}"
		fi
	else
		echo "${IMAGE}: ${IMAGE_SIZE} (${EXIV})"
		symlink "${IMAGE}" "${EXIV}"
	fi
done

If you have suggestions on how to improve the script or smarter alternatives, please let me know

Verfasst von: egore911

I've recently decided to give nginx a try. So far I've used Apache httpd 2.4 exclusively, but I wanted to get to know the competitor prior to sticking with Apache httpd or switching to nginx depending on the result. There are lots of claims about nginx's performance and Apache httpd's bloat, but I simply wanted to get started with a test scenario. For me this scenario was running the cgit web interface on http://localhost/cgit/. Next to the configuration files the only major difference to me is: nginx only provides a FastCGI interface, while I was using the built-in CGI interface in Apache. Luckily FastCGI is not hard to set up nowadays. On ArchLinux it basically boils down to the following three commands:

pacman -S nginx fcgiwrap
systemctl enable fcgiwrap.socket
systemctl start fcgiwrap.socket

After this you can use FastCGI, and thanks to systemd it is socket activated, i.e. it is only started when someone is accessing it. Afterwards I reused my /etc/cgitrc from the previous Apache httpd, which looks more or less like this:

root-title=My git Server
root-desc=This is my very own git server!
css=/cgit-web/cgit.css
logo=/cgit-web/cgit.png

virtual-root=/cgit

section=Some section

repo.url=Some Repo
repo.path=/srv/git/somerepo.git

For me the largest obstacle was setting "virtual-root = /cgit", which was not necessary for Apache httpd, but mandatory for nginx. This has to match the property set in /etc/nginx/nginx.conf

http {
 ...
 server {
 ...
   location /cgit {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi;
    fastcgi_pass unix:/run/fcgiwrap.sock;
    fastcgi_split_path_info           ^(/cgit/?)(.+)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param QUERY_STRING $args;
   }
   location /cgit-web {
    rewrite ^/cgit-web(/.*)$ $1 break;
    root /usr/share/webapps/cgit;
   }
 }
}

After performing this small amount of configuration in nginx the server was up and running. In my very own and non-representative test scenario nginx and Apache httpd performed very similar (tested using jmeter). Even the memory usage was not that different. So at least for me the difference was not enough to convince me to permanently change my setup for now. Most of the things I need (PHP, ~/public_html, cgit) work fine on both, and my Apache httpd configuration is solid and proven for years.

If you have other suggestions on why to use nginx over Apache httpd feel free to inform me about it.

Verfasst von: egore911

If it's not tested, it's broken. - Bruce Eckel

I'm a great fan of reliable software. And as a software developer I only want to create software that works reliable. In my opinion crashes in any software (or even worse: data loss) cause distrust from the user. Would you want to run a piece of software that crashes? I wouldn't. That's why I think that testing software (and finding crashes before your user does) is a very important part of software development.

So how do we test software? As usual Wikipedia knows lot's of testing types. You see, there is a large amount of ways to test software. I'll focus on testing typically done by software developers: unit testing. Unit testing is done, as the name suggests, one a "unit" of the software. I prefer to use my classes and their methods as my units, others might do differently. So let's start with a trivial example unit, the SomeDao:

package de.egore911.test;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Id;

public class SomeDao {
	public static class Some {
		@Id public Integer id;
	}

	@Inject private EntityManager em;

	protected EntityManager getEntityManager() { return em; }

	public Some comeGetSome(Integer id) {
		return getEntityManager().find(Some.class, id);
	}
}

This code is really simple. We have a DAO (data access object) which is able to load entities of the type Some by their ID. The class itself uses CDI to inject the EntityManager instance. This is a very common type of class I've seen in lots of web projects, but how to test this unit? At first glance it depends on an injection framework, which needs an entity-manager, which needs a database, which needs dummy data. This is a lot and lot's of things could cause the test to fail that should not be part of this unit test (e.g. the database was not available). So we need to have a mock object for the EntityManager, which does not actually need to be injected and also does not need a database. This is where mockito comes into play.

import javax.persistence.EntityManager;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

public class SomeDaoTest {

	@Test
	public void testComeGetSome() {
		// Mock the EntityManager to return our dummy element
		Some dummy = new Some();
		EntityManager em = Mockito.mock(EntityManager.class);
		Mockito.when(em.find(Some.class, 1234)).thenReturn(dummy);

		// Mock the SomeDao to use our EntityManager
		SomeDao someDao = Mockito.mock(SomeDao.class);
		Mockito.when(someDao.comeGetSome(1234)).thenCallRealMethod();
		Mockito.when(someDao.getEntityManager()).thenReturn(em);

		// Perform the actual test
		Assert.assertSame(dummy, someDao.comeGetSome(1234));
		Assert.assertNull(someDao.comeGetSome(4321));
	}
}

You can see that this is fairly simple. First you mock an EntityManager that will return a dummy object when the EntityManager.find() method called. Then we make sure our mocked EntityManager is returned when SomeDao.getEntityManager() is called and also the real SomeDao.comeGetSome() is invoked. Of course all this could be done using reflection ourselves, but mockito does all this groundwork for us.

Mockito offers some other nice features, but my primary use is stubbing method calls.

Verfasst von: egore911

Today I felt like ... creating a chair! That's the virtual result. Now I just need to figure out how to do that for real ;-)

Verfasst von: egore911

Whenever I hear about users credential data being stolen from servers I wonder how good (or bad) it was stored in regards of security. There are several layers of security I apply to passwords. The following article will explain these layers and my reasons for them. I'll explain these starting with the worst example I've ever seen in production.

Starting of really bad

I was assinged to work on a web application once, that contained the following table:

login password email
user1 123456 user1@hotmail.com
user2 somedude22 randomguy@somemail.com
... ... ...

This was a table storing the plain text password along with the username and the email address. This is the absolute worst case scenario, because users tend to reuse the same username, email and password combinations. It is even likely that the password for the e-mail address would be the same as stored in the database. If an attacker would get access to this database it would not only harm the application the password was stolen from, but possibly the whole digital identity. If the same credentials were used for an online store it is possible the attacker could get access to credit card numbers and similar sensitive information.

Another very critical point is that the password may contain personal information (like religious view or sexual orientation) you are not allowed to store without explicit permission of the user. I'm not aware of any lawsuite regarding this topic, but I wouldn't want to be the first.

Hashing passwords

To improve this it is actually a wise decision never to store the users password, only a hashcode of this password. I rely on hashing algorithms natively supported the technology stack used when developing an application. In the past I commonly used MD5, but nowadays I tend to use SHA-1. Feel free to pick whatever hashing algorithm suits your needs or that you are familiar with. The only restriction is that you should never use an algorithm known to be weak or even one that was already broken.

Important note: Some might argue SHA-1 is already broken. This is formally correct, but right now there is no implementation for the strategy proposed in breaking it. Next to that it's an algorithm supported by many layers of the technology stack (e.g. MariaDB and Java). I would no longer use it if I would be starting a new application, but rather SHA-256.

login password email
user1 f447b20a7fcbf53a5d5be013ea0b15af user1@hotmail.com
... ... ...

Now you only have stored the password with a little bit of security applied.

Protecting users with weak passwords

It is hard to determine the plain text password from the stored hashes, and it is really expensive. You can use brute force to calculate the hashcode for lots and lots of passwords until you find a match. But the greatest threat to breaking the passwords are rainbow tables. A rainbow table basically is a really large table storing the hashcode along with its input. The table is then used to lookup hashcodes to quickly get the input. Common passwords, like '123456', will be broken within a fraktion of seconds. To protect users with weak passwords you need to use 'salting'. This basically means you append a constant random string to the password prior to calculating the hashcode. If the users passwords was 123456 and our salt would be atho3aifeiR2, the string sent to the hashcode calculation would be atho3aifeiR2123456. If you choose your random string wisely it's unlikely rainbow tables will contain this. Next to that most of the rainbow tables were built using only short passwords. If the salt itself is lengthy (e.g. 12 chars and more) it provides and additional chance of it not being in the rainbow table. So never use short and easy salts, like '1' because this does not provide any security at all.

Double hashing passwords

Now your passwords are stored pretty secure. But if the attacker was able to obtain your salt with the hashed passwords he could still build a rainbow table for all passwords starting with your salt. For simple passwords this would still harm the security. I'm using a chain of hashing algorithms to work around this. Basically you salt the password and hash it as done before, but after that you go ahead and calculate the hashcode of the hashcode. You can repeat this step several times, like

md5(md5(md5('atho3aifeiR2' + password)))
. This way a possible attacker can not use any rainbow table but only rely on brute force attacks. The great advantage of this approach is that the attacker needs to know your implementation to actually produce usable results. If he was able to break into your database server but not your application server, your users passwords are safe.

Protecting against weak algorithms

If you used a weak algorithm (or one that was broken after you introduced it) your users still could be at risk. If you use a chain of different algorithms this threat is actually minimized. So our pseudo-code looks like this

SHA2(sha1(md5('atho3aifeiR2' + password)), 256)
. In case all of these were broken, you can still wrap the whole chain using a stronger algorithm, like
SHA2(SHA2(sha1(md5('atho3aifeiR2' + password)), 256), 512)
, and apply the outer most hashfunction to your existing data, e.g.
UPDATE user SET password = SHA2(password, 512)

Verfasst von: egore911

My company maintains a software of one of our customers that is using Adobe LiveCycle to render HTML/PDF forms. Our customer got a support contract with us and with Adobe so that we will keep the software running on the new LiveCycle versions. This meant that we were updating our software recently to use ES4. The update went pretty smooth except for a single fact: Paging would no longer work to any page after the second page.

The paging itself was implemented using the simple server-side-script "xfa.host.pageDown()". Paging from the first to the second page worked fine and paging back as well. Just paging from page 2 to page 3 would just bring us back to page 2. So we started to research that. We came up with a testcase that worked and simplified our production code and added complexity to the testcase until there were almost no differences in the requests sent to the LiveCycle webserivce. The only remaining difference was how the XDP file was sent to the server. In both cases we just provided an URL. In our testcase we were using a simple Apache httpd hosted web directory, in our production code we were hosting it using a custom Java Servlet from a database. We dumped the traffic between the LiveCycle server and the file server hosting the XDP and finally found a tiny but important difference. The webserver hosted file was using "Last-Modified" and "If-Modifed-Since", which seems to be the default for Apache httpd. The traffic looked like this:

  • the initial GET request came in from the LiceCycle server, containing a "Last-Modified: 1970-01-01", Apache httpd return HTTP status code 200 with data and a modification timestamp of the file
  • following GET requests from the LiceCycle server contained a "Last-Modified" with the timestamp of the file, and Apache httpd returned HTTP status code 304 Not modified

Our servlet wasn't using the Last-Modified header and was returning every request with HTTP status 200 and the data. This tiny little difference caused LiveCycle not to jump to the third page. So what do we learn from this experience: Use HTTP status codes properly and evaluate Last-Modified header manually (if your framework doesn't do this for you). And make sure that your application logic return status code 304 on consecutive requests by LiveCycle if the content didn't change.

Verfasst von: egore911

I recently learned that the Intel i965 hardware is capable of handling GLSL 1.30, but nobody got around to add support for this in the DRI/mesa 3D driver. The developers at Intel are focusing on their latest hardware which means GLSL 1.30 support won't be added soon. The core mesa supports GLSL 1.30 and later generations of the Intel hardware are supported as well. Luckily Intel provides all the necessary 3D documentation that allows anyone to implement it.

But how do we get started? First of all you need to test the driver and see where you are starting. The best way to do this is using piglit. Piglit is an awesome tool maintained by the open source mesa developers to perform reproducible tests. You can see it as a conformance suite or a regression test. So the first thing is figure out what tests from piglit can be used to check for GLSL 1.30 support. Piglit ships lots of tests for specification conformance, including tests/spec/glsl-1.30.

Piglit also ships some test profiles, including all.tests. This will execute all tests known to piglit. For our purpose it is sufficient only to run the GLSL 1.30 tests. I went ahead and commented the tests not relevant for now.

$ ./piglit-run.py tests/all.tests results/2013-02-13_base
$ export MESA_GLSL_VERSION_OVERRIDE="130"
$ ./piglit-run.py tests/all.tests results/2013-02-13_base_130
$ ./piglit-summary-html.py --overwrite out results/2013-02-13_base*

I started with the command listed above. It will run the piglit tests using your currently installed driver. The first run will be using GLSL 1.20 which is announced by the driver, the second run will use 1.30. After that you can generate a nice HTML form to show the differences. If everything went fine you will quickly see tests changing from skipped to failed or passed. These will be the tests you will need to look into.

For me the tests caused a GPU lockup somewhere in the tests. This is to be expected when overriding the GLSL version to something not supported by the driver. Only use this when you are developing the graphics driver! Piglit already wrote parts of the result file so I started to compare the incomplete differences and picked the first that failed. In my case this is varying-packing-simple float separate -auto -fbo which caused a segfault (it's not the GPU lockup, but let's start with an easy example). Before you start of installing debug packages for you distribution you should verify that a failure is still present in the latest git code. It is best to build mesa using the same configuration options as your distribution does (I'm not going into the details of how to get these as they vary from distribution to distribution).

Now on to the interesting part: How do you use a different version of libGL and the DRI drivers without messing with your installed drivers? It's pretty easy once you know the trick. First of all you need to tell the linker where to look for shared objects.

$ ldd varying-packing-simple float separate
  ...
  libGL.so.1 => /usr/lib/libGL.so.1 (....)
  ...
$ export LD_LIBRARY_PATH=/home/cbrill/source/mesa/lib
$ ldd varying-packing-simple float separate
  ...
  libGL.so.1 => /home/cbrill/source/mesa/lib/libGL.so.1 (....)
  ...

Now you managed to load a different libGL.so when you are executing you tests. But be aware: libGL will dynamically load your installed hardware drivers! This might cause some crashes if the installed driver does not match the development libGL.

$ export LIBGL_DRIVERS_PATH=/home/cbrill/source/mesa/lib
$ export EGL_DRIVERS_PATH=/home/cbrill/source/mesa/lib/egl

Now you are using your a local copy of mesa to test your implementation. The benefit of user space 3D drivers is pretty huge here, because otherwise you'd have to load/unload a kernel module very often. And debugging crashes in kernel space is much more complicated than in user space.

In my case the segfaulting test no longer crashed when using mesa from git. I'm currently in the process of generating a piglit run but I get a GPU lockup and don't see the results. A good recommendation would be to run tests from a different machine that is not affected by your test (e.g. serial console or ssh connection). To run applications on the display when connected by ssh you need to do the following on you test machine

$ xhost +

After that that you can run any command, e.g. glxgears, on that display by doing:

$ DISPLAY=:0 glxgear

That pretty much sums up everything you need to test your driver. Have fun!

Verfasst von: egore911

Android provides very useful components to create Apps very fast. That sounds like a marketing claim, does it? OK, let's see if that acutally is true! Let's create a file browser.

Let's start off by create a default "Hello World"-App that will consist of a layout file and a matching activity. Knowning what we want to build we name the layout activity_list_files.xml and name the Activity ListFileActivity. If you are developing using eclipse the default layout editor will show up displaying your wonderful "Hello World"-App. Let's start by replacing the layout using the following code:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent" android:layout_height="match_parent">
  <ListView android:id="@android:id/list" android:layout_width="match_parent"
    android:layout_height="wrap_content" />
</LinearLayout>

Now you have a very simple layout which only consists of a single element, a ListView. The ListView will be the component displaying our files. That's it? Yes it is! But how will it be populated with data? That's where our activity comes into play.

public class ListFileActivity extends ListActivity {

  private String path;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_list_files);

    // Use the current directory as title
    path = "/";
    if (getIntent().hasExtra("path")) {
      path = getIntent().getStringExtra("path");
    }
    setTitle(path);

    // Read all files sorted into the values-array
    List values = new ArrayList();
    File dir = new File(path);
    if (!dir.canRead()) {
      setTitle(getTitle() + " (inaccessible)");
    }
    String[] list = dir.list();
    if (list != null) {
      for (String file : list) {
        if (!file.startsWith(".")) {
          values.add(file);
        }
      }
    }
    Collections.sort(values);

    // Put the data into the list
    ArrayAdapter adapter = new ArrayAdapter(this,
        android.R.layout.simple_list_item_2, android.R.id.text1, values);
    setListAdapter(adapter);
  }

  @Override
  protected void onListItemClick(ListView l, View v, int position, long id) {
    String filename = (String) getListAdapter().getItem(position);
    if (path.endsWith(File.separator)) {
      filename = path + filename;
    } else {
      filename = path + File.separator + filename;
    }
    if (new File(filename).isDirectory()) {
      Intent intent = new Intent(this, ListFileActivity.class);
      intent.putExtra("path", filename);
      startActivity(intent);
    } else {
      Toast.makeText(this, filename + " is not a directory", Toast.LENGTH_LONG).show();
    }
  }
}

Let's take a closer look at the activity. First of all I'll give a short overview of the thoughts behind this activity: The activity displays all files within a given path. If we switch the path, we switch to a new activity displaying all files within the given directory. Easy right? To achieve that we extend the ListActivity which provides us methods like getListAdapter(), setListAdapter() and onListItemClick() to interact with the list in our layout. So when our Activity is started by Android and onCreate gets called the first thing we do (after setting the layout) is: Set the path as our activitiy's title. In the next step we are going to read all the files from the given path, but there's a catch: Android locks several paths from being accessed by apps. This is intended and necessary to keep apps from spying on each other (the "/data"-folder for example contains all the databases from the apps, including stored credentials). For this reason we add a note to the title and we need to check if File.list() actually returns an array. The javadoc states that it will only return null if you called the method on a file, but it also is true for inaccessible directories.

The lower part of onCreate is also interesting. See how we create our data adapter? We use Android's ArrayAdapter, which allows us to pass it a List and tell it how to render it. Really easy and actually suited for many needs. Finally the onListItemClick will launch a new instance of our ListFileActivity to display another folder. Using the back button on your device will get you back to the previous folder.

You can see that creating a very simple file browser can be done in a very short amount of time and using very few lines of code. Of course this could be improved a lot (e.g. splitting onCreate into several methods) but there are already really good file browsers available on the Google Play store (and it would take way more than 15 minutes to match their features). Anyway I hope you enjoyed this little introduction into Android development using ListView.

Thanks to Simeon M. and Laurent T. for pointing out minor typos!

Verfasst von: egore911

Jeder der mit dem Versionskontrollsystem git zu tun hat, wird früher oder später feststellen wie man Commit-Kommentar aussehen sollte. Für alle, die das bisher noch nicht wissen, hier mal ein kurzes Beispiel:

Kurzer Betreff, max. 80 Zeichen

Optionaler längerer Text, der den Commit beschreibt. Dieser darf gern mehrzeilg
sein und die Beweggründe erläutern.

Optionale Signaturen.

Nun stellt sich die Frage: Warum macht man das so? Dies möchte ich anhand eines praktischen Beispiels erläutern:

mesa: remove '(void) k' lines

Serves no purpose as the k parameter is used later in the code.

In diesem Commit wurden mehrere Codezeilen gelöscht. Hätte der Autor gar keinen Kommentar angegeben, wäre rätselhaft warum er dies getan hat. Glücklicherweise erzwingt git immer eine Commit-Meldung. Aber auch die erste Zeile alleine ist nicht aussagekräftig, sondern folgt dem "stating the obvious"-Prinzip. Man findet damit den Commit leicht wieder, aber man kennt immer noch nicht den Grund. Dies wird erst durch die letzte Zeile klar.

Signaturen

Es gibt in git die Möglichkeit Signaturen in einer Commit-Meldung anzugeben, z.B.:

Signed-off-by: Christoph Brill <webmaster@egore911.de>

Diese dienen dazu, zusätzliche Informationen über die an dem Commit beteiligten Personen anzugeben. Es gibt keinen offiziellen Standard für diese Signaturen, aber folgende haben sich in verschiedenen Projekten als hilfreich erwiesen:

  • Signed-off-by: Der Commit wurde durch den Signierenden in die Repository aufgenommen. Diese Meldung dient mehr oder weniger als zusätzliche Autorenangabe
  • Reviewed-by: Der Commit wurde vom Signierenden durchgesehen und für sinnvoll befunden
  • Tested-by: Der Signierende hat den Commit in seinem lokalen Sourcecode eingespielt und getestet.

Verwendung im Alltag

In einer idealen Welt würde jeder detaillierte Kommentare (sowohl im Code als auch in Commit-Meldungen) verwenden. Die Praxis zeigt jedoch, dass dies nicht immer zutrifft. Selbst disziplinierte Projekte werden Commits aufweisen, die weit von diesem Ideal abweichen. git erlaubt es allerdings mit minimal strukturierten Commit-Meldungen anderen Entwicklern (oder dem Entwickler selbst zu einem späteren Zeitpunkt) den Commit zu verstehen, ohne jede Zeile Code des Commit gelesen zu haben.

Verfasst von: egore911

Im Zuge der Umstellung auf JSF sind mir einige Exceptions begegnet. Eine davon ist relativ trickreich zu beheben. Sie äußert sich dass beim Deployment der Anwendung auf dem Server folgende Exception auftritt:

java.lang.NullPointerException
  at com.sun.faces.config.InitFacesContext.cleanupInitMaps(InitFacesContext.java:278)
  at com.sun.faces.config.InitFacesContext.(InitFacesContext.java:102)
  at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:156)
  ...

Dieser Fehler verhindert dann auch den Start der Anwendung. Woran liegt das? Dazu sehen wir uns mal eine Funktion der JSF-Standard-Implementierung Mojarra an:

static Map getInitContextServletContextMap() {
  ConcurrentHashMap initContextServletContext = null;
  try {
    Field initContextMap = FacesContext.class.getDeclaredField("initContextServletContext");
    initContextMap.setAccessible(true);
    initContextServletContext = (ConcurrentHashMap)initContextMap.get(null);
  } catch (Exception e) {}
  return initContextServletContext;
}

Hierbei fällt auf, dass beim Zugriff mittels Reflection auf ein Feld der Fehlerfall einfach ignoriert wird und null zurück gegeben wird. Die Methode besitzt keine Dokumentation oder einen Hinweis darauf, was der Rückgabewert ist. Also muss der zugreifende Code den Fehler abfangen können. Aber tut er das? Sehen wir uns das mal an:

Map initContextServletContext = InitFacesContext.getInitContextServletContextMap();
Set<Map.Entry<InitFacesContext, ServletContext>> entries = initContextServletContext.entrySet();

Damit wird schnell klar: Es wird NullPointerException geben und man sieht an der auftretenden Exception nicht den eigentlichen Grund. Dieses Fehlverhalten ist damit nicht ganz einfach zu beheben. Grundsätzlich ist es schlechter Stil eine Exception einfach zu schlucken. Besser ist es diese zumindest zu loggen, vielleicht sogar mit hilfreicher Zusatzinformation wie:

...
} catch (Exception e) {
  log.error("Could not access FacesContext#initContextServletContext, " +
    "probably JSF-API and implementation mismatch!", e);
}

Jetzt ist offensichtlich, woher der Fehler kommt: die JSF-API und die Implementierung im Classpath passen nicht zusammen. In meinem Fall wurde eine weitere JSF-API über Maven als Abhängigkeit hinzugefügt, die dann "falsche" Klassen in den Classpath lädt. Ich hoffe diese Erläuterung hilft anderen, die auf diese Exception stoßen.

Verfasst von: egore911

Hibernate kann mit seinen Reverse Engineering Tools sehr leicht ein Modell für eine existierende Datenbank erstellen. Aber was ist, wenn diese Datenbank nicht allen Regeln der NormalForm entspricht? Fangen wir zuerst an, wie eine hibernate.reveng.xml-Datei für MS SQL aussieht:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd" >
<hibernate-reverse-engineering>
  <schema-selection match-schema="dbo" />
</hibernate-reverse-engineering>

Dieser Code legt fest, dass wir immer mit dem dbo-Schema arbeiten wollen. Dies ist bei MS SQL das Standardschema. Nehmen wir jetzt an, dass wir die Tabelle 'XYZ' ausschließen wollen, sprich es soll keine Mappingklasse für diese Tabelle erstellt werden:

  <table-filter match-name="XYZ" exclude="true" />

Damit taucht diese Tabelle nicht mehr auf. Jetzt wollen wir die Spalte 'abc' aus der Tabelle 'ABC' ausschließen:

  <table name="ABC" schema="dbo">
    <column name="abc" exclude="true" />
  </table>

Und die Spalte 'def' der Tabelle 'ABC' hat den falschen Typ (es stehen Zahlen in einer VARCHAR-Spalte):

    <column name="def" type="int" />

Und es fehlt auch noch ein Foreign Key von GHI auf DEF:

  <table name="GHI" schema="dbo">
    <foreign-key foreign-table="DEF" foreign-schema="dbo">
      <column-ref local-column="defId" foreign-column="ID" />
    </foreign-key>
  <table>

Und es gibt zwei Tabellen mit existierenden Foreign Keys, doch Hibernate generiert keinen brauchbaren Namen:

  <table name="GHI" schema="dbo">
    <foreign-key constraint-name="FK_GHI_GFI">
      <column-ref local-column="defId" foreign-column="ID" />
      <many-to-one property="parent" />
      <set property="children"/>
    </foreign-key>
  <table>

Und er Tabelle QWE fehlte der Primary Key:

  <table name="QWE" schema="dbo"> 
    <primary-key> 
       <key-column name="ID" /> 
    </primary-key> 
  </table> 
 

All das simuliert der Modellgenerierung von Hibernate eine Datenbank, die vorhandene Schwächen versteckt, ohne tatsächlich Änderungen an der Datenkbank zu machen (und damit evtl. bestehende Anwendungen zu gefährden). Diese Beispiele veranschaulichen nur einen Teil dessen, wie man mit Hibernate ein brauchbares Datenmodell für eine 'legacy' Datenbank erstellen kann. Ich kann als weitere Lektüre Chapter 6. Controlling reverse engineering empfehlen.

Verfasst von: egore911

I wanted to use a back button in my DRI-Log App, allowing the user to return to the previous Activity. Sadly Android does not provide a proper graphic for such backbutton. In Apple's iOS for example you are given a button, that is pointy at its left side. I was searching for this shape on Androidbut couldn't find it.

So what can be done if you are searching for something that does not yet exist? Create it yourself!

I imported the original graphics from Android in Inkscape as PNGs and recreated them. After I was finished I changed them to point to the left. Until now these buttons only share the same style and design language as Android 2.2 und 2.3, because my App isn't optimized for Android 3.0 or later. I will create a button for Android 3 and later if I need them.

Btw: The original graphics in SVG-Format can be found here.

Verfasst von: egore911

Für meine DRI-Log App wollte ich einen Button verwenden, der den Benutzer zurück zur vorherigen Activity bringt. Leider gibt es bei den unter Android verfügbaren Buttons keinen Zurückbutton. Apple's iOS bringt einen Button mit, der an der linken Seite spitz zuläuft. Genau diese Form habe ich auch für Android gesucht und leider nicht gefunden.

Was tun, wenn man etwas sucht, dass es noch nicht gibt? Man macht es selber!

Ich habe dazu die Originalbuttons von Android in Inkscape als PNG importiert und bestmöglich nachgebaut. Anschließend habe ich sie spitz zulaufen lassen. Ich habe den Button im gleichen Stil wie Android 2.2 und 2.3 erstellt, da meine App bisher noch nicht für Android 3.0 oder neuer optimiert ist. Es wird ein Zurückbutton für diese Versionen folgen, wenn ich ihn benötige.

Achso: Falls mal jemand ein SVG von den Original-Android-Buttons benötigt, so findet er sie hier.

Verfasst von: egore911

Ich musste gerade auf einem Windowssystem herausfinden, ob eine DLL 32 oder 64 bit hat. Jeder, der den Befehl file unter Linux kennt, sucht nach einer ebenso einfachen Möglichkeit unter Windows. Wenn man nach diesem Problem online sucht, findet man diverse absurde Lösungen ... ein Perl-Skript, kurz mal Visual Studio installiern, etc.

Die einfachste Lösung fand ich beim ReactOS-Projekt, den Dependency Walker. Dieser zeigt einfach bei allen Symbolen der DLL ob sie 64 oder 32 Bit verwenden. So einfach kann es sein und der Dependency Walker muss nicht mal installiert werden.

Verfasst von: egore911

Ich verwende für eine App eine ListView. Diese ListView wird mit Layoutelementen befüllt, die aus einem Bild links und einem Text rechts bestehen. Soweit so trivial. Eine Zeile muss dabei nicht immer ein Bild haben und es ist natürlich viel schöner, das Nachladen der Bilder über einen Task zu machen. Dieser Task lädt die Bilder von einem Server herunter, der sie vorher auf die gewünschte Größe skaliert hat.

public class DownloadImageTask extends AsyncTask {

 private final ImageView image;

 public DownloadImageTask(ImageView image) {
  this.image = image;
 }

 protected Drawable doInBackground(String... url) {
  return HttpUtil.getDrawableFromUri(url);
 }

 protected void onPostExecute(Drawable drawable) {
  if (drawable != null) {
   image.setImageDrawable(drawable);
  }
 }
}

Damit erhält ist das übergebene Drawable in onPostExecute immer ein 120x120 Pixel großes Bild. Sobald dieser Code allerdings durchgelaufen ist, sind über und unter dem Bild viel zu große Abstände. Mit Hilfe der View Hierarchie-Perspektive der Android-Tools für Eclipse konnte ich feststellen, dass das Drawable mit dem Bild eine Breite von 50 Pixeln und eine Höhe von 120 Pixeln hatte. Das erklärte den Abstand. Aber woher genau kommt er? Sehen wir uns doch mal den Code für das Bild an:

 <ImageView
  android:id="@+id/item_image"
  android:layout_width="50dp"
  android:layout_height="wrap_content" />

Dieser Code legt die Breite auf 50 Pixel fest, allerdings nicht die Höhe. Es gibt zwei Lösungen für das Problem.

  • Entweder man setzt die Höhe fest auf 50 Pixel. Das funktioniert allerdings nur bei quadratischen Bildern.
  • Oder man fügt ein android:adjustViewBounds="true" in den ImageView-Code ein. Damit werden die Bilder korrekt auf max. 50 Pixel Breite unter Einhaltung der Aspektrate skaliert.
Verfasst von: egore911

Ich habe mir vor etwas über einem Jahr auf meinem Laptop ein Ubuntu 10.4 LTS installiert. Mein Laptop muss nicht mit der neusten und tollsten Software laufen. Er muss stabil sein, weil ich damit arbeite. Ich will (und kann) mich nicht mit dem darunterliegenden Betriebssystem aufhalten. Allerdings hatte das System irgendwann beim Booten einen Kernelpanic. Da ich schnell wieder ein funktionierendes System benötigte, habe ich eine Gentoo stage3 in das existierende System eingespielt. Damit hatte ich ein stabiles System, was allerdings beim Installieren von Software aus offensichtlichen Gründen immer Probleme verursachte. Das System musste also wohl oder übel neu installiert werden.

Da ich einige Entscheidungen von Canonical bezüglich Ubuntu nicht vollständig teile (um mal die Schlagworte Unity, Ubuntu-One, CouchDB, Banshee zu nennen) und über Fedora sehr viel gutes gehört habe, wollte ich es mal ausprobieren.

Installation

Der Installer von Fedora (anaconda genannt) ist relativ elegant. Man kann mit minimalem Aufwand ein System installieren, dass direkt funktioniert. Das ist ein großer Vorteil gegenüber Gentoo. Die einzelnen Schritte zum Installieren eines Gentoo-Systems beherrsche ich zwar im Schlaf, aber sie sind aufwendiger (insbesondere wenn man nicht nur ein Kernsystem haben will, sondern auch X11, gnome und einen Browser). Die installierte Auswahl an Paketen ist grundsätzlich gut, bringt aber so manches Programm mit, was ich nicht benötigte.

Paketmanager

Gentoo bringt keinen graphischen Paketmanager mit. Es gibt aber diverse Ansätze um diesen zu etablieren, unter anderem PackageKit. Aus Ubuntu kannte ich synaptics, der mir wirklich gut gefiel. Fedora scheint keinen eigenen Paketmanager zu besitzen und statt dessen auch auf PackageKit zu setzen. Ich konnte mich zwar schnell wiederfinden, aber gpk-application ist bei weitem nicht so rund wie synaptics. Es ist schwierig die installierten Pakete zu finden, es wird zu viel wert auf die (leider meist schlecht gepflegte) Beschreibung anstelle des Paketnames gelegt und, was das größte Problem ist, die GUI versetzt sich des öfteren in einen Zustand, in dem nichts angeklickt werden kann (einfachstes Beispiel: nichts auswählen und Ausgewählte Pakete anklicken). Ich bin dazu übergegangen yum zu verwenden. Das Kommandozeilenprogramm lässt sich einfach bedienen und erfüllt seinen Zweck. Da ich unter Gentoo gewohnt bin mit emerge zu arbeiten, ist dies keine große Umstellung.

Software

Es gibt viel Software in Gentoo, die es nicht in Fedora gibt und umgekehrt. Interessant finde ich den Ansatz von Fedora, nur Software zuzulassen die aus den Quellen übersetzt wird. Das mag zwar theoretisch ein ganz toller Ansatz sein, ist aber in der Praxis kaum umzusetzen. Ich benötige beispielsweise den android-sdk. Gentoo stellt ein ebuild bereit, um das Binärpaket nach /opt zu installieren. Mit der richtigen Gruppenberechtigung darf der normale Nutzer auch neue API-Versionen installieren. Super. Unter Fedora wollte ich ebenfalls diesen Luxus. Theoretisch kann man sich den Android SDK selbst bauen (so weit ich weiß sollte alles daran Open-Source sein), aber wieso auf die vorbereiteten Pakete von Google verzichten? Ich bin dazu übergegangen aus Gentoo-ebuilds mir rpm's für Fedora zu erstellen. Beide haben eine gewisse Ähnlichkeit obwohl ebuilds meines Erachtens bedeutend luxuriöser sind. Aber dazu ein andermal mehr.

Fazit

Gentoo bietet mit den ebuilds (und zugehörigen USE-Flags) eine perfekte Möglichkeit ein System genau so zu bauen, wie man es benötigt. Aber: es braucht Zeit. Fedora stellt ein sehr gut nutzbares System zur Verfügung. Es ist bei weitem nicht so "poliert" wie Ubuntu. Es ist auch stärker auf Geeks ausgelegt (z.B. durch Verwendung von SELinux per Default, was nicht das einfachste Sicherheitsframework ist). Alles in Allem ist es aber absolut brauchbar und nach ein paar Konfigurationseinstellungen (SELinux deaktivieren, Themes installieren, Fonts anpassen, PS1 anpassen) sehr gut zu benutzen.

Verfasst von: egore911

Um einen Apache Tomcat per mod_jk hinter einen Apache HTTPd zu hängen, gibt es das AJP-Protokoll. Dies wird vom mod_jk implementiert, was für die Kommunikation zuständig ist. Soweit die Theorie. In der Praxis wollte das nicht funktionieren und ich fand folgenden Logeintrag:

connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=13)

Die Debug-Ausgaben von mod_jk ergaben, dass eine Verbindung zu 127.0.0.1:8009 fehlschlug. Zuerst hatte ich IPv6 in Verdacht. Also habe ich es erstmal deaktiviert:

echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6

Dies brachte keine Besserung. Der Service lief jetzt zwar unter IPv4, telnet klappte, aber der Apache HTTPd wollte sich trotzdem nicht verbinden. Dann fand ich folgenden Logeintrag

[error] init_jk::mod_jk.c (3235): Initializing shm:/var/log/httpd/jk-runtime-status.16551 errno=13. Load balancing workers will not function properly.

Eine kurze Recherche ergabe, dass SELinux dazwischen funkt. Ich weiß nicht, warum Fedora SELinux per Default aktiviert. Es mag zwar für die Sicherheit gut sein, aber ich hatte bisher nur Probleme damit. Meine Lösung ist es in der Datei '/etc/selinux/config' folgende Zeile einzufügen.

SELINUX=disabled

Anschließend funktioniert alles und mein System reagiert gefühlt schneller.

Verfasst von: egore911

Kürzlich habe ich mal wieder Lust dazu bekommen, mein Wacom Tablet auszuprobieren. Daher habe ich diese kleine Szene gemalt:

Es ist das erste Mal, dass ich mit dem Tablet tatsächlich ein ansehnliches Ergebnis produziert habe. Das hat mit selbst etwas überrascht und ich bin dem etwas nachgegangen. Bisher habe ich das dem Table beiliegende Corel Essential 2 oder Gimp verwendet. Beide sind zwar nette Spielereien für Tablets, aber kommen darüber nicht hinweg. Da ich durch Zufall von MyPaint gehört hatte, wollte ich das mal ausprobieren. Ich muss sagen: Ich bin sehr zufrieden, denn die guten mitgelieferten Brushes sind der Grund, warum ich dieses Mal mehr als ein "Hallo, dies ist ein Test" gemalt habe. Und natürlich, dass ich vor Kurzem in die Bob Ross DVD rein gesehen habe ;-).

Verfasst von: egore911

Da ich bereits mehrfach gefragt wurde, wie man mit Maven und ADT ein Projekt multimandandenfähig macht (d.h. aus einem Sourcebaum entstehen mehrere Apps), fasse ich das hier mal kurz zusammen.

Grundsätzlich benötigt man die Maven-Struktur für ein Android Projekt. Diese sieht wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>de.egore911.mobile</groupId>
 <artifactId>test</artifactId>
 <version>0.1-SNAPSHOT</version>
 <packaging>apk</packaging>
 <name>${project.artifactId}</name>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <dependencies>
  <dependency>
   <groupId>com.google.android</groupId>
   <artifactId>android</artifactId>
   <version>2.2.1</version>
   <scope>provided</scope>
  </dependency>
 </dependencies>

 <build>
  <plugins>
   <plugin>
    <groupId>com.jayway.maven.plugins.android.generation2</groupId>
    <artifactId>android-maven-plugin</artifactId>
    <version>3.0.0-alpha-14</version>
    <configuration>
     <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
     <assetsDirectory>${project.basedir}/assets</assetsDirectory>
     <resourceDirectory>${project.basedir}/res</resourceDirectory>
     <nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>
     <sdk>
      <platform>8</platform>
     </sdk>
     <deleteConflictingFiles>true</deleteConflictingFiles>
     <undeployBeforeDeploy>true</undeployBeforeDeploy>
    </configuration>
    <extensions>true</extensions>
   </plugin>

   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>

  </plugins>
 </build>

Ich werde an dieser Stelle nicht auf die einzelnen Teile eingehen. Es geht jetzt darum, wie man Resources austauschen kann. Dazu verwendet man in Maven Profile. Ich verwende z.B. ein Profil namens "demo".

<profile>
 <id>demo</id>
 <activation>
  <property>
   <name>config</name>
   <value>demo</value>
  </property>
 </activation>
 <build>
  <plugins>
   <plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.5</version>
    <executions>
     <execution>
      <id>copy-assets</id>
      <phase>initialize</phase>
      <goals>
       <goal>copy-resources</goal>
      </goals>
      <configuration>
       <outputDirectory>${basedir}/assets</outputDirectory>
       <resources>
        <resource>
         <directory>${basedir}/templates/assets/demo</directory>
         <filtering>false</filtering>
        </resource>
       </resources>
       <overwrite>true</overwrite>
      </configuration>
     </execution>
     <execution>
      <id>copy-res</id>
      <phase>initialize</phase>
      <goals>
       <goal>copy-resources</goal>
      </goals>
      <configuration>
       <outputDirectory>${basedir}/res</outputDirectory>
       <resources>
        <resource>
         <directory>${basedir}/templates/res/demo</directory>
         <filtering>false</filtering>
        </resource>
       </resources>
       <overwrite>true</overwrite>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
</profile>

Hierbei sind zwei Dinge zu beachten:

  1. Das Kopieren der Ressourcen muss vor der Ausführung das Android-Plugins passieren. Da das Android-Plugin in der Phase "generate-sources" ausgeführt wird, habe ich "initialize" als Phase gewählt (Warum erschließt sich bei der Betrachtung des Maven Livecycle).
  2. Per Default überschreibt das maven-resource-plugin nicht bestehende Resourcen, wenn diese neuer sind. Dies ist für den gegebenen Anwendungsfall natürlich unpraktisch.

Damit kann jetzt jeder seine App auch als Demo ausliefern. Es bleibt dem Entwickler überlassen, ob er die Vollversion in den res und assets-Ordnern pflegt oder diese auch als Profile realisiert. Ich habe letzteres verwendet, damit ich mir nicht aus Versehen teile der Demo in die Vollversion stecke (oder umgekehrt). Man sollte in diesem Fall darauf achten, dass die Daten nicht ins Versionskontrollsystem eingecheckt werden. Dies kann dann allerdings zur Folge haben, dass wenn kein Profil aktiv ist, die Daten fehlen und der Android-Buildprozess fehlschlägt. Als Lösung bietet sich an, entweder ein Profile auf "activeByDefault" zu stellen, oder in der Entwicklungsumgebung das Profil zu aktivieren.

Verfasst von: egore911

Man kann mit Eclipse und den dazugehörigen ADT sehr elegant für Android entwickeln. Allerdings bin ich darüber gestolpert, dass man damit nicht ohne weiteres "Demos" einer vollwertigen Applikation (d.h. ein APK, dass gewisse Einschränkungen gegenüber einer Vollversion der selben Software hat) aus den gleichen Sourcen erzeugen kann.

Es wäre evtl. möglich dass in den Ant-basierten Build einzubinden, allerdings habe ich gleiches bereits für Maven konzipiert und will das Rad nicht neu erfinden. Bei einer kurzen Internetrecherche bin ich über das android-maven-plugin gestolpert. Es erlaubt einem, dass Ant-basierte Buildsystem durch Maven zu ersetzen. Nachdem ich diesen Schritt vollzogen hatte, ließ sich unter Verwendung der Maven-Profiles problemlaus eine Demo erzeugen.

Verfasst von: egore911

Ich habe heute beschlossen, meine Experimente mit Enticore zu beenden. Ich hatte das System ursprünglich erdacht, um ein leichtgewichtiges und modulares CMS zu erstellen. Zum damaligen Zeitpunkt gab es zwar schon diverse in PHP entwickelte Open-Source-CMS, aber keines davon war "mal auf die Schnelle" eingerichtet. Von Leichtgewichtig ganz zu schweigen.

Aber die Zeiten ändern sich. Ich habe vor ca. einem Jahr Drupal 6 kennen gelernt und viele Grundideen von Enticore dort wiedergefunden. Insbesondere die Modularität ist in Drupal sehr gut umgesetzt. Allerdings hatte Drupal 6 in meinen Augen eine gravierende Schwäche: Der Kern des CMS konnte zu wenig und musste durch Module erst einmal nutzbar gemacht werden. Dieser händische Aufwand entfiel mit Drupal 7, weil dieses schon einige essentielle Module mitbringt. Ich konnte diese Seite mit wenig Arbeit in Drupal 7 umsetzen und bin zufrieden damit.

Frei nach dem Motto "Code, den ich nicht selbst pflegen muss, ist guter Code", läute ich hiermit das langsame aber sichere Ende von Enticore ein. Die Plugins von Enticore, für die es in Drupal noch keine Entsprechung gibt, werde ich portieren.

Verfasst von: egore911

Ein kurzer Tipp, wie man sich das Leben mit angepassten Projekten vereinfachen kann. Dazu nehme man ein beliegiges Open Source Projekt, dass man anpassen muss, bevor man es benutzen möchte. Das Problem dabei: Wie integriert man eventuelle neue Versionen?

Die Lösung dazu: git (das Versionskontrollsystem). Die Idee ist so einfach wie genial. Zuerst importiert man den initialen Stand der Software. Diesen Stand brancht man in 2 Richtungen ab:

  1. Der offizielle Stand der Software (upstream)
  2. Meine eigenen Änderungen (master)

Jetzt kann im "master" Branch wie gewohnt angepasst werden. Sobald eine neue Version der Software erscheint wechselt man in den "upstream" Branch und importiert die neue Version. Sobald man mit git den Branch "upstream" wieder in den "master" merged, bekommt man die Änderungen, die durch die neue Version hinzugekommen sind.

Aber was macht man, wenn man erst zu spät feststellt, dass man sich das Leben mit git so einfach machen kann?

Ganz einfach: Man erstellt den Branch "upstream" indem man ihn vom "master" abspaltet. Jetzt wechselt man in diesen Branch, löscht den gesamten Inhalt und importiert den offiziellen Stand der Sotware (der zu dem Stand im "master" Branch passt, d.h. wenn master eine angepasst Version von 3.4.8 ist, würde man die offizielle Version 3.4.8 importieren). Jetzt würde bei einem Merge natürlich das schlimmste Chaos entstehen. Daher muss man git ein wenig helfen. Wir behaupten einfach, dass alles, was derzeit im "upstream" Branch steckt, bereits zurück in den "master" gemerged wurde:

git checkout master
git merge -s ours upstream

Damit kann man dann genauso wie oben beschrieben arbeiten, also in "upstream" immer den aktuellen Stand importieren und in den master mergen.

Dieser kleine Trick reduziert d die Dauer von 4 Stunden im händischen Vergleich (die damals ein Kollege durchgeführt hat) auf 10 Minuten durch diese Automatisierung. Ein anschließendes Testen ist allerdings trotzdem angebracht.

Verfasst von: egore911

Ich habe heute ein Problem mit der Seitengenerierung von Maven gehabt. Für die Seitengenerierung verwende ich unter Anderem das maven-project-info-reports-plugin. Dieses Plugin erzeugte bei jeden Aufruf eine Exception, die nicht direkt einleuchtend war:

java.lang.ArrayIndexOutOfBoundsException: 1
    at org.apache.maven.doxia.module.xhtml.XhtmlSink.tableCell(XhtmlSink.java:791)
    ....

Das Problem dabei war, dass die Version des maven-site-plugins zu alt war. Nachdem ich folgendes in die pom.xml des Projekts eingetragen hatte, funktionierte es:

 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-site-plugin</artifactId>
    <!-- Version 2.3 oder neuer wird für das maven-project-info-reports-plugin benötigt -->
    <version>2.3</version>
   </plugin>
  </plugins>
 </build>

Diese kleine Änderung ist durchaus entscheidend

Verfasst von: egore911

Nachdem mein alter Druckern, ein Canon i3000, leider kaputt gegangen ist, wurde er durch einen Netzwerkdrucker ersetzt. Damit ist es möglich, von meinem Rechner oder meinem Netbook zu drucken. Aus Kostengründen bin ich beim Brother DCP-585CW gelandet, der neben einer WLAN-Karte auch einen Scanner besitzt. Diesen hatte ich bisher nicht in Benutzung, weil mein alter Epson 3590 Perfection immer gut funktionierte. Doch auch dieser scheint nicht mehr so ganz zu wollen.

Daher habe ich versucht den Scanner des Brother unter Linux zu benutzen. Brother stellt direkt offizielle Treiber für Linux zur Verfügung und beschreibt im Detail, wie man den Treiber installiert. Doch dieser weigerte sich mit Händen und Füßen. Auch die Anleitung von Ubuntuusers brachte nicht den Durchbruch. Nach längerer Recherche fand ich die Lösung im Gentoo Forum:

In der /etc/sane.d/dll.conf fehlte bei mir die folgende Zeile:

brother3

Danach funktionierte der Scanner endlich. Allerdings musste ich dann herausfinden, dass die Optionen von "scanimage" wohl proprietär sind. Der alte Scanner kannte '--mode=Lineart', der neue Scanner verwendet '--mode="Black & White"'.

Verfasst von: egore911

Für den zuvor beschriebenen Mailserver wird neben dem Empfang natürlich auch der Versand benötigt. Bisher hatte ich meine E-Mail-Clients so eingestellt, dass sie beim Versand direkt an den E-Mail-Server der E-Mail-Adresse senden. Dies hat den Nachteil, dass man in jedem Client die Passwörter neu eingeben muss. Daher war die Idee einen zentralen Server auf Postfix-Basis auf dem gleichen Rechner wie dem IMAP-Server zu betreiben, der dann SMTP-Relay macht.

Dieses Setup hatte ich vor mehreren Jahren bereits ausprobiert und hatte die Annahme, dass die Einrichtung genauso funktioniert. Allerdings ist SMTP-Relay heute auf Grund des Spam-Aufkommens bedeutend restriktiver. So erlaubt z.B. der Mailserver der Domain "christophbrill.de", das ausschließlich E-Mail mit Absenderadressen von "@christophbrill.de" weitergereicht werden. Da ich auch im Besitz einer Freemail-Adresse bin, würden diese E-Mail immer abgelehnt. Also war die einzige Option einen Relay pro Absender zu verwenden. Glücklicherweise kann Postfix dies von Hause aus.

In der Datei /etc/postfix/main.cf wird zusätzlich folgendes benötigt

smtp_sender_dependent_authentication = yes
sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = plain, login

Damit wird das Relaying pro Sender aktiviert. Jetzt müssen natürlich noch die Absender und relayhosts konfiguriert werden. In der Datei /etc/postfix/sender_relay stehen dann Einträge der Form

emailadress1@irgend-ein-provider.de   smtp.irgend-ein-provider.de

und in der /etc/postfix/passwd stehen dann die zugehörigen Zugangsdaten

emailadress1@irgend-ein-provider.de   benutzername:passwort

Bei mir sind dabei folgende Fehler aufgetreten, die man in /var/log/mail.err:

fatal: open database /etc/postfix/sender_relay.db: No such file or directory

Das passiert dann, wenn man postmap hash:/etc/postfix/sender_relay noch nicht aufgerufen hat

Relay access denied

Dieser Fehler tritt auf, weil Postfix per Default in mynetworks nicht mein privates Netzwerk stehen hat und in der Standardkonfiguration nur Hosts aus dem privaten Netzwerk einen Relay machen dürfen.

SASL authentication failed; .... no mechanism available

Dieser Fehler tritt auf, weil Postfix per Default keinen SASL-Mechanismus vorgibt. Mit Hilfe des Parameters smtp_sasl_mechanism_filter lässt sich dies leicht steuern.

Alles in Allem war das SMTP-Relay in weniger als einer halben Stunde eingerichtet und funktioniert jetzt problemlos. Meine E-Mail Clients "reden" jetzt nur noch mit dem zentralen Server, was den Konfigurationsaufwand pro Arbeitsplatz minimiert (ok, es ist nur Desktop-Rechner und ein Netbook, aber es geht ja ums Prinzip ;-).

Verfasst von: egore911

Ich habe vor kurzem ein IMAP-Mailserver auf Basis von Dovecot installiert. Dieser dient als Ersatz für mein vorheriges Setup auf Basis von Courier-IMAPd + Procmail. Der Hauptbewegrund war Sieve, eine modernes Mail-Sortier-und-Filter-System.

Bisher funktionierte mein Server so: fetchmail ruft die E-Mails ab, übergibt sie an den SMTP-Server postfix, der übergibt sie an procmail (der sie mit Hilfe der .procmailrc sortiert) und sie können dann über courier-imapd abgerufen werden. Das klingt nicht nur kompliziert, sondern ist es auch.

Jetzt funktioniert es einfacher: fetchmail ruft die E-Mails weiterhin ab, übergibt sie aber an dovecot (an den deliver LDA um genau zu sein) und wir sind fertig. Kürzer. Weniger fehleranfällig. Konfigurierbar über die managesieve-Erweiterung für Thunderbird (was der Hauptbeweggrund war, um von .procmailrc weg zu kommen).

Eigentlich sind dafür relativ wenig Konfigurationsoptionen notwendig:

1.) In der dovecot.conf im protocol lda as Sieve-Plugin aktivieren.

2.) In die /etc/fetchmailrc

mda "HOME=/home/%T /usr/bin/sudo -u %T /usr/lib/dovecot/deliver"

eintragen

3.) Mittels visudo folgenden Filter eingeben:

fetchmail ALL=(ALL) NOPASSWD:/usr/lib/dovecot/deliver

Der einentliche Trick dabei ist es, dass fetchmail bei mir als globaler Service ausgeführt wird, und zwar als eigener Benutzer 'fetchmail'. Ein direkter Aufruf von deliver allerdings hat zur Folge, dass die E-Mails im Ordner des Fetchmail-Benutzers landen und nicht dem in der fetchmailrc konfigurierten(!). Diese kleine Information ist extrem entscheidend für das erfolgreiche Abrufen von E-Mails und hat mich ein paar Stunden des Grübelns gekostet. Jetzt funktioniert alles und ich kann endlich wieder E-Mails abrufen... und vor allem sortieren :-)

Verfasst von: egore911

Ich bin derzeit mal wieder dabei an Opengate rumzuexperimentieren. Dazu benötige ich ogreopcode, einen Wrapper der Ogre (eine 3D Engine) mit Opcode (einer Bibliothek zur Kollisionserkennung). Allerdings war dieser nicht mit der neuesten Ogre Version (1.7.1) kompatibel. Daher habe ich folgende Ändernungen gemacht:

===================================================================
--- src/IOgreCollisionShape.cpp (revision 417)
+++ src/IOgreCollisionShape.cpp (working copy)
@@ -264,7 +264,7 @@
                if(!mHasCostumTransform)
                {
                        getParentSceneNode()->_update(true, true);
-                       getParentSceneNode()->getWorldTransforms(&mFullTransform);
+                       mFullTransform = getParentSceneNode()->_getFullTransform();
                }
                return mFullTransform;
        }
Index: src/OgreBoxCollisionShape.cpp
===================================================================
--- src/OgreBoxCollisionShape.cpp       (revision 417)
+++ src/OgreBoxCollisionShape.cpp       (working copy)
@@ -204,7 +204,7 @@

                calculateSize();

-               mParentNode->getWorldTransforms(&mFullTransform);
+               mFullTransform = mParentNode->_getFullTransform();
                //mFullTransform = mParentNode->_getFullTransform();

                return true;
Index: src/OgreMeshCollisionShape.cpp
===================================================================
--- src/OgreMeshCollisionShape.cpp      (revision 417)
+++ src/OgreMeshCollisionShape.cpp      (working copy)
@@ -287,8 +287,7 @@
                }

                mParentNode = mDummyNode;
-               //mFullTransform = mEntity->getParentSceneNode()->_getFullTransform();
-               mParentNode->getWorldTransforms(&mFullTransform);
+               mFullTransform = mParentNode->_getFullTransform();
                return rebuild();
        }

Das ist einer der großen Vorteile von Open Source: Wenn es nicht funktioniert, hat man die Chance herauszufinden warum nicht.

Verfasst von: egore911

Nerdy-Lines sind Icons für den Linux Desktop, die einen zeichnerischen Stil verwenden.

Ich habe eben gesehen, dass meine Nerdy-Lines Icons mittlerweile mehr als 100000 Mal heruntergeladen wurden. Ich hatte sie eigentlich nur für mich erstellt und dachte nicht, dass das Interesse so groß ist. Daher freue ich mich um so mehr, dass die Icons eine sinnvolle Verwendung haben.

Nerdy Lines Icon Theme

Verfasst von: egore911

Seiten