Ikke's Blog

Archives for: June 2005

Jun 25
LinuxTag day 2

So, I'm at LinuxTag currently, bloody tired, but well, having quite a good time after all (god I hate qwertz). I wouldn't say it's superb (talks tend not to go deep enough etc), but meeting some guys you've known on IRC for a while already in real life now is just great. Hacking on some things together (too bad I still havent got a laptop, which disables me from doing any real hacking myself, actually, we can only work together on one machine which does give problems from time to time), grabbing a beer (not to much, as beer is not as free as the speech couterpart ;-)), discussing things, just hanging around... Well, pretty much the things everybody does in here :-)
I won't write too much now (waaaaaay too tired), a larger "report" including some pictures might follow later (although that later might become "not within 2 weeks", as the following week I'll hardly be at home).

Fortunately we got some great wheather (although sometimes it tends to be too hot :-/)

Ikke • Life, LinuxPermalink 1 comment
Jun 22
LinuxTag 2005

So, I'll be heading to Germany tomorrow after my last exam, to attend at LinuxTag on Friday and Saturday. Most likely I will be at the Social Event too.
If you're reading this and you're coming as well, let me know, maybe we can meet :-) Leave a comment or send me some email, although I cannot promise I'll be able to check my email/blog comments over there... (I hope there'll be some public terminals)

Ikke • LifePermalink 1 comment
Jun 20
*g*

Check the first comment here. Rodrigo has some good points in his post, gives some hints on how to solve the problem, tries to be constructive.
Anonymous Coward replies.

Ignore, let's move on.

Jun 19
To Philip

Philip:
Don't get too frustrated ;-) Lots of people know about these issues. Lots of them care. But as you mentioned, people need to get together, and come out with real-world solutions for real-world problems.
You're right when you state there's a lot of flaming on xdg. But not on all subjects. Take D-BUS and HAL, two promising technologies that get widely accepted, and are truly desktop-agnostic. Both Gnome and KDE start to make heavy use of it.
I'm not really familiar with the copy-paste issues. But as far as I know there is a clipboard specification on fd.o. If that's not sufficient for new applications, everyone is free to propose extensions for the specification. But why do we need a spec if applications don't use it? Currently Gnome got no real clipboard manager, I heard KDE does though.

Some parts of the desktop should be standardised, and shared between both (or should I say "all"?) Desktop Environments we got in the Free Software world. A normal non-techie desktop user wants to be able to copy-paste between Kmail and Gaim without any problem. And he's right when he wants this.
Low-level non-interfacing libraries like D-BUS and HAL should be shared too. It'd be pointless if both Gnome and KDE would start writing up something like HAL. I've been following HAL development for a logn time already, and it's taking lots of effort and thorough decission-making to develop it (kudo's to the devs, especially David :-)), so duplicating something like it is a wasted effort. We could use the amount of work the devs put in the 2nd implementation elsewhere.
Same goes for D-BUS: we all know the story of CORBA and all it's implementations. Finally, with D-BUS, sending some simple dumb signal becomes a matter of writing 3 lines of code (now don't count, it's just a number), a dev does not have to write up IDL files and whatever more. Some people told me once only the guys that wrote Bonobo know how to use it, and maybe they were right (although I know D-BUS and CORBA/Bonobo aren't 100% the same thing, bleh).

But where is the line? I mean, if both Gnome and KDE should share everything (not only in standards, something they should share, but also in libs) we can as well just start dropping one of them and only developing on the other one. And we all know what happens when someone gets a monopoly ;-)

So (finally, the key matter): DConf. I did follow the lengthy discussions (url is just one of the many threads) when they were on xdg. And I must admit, at that time, sometimes they bored me to that. I also laughed when I read that "Over my dead body" comment. Actually, I used it several times to demonstrate what's going on between Gnome and KDE. Although there's one big thing to note: the comment was made by someone who was, afaik, no KDE developer. Waldo, who is one, did participate in a positive manner IIRC.

