Archive for the ‘ Fedora ’ Category

Tidbit: More technical

In the previous post I covered the ideas behind tidbit. In this post I will try and cover the technical aspects of the tidbit system. Currently the work is very exploratory, so everything may change.

Tidbit record structure

This is a typical tidbit which was generated using the Rhythmbox plugin:

TIDBIT/0.1; libtidbit/0.1; Rhythmbox Tidbit Plugin v0.1
tidbit_userkey==usePzEg4Cl4g1ASdzpssVHtQ1hJJilS+ryiBWjF...
tidbit_table==audio/track
tidbit_created:=1281479640
tidbit_expires:=1313037240
artist==Arcade Fire
title==Keep The Car Running
album:=Indie/Rock Playlist: May (2007)
genre:=Indie
year:=2007
play_count:=34
rating:=0.8
tidbit_signed:=JyJ1fIwhRL5t3y9CACmshm/UibYVhvInxh7XVx4...

The first line is the header. It states the version of the tidbit followed by the user agent. The rest of the record is composed of key-value pairs. The key has a strict format of lower-case letters and underscore. The value can contain any character above 0x1F, and is terminated by a new line. Other characters must be escaped. The first  four pairs are compulsory and they all contain “tidbit_” at the start to distinguish them from normal data. The userkey is a unique(ish) 1024 bit RSA key the user uses to identify themselves and also serves as the public portion of their signing key. It is base64 encoded and in the text above it is clipped but in reality it is over 100 characters long. Table is compulsory field which designates the subject matter. The created and expires values state when the record was created (must be in the past) and when it will expire. Expired records are no longer valid. These are currently using Unix time, but a more general format will be used in the future. This is followed by a number of values specific to the record type. Finally, the record is completed by a signature which signs the body up to that point (also base64 encoded). The signature is generated using the user key which signs an SHA512 hash of the record (up to that line). There is a hard limit of 2KB per record to prevent abuse.

The separation between the key and the value is either ‘==’ or ‘:=’. These signify if to search for that value, or overwrite the value. When inserting a new record, a search is performed for any records which match all the key/value pairs with the ‘==’ separator. These records are discarded as they are overwritten by the new record. To ensure the correct sequence in cases where an old record is re inserted into the database, the created date is checked. This allows a record to be updated by destroying an older version.

Library

A library (libtidbit) handles most of the complexity of creating tidbits, key handling, communicating with databases and performing queries. Keys are stored in a gnome-keyring. There are also python bindings which make creating plugins simple. Here is partial mock-up of an example use in Rhythmbox:

In this plugin, forming tidbits and passing the out is very easy. Presenting the data is the hard part.

Databases

There are several database backends used in tidbit:

  • Memory database is used to cache recently accessed records.
  • Fork database is not a real database but rather a connection to two, which fetches records from the local database to minimise long distance transactions.
  • D-Bus database is a service which allows several applications to share a single cache, and minimise external accesses.
  • HTTP database is the method used for long distance transactions with the global servers.
  • Sqlite database allows cached records to be saved between sessions.

The default database supplied for libtidbit access is a caching fork of a memory database and a D-Bus connection. The D-Bus service wakes up automatically to connect the applications to the global servers.

There are just three database commands at the moment:

  • Insert to push new tidbits into the system
  • Query to ask for tidbit GUIDs which match a query
  • Fetch to get the full record from a GUID

The GUID is actually the signature and is unique(ish) to each record.

Example

Lets do a 2 minute into of how to create and post a tidbit for a fictional TV application. The following should be the same in both C and Python (although C requires types).

Step 1: Get a key

key = tidbit_key_get ("mytv", "MyTV v1.2");

Here we supply the name of out application twice. The first should never change so we pick up the same key each time, and the second is used for the user agent.

Step 2: Get a database

database = tidbit_database_default_new ();

This gets the default database on the system.

Step 3: Create the record

record = tidbit_record_new ("television/episode");

This creates a new record we can put data into. The table name is compulsory so we supply it here.

Step 4: Add the data

tidbit_record_add_element (record, "series_name", "Ugly Betty", TIDBIT_RECORD_ELEMENT_TYPE_KEY);
tidbit_record_add_element (record, "episode_name", "The Butterfly Effect (Part 1)", TIDBIT_RECORD_ELEMENT_TYPE_KEY);
tidbit_record_add_element (record, "rating", "0.6", TIDBIT_RECORD_ELEMENT_TYPE_VALUE);

Note the difference between the key and value entries (as the ‘==’ and ‘:=’ before). We may change our rating later, so that is a value, and so overwrite the records which match on the keys.

Step 5: Sign the record

tidbit_record_sign (record, key);

Once a record is signed, it cannot be altered.

Step 6: Insert it into the database

tidbit_database_insert (database, record);

Step 7: Tidy up

tidbit_record_unref (record);

Now we are finished with this record, we free it. By now, the record is happily on its way around the world.

Development

If you have interests in the semantic web/distributed hashtables, you have an idea for an awesome application, you found a fundamental error or you just want to have a bit of a play, then the source is available.

Tidbit: A global database for exchanging signed tidbits of information

Social everything

Many of us, use a range of range of so-called Web2.0 services.

  • Social bookmarking which enables you to recommend sites as well as tag sites with relevant words to make searching easier.
  • Microblogging services allowing you to inform your friends (and others) of your status, while attaching tags to the message.
  • Systems which note the music you have listened to recently and share that with the community, recommending other music and events.
  • You can declare yourself as going to an event and check if your friends are too.

This is a system which will keep expanding and undoubtedly within a couple years your bike will send out a message to say you are stuck in traffic which warns your friends that you will be late, while telling others to avoid your route. As you take a photo of the space invader mosaic, your phone will ping out the image with its GPS position to an urban art site with the tag of the artist, while informing you that there is another one just round the corner.

Fear of clouds

Great! The future is awesome! Well, not quite. There are several weaknesses to these systems.

  • Each system requires a sign-up. There are solutions like OpenID which make this easier, but generally you cannot use them anonymously very easily.
  • There are multiple providers for each kind of service, so you may have to keep several profiles up to date and post your data to several services.
  • The data is transferred to the service owners so only one company can make use of it. Users are giving this data out for free, and that’s the way they would like to keep it.
  • Services close. If you have built up a massive profile of contributions with millions of followers and the service dies, you are left with nothing. No you can’t take the data and create your own.
  • Competition is stifled. Imagine that you thought of a system like Facebook but better. Who would sign up for that? There is no chance of cooperation between companies to allow new competitors.
  • It is difficult to queue up data when not connected to the internet. You have to wait till you get home to write a review of that restaurant in Thailand which does great tofu.

So, this “Tidbit” thing?

The principle is pretty simple. You don’t send your data directly to the service provides, but to a distributed open database. Each piece of information is a “tidbit”. Anyone can post, read and search for these tidbits. If you wish to provide a service, you read the tidbits that are of interest to you. No one gets to keep a monopoly on the data and everyone has the opportunity to to use the data to make new inspired products.

Anatomy of a tidbit

Each tidbit contains:

  • Your username. The username is actually your public signing key. You can generate a new one whenever you like and is completely private (unless you reveal your identity to someone).
  • The date the tidbit was created and when it should expire. Most data becomes irrelevant after a year so that is the default unless you set it to be longer.
  • The table the data belongs in. For example “audio/track” would be talking about an audio track you have listened to.
  • A set of key value pairs which hold the data you wish to tell the world. There is no fixed structure so your tidbit can contain fields which will be ignored by some applications.
  • A signature to make sure it was you that generated that tidbit. It is impossible to adjust the data without damaging the signature, so no one can spoof as you.

You can’t trust this

Stop! Reality time! This is bound to be abused by spammers, robots etc, just like the current services, but worse. I can’t trust anyone.

On top of this system, you can extend a web of trust. You can post a tidbit stating your trust of someone. Say you only fully trust the 10 people you know, but they trust 10 more and so on. You might only trust an individual a little (since they are several friends away), but if you combine a whole group of people you trust a bit, you get a fairly sensible picture. You can also partly trust someone who you have only a little confidence in due to information they posted, and perhaps only for some kinds of information (music taste only). Producers of original content are thus rewarded with respect of their audience, while building a network that gives people confidence in the data.