Now why do people accept something like HAL, and tend to be against something like DConf? I think it's fairly simple: currently both KDE and Gnome got their configuration infrastructure, KConfig and Gconf. Almost all apps who target one of these environments use the corresponding configuration libraries and standards. This is a large part of all desktop apps, including some of the largest (well, except the Mozilla and OOo stuff).
So I can understand some people are a little reluctant when all at once someone on xdg comes to tell them we need a new, common configuration interface. I'm not saying this is a good thing, just trying to understand how they think:

  • When KConfig or Gconf would be dropped one day in favour of Dconf, lots of code that accesses configuration settings should be rewritten to use the new API's
  • It is possible even the internal logics of this code will need to be rewritten, if they use some special features of the system they use now that won't be included in Dconf
  • "We already got a config system that does what we need, why can't the (fill in other/'rival' DE) guys just use ours?"
  • "Dconf offers this and this, but hell, I don't need all that! It only makes my simple I-administrate-one-desktop life more difficult"

and there could be more than 100 other reasons.

So what's the big difference between, say, HAL and Dconf? HAL is new. Desktop developers can just say "Hey, that's some cool new technology, let's write some application (gvm/ivman/kvm/...) around it, or add some functionality to something we got now (gnome-vfs/kioslaves/...) using it".
Dconf will also be something new. But the functionality it offers won't be. So existing things will have to be adapted or rewritten.

Summary: I agree with you on large parts of your rant. Basic libraries like GStreamer should be adopted by both platforms (as long as the development team does, well, a good job... together), duplicating effort is useless there.
Standards should be written and implemented, so a normal desktop-user shouldn't care whether he's running KDE applications or Gnome apps in some random environment. Copy-paste between two Gnome apps should be as easy/workable as doing it between a Gnome and a KDE app.
But we should not make just one melt pot of both platforms. Some concurrention is a good thing ;-) I hope you're not saying something like "Hey, let's drop GTK+, let's use Qt too, to avoid duplicate efforts".
As for ISV's: it's not a bad thing they should choose between GTK+ or Qt. Both platforms got their strengths, every ISV got it's preferences and knowledge. And both platforms get vendors that use them: GTK eg by VMWare, Qt by Skype. But we should make sure indeed VMWare can run flawlessly on a desktop running KDE, taking care VMWare should not use any special tricks to get that working (eg configuration management). Like this all ISV's can choose their preferred platform, without being forced to ask the client "Hey, what desktop are you running?"

Somewhat unrelated: we, in the FOSS world, should make sure we get more enterprise-ready (and Dconf is one step in the right direction). We are not limited to single-desktop employments. There are some good efforts like Sabayon, or Fedora Stateless, and maybe some non-Gnome-based counterparts I don't know of, but these need much more attention, as they are not completely usable yet (as you can see while reading our experiences with Fedora Stateless). 100-workstation deployments should become fun for the administrator, not a hell as it is now. If we could ever reach that goal, FOSS would get the oportunity to get a strong share in the corporate desktop market, as deploying concurrent desktops in a big environment isn't always a breeze either these days (wink@Jeroen and DICT, if someone'd ever read this).

Bleh, I dislike writing long rants as I'm not good at it so I stop here. By the way, didn't we agree not to blog on Dconf and keep it silent for a while? ;-)

Completely unrelated: I got some email from Nokia saying I'll get a code to get one of their N770's at 99

Jun 19
Windows Picture and Fax preview question, and a little update

I guess most of you saw the Windows Picture and Fax viewer at least once already:

PictureFaxViewerThumb
(click on the tumbnail for a full scale view)

Never mind the screenshot's content, it was the first one I could find on Google Images.

Now what's so special about this? Let's take a closer look:

PictureFaxViewerButtons

"If you want to rotate the picture to the right, please click the button on the left. If you want to rotate left, you need the button on the right"

Is it just me who doesn't get the logics behind this? Guess I won't ever become a good UI-designer...

If anyone got a good explanation for this, please let me know.

Next to that: I haven't been working too much on coding lately, trying to study. I might overhaul the opluginmanager API completely once more, playing around with some idea's to make it more usable from languages other than C, so as long as I didn't decide on the final design (on which I'd still love to get some input) it's stalled a little.