I want my privacy

Privacy is at the core of the system. You may choose to only reveal your username to your friends. Only they will know who you are. All applications work with a different auto-generated username, so unless you manually set your movie watching application to use the same username as your dating profile, you essentially remain as two different people. Obviously, all data you post is open for anyone to read, so posting personal information is a bad idea. This is not a system which sensibly replaces private social networks.

Let’s get technical

The next post will be somewhat more technical and explain the system in glorious geeky detail. There is a git repository you can take a look at and if you have questions there is a room #tidbit on irc.freenode.net, or leave a comment or email me.

Utopiums are back

After months being manufactured, the Utopiums are back! I will explain more about what they are in another post, but for now here are some photos.

Here are the packaged chips (20 of).

They also send you the remaining unpackaged dies. These have an excellent ability of confusing the camera’s auto focus.

The full die is 5mm by 3mm.

And this is what they look like under a microscope. They do get dirty very quickly when exposed to a dusty room.

On the bottom right of the chip logo are the thank-yous. The Tux and the Fedora logo are about 0.5 mm tall (perhaps the smallest ever?). You can see the diffraction grating giving a nice secondary colour.

At different angles, they look very different.

And here is a wise comment left by the one of the Async symposium reviewers.

I am still testing the beast, but it does work. It has executed a number of programs and the wagging slices do become by-passable. The biggest worry was the reset as that is quite complicated, but it seems fine. I will open source the design and the tool set some time next month.

Falling blocks game in Plymouth

So, you have sat down at your computer and you’re waiting for it to boot, then suddenly you realise that it is doing a full fsck which is going to take a few minutes. What to do. You have two options:

  1. Sit quietly watching the little bar move slowly across
  2. Plymouth falling blocks game!

This is not a serious proposal, I just wanted to exercise the scripting system to see if I could find any bugs, but if you want to have a play with it, the script is available.

Fedora on USB sticks

I ordered some USB sticks to give away to the better students to encourage them to contribute to open source software. The idea is that they can run their own installation where they can install development libraries etc. I’ll write more about this in a few weeks when I know how successful this has been.

Installing Fedora on the disks is relatively easy. Nowadays I install computers using a USB drive, by simply DDing the iso directly to the device.

dd if=Fedora-12-i686-Live.iso of=/dev/sdb

The target USB stick will look just like any other hard drive. You just have to make sure you install the bootloader onto the target stick by overriding the BIOS boot order in the grub installation screen.

Once installed, I didn’t want to actually boot the device as I wanted the students to go through the first boot process of setting up a their own user. But I wanted to install some development packages and do a full system update. This can be done by mounting the device, chrooting and running yum commands. The live image has a /mnt/sysimage which is already set up to do something like this by already having /proc and /dev correctly set up.

mount /dev/sdb1 /mnt/sysimage
chroot /mnt/sysimage

The biggest issue with running from USB sticks is that they have no on device cache, thus each fsync command takes absolutely ages. Yum, correctly, makes heavy use of fsync to make sure it leaves the system in a sensible state even if interrupted. To speed things up I tried libeatmydata, which worked surprisingly well. I updated the installation several times faster. LibEatMyData is named thusly because of it’s real ability to screw things up royally, but in this situation if anything went wrong, I could just restart. Maybe some yum devels could mention if this is outright dangerous, or a fairly safe trick if you can guarantee no interruptions.

Of cause at this point I only have one stick installed, and making six this way is out down right boring. So long as the other disks are the same size (or larger), you can clone the disks from one to another. You need a bit of storage space so best to do this from another machine.

dd if=/dev/sdb of=master_image
dd if=master_image if=/dev/sdc
dd if=master_image if=/dev/sdd
dd if=master_image if=/dev/sde
...

Watch out though if you use this method, all the partitions will gain the same UUID, which will confuse the system when more than one is plugged into a single machine.

The postage costs are annoying so I went with play.com, who offer free postage (which is nice). What was ridiculous is that they post each item in a separate box which is way too big. For a tiny piece of plastic, there is a Kingston presentation box, each placed in its own massive cardboard box and posted separately. I hear this is because they have some kind of tax loophole where parcels of value below some threshold are not taxed.

The entire CS department has be refitted with awful Dell machines which have some screwy USB chipsets which allow booting off a memory stick only from the back ports on some manufacturers. I did something really stupid by accidentally mentioning to duty-office that it was possible to boot the departmental machines off a USB device. Now they are now going to go through and disable this feature (Grrr).

Updating your BIOS without Windows or a USB stick

On some of the new lab machines I made, I noticed the CPU clock did not drop when idle. This is usually due to a motherboard not having support for a new CPU, and can be fixed by doing a BIOS update. The really old way of doing this using a floppy disk. This really is not an option, but writing a CD or a USB stick can be as much hassle. Here is a dead easy set of steps to update your BIOS on a Fedora system. The following should be done as root.

yum install syslinux
cp /usr/share/syslinux/memdisk /boot/
wget -O /boot/floppy.img.gz http://www.fdos.org/bootdisks/autogen/FDSTD.288.gz
gunzip /boot/floppy.img.gz

Now edit /etc/grub.conf and add the following lines at the bottom

title Floppy Image
    root (hd0,0)            # Or whatever the other entries use
    kernel /boot/memdisk
    initrd /boot/floppy.img

Of cause the floppy image does not yet contain the flash program or data. To get these you will need to look up your motherboard at the manufacturers website and click on support. Then find the latest BIOS data file. These will be either in a ZIP or an archive EXE. If it is an EXE then usualy you can extract their content without having to resort to Windows. Try using unzip, unrar (available from RPMFusion) and 7za (available in the p7zip package). Gigabyte for example use both rar and 7zip based executables. Once you have extracted it, you should have a flash file (the file extensions on these are completely random) and a flashing program (something like FLASHSPI.EXE or AWDFLASH.EXE). To copy these to the floppy image execute the following:

mkdir /mnt/floppyimage
mount -o loop /boot/floppy.img /mnt/floppyimage
cp {your flash and executable files} /mnt/floppyimage/
umount /mnt/floppyimage/

What you have now is a FreeDOS floppy disk image which can be booted by selecting it in the grub boot menu. Remember the grub menu is now hidden, so keep any key pressed during the boot reach it. Once it has booted (you can press F5 to bypass executing autoexec.bat) simply run the program as instructed by the motherboar website:

flashprog.exe flashfile.123

Happy flashing!

Will’s TV box

Will and Sophie got married last April and the gift list they had was, lets say “disagreeable” (a £30 gravy boat is silly). Luckily Sooty and I had a policy of giving gifts on the first anniversary (should they last that long). I wanted for years to make Will a TV/server box, so this seemed like the perfect opportunity.

Ebuyer had the MSI Media Live bare-bone systems for £120 which is reasonable for a sleek case. Andrew bought one of these a couple months earlier, when I pointed them out, and he had no problems. There were also positive reports about these by MythTV users.

The Athlon X2 issue

Here there was a bit of pain. I ordered an AMD Athlon 5000+ to go into it (it was on the supported CPU list). I plugged it in, and no response. So I take the whole machine to Andrew’s house, try the 5000 in his machine and again nothing, while his 4400 works in mine. Grrrr I think, borked CPU. Got an RMA, CPU was picked up, a replacement arrives a week later. Exactly the same problem. Then I start reading into this more.

Apparently there are two CPUs which have the exact same name (AMD Athlon 5000+ AM2). The newer version is in fact a low end Phenom based CPU which has two cores disabled. This is the only Phenom based chip which goes under the name Athlon X2, so had I picked any other chip in that range, I would have been fine. Most new boards will support Phenoms, but this one does not (even witha BIOS update). So I ordered a 5400 and kept the 5000 to upgrade my own machine (a painfully slow Athlon 1700). On the positive side, that part can be overclocked rather well and one of the cores can be unlocked with a good motherboard.

The machine