I'll have my last exam on Thursday afternoon, then probably I'll take off to Germany to visit LinuxTag (let me know if you're coming), I'll be at Rock Werchter one day, then the VTK Weekend follows, our annual GAO barbeque,... Busy times to come :-)

Jun 16
Wikipedia Article of the day

Hija,

Today I implemented an idea I had been playing with for some time already: make a daily RSS feed of Wikipedia articles.
Why? If you add this feed to your aggregator, you'll be served a random article every day (or maybe twice a day, still have to decide at which frequency the cronjob should run) to expand your global knowledge, not only regarding tech-stuff ;-)

The blog page is here, you can find links to the RSS/Atom/... feed on the right.

Things could be somewhat buggy for now (there are lots of articles with lots of markups, some of them forbidden by b2evo, so I have to filter them out) but as more articles are aggregated, I'll be able to squash them :-)

I hope you like (and use) the service ;-) Spread the word!

Jun 15
Gnome tip

This must be the greates Gnome tip I ever read (the dragging part at least). Now finally one doesn't need to crawl through one Save and one Open dialog to send a simple screenshot to some buddy. Thanks Karel!!!

Next to that: this is some of the most insane projects ever. A Unix shell written in JavaScript, that can be run from a browser. Check the "Open Shell" link on top of the page. Pretty nifty, didn't look at the code yet, will do that later.

Started working on the "save and restore enabled plugins" functionality today. I decided to use GMarkup instead of libxml2 so I don't add another dependency (next to glib), and the config strings are so easy formatted GMarkup is more than sufficient to parse them. But it made me discover once more how much I hate dreaded SAX parsing. Someone who enjoys writing SAX based parsers must be on a serious crack overdose :crazy:

Jun 14
One more status update

I implemented Python plugin loading this afternoon. It's almost finished, only calling functions does not work yet (thats only like 10 lines or so, but my eyes start to hurt). It's using the Python plugin base class I blogged about yesterday.

The code is far from perfect, it might leak like hell etc, but hey, it's working ;-) You can't debug or clean code that is not working at all :-)

Here's the current output of the test loader I wrote:

** (process:19360): DEBUG: Loading all modules in .libs
** (process:19360): DEBUG: Suffix for .libs/libtestplugin1.so is valid, loading module
** (process:19360): DEBUG: [OPluginManagerPlugin] [test-plugin1] Got an init function
** (process:19360): DEBUG: [test-plugin1] Init with data "test-init-data"
** (process:19360): DEBUG: Module .libs/libtestplugin1.so is valid, adding
** (process:19360): DEBUG: Suffix for .libs/libtestplugin2.so is valid, loading module
** (process:19360): DEBUG: Module .libs/libtestplugin2.so is valid, adding
** (process:19360): DEBUG: Loading all modules in .
** (process:19360): DEBUG: Suffix for ./TestPlugin.py is valid, loading module
Creating new OPluginManagerPythonPlugin instance: PythonTest
** (process:19360): DEBUG: Module ./TestPlugin.py is valid, adding


Found 3 modules
** (process:19360): DEBUG: Dumping module 0:


================================================
Dumping data for: .libs/libtestplugin1.so, type is "native"
=================
* Name: test-plugin1
* Summary: A simple test plugin, full-featured
* Description: This is a sample test plugin, to test the OPluginManager functionality, giving sample usage of all possibilities
* Version: 0.1
* URI: http://www.eikke.com
* Authors:
        ikke
        -----------
                Email: eikke eikke com
                URI: http://www.eikke.com
* Module got an init function
* Module got a data free function
* Module got a configure function
================================================



** (process:19360): DEBUG: Dumping module 1:


================================================
Dumping data for: .libs/libtestplugin2.so, type is "native"
=================
* Name: test-plugin2
* Summary: A simple, small test plugin
* Description: This is a sample test plugin, to test the OPluginManager functionality. It only offers limited functionality
* Version: 0.1
* URI: http://www.eikke.com
* Authors:
        ikke
        -----------
                Email: eikke eikke com
                URI: http://www.eikke.com
        John Doe
        -----------
                Email: foo@bar.com
                URI: http://www.foobar.foo