The actual box is fine, nothing amazing, but just works. The other parts were: a 1.5TB Samsung F2 disk (I didn’t test the speed but the F3 we have in the office is incredible), 2GB of RAM, a Hauppauge dual DVB-T receiver and the KeySonic wireless keyboard/touch-pad. The keyboard was so good, Andrew decided to buy one for himself to replace the Apple bluetooth keyboard and mouse he was using until that point. Its nice to see the Linux bluetooth support is very smooth. The other day Will took over an hour to bind his new Apple mouse with his Mac laptop. In the mean time I managed to sense the device from the other end of the room and bind with it within seconds.

As an always on machine, it is important to look at the power consumption. The rule of thumb is 1Watt is £1 per year (more like a $1 at the moment). This makes it easy to calculate how much you will save should you go for a lower power part. The TPD (Thermal Design Point) is roughly double to triple the average power consumption. The second thing to look for is the clock scaling. The 5000 I took for my machine scales from 2.2GHz, down to 800MHz (where it spends most of it’s time). This is a very good range compared to my Core2, at work, which scales from 3GHz to 2GHz. The added advantage of having a low power system, is the fans will rarely spin up to their higher speed. Andrew’s machine, which is practically identical, pulls 63W when idle.

The on board video card has a HDMI output, which is connected to the digital audio on the sound card. This is quite common nowadays in on-board cards, but I have also seen ATI cards which have a digital only sound chip on the card for HDMI audio. One shame is that MythTV doesn’t play well with pulseaudio and likes to grab the digital ALSA output. Apparently this is annoying when you want to pause TV and play a YouTube video. I recommend ignoring the digital output as that connects to the television and thatwill probably have awful speakers. Instead use the 7.1 analogue audio system already in the machine and attach it to some reasonable speakers.

Fedora and MythTV

Fedora was happily running on the machine detecting all the devices (although the DVB card requires some extra firmware which is well documented). MythTV has improved in the setup area greatly and installing the Rpmfusion MythTV packages did practically all the work for me. The first TV box I made for myself took about three days to get properly going. The remote was fairly easy too as the new remote control configuration tool works reasonably well and saves you having to search for the appropriate set-up file. One down side of the remote is the ugly windows logo on the middle button. This is easy to change using a torx head screwdriver and a plastic spudger. Andrew has a Fedora logo one, and Will’s one has a Tux.

For a machine that is only used to record and watch TV, 1GB is usually enough, but since the machine will be on all the time it can also be used as a server. On mine I run MySQL, DHCPd, DNS, MLDonkey, Apache, Ping proxy, DNS proxy, Squid (with passive redirection) and a VNC desktop I can log into. Will additionally has a DAAP server and VMware Widnows session just to run something called SoulSeek.  These can chew though another GB.

So far it has been 4 weeks since they started using the machine. No major complaints yet apart from the DVD menu system being a bit poor (I recommend you don’t play DVDs and just rip them to the hard disk). The statistics of my machine are a testament to how useful it is (Number of shows: 1436,  Number of episodes: 11218).

A couple cute Linux games

I spent Christmas writing lectures and I thought I deserved a little break. As a reward I had a brief look though some commercial games available on Linux. I am not all that keen to support closed source development, but the game side of the open source world is sadly relatively weak, and I am pro supporting publishers who develop with Linux in mind. Traditionally, closed source games were a pain to install and would break after updating the kernel or libc (as I found recently when trying to play some). This seems no longer the case. I have gone though maybe 20 demos and all worked out the box on Fedora 12. Here are the two that really stood out.

Machinarium

This is a game by Amanita Design who have been making some fantastic things with flash for years now. One of the best things I have seen from them is a very short game they made for The Polyphonic Spree (who are amazing in their own right) where it became a different way to experience their album.

Machinarium is a much longer and fuller game with vast amounts of detail. You play as a cute little robot who has been discarded in a pile of junk.

The scenery of every screen is fantastically detailed with layered moving foregrounds and animated background characters.

The body of the game is a puzzle adventure. These are often frustrating as you spend hours of your time trying to rub every object against every other object to make anything happen. The puzzles here are, on the whole, rather logical. You rarely have more than four items in your inventory and the game has a fantastic hint system. There are two types of hints, the hint icon simply repeats the obvious stuff you should have noticed. The second hint system gives you a cheat sheet for that screen, only if you pass a level of a mini game. The mini-game is a last resort thing but the cheat sheet is a hand drawn scribble notes explaining the solution in an incredibly cute way. When the robot gets a bit bored he starts day dreaming, giving a short entertaining animation.

Having said that, there were some weird dead ends I ended up getting into. At one point, I needed an oil drum which was offered in a shop. The shop owner asked for moeny, so I spent ages wondering around looking for sources of cash. The actual solution (SPOILER ALERT: of throwing a swarm of flies into his eyes and stealing the drum) was somewhat bizarre.

For $20 (£12.40 in the UK) you get about 4 hours of game-play. If you like this game, you should also try Samorost (Free) and Samorost 2 ($5).

Aquaria

This is not the first time I played Aquaria. It was an addiction of mine a couple years ago, before I removed my Windows installation. This is one of the most engrossing games I have ever played. On the face of it, you basically swim around and solve the mystery Aquiaria. The game is part puzzle mystery, part atmospheric escapism and part arcade shoot-em-up and one of my favourite games of all time.

The swimming comes very naturally and it is a pleasurable experience just to have a bit of a swim though the environment. As the game progresses, you attain more powers, which open up more of the vast map to explore. Unfortunately this was ruined somewhat by one of the final powers, the power to get a boyfriend. I liked Niaja (the main character in the game), she is strong, determined and has kick ass moves. Yet then she falls in love with the most pathetic guy who follows her around, occasionally throwing a fire bolt at some harmless fish and uselessly getting stuck flapping around on every piece of rock you go past. Then he manages to get himself captured and I could never get past the final boss to free him. This is possibly because I suspected the final scene would be them swimming hand in hand towards the sunset while I was screaming at the monitor “NOOOOOOO! You can do so much better! He is not the only fishman in the sea!” (well actually he is, but that’s not the point).

So, as I mentioned earlier, the game can be very hard at points. This can frustrate you if you can’t get past some stage. The second issue is the enormity of the map. The game is sandboxish, which allows you a bit of freedom to the order in which you attain your powers. On the other hand, you can spend quite a while swimming around looking for areas you have not explored.

It is a shame that many people will snub this game for it’s girly overtones. Cookery and collecting recipes features heavily which I found a bit bizarre at first become compelling after a while as you collect ingredients to attain special temporary attributes. I was completely trapped by this game for weeks and enjoyed it immensely.

Aquaria still has not been released for Linux, but the beta has. The free beta version is of the full game with no restrictions (although the site says this is only until mid February 2010), and I have not seen any bugs yet. There is a solid month worth of game-play here and even when the game becomes final, it is easily worth the £13.54 that the Windows and MacOS versions are selling for. I should also mention that the game does use a lot of open source elements. There is a heavy use of ogg/png and the lua scripting language.

Plymouth theming guide (part 4)

This the final part of the theming guide. As I mentioned in the last post, you already know everything you need to write your themes. In this post I will show a couple themes I wrote to explore the system and some fancy high level aspects of the scripting language. You don’t need to know these, they are just a cute method to solve a problem that others may find useful.

Themes

To install these themes, extract them to /usr/share/plymouth/themes and run the appropriate plymouth-set-default-theme line.

Vizta

A very simple theme matching what the Vista theme does. It has just 30 lines of custom code.

http://brej.org/blog/wp-content/uploads/2009/12/vizta

source

Dandelion

This theme has the target of stressing the system. A couple months ago it was running at about 3 fps, now my machine hits 30 fps and spends some time idle.

http://brej.org/blog/wp-content/uploads/2009/12/dandelion

source

Inheritance

When I first proposed doing a scripting system Ray said “If you do this, I guess I’d recommend you keep it very simple”. I agreed, so what I aimed to do was to implement all the features with the minimum space. The solution I came up was to kill several birds with one stone. The stone being an inheritance system.

The important operation for inheritance is the single bar (“|“), inherit operator. Think of it as a very lazy OR function. As an example take the statement:

A = B | C;