* Module got no init function
* Module got no data free function
* Module got no configure function
================================================



** (process:19360): DEBUG: Dumping module 2:


================================================
Dumping data for: ./TestPlugin.py, type is "Python"
=================
* Name: PythonTest
* Summary: A little test plugin
* Description: Some longer description of this test plugin
* Version: 0.1
* URI: http://www.eikke.com
* Authors:
        Ikke
        -----------
                Email: eikke eikke com
                URI: http://www.eikke.com
* Module got no init function
* Module got no data free function
* Module got no configure function
================================================



** (process:19360): DEBUG: Deleting 3 modules
** (process:19360): DEBUG: [OPluginManagerPlugin] Freeing "test-plugin1" data
** (process:19360): DEBUG: [OPluginManagerPlugin] Running free function
** (process:19360): DEBUG: [test-plugin1] Freeing data "Test plugin 1 data"
** (process:19360): DEBUG: [OPluginManagerPlugin] Freeing "test-plugin2" data
** (process:19360): DEBUG: [OPluginManagerPlugin] No free function provided

As you can see, it loads 3 modules: 2 native (C) ones in .libs, one fully fledged, one minimal, and loads one Python plugin.
The Python plugin code is very simple, but can still offer almost the same flexibility as the C interface does:

from OPluginManagerPlugin import OPluginManagerPlugin, OPluginManagerPluginAuthor

class TestPlugin(OPluginManagerPlugin):
        def __init__(self):
                tmpauthor = OPluginManagerPluginAuthor("Ikke", "eikke eikke com", "http://www.eikke.com")
                OPluginManagerPlugin.__init__(self, "PythonTest", "A little test plugin", tmpauthor, "Some longer description of this test plugin", "0.1", "http://www.eikke.com", self.Init, self.FreeData, self.Configure)

        def Configure(self):
                print "Configuring"

        def Init(self, init_data):
                print "Initializing with data \"" + init_data + "\""
                return "testplugindata"

        def FreeData(self, data):
                print "Freeing \"" + data + "\""

def OPluginManagerPluginInit():
        return TestPlugin()

I should learn how to work with Python lists etc to be able to implement multi-author functionality etc though.

I updated CVS heavily, so you can find (and checkout) all current code here. Please play around with it and let me know what you think of it (as a comment here or on the live.gnome wiki page), so I know what I should enhance, add,...

Oh, I got one more terrible exam today (part 2 of the one I got yesterday). Life's great :-p

Jun 13
OPluginManager getting it's final forms

I tried to stabilize the OPluginManager interface today, after a terrible exam. Look at the OPluginManager page at live.gnome.org to get a view of the current structure.