This creates a new object (A) which is an inheritance of B and C. A now gains all the properties of B and, as a fall-back, C. There are three ways of using inheritance objects.

Direct

Consider the following statement:

A = "Seven" | 7;
B = String(A).CharAt(2);
C = 80 + A;

So A is an inheritance of the string “Seven” and the number 7. This means when in situations where a string is preferred, it will act as a string, and when the a number is preferred, it will act as a number. The value in B will be the third character in the string (“v”), and the value in C will be the number 87.

This kind of inheritance is used to allow native C objects (images, sprites etc.) to be able to be used as hashes to find appropriate functions to call. An object is created which inherits from the native object and the object template hash (which holds all the functions). The constructor function is also connected to the template using an inheritance. Thus you can treat it as a function, or as a hash of functions and it will adopt the appropriate behaviour.

text_image = Image.Text("string"); # Treat Image as a hash
png_image = Image("filename.png"); # Treat Image as a function

Hashed

Hashes are the main containers in the system. When an object inherits from two hashes, accessing the inner elements will trigger a crawl through all hashes for that element.

A.a = "a";
A.b = "b";   # A: a="a", b="b"
B.b = "B";
B.c = "C";   # B: b="B", c="c"
C = A | B;   # C: a="a", b="b", c="c"

When accessing the elements within C, the system looks within A, then B (also within any object they inherit from). Thus, elements within B can be overridden by A. This is very much like the __proto__ in Mozilla JavaScript.

Functional

Just like hashes, when functions are inherited, the system goes through them in the inheritance sequence, executing each one and moving onto the next if it has failed.

Fib = fun (v) {if (v <= 2) return 1; else fail;}
    | fun (v) {if (FibCache[v]) return FibCache[v]; else fail;}
    | fun (v) {return FibCache[v] = Fib(v-1) + Fib(v-2);};

If you have ever programmed the ML languages, you will already be somewhat familiar with this. In those, you can put constants in the function variable decelerations and functions which do not match these to the passed parameters, fail. Here, at any point in the function, you can choose to fail. The system then tries to execute the next function in the inheritance.

Plymouth theming guide (part 3)

Now the basics have been covered in part 2 of this guide, we can now tackle some more advanced tasks. This part is for beginners to intermediate. If you have never programmed, then this will be a rough introduction to the field and thus you may need to ask for help about some confusing aspects.

Until now, all the examples have been simple assignments and there hasn’t been much “programming”. At the end of the last part, the background image needed to be scaled without distorting the aspect ratio. If the image is wider than the screen, then the image needs to be scaled up to the height of the screen and let the sides hang over the edges. If the image is taller than the screen, the image should be scaled to the screen width and allow the top and bottom to go beyond the edge of the screen.

scale_ratio

You can get the screen ratio using the Window.GetWidth and Window.GetHeight functions introduced in the previous part. The ratio is height to width. The greater the number, the taller the proportions.

screen_ratio = Window.GetHeight() / Window.GetWidth();

GetWidth and GetHeight functions also work on images.

flower_image_ratio = flower_image.GetHeight() / flower_image.GetWidth();

To create the scaled image, the scale factor needs to be determined. If the screen is tall, we make the scale factor such that the image will be the same hight as the screen, and allow it to dangle off the edges. For a wide screen, make the image match the width and allow the top and bottom to go beyond the edges. The scale factor can then be used to scale the image width and height.

if (screen_ratio > flower_image_ratio)
  {  # Screen ratio is taller than image ratio, we will match the screen height
     scale_factor =  Window.GetHeight() / flower_image.GetHeight();
  }
else
  {  # Screen ratio is wider than image ratio, we will match the screen width
     scale_factor =  Window.GetWidth() / flower_image.GetWidth();
  }
scaled_flower_image = flower_image.Scale(flower_image.GetWidth()  * scale_factor,
                                         flower_image.GetHeight() * scale_factor);
flower_sprite = Sprite(scaled_flower_image); # Create the a sprite using the scaled image

Now the image is scaled to the correct width and height, it needs to be placed in the centre of the screen.

flower_sprite.SetX(Window.GetWidth()  / 2 - scaled_flower_image.GetWidth()  / 2); # Place in the centre 
flower_sprite.SetY(Window.GetHeight() / 2 - scaled_flower_image.GetHeight() / 2);
flower_sprite.SetZ(-10000); # Place right at the back

mytheme_placed

If everything went right, your code should look like this:

flower_image = Image("flower.png");

screen_ratio = Window.GetHeight() / Window.GetWidth();
flower_image_ratio = flower_image.GetHeight() / flower_image.GetWidth();

if (screen_ratio > flower_image_ratio)
  {  # Screen ratio is taller than image ratio, we will match the screen height
     scale_factor =  Window.GetHeight() / flower_image.GetHeight();
  }
else
  {  # Screen ratio is wider than image ratio, we will match the screen width
     scale_factor =  Window.GetWidth() / flower_image.GetWidth();
  }

scaled_flower_image = flower_image.Scale(flower_image.GetWidth()  * scale_factor,
                                         flower_image.GetHeight() * scale_factor);
flower_sprite = Sprite(scaled_flower_image); # Create the a sprite using the scaled image

flower_sprite.SetX(Window.GetWidth()  / 2 - scaled_flower_image.GetWidth () / 2); # Place in the centre
flower_sprite.SetY(Window.GetHeight() / 2 - scaled_flower_image.GetHeight() / 2);
flower_sprite.SetZ(-10000); # Place right at the back

If you wish for your background to match the one in your desktop, copy it to the theme directory and edit the script to load the image of that filename. Only PNG files are allowed.

mytheme_constantine

Finally to install your theme into the ramdisk, so it is loaded when your computer starts, add –rebuild-initrd to the plymouth-set-default-theme command. Do be careful not to install a theme which deadlocks. Make sure you have a backup kernel or initrd image if all goes wrong

plymouth-set-default-theme mytheme --rebuild-initrd

Animation

Start by making a new sprite with an image of a butterfly:

butterfly_image = Image("butterfly0.png");
butterfly_sprite = Sprite(butterfly_image);

animation_step1

At the bottom of the block of code you are editing, there is a function named refresh_callback. This is called 50 times a second (unless the system is busy) just before refreshing the screen. Within the function, you can move the sprites around and these movements will be updated on the screen. Take a look at this example:

progress = 0;
fun refresh_callback ()
  {
    progress++;
    butterfly_sprite.SetX(progress);
  }

animation_step2

At every refresh, the butterfly will be moved one pixel to the right. To make the butterfly flap it’s wings, several frames are needed. Instead just loading one image, this requires an array of images to be loaded. Replace the original two lines that loaded the butterfly image and created the sprite, with these:

for (i = 0; i < 4; i++)
  butterfly_images[i] = Image("butterfly" + i + ".png");
butterfly_sprite = Sprite();

You can append strings to numbers to create the four filenames. Secondly, if a sprite has not been attached to an image, it will simply be empty until one is set. Adding the following line into therefresh_callback function should rotate through the 4 butterfly frames. Because the progress is divided by 6 in order to slow the animation to one frame every 6 refreshes, we use a Math library function to round down a number to an integer.

butterfly_sprite.SetImage(butterfly_images[Math.Int(progress / 6) % 4]);

animation_step3

There are some other math functions available, sin and cos are often useful. Replace the SetX line with the following to make the butterfly go around in a circle around the centre of the screen.

theta = progress / 100;
butterfly_sprite.SetX(Window.GetWidth() / 2 + Math.Sin(theta) * 200);
butterfly_sprite.SetY(Window.GetHeight() / 2 - Math.Cos(theta) * 200);

animation_step4

Now the butterfly looks a little weird pointing the wrong way as it is going around in a circle. We need to rotate the butterfly image so it is flying forward. Add .Rotate(theta) to the image while setting it to the sprite. This creates a new image which is rotated by the angle theta.

butterfly_sprite.SetImage(butterfly_images[Math.Int(progress / 5) % 4].Rotate(theta));

animation_step5

If you have reached this point, you should now have all the knowledge you need to start creating your own themes. For a full list of available functions and script syntax take a look at the freedesktop plymouth script wiki. Good luck, have fun and make some nice splash screens.