I updated the test cases I got here locally (one example is the plugin code I got on that wiki page too). The directory-loader is finished too, almost everything is in place now actually, except the UI part and the "only-load-enabled-modules" feature. These things should be fairly trivial (don't we love that word, NVDB?) to implement.

Here's a sample app:

#include <glib.h>

#include "o-plugin-manager.h"
#include "o-plugin-manager-plugin.h"

gint main(guint argc, gchar *argv[]) {
        gint cnt = 0;
        gchar *dir = NULL, *dir2 = NULL, *modulepath = NULL;
        const OPluginManagerPlugin *plugin = NULL;
        OPluginManager *manager = NULL;

        g_type_init();

        manager = O_PLUGIN_MANAGER(o_plugin_manager_new());
        o_plugin_manager_load_modules(manager, ".libs", "test-init-data", NULL);        

        g_print("\n\nFound %d modules\n", o_plugin_manager_get_num_modules(manager));

        /* Check whether we got a 0'st module, call its configure function */
        if(o_plugin_manager_get_num_modules(manager) > 0) {
                plugin = o_plugin_manager_get_module(manager, 0);
                g_debug("Dumping module 0:\n");
                o_plugin_manager_plugin_dump(plugin);
        }

        g_object_unref(manager);

        return 0;
}

As you can see, this code loads all valid modules in .libs with the string "test-init-data" as init data, then checks whether a 0st plugin is available, and dumps the plugin info.

This is the current output:

** (process:14246): DEBUG: Loading all modules in .libs, suffix is so
** (process:14246): DEBUG: Suffix for .libs/libtestplugin.so is so, loading module
** (process:14246): DEBUG: [OPluginManagerPlugin] [test-plugin] Got an init function
** (process:14246): DEBUG: [test-plugin] Init with data "test-init-data"
** (process:14246): DEBUG: Module .libs/libtestplugin.so is valid, adding


Found 1 modules
** (process:14246): DEBUG: Dumping module 0:


================================================
Dumping data for: .libs/libtestplugin.so
=================
* Name: test-plugin
* Summary: A simple test plugin
* Description: This is a sample test plugin, to test the OPluginManager functionality
* Version: 0.1
* URI: http://www.eikke.com
* Authors:
        ikke
        -----------
                Email: eikke eikke com
                URI: http://www.eikke.com
        John Doe
        -----------
                Email: foo@bar.com
                URI: http://www.foobar.foo
* Module got an init function
* Module got a data free function
* Module got a configure function
================================================

** (process:14246): DEBUG: Deleting 1 modules
** (process:14246): DEBUG: [OPluginManagerPlugin] Freeing "test-plugin" data
** (process:14246): DEBUG: [OPluginManagerPlugin] Running free function
** (process:14246): DEBUG: [test-plugin] Freeing data "Test plugin data"

Here libtestplugin.so is the plugin you can see in the live.gnome wiki.

I also tried to implement a plugin structure in Python, although I'm no Python-expert at all. Current code is available here.
To give a little overview: every Python-based plugin should be a class extending from OPluginManagerPlugin, in this sample PluginTest is an implementation. There should be one fixed-name function in the __main__ module that returns an instance of this plugin class. Like this we just have to call that fixed-name function in our C wrapper, get it's return value in a PyObject *, then check whether it's type descends from OPluginManagerPlugin, and if that's the case start using the object as if it's just an OPluginManagerPlugin, we don't have to care about the details.
The code needs lots of enhancements and cleanups. If you could elaborate on this, please contact me. Especially the function-pointer part (passing (int)0 if no function is given) is ugly: I need to be able to check whether the var is a real function pointer before I call it, not only checking whether it's != 0. Next to this, I should figure out how to do proper error handling. Once that's done, I should be able to write a small wrapper plugin in C so I can start using plugins written in Python from within C.

Jun 12
Using Python objects in Python-C interop

As I wrote in my previous article, I did not know yet how to handle Python objects, and call their member functions.

After getting some help from Adam "adamh" Hooper, it became clear this is actually very easy to do.

Here's some code (I'm not reposting the whole C file, just append this to the end, it should be clear):

g_debug("Calling pytest::test using the helper function");
PyObject_CallMethod(ret, "test", NULL);

Py_XDECREF(ret);
ret = NULL;
        
g_debug("Calling pytest::test, no helper function");
g_debug("Creating a new pytest object");
ret = PyInstance_New(PyDict_GetItemString(dict, "" MODULE_NAME), NULL, NULL);
g_assert(ret != NULL);
PyObject_CallMethod(ret, "test", NULL);
Py_XDECREF(ret);

Watch out: you should not Py_XDECREF(ret) before doing this, of course.

As you can see there are 2 ways to achieve our goal:

  • In the first part of the snipper, we use "ret". This is the return value of the global function called "test", which is a "pytest" instance (the "test" function ends with return pytest()). We just call PyObject_CallMethod(object, name, args) to call the function.
  • In the first "solution" we use some ugly hack to get a pytest instance. In the second part we use a cleaner method, by calling PyInstance_New(type, constructor_args, kw). As you can see, we get "type" in the same way we got the entry point to the global "test" function. Now again we can just call a method on the object as in the first part.

This should be the output now:

** (process:13267): DEBUG: Initializing Python
** (process:13267): DEBUG: Setting PATH
** (process:13267): DEBUG: Trying to import "pytest"
** (process:13267): DEBUG: Success loading global test function
In main test function, argument is "testarg"
Initializing a pytest object
** (process:13267): DEBUG: Calling pytest::test using the helper function
In pytest's test function
** (process:13267): DEBUG: Calling pytest::test, no helper function
** (process:13267): DEBUG: Creating a new pytest object
Initializing a pytest object
In pytest's test function

Looks like Python/C interop is not that hard actually :-) You can find the final code here.

Jun 11
Calling Python from C

As I wrote on the OPluginManager overview page, I'd like to provide functionality to write plugins in Python. To achieve this I need to be able to call Python code from C (as the base OPluginManager framework is C-based). After asking around a little and reading some code samples (mostly in the Epiphany extension loading code) I figured out the basic calls one needs.

Here's what we need to do:
First we need some Python code. Take this as a test (pytest.py):

 class pytest:
        def __init__(self):
                print "Initializing a pytest object"

        def test(self):
                print "In pytest's test function"

def test(a):
        print "In main test function, argument is \"" + a + "\""
        return pytest()

Now we want to call some of this from C (pytest.c):


/* We want Python functionality */
#include <Python.h>
#include <glib.h>

/* To make life easier for us */
#define MODULE_NAME "pytest"

gint main(guint argc, gchar *argv[]) {
        /* The module object */
        PyObject *module = NULL;
        /* Objects we need to get a reference to a function */
        PyObject *dict = NULL, *func = NULL;
        /* Stuff we need to be able to load a module not in PYTHONPATH */
        PyObject *path = NULL, *pwd = NULL;
        /* Args we offer to the called function, and a reference to the return value */
        PyObject *args = NULL, *ret = NULL;

        /* Initialize the Python framework */
        g_debug("Initializing Python");
        Py_Initialize();

        /* "pytest.py" is in ".", so we need to alter the module search path
           "." is not in it by default */
        g_debug("Setting PATH");
        /* Get the current path (this is a list) */
        path = PySys_GetObject("path");
        /* Create a value to add to the list */
        pwd = PyString_FromString(".");
        /* And add it */
        PyList_Insert(path, 0, pwd);
        /* We don't need that string value anymore, so deref it */
        Py_DECREF(pwd);

        /* Load the module */
        g_debug("Trying to import \"%s\"", MODULE_NAME);
        module = PyImport_ImportModule("" MODULE_NAME);
        /* Check whether we succeeded */
        if(module == NULL) {
                /* If not, print the error message and get out of here */
                PyErr_Print();
                PyErr_Clear();
                g_warning("Failed to initialize \"%s\"", MODULE_NAME);
                return 1;
        }

        /* Get a dict from the module
           I should look up the API, but I presume this is something like
           "function_name" => function_entry_point */
        dict = PyModule_GetDict(module);
        /* Get the entry point of our "test" function
           This is -not- the pytest:test function */
        func = PyDict_GetItemString(dict, "test");

        /* Check again whether we succeeded, and whether the function can be called */
        if(func != NULL && PyCallable_Check(func) == TRUE) {
                g_debug("Success loading global test function");
        }
        else {
                /* Something bad occured, print out the Python error and abort */
                g_debug("Failed loading %s", MODULE_NAME);
                if(PyErr_Occurred()) {
                        PyErr_Print();
                        PyErr_Clear();
                }
                return 1;
        }

        /* We want to offer some args to the test(a) function
           These args should go into a tuple */
        /* Create a tuple with one element */
        args = PyTuple_New(1);
        /* Add a new element to the tuple, at position 0, a new string with content "testarg" */
        PyTuple_SetItem(args, 0, PyString_FromString("testarg"));

        /* Call the test function, with the "args" tuple as arguments */
        ret = PyObject_CallObject(func, args);
        /* Something went wrong.
           I must admit I still have to figure out what the return value of CallObject actually is.
           What would ret be if test(a) returns nothing? */
        if(ret == NULL) {
                /* Print error and abort */
                PyErr_Print();
                PyErr_Clear();
                g_warning("Failed to call test function");
                return 1;
        }

        /* Free the returned value, and the args tuple
           We don't really free, we unref the objects.
           I should look up what the difference between XDECREF and DECREF is. DECREF seems to be a standard unref thing */
        Py_XDECREF(ret);
        Py_DECREF(args);

        return 0;

        /* Maybe we should free the module too, and deinitialize Python
           This is not done in the code I read though */
}

Comments inline. This code might look huge, but actually it mostly consists of error checking ;-)

We need a rather "large" line to compile this:

gcc -o pytest -g `pkg-config --cflags --libs glib-2.0` -I/usr/include/python2.3 -lpython2.3 pytest.c

(You should adjust this to match your Python version if necessary)

When we run the program, this is what we get:

** (process:30233): DEBUG: Initializing Python
** (process:30233): DEBUG: Setting PATH
** (process:30233): DEBUG: Trying to import "pytest"
** (process:30233): DEBUG: Success loading global test function
In main test function, argument is "testarg"
Initializing a pytest object

Which is somewhat what we could expect.

In this sample I only use a global method, I don't use any Python object (like "pytest"). I must admit I don't know how to do this yet :oops: but hey, I'm just taking my first steps :-)

Jun 9
Done today
  • Created an initial page on OPluginManager on live.gnome.org.
  • Started writing a longer article on women in the FOSS community, now Gnome-Women was launched (actually, did that yesterday ;-))
  • Sent an email to the author of this article in our local newspaper to explain crackers are no hackers (and the other way around). WikiPedia got some decent information on this issue.
  • Did not study enough :-(

TODO:

  • Continue working on the OPluginManager design, then implement some more of it. Get to learn some more on GObject<->Python/Mono interaction, and Python/Mono<->native calling code (ie how to allow using an OPluginManager object in Python/C#, and how to allow OModuleLoader/OPluginManager to work with Python/C# based plugins).
  • Finish the mentioned article
  • Poke jdub to get some response (even if it's negative) ;-)
  • Write some of my ideas on the Tag based desktop down, decide wether to send it to desktop-devel@gnome or xdg@fdo, and do so accordingly.
  • Study!!!!
Jun 6
Debian Sarge released

I'm not willing to offend any Debian user, but this is just hilareous:
This release includes a number of up-to-date large software packages, such as the K Desktop Environment 3.3 (KDE), the GNOME desktop environment 2.8, the GNUstep desktop, XFree86 4.3.0, GIMP 2.2.6, Mozilla 1.7.8, Galeon 1.3.20, Mozilla Thunderbird 1.0.2, Firefox 1.0.4, PostgreSQL 7.4.7, MySQL 4.0.24 and 4.1.11a, GNU Compiler Collection 3.3.5 (GCC), Linux kernel versions 2.4.27 and 2.6.8, Apache 1.3.33 and 2.0.54, Samba 3.0.14, Python 2.3.5 and 2.4.1, Perl 5.8.4 and much more.

So

  • KDE 3.3
  • Gnome 2.8
  • XFree86 4.3.0
  • GCC 3.3.5
  • Linux kernel 2.6.8

are up-to-date now? Right :roll:

Disclaimer: I guess I could be flamed now as some some stupid Gentoo user thinking he's ultra 1337 etc etc, that's not my intention at all, I just think this is funny

[edit]As just seen on IRC:
17:48 <Em> the debian world must be in an uproar. you know. with gearing up for the next release in 2009
*grin*[/edit]

Jun 2
KEW2005

Just sit back and relax. Enjoy

If you really want to know what it is: Johannes Brahms' "Sonate nr. 3 in d Op. 108", by Yossif Ivanov (BE), 2nd price at the Queen Elisabeth concours last week. A magnificent piece in a superb performance. Partial movie is here, you need the latest WMP codecs to play it when running Linux.

Ikke • LifePermalink 2 comments
Jun 1
10X10


No comment ;-) Let's go for it.

Categories

Who's Online?

  • Guest Users: 475

Misc

XML Feeds

What is RSS?