Oracle
After being aware of it for along time, today I finally had a brief look at Oracle's RDF support in 10g. I was really hoping that Oracle would bring their experience in developing database structures to the RDF domain, creating something very fast and scalable.
Unfortunately, it appears that 10g implements RDF as a schema in a set of standard relational tables, and have wrapped access to the system within Sesame interfaces, including SAIL. There's nothing wrong with building a Sesame system with an Oracle backend, rather than MySQL, but this isn't the Oracle system that I was hoping for. It doesn't bring in the extra efficiencies needed to make RDF really move. After all, RDF has a strict shape to the data, while a RDBMS needs to handle data of all kinds of shapes. This is why Kowari has such fast load times (when configured correctly).
Interestingly, the paper which describes the details of the system references Kowari. I was surprised at this when I read marketing phrases like:
Oracle Spatial10g release 2 introduces the industry's first open, scalable, secure and reliable data management platform for RDF-based applications.
Kowari was open, scalable, and reliable (to the best of my knowledge), and TKS was secure (one of the reasons for buying the commercial system over the Open Source Kowari).
Another quote says:
A key feature of RDF storage in Oracle is that nodes are stored only once - regardless of the number of times they participate in triples.
The wording here suggests that Oracle is unusual in this regard, but almost all the RDF systems I am aware of share this feature, including Kowari. Perhaps the multiple indexing in Kowari caused some confusion here?
It appears that RDF support by Oracle has been implemented at the highest layers by RDBMS programmers. While it undoubtedly works, I'm disappointed that they haven't implemented RDF at a lower level. Still, it would be interesting to see how many triples a second it can load.
Free Lists
Now that I've discussed the principle behind phases, the next step is to discuss the classes which support this process. At the lowest level this is the class called FreeList. This class manages resources which are allocated and/or released in various phases. It enables new resources to be created as needed, and freed resources to be re-used efficiently.
The kinds of resources managed by the FreeList class are all the fixed-length records within data files, and also the numeric identifiers used for RDF nodes. The name of the class is an historical holdover from when it was simply used to hold a list of items which had been allocated and then freed. It does a lot more now.FreeList sits over the top of two other classes called BlockFile and IntFile, both of which are relatively easy to describe. Unfortunately, FreeList itself will take me some time to write about, and a late night is not the time to start. So I'll get into it in my next entry.
Tuesday, February 14, 2006
Monday, February 13, 2006
Files
With work and the move keeping me busy it's been a while since I last looked inside Kowari. To kind of ease myself back into it, I thought I should finally get around to writing some notes on the Kowari file system.
Phases
At all levels of abstraction inside the Kowari file system, the concept of phases keeps appearing. Phases are a way to keep track of a constant state in the system, regardless of any write activity that may be occurring. They are also used to serialize write access from different connections. While this does enforce consistency in the data on disk, the inability to allow multiple parallel writers is a current weakness in Kowari. (This is the principle reason the XA2 file system has been proposed).
Phases were borrowed from the TUX2 filesystem. In this approach, all data is laid out in a tree, with pointers going down from parent nodes to child nodes. This is a common pattern for data storage. (When I get OmniGraffle working again I'll put in a simple diagram of a tree here).
When a change needs to happen to a node in the tree, then that node is first copied to one side. The new copy contains pointers to the same children as the original node. Then each ancestor of this node is copied recursively, all the way up to the root of the tree. Each new parent node will refer to the copied child, but all the other children will be the same as the original node. The result is a pair of roots to two trees which are indistinguishable from each other, and which share many of the same nodes. (This is where I really need the diagram).
At this point, the new nodes can be modified without affecting the old tree. If modifications are required on any nodes in the old tree, these nodes can also be copied, along with all the parents up to an already copied parent. As soon as a node is found that has already been copied, then the existing copy can be adjusted to point to the new child node.
Once the write operation to the tree is complete, the old root will refer to the tree before the write, while the new root will refer to the tree after the write. The old tree was never touched, so it is guaranteed to be completely consistent. Once the new tree has been completely written, and is in a consistent state, then both trees will be completely consistent. That means that it is safe to use either root of the tree, without fear of power blackouts, OS crashes, etc.
At this point, a single number which holds the address for the current root of the tree can be updated. This can be performed atomically on any hard drive. Even if the power fails, every hard drive available today has enough capacitance to complete the write operation of a single block.
To guarantee an atomic write like this (ie. to guarantee a consistent tree on disk) the host operating system has to allow a force operation to disk. This is supported in Java, which in turn relies on the file system API of the underlying operating system. It is concerning that some operating systems have been known to postpone "force" operations (eg. Mac OSX), but this is a matter that is out of the control of user level code. Fortunately, the conditions required for this to cause a problem are far less likely to occur than the likelihood of hardware failure, so the risk is manageable.
Note also that the new root of the tree can be abandoned at any time with no consequences for the original tree. All that is required then is the ability to clean up or recover all the copied nodes created for the abandoned tree.
A new root to a tree as described here is called a new phase. Selecting a phase to be the new primary root of the tree, is known as committing the phase. Committed phases are always in a consistent state, removing the need to journal modifications.
Another feature of phases is that at any point in time a phase may be "kept" for reading. Any future modifications will start up a new phase (creating a new root to the tree). This means that it is possible to keep multiple phases active at any time, with each phase representing a "snapshot" of the data in the tree at the time that phase was kept. This is important for multiple readers to be able to get the latest available data while a long write operation is continuing. To ensure that the snapshots are kept consistent, they must not be modified. This means that only the most recent phase may be written to.
This describes Kowari's inability to allow multiple writers. However, this strategy is done to ensure that Kowari has a completely robust filesystem that is efficiently capable of withstanding any error, including the sudden removal of power. While speed and robustness are important, enterprise systems also require multiple concurrent writers. This has led to the plans for XA2.
XA2 will allow for multiple writers, but this in turn will require a form of journaling. Journaling is less efficient than phase trees, but we expect to gain in other areas of efficiency, making the overall performance even better. The system is more complex than the phase trees discussed here, so I will leave discussion of this for another time.
Posted by
Paula
at
Monday, February 13, 2006
0
comments
Thursday, February 09, 2006
Landed
I resisted the title "Sweet Home Chicago", as I'm sure everyone who has ever moved here has said that. :-)
We got through the flight successfully, though we didn't get much sleep. It's harder to sleep when looking after children who aren't sleeping much either. Luc was amazingly well behaved. It was only in the last couple of hours that he started getting hyperactive (maniacal laughter, treating everything as a game, getting into everything, etc). Fortunately there were no tears or tantrums. Nic just slept.
Membership of the Qantas Club was wonderful at LAX. We got internet access (so I could confirm the flight time with JohnN at work), but more importantly, they had a room specifically for children. So we got a little private space, and Luc got to play with Tonka toys while watching Nickelodeon. Compared to sitting on a crowded concourse it was a little slice of heaven.
JohnN picked us up at O'Hare airport, and drove us into town. We had a lot of bags, so I'm glad we didn't have to arrange our own transport. I was also glad to have someone else driving, as it started snowing when we arrived. I've been in snow, but almost never seen it falling, so it was nice to see (though I'm sure the locals didn't enjoy it).
The apartment is minimally set up, which has been enough for the first day, but we need to get out and buy things like shelves if we want to stop living out of suitcases. We also need to buy some good cold-weather clothing for the boys, as they don't have enough. Frustratingly, most places have sold out, as they are bringing in the new season in preparation for Spring.
So yesterday and today are being spent shopping for essentials. I'm just grateful I don't have to deal with work, as I'm still suffering pretty badly from jet lag.
Wireless
The apartment came with cable access for the internet, but the company hadn't got around to brining over a wireless router. Fortunately, I had my AirPort Express with me, plus an extra US power adapter, so I plugged it in expecting it to all work.
While connecting the modem directly to my notebook worked fine, I couldn't make it work with the AirPort. The notebooks could connect to the AirPort just fine, but all routing stopped at that point, and there was no DNS.
I tried changing every setting I could think of, including setting the IP details statically to the details obtained when I plugged the notebook in directly. But the AirPort kept acting as if the ethernet was not there at all. I finally reset everything to what I thought it should have been (the settings I'd originally used, and then disconnected power to both the AirPort and the cable modem. 30 seconds later everything worked.
This isn't the first time I've seen certain devices fail connecting to a network, but not others. I wonder who was at fault in the protocol here... the AirPort or the cable modem?
Posted by
Paula
at
Thursday, February 09, 2006
1 comments
Monday, February 06, 2006
Stress and Moving
This is probably my last entry from Australia for the time being. We've just spent the last few days in a mad scramble trying to finalize the things we thought were already done, or easier to complete than they really were. I hope we're near the end of it.
Tomorrow morning will see the moving company arrive, and take almost everything we own. We won't see any of it again for at least 8 weeks. We were told 8-14 weeks, so I'm expecting that it will really be around 16 weeks. Then off to a hotel, and onto a flight the next morning. It's a 12:10pm flight to LA... meaning that we have to check in no later than 9:10am! Sounds excessively early to me, but I suppose they need that to deal with the conditions set out at LAX.
In the meantime, we've been running all over town managing accounts, banks, and insurances. I've also had to spend a significant sum on travel insurance to cover us until my medical insurance becomes valid in April. This wasn't easy, as most providers won't handle people taking one-way trips. It had to be travel insurance, as we needed to be covered in case of problems on the trip, particularly if something happened to my notebook computer. Unfortunately, the only "one-way" insurance I found does not cover computers (only cameras), so I had to spend another couple of hundred to cover the computer as well. It all adds up, and I don't expect to see my credit card reimbursed soon. I'm going to be in a lot of debt for a while on this one.
Luc seems to be dealing with everything very well, and is still happy most of the time. I'm very grateful for this. He still needs his attention, so it can get difficult on occasion. Nic is as happy as ever. Anne and I are both very tired, and I'm looking forward to it all being over.
We've been told that we'll have internet access when we get there, so here's hoping I can get online quickly once we do.
Posted by
Paula
at
Monday, February 06, 2006
1 comments
Friday, February 03, 2006
Drowning
The visas finally arrived, and now I can do all the last minute things I have to get done before leaving Australia for good. The power will go off at the appointed time, as will gas, phone, internet, etc. Annoyingly, I can't cancel my mobile phone until I want it cut off, so I'll have to wait until the appointed time. I'll do that from overseas, as I'd like a bit of overlap so I can continue to make calls.
More frustrating is my health insurance. The Australian government gives a small subsidy to private health insurance but this is reduced if you spend any time after turning 30 without private cover. Because of this, I can only cancel my account without future penalties if I show my travel itinerary at an office. I have the itinerary now, but I'd rather not have to travel in.
My main problem at the moment is that I'm swamped with paperwork. Flights (obviously), visas (done, thank goodness), mail redirection (sorted), insurance (travel, landlords, shipping), mortgage (refinanced because the CBA would be a nightmare to deal with from the USA - they're bad enough in Australia), shipping forms, customs declarations, car sale, and rental documents. In the midst of this, our printer has decided to start mangling paper, so all those PDF documents I've been sent to fill in aren't helping.
Most of it takes a little time, but my "Supplemental Declaration for Unaccompanied Personal and Household Effects" form has one sticking point. It requires my "Resident Alien No." only I know nothing about this. My visa isn't forthcoming, and I have no other documents.
The visa has a 14 digit "Control Number" on it, but that seems to be a different number altogether. I found a document on the web (an application for info form at Sandia) which asks for both the Visa Control Number and the Resident Alien No. There is also an 8 digit number in red on the visa, but it's completely unlabelled, so I don't know what it might be. Google was surprisingly unhelpful in this regard. The best I've been able to do os to find the same form provided by other shipping companies, with all of them saying that the questions should be "self-explanatory". Great.
While writing some of this, my brother has come online and has started explaining some of it. I knew that I have to apply for an SSN once I get there (why not make it a part of the visa process?), but I didn't know that I also need to get a "permanent residence card". He also told me that he didn't get his "Resident Alien Number" until he'd been living there for a few months.
I'm starting to get confused about how I can actually move to this country. Is it possible?
Work
Unsurprisingly, work has slowed right down now, though I'm still trying to keep my hand in.
Someone had a problem the other day about using decision trees. They weren't scaling all that well (they scale by log(n) obviously), and he was trying to pick up some scalability from somewhere. He thought of breaking the tree into several subtrees, which might make the structure more manageable, but still requires the same number of decisions.
I started thinking about the first decision, which determines the sub-tree to go to. It occurred to me that several layers of decisions could be merged into a single "hashcode", which then finds the tree through a hash map. This tries to trade time for memory (less time for decisions, but more memory in the hash table). It's possible to go this route, but it requires careful merging of the data into the hashcode. If each of the elements going into the code require a test of some sort, then the number of tests to find the final data will not change. It's one of those things where you really need to see the shape of the data involved to see whether or not a particular optimization will work.
Merging data into a single "hash" is kind of like representing each of the elements of the data as separate dimensions. The hash code then leads to a point in N-dimensional (N-D) space representing the data you have so far. Using the hashcode to find the decision tree to use, means that these trees represent the work to be done for various regions of N-D space. This then brought me back to neural networks, as this is similar to how they are modeled.
This made me realize that in some ways a hash table can act like a neural network. The main difference here is that neural networks are forgiving for unexpected data. Hashtables can only be made to work this way if they can cover all allowable points in space. If the space isn't sparse, then that means that the hashtable might as well be an array - just so long as there is a way to map co-ordinates to something.
Anyway, it has me thinking that I might have to pull out some neural network algorithms, dust them off, and have a go at applying them to some of our problems in document categorization. I haven't used them in years, so it will be a real blast of retro for me.
RDF
In the meantime, it's about time that I look at RDF again. I still plan to use Kowari (since it's under the MPL, and that can't be changed), but while NGC are making things awkward I've been considering other routes. I'm tempted to use Sesame for a while, to learn more about it if nothing else. However, I'm not sure that I can make my thesis work in this framework, so I still need to look at other options.
I've been thinking of having a go at DavidM's skiplist code, to see if I can use it as the core to a new storage layer. If that works out, then I can start building some of the other layers on top, avoiding the problems that have had to stay in Kowari for historical reasons. Many of the top layers in Kowari were developed (as open source software) in the last year, so these can be transplanted easily.
I don't pretend that this would turn into a fully fledged RDF store (at least, not without a lot of time and help), but it could be a useful exercise. It would be enough for what I want to do OWL inferencing anyway. It might also go a bit quicker than Kowari, since I've already done a lot of this stuff once before! :-)
I'd rather work with Kowari (for the time being), but at least this way I don't have to worry about NGC interfering. It also starts introducing the skip list code that Kowari has needed for some time.
I'll see if I get any time for this in the coming week. It may be hard. I can't even do much on the plane, as we will be watching two young children. Still, it doesn't hurt to keep thinking these things over.
Posted by
Paula
at
Friday, February 03, 2006
1 comments
Tuesday, January 31, 2006
1 Day Processing
As expected, bureaucracy is alive and well at the US consulate. Since we were told that processing would take 1 day, we thought that flying 9 days later would be safe. Unfortunately, this was not the case.
The original plan had the movers packing for us tomorrow, moving us out on Thursday, and us flying on Friday. However, I've been putting off canceling utilities, paying for the flight, and confirming the movers until the visas arrived. We expected the paperwork yesterday (Monday), and accepted that they might get delayed a day (Today), but still nothing is forthcoming. So once 5pm rolled around we called everyone up and postponed until next week.
Other than the annoyance of waiting longer before we travel, the postponement did reduce some of the pressure initially (especially for Anne). However, it has caused a whole new set of problems. For instance, our mail starts being redirected this Friday, and requires 5 days notice to change (along with a fee). If the visas haven't arrived before the redirection, then they won't get here at all! This is because they are being sent via the Australia Post overnight courier service, which shows up with the mail.
I don't think Express Post items get redirected like normal mail does. Instead, they will be returned to the sender - in this case, the consulate. I think I'd have more luck getting the documents if they followed the redirection to Chicago.
The movers are booked solid next week, so they're coming tomorrow anyway. I'm not sure how we'll get by with everything packed up: plates, cutlery (or flatware), summer clothing, etc. But we'll have to make do.
In the meantime I'm trying to work, but my productivity is steadily declining this week (it wasn't too bad yesterday, wasn't too good today, and I expect it to be non-existent by tomorrow). As such, I don't think I'll be writing much on technical topics for a few days.
Posted by
Paula
at
Tuesday, January 31, 2006
0
comments
Friday, January 27, 2006
Visas
Anne, Nic and I flew to Sydney on Wednesday to visit the US consulate. This was to present our paperwork, and attend a 5 minute interview in order to get our visa. The rules said Anne had to be there, and Nic naturally has to be with Anne. Luc got to stay with his grandparents for the day. Refer to Anne's entry for his day. (That reminds me... I need to tell her to use JPG instead of PNG. Even with low compression the photo is 1/4 the size).
I can only presume everything went well, as they said we would have our paperwork back in a couple of days. This is sure to be delayed an extra day with the Australia Day holiday on the Thursday.
I can't say I enjoyed the process very much. We had to be up at 4:30am in order to get our flight, and we needed to go through security at the consulate early enough to make our "appointment", which was set at 10:30am. What really happened, was that we cleared security with 5 minutes to spare, and then waited in line for several hours before being called up. At that point our documentation was inspected and filed, and we were asked to take a seat again, until the interview.
At this point we've been in there for several hours, having drunk a couple of coffees to help deal with the lack of sleep (Nic is a good sleeper, but he's still a 10 week old baby and needs feeding overnight). We were in a room where all the staff are behind thick glass (why are they so paranoid about security then?) and the only way in or out is a thick security door. The nearest accessible rest rooms were 59 floors away, and on the other side of security. This made for a very unpleasant wait.
Babies being as they are, Nic needed changing after a couple of hours, so Anne took him downstairs and back through security again. Coffee being as it is, I was obliged to follow soon after. I was lucky, since I got back just in time for the interview. Five minutes and $520 later, and it's all over. We grabbed a bite to eat, caught a train back to the airport, waited on the tarmac while they fixed a faulty fuel pump, and came home.
Time from leaving the house to getting home again? 14 hours. What a waste of a day.
Posted by
Paula
at
Friday, January 27, 2006
2
comments
Monday, January 23, 2006
Syntactic Sugar
I really like some of the new features in the language for JDK 1.5. Generics, autoboxing, and annotations can make code easier to write and maintain. However, Java has implemented a number of these simply as syntactic sugar, rather than as a real change to the environment. This was important for maintaining compatibility, but sometimes it gets annoying.
While looking for a bug today (it turned out to be a typo that happened to compile) I decided to print out various forms of Unicode. These included a char[], a Character[], and a List<Character>. The code to print these used the new looping construct:
void print(char[] c) {
for (char x: c) System.out.print(x);
System.out.println();
}
void print(Character[] c) {
for (Character x: c) System.out.print(x);
System.out.println();
}
void print(java.util.List c) {
for (Character x: c) System.out.print(x);
System.out.println();
} Notice how the difference between each method is trivial? If Java used templates in a similar way to C++, then this would be one method. Yes, I know the compiler creates 3 methods in the binary. But why would I care about code redundancy on that scale when Universal binaries make duplicates of every piece of executable code? These days we need space for data, and almost never for code (even embedded applications typically have megabytes available to use).So generics are nice, but when they can't be used in methods like these, they feel too restrictive.
The other thing that bothers me, is that the only way to describe management of an array is to create static methods that take arrays as parameters, and/or return arrays. Java arrays have no inherent extensibility. Sometimes I find that it would be useful to complement certain classes with another class that holds an array of the first class. Unfortunately, these classes are not compatible with real arrays. At least lists are there to take up some of the slack, but
ArrayList can only get you so far.I'm probably just a little sensitive to the inflexibility of arrays, as I've been (finally) learning some Python, where life is definitely better for arrays. I therefore found it amusing that one of my responses to the sort/unique problem of the other day was from Stephen where he showed of his 1337 h4x0r skillz with Python to solve the problem in 2 lines using built-in language features. Maybe I should be moving to Jython. :-)
Family Life
Anne has recently decided to put up a web page on our domain. She's using iWeb and I've been impressed with how quickly she was able to put together a site that looks reasonably attractive. I just hope it doesn't look like the web site of everyone else who uses iWeb. :-)
This will only be of interest to people who know us personally, as it is very focused on our family. I have no control over content, though I have been encouraged to read it myself. I think Anne just wants someone to proof read. ;-)
Posted by
Paula
at
Monday, January 23, 2006
1 comments
Thursday, January 19, 2006
Unicode
In my last post I was converting arrays of char into arrays of java.lang.Character. However, under Java 1.5 this runs into a new problem.
In Java 1.4, the Character class was based on Unicode 3.0, which defined Unicode characters in a 16 bit space. In Java 1.5 this has been revised to Unicode 4.0, which defines Unicode in a 21 bit space. Unfortunately, the 1.4 implementation of Character wrapped the 16 bit char native type, and is not extensible enough to deal with Unicode 4.0.
Instead of creating a new class to deal with this, Character has included a new set of static methods to work with the larger characters. The result is a little messy.Character now works with 32 bit integers, which it refers to as CodePoints. Most of the static methods which take a char have been duplicated to accept an int as a CodePoint. This all works from the perspective of the static methods, but there is no longer a class that represent a complete Unicode character. The closest available is java.lang.Integer, which is fine for storing the value, but has no support for character operations.
I first realized this problem when I tried to convert from a String.toCharArray() into an array of Character. The new Character class has a static method for reading from a Unicode character from a char[], which holds characters in UTF-16 format. This made me wonder if the char[] from String.toCharArray() were actually being returned in UTF-16. This isn't explained explicitly, but the documentation for String indicates that the result is in UTF-16.
UTF-16 refers to an array of char where most Unicode characters (or CodePoints) fit into a single char or Character. However, if a character falls into a particular range, then it is not a complete Unicode character on its own, but instead it is merged with the following char to form a full 21-bit value. A pair of characters like this is called a surrogate pair.
Since an individual char is no longer guaranteed to represent a complete CodePoint, it is not possible to sort an array of char or Character as previously described. Instead, each character has to be decoded into a CodePoint first, and the array of CodePoints can then be sorted. Only there is no such object as a CodePoint, so an array of Integer has to be used instead.
But what about the method to convert a char[] to a Character[]? This now needs to be updated to convert a UTF-16 char[] into and array of objects which are large enough to handle full CodePoints. There also needs to be a corresponding method to convert back to a UTF-16 char[]. With all this work, why not create a new class for CodePoint, which includes these methods, plus all the methods appropriate to manipulating CodePoints?
Again, all the iterative code can be encapsulated in methods to hide the details, but now these methods can be attached to the object in question. This time the code is more complex, as it needs to test each character to see if it is part of a surrogate.
I've coded most of the CodePoint class, but I still have to bring over a few of the static methods from Character and make them instance methods on CodePoint. There are a LOT of methods, so I don't see myself writing tests for all of them. Maybe I'll have a go if other people are interested.
This may be overkill, given that only a few languages need characters which fall into the surrogate range. All Latin based languages are completely covered by char and Character. However, all it would take would be a single extended character to break an application which didn't handle all CodePoints. We've had comments about appropriate Unicode support for Chinese characters in Kowari before, so it's a legitimate concern.
Posted by
Paula
at
Thursday, January 19, 2006
2
comments
Loops Considered Harmful
Yesterday someone from work told me that he was trying to take all the characters in a java.lang.String, and return a string containing a single instance of each of those characters, in sorted order.
He had some straightforward code to do the work, but he had used a boolean array of ASCII bytes, and couldn't handle UniCode chars. In my cleverness, I wanted to show him how to do the work in 2 lines of code, only I immediately started running into limitations within Java.
Why two lines? Well it should be possible to put the contents of a string into an object that can sort them and remove duplicates, and then pull this data back out and put it into a new string. Learning Lisp I've learnt to expect the sort of functionality needed to do this simply and easily. There shouldn't be a need to iterate over the characters, recording the ones in use, and manually sorting. The data being manipulated should be a single "entity", rather than arrays of elements that require iterative techniques to manipulate. This functionality should all be available, making the final function a trivial call to just a few methods. As Abelson and Sussman said, "Programs must be written for people to read, and only incidentally for machines to execute." Iteration, sorting, and other mechanical operations should all be services found in lower levels of the code, and abstracted away.
Incidentally, this is exactly the sort of thing that is done all the time with the STL in C++. Because all of the collection classes (and arrays) meet the required interfaces, then almost any data type can be used in any position. All you need here are algorithms for sorting and removing duplicates, feeding in a string and getting one out the other side. Admittedly, C++ contains language features which allow significant abuse (and I've seen it abused quite badly), but it also allows for some very elegant code. Since C++/STL is an "unsafe" language offering some of the functionality you expect to see in Lisp, then this brings to mind the quote from Philip Greenspun: Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified bug-ridden slow implementation of half of Common Lisp.
Back to Java, the obvious way to handle a problem like this is with a java.util.SortedSet (the only implementation of this in java.util.* is TreeSet). I just had to get the characters out of the string, insert them into the SortedSet and get them back out again, in String form. You'd think this would be easy, but I encountered several problems, showing up problems in the Java libraries, and even the Java language.
The String, the characters retrieved from it, and the sorted set of characters should all form "entities", which are simply different representations of exactly the same data. Since Java and its libraries expect each of these representations at different times, it should be easy and trivial to go from one representation to another. However, this isn't the case.Strings can provide their contents as an array of char. However, these SortedSets need to take objects as their basic elements. (I understand why the language is built this way, but it still frustrates me that I can't declare a SortedSet<char>.) The object that wraps a char is java.lang.Character, so the array of chars will need to be converted to Characters before they could be put into a SortedSet. Also, since we want to treat the data as a single entity, we want to avoid iterating through the data, and instead insert the entire entity into the SortedSet. This means converting a char[] into a Character[].
Autoboxing
While Java 5 now supports autoboxing between native types and their associated objects, there is no way to convert an array of a native type into an array of associated objects. Since arrays are a part of the language, and not an accessible class, there is no way to extend arrays into doing this either. Instead, a loop must be written to iterate through one array, converting the elements to the types in the other array. This is an easy thing to do, but it's the kind of fundamental operation that should be found in a library, rather than being re-implemented by every developer.
So the first thing I had to do was write a method to autobox a char[] into a Character[] and another method to unbox it back again. These are quite trivial:
private static final Character[] toCharacters(char[] chars) {
Character[] characters = new Character[chars.length];
for (int i = 0; i < chars.length; i++) characters[i] = chars[i];
return characters;
}
private static final char[] toChars(Character[] characters) {
char[] chars = new char[characters.length];
for (int i = 0; i < characters.length; i++) chars[i] = characters[i];
return chars;
}So this will create an entity that holds all of the characters in java.lang.Character objects, rather than the char values that come from a String. Unfortunately, Java arrays are not compatible with the collections classes (unlike other languages, like Python, or C++ when using the STL), so the array needs further conversion still. This time there is a utility to convert an array into a collection-compatible object, called java.util.Arrays.asList(). So now I can finally put the string into a SortedSet:SortedSet charSet = new TreeSet<Character>(
Arrays.asList(toCharacters(inputString.toCharArray()))); The java.util.Collection interface also specifies the toArray() method for converting the collection into an array, so it is possible to move back this way as well. However, the String class still needs to work with char rather than java.lang.Character, so the array unboxing method above is needed to convert this way:public static String sortedWithoutDuplicates(String inputString) {
SortedSet<Character> charSet =
new TreeSet<Character>(
Arrays.asList(toCharacters(inputString.toCharArray())));
return new String(
toChars(charSet.toArray(new Character[charSet.size()])));
}It's still disappointing how ugly this looks at the end. The first line has two more method calls than it should need:toCharacters()to convert thechar[]frominputString.toCharArray()to aCharacter[].Arrays.asList()to convert theCharacter[]to aList<Character>
String.toCharacterArray(). With just those two changes the first line would instead be: SortedSet<Character> charSet =
new TreeSet<Character>(inputString.toCharacterArray());Similarly, the second line has some ugliness to it as well:java.util.Collection<E>defines the methods:<T> T[] toArray(T[] a)Object toArray()
Character[], but this means we need to create the array manually before calling the method.toChars()to convert theCharacter[]into achar[]for theStringconstructor.
Object toArray() method had be redefined into: E[] toArray(). I can't see why this change wasn't made with the release of generics, since E[] is still a valid Object[], and the other method got redefined this way when generics came out. I'd also like to see String accept a Character[] in a constructor, in the same way I'm looking for a String.toCharacterArray() method. These changes would make the second line look like: return new String(charSet.toArray());So my fictional extensions would turn the three methods above (toCharacters(), toChars() and the mess in sortedWithoutDuplicates()) into the following single method:public static String sortedWithoutDuplicates(String inputString) {
SortedSet<Character> charSet =
new TreeSet<Character>(inputString.toCharacterArray());
return new String(charSet.toArray());
}As a postscript, I should explicitly point out that I don't think that the constructor for TreeSet<Character> should take a String, nor should a String constructor accept a SortedSet<Character>. These operations are too specific to the described task, and do not merit inclusion in a standard library. In particular, they would only apply if the wrapped type of the SortedSet is Character, and would break down on other types.Why would I make suggestions about modifications to the standard libraries? While we have to work with them, we shouldn't just lie down and accept the shortcomings of Java. It doesn't happen all the time, but Sun do listen to suggestions on the language and libraries, particularly when suggestions extend the standard libraries without breaking them. Also, if they ever release Java as open source software, then we will have an opportunity to make contributions which may even get accepted.
Posted by
Paula
at
Thursday, January 19, 2006
14
comments
Saturday, January 14, 2006
Universal Binaries
Now that Macs are finally available with Intel chips, it occurred to me to give serious consideration to Universal Binaries. I never considered it a big deal, since XCode handles that for you. But all my recent binary code (non-Java) has been built with Makefiles so it can be compiled for multiple platforms. So I thought I'd better learn how to do it from the command line.
My first thought was that gcc might have some sort of "Mac-universal" option for the -arch flag. The man page says:
-arch arch
Compile for the specified target architecture arch. The allowable
values are i386, ppc and ppc64. Multiple options work, and direct
the compiler to produce ``universal'' binaries including object
code for each architecture specified with -arch. This option only
works if assembler and libraries are available for each architecture
specified. (APPLE ONLY)
I naively thought that -arch i386 -arch ppc would work. However, the result was just a PPC file. The man page for ld had the answer for this: The link editor accepts ``universal'' (multiple-architecture) input
files, but always creates a ``thin'' (single-architecture), standard
Mach-O output file.
...
Only one -arch arch_type can be specified.So how were universal binaries made if the linker can't do it? Again, the man page for ld provided the answer: The compiler driver cc(1) handles creating universal executables by
calling ld(1) multiple times and using lipo(1) to create a ``univer-
sal'' file from the results of the ld(1) executions.So it looks like the build process starts in the same way that it always did, only now it repeats the process for the other architecture, and merges the final executables. This means that intermediate files either need to be in separate directories, or else they need to have different names (which doesn't sound like a good idea to me). It also includes the new lipo tool for merging. (I can't think of what this might be short for. I keep thinking "liposuction".)I tried using this technique to build a universal binary for a "Hello World" program, but kept getting missing symbols for the linker stage on the i386 architecture. A look at the compiler log for an XCode project showed an option of -isysroot /Developer/SDKs/MacOSX10.4u.sdk. This isn't mentioned in the manual for gcc or ld, but it does the trick.
To illustrate the process, a simple program might be built from two files: first.c and second.c
gcc src/first.c -c -o obj/first.o
gcc src/second.c -c -o obj/second.o
gcc obj/first.o obj/second.o -o bin/program(I've used gcc to handle linker arguments automatically for me.)The same build for a universal binary would look like:
gcc src/first.c -c -arch ppc -o obj/ppc/first.o
gcc src/second.c -c -arch ppc -o obj/ppc/second.o
gcc obj/ppc/first.o obj/ppc/second.o -o bin/ppc/program
gcc src/first.c -c -arch i386 -o obj/i386/first.o
gcc src/second.c -c -arch i386 -o obj/i386/second.o
gcc obj/i386/first.o obj/i386/second.o -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk -o bin/i386/program
lipo -create bin/ppc/program bin/i386/program -output bin/programlipo can also be used with the -info flag to check a file type: $ lipo -info bin/ppc/program
Non-fat file: bin/ppc/program is architecture: ppc
$ lipo -info bin/i386/program
Non-fat file: bin/i386/program is architecture: i386
$ lipo -info bin/program
Architectures in the fat file: bin/program are: ppc i386This is all fine for Apples, but how should I write a portable Makefile that does all of this? Looking at a current Makefile, I really want to define the architecture in variables, and call into the same Makefile twice, followed by the lipo command to merge the results. However, Makefiles are not as easy to program as most languages. The biggest problem for me is how to call into another Makefile regardless of which target you are currently making. A test for "Mac OS X" at the top of the Makefile will not work, as commands can't be placed outside of a "target" block.The only way I know to do this is to test for "Mac OS X" in every target, and duplicate the compilations. This would be tedious to write, be prone to errors, and be awkward to update (particularly for non-Mac users). I suppose I need to learn a lot more about Makefiles, but I'd rather not have to.
This could be easier in Ant. After all, the code I'm writing is actually a JNI library. Maybe I should write a gcc module?
Posted by
Paula
at
Saturday, January 14, 2006
1 comments
Monday, January 09, 2006
CAS
The interfaces in UIMA have seemed rather obtuse recently.
To process a document, an analysis module is given a CAS (Common Analysis System), and returns a CAS. The CAS contains a reference to the original document, and any annotations that have been made so far. A module can ask the CAS for the original document, perform its analysis, and add any annotations back into the CAS. At the end of the process, the UIMA framework returns a CAS object which can be checked for annotation properties.
Adding annotations to a CAS is an easy process for a module. An appropriate Annotation derivative is created for the current CAS (the CAS object is passed as a parameter to the Annotation's constructor). It is also easy to read these annotations after UIMA has finished. However, the CAS objects in each case are accessed through different classes, with different features. In an analysis module I have a JCas object, but the results of the UIMA run are returning a TCAS object instead. TCAS is actually just a specialization for handling text of a standard CAS object, but I didn't see that immediately (I should have paid closer attention).
Fortunately, a JCas object has a method called getCAS(), and a CAS has a getJCas() method, as these objects have a 1:1 correspondence. Why have two objects? I think it's to separate out the CAS concepts from the Java specific information needed to manipulate a CAS. But don't quote me.
Separating these two classes, and providing different types in different circumstances has tripped me up a bit. Maybe someone can explain the reasoning, but I've just found it annoying.
Posted by
Paula
at
Monday, January 09, 2006
33
comments
Speculation
The blogosphere has started picking up some of the hassles between Kowari and NGC, so I figured that it's my turn to comment.
Last year, NGC asked for a 1.2 release to be pushed back to the 9th of January. Being an Open Source project, NGC could not force this postponement, even though they now own the copyright for the core of the code, and have initial contributor status (as defined in the MPL). But Open Source is new for NGC, and we wanted to support them supporting us, so we accepted the delay.
Then last week an NGC lawyer asked David to push it back further, citing "irreparable harm" to their company if the release proceeded as scheduled. To me, this speaks of a misunderstanding of the entire Open Source development process. The code and documentation is already out there for anyone to see. Just do a cvs update on Sourceforge. A "release" in this context simply means a marker on the code to indicate a certain level of features and stability. (We did a little more as developers, due to the code freeze, testing, and so on, but that doesn't influence users directly).
With NGC giving inappropriate directives to David, and given the work he has done with them, he decided that his best course of action is to leave the Kowari project.
While I don't think that NGC are acting to squash the Kowari project, they have put some serious blocks in the path of administering it. This has stemmed from them not understanding Open Source development, nor the MPL licence that Kowari has been released under. This is understandable, given their corporate/defence background, but it is still frustrating.
Since NGC are not aware of how an Open Source project works, it is conceivable that they would try to interfere with users' ability to continue to use and extend Kowari. Fortunately, the MPL offers protection for everyone here. Any challenges to a user's rights under this licence would necessitate a number of large corporations coming to the defence of the MPL, among them would be AOL and IBM.
Similarly, the MPL protects developers. We still have copyright on personal contributions (which excludes those contributions made while working for the Initial Developer). Those bits can be used elsewhere. There are also rights to do other things like "forking" the project. Personally, I'd rather not do anything like that, as it means abandoning the reputation that Kowari has built up over time, and antagonising NGC in the process.
The situation is annoying for developers (and untenable for David), but it shouldn't mean big problems for users. Kowari, or something like it, should continue. In the worst case, a snapshot of the currently accessible source (January 10, 2006) will always be usable by the community.
I haven't done any Kowari work in the last month, and probably won't do much until I get to Chicago next month. After that, I plan on continuing developing for Kowari, or a project like it.
Posted by
Paula
at
Monday, January 09, 2006
4
comments
Thursday, December 29, 2005
Domains
I've always thought that domain squatting was an unethical way to make money, but had only heard stories of it before now.
Anne suggested that it might be nice to pick up the gearon.com domain, if it was available. After all, I normally take up a lot of the first result page at Google when you type in my surname. (Just looked, and today I don't! I really need to blog more often.) OK, so I'm not a commercial entity, but everyone recognizes .com, while people often look at me funny when I say .org or .net. The .com thing has brand recognition.
So I had a look, and discovered that the domain is already registered, but it is for sale. It turns out that it's available for purchase through the bidding process available at Afternic.com. The minimum bidding price was way more than I'd have liked to spend, but it's my name, so why not?
A week later I discovered the bid was rejected. I asked Afternic what a decent price is supposed to be (according to their market analysis). Their response was that the current market value is $200. Still far too much, but it gave me confidence to ask the current domain holder how much they would like.
The answer? $2950. Quoting from the email:
Price is very low for a family name.
Huh? Whose family? The Rockefellers?
I didn't care about the domain all that much (it should probably go to a more commercial interest, like something run by Michael Gearon or Tierney Gearon), but registering a name and then charging to give it back to an owner of that name is a principle I find rather offensive. I suppose I should be grateful she was asking for $3000 and not $30,000.
I resolved it by registering gearon.org for $8.20.
UIMA
The other day I followed a link over to IBM's DeveloperWorks, and found that they have an RSS feed for their tutorials. I was pleased to find a simple Python tutorial that I'm using to finally introduce myself to that language. But more importantly, I found a tutorial for generating a UIMA annotator.
The UIMA docs are very verbose, and a tutorial like this has been great for cutting through the chaff. It's still full of stuff I don't need (mostly because I've already learnt it from the official UIMA docs), but it's still been a real help.
My biggest problem at the moment is that UIMA wants all my annotations in character offsets. Unfortunately the library I'm using is providing my information in word offsets. That's trivial to convert when words are separated by whitespace, but punctuation leads to all sorts of unexpected things, particularly since the grammar parser treats some punctuation as individual words, while others get merged into existing words.
I'm starting to wonder if I need to re-implement the parser so I know what the character offsets of each word will be. Either that, or I'll be doing lots of inefficient string searching. I don't find either prospect enticing. Maybe if I sleep on it I'll come up with something else.
Posted by
Paula
at
Thursday, December 29, 2005
0
comments
Wednesday, December 28, 2005
Gödels Theorem
I was just looking at the fascinating exhibit of equations by Justin Mullins. I'm not sure if I see the exhibit as art, since the visual appearance evokes little in people who do not understand the equations (with the possible exception of the Four Color Theorem), but they are certainly beautiful.
I particularly loved the end of the narrative for Gödel's theorem:
Others have wondered what Gödel’s theorem means for our understanding of the human mind. If our brains are machines that work in a consistent way, then Gödel’s theorem applies. Does that mean that it is possible to think of ideas that are true but be unable to prove them? Nobody knows.
Note the sentence that I highlighted. If it is true, then that sentence is an unprovable idea. I love it.
Posted by
Paula
at
Wednesday, December 28, 2005
0
comments
Saturday, December 17, 2005
Qubytes
Lots of places are commenting on the new quantum memory chips in silicon.
I'm surprised at this. I expected that embedding quantum devices in silicon would be done with quantum dots, rather than ion traps. It is probably better than it was done with ion traps as there seems to have been more research into quantum processes using this technology. After all, what good is a quantum state if you can't apply transformations on it without collapsing the state?
All the same, a chip like this is just a first step in a long line of problems to be solved. There is no discussion about setting up quantum states, nor reading them back. There is no discussion about the ability to entangle the qubits on the chip, and how far that will scale. Transformations will eventually have to be built in to the chip. But if research has taught me anything, it's that the big problems are usually solved by lots of people chipping away at the little problems. By the time the final solution comes around, it doesn't seem like a big deal any more.
Tracker
The little tracker icon I have on this page is a link to a service that tells me how many hits the blog is getting (but not the RSS feed). I haven't bothered to look at the stats in a long time. After all, I'm rarely writing, so why would anybody (beyond my friends) bother to read?
Apparently I was wrong in that assessment. I'm averaging over 20 hits a day, with peaks over 40, and I'm writing less that once a week. My infrequency is due to lack of time. Given how many people are reading so little here, I'm wondering if anyone else suffers the same problem. :-)
Posted by
Paula
at
Saturday, December 17, 2005
0
comments
Thursday, December 15, 2005
Blogging
I notice a new post on the Google Blog describing a new tool for Firefox. When installed, a small message will appear on any page you visit, showing a list of blogs which refer to that page. Sounds cute.
I normally browse with Safari (gotta love those native widgets), but I keep Firefox installed (after all, some pages have extra features when viewed with Firefox). So here was a chance to upgrade my version of Firefox (I hadn't picked up 1.5 yet) and install Google's new tool.
So where should I go first to check out the comment? Well obviously my usual home page of Google comes up, and there are ample comments. How about the page talking about the new tool? Lots of comments there too. Oh, I know! How about this blog? :-)
Unfortunately the list of comments was a little disappointing, mostly including my friends. That will teach me to not blog regularly. However, I did find one blog on semantic web development that I found really interesting. I was just disappointed that he didn't have a lot of incoming links (though there was one worth checking out).
All in all, it's a tool that I like. In fact, I wouldn't mind a similar tool that did a link: search on Google, rather than just in the bloggosphere.
Posted by
Paula
at
Thursday, December 15, 2005
0
comments
Tuesday, December 13, 2005
Modeling Talk
Last week I was invited along to a talk given by Bob at SAP. I enjoy seeing what Bob's working on when I'm not discussing OWL with him. He's a clever guy, and understands modeling quite well. I just wish I'd written about it sooner, as I won't be so clear anymore.
Probably the most important thing I got out of his talk was an overview of category theory. Andrae and Simon have both spoken about it, and I've come to understand that it's relevant, but as yet I haven't learnt anything about it. Bob gave the 30 second overview for computer scientists, which I found quite enlightening.
I finally got my copy of Types and Programming Languages (otherwise known as TAPL), and have been looking forward to reading it. But when ordering this book I discovered that Benjamin Pierce has also written a much smaller book called Basic Category Theory for Computer Scientists. I had considered getting this book (at only 117 pages, it looks like a relatively quick read), and Bob's talk has now convinced me. The only problem is that I'll have to put the order off until we move to the States... whenever that happens.
modeling
Speaking of books, I also picked up a copy of MDA Distilled, Principles of Model-Driven Architecture. Some of the work I did with SAP came out of this book (virtually guaranteed when you work with one of the authors), and it talks about the kind of dynamic modeling that I've been talking about investigating with OWL. I haven't been through all of it before now, so I thought it would be worthwhile reading it in detail.
Coincidentally, I was explaining some of my ideas to someone at work today (Indy), and referred to this book to describe some of the background. I had some idea that Herzum Software worked with MDA (which is why I thought they might be interested in this work), but I had never thought of it as a formal association. Indy quickly made it very clear that Herzum Software specifically put themselves out there as an MDA company. That makes perfect sense as it aligns with what I already knew, but being in my own little corner of the world has kept me isolated from the advertising of it. Anyway, it's nice to know that the direction I'm moving in is paralleled by the work of my new employer.
RDFS Entailment
I've also been in an email discussion about entailment on RDFS. It seems that the following statements:
<camera:min> <rdfs:range> <xsd:float>
<_node301> <camera:min> '15.0'^^<xsd:float>will lead to an entailment of: <xsd:float> <rdfs:subClassOf> <rdfs:Resource>
'15.0'^^<xsd:float> <rdf:type> <xsd:float>
'15.0'^^<xsd:float> <rdf:type> <rdfs:Resource>It seems that I didn't cover all the possible rules which could lead to a literal in the subject position. It's quite annoying, as these are completely valid entailments, according to RDF semantics. Making special cases to avoid particular results seems like a hack.In a similar way, it seems wrong to not allow entailments about blank nodes. I should re-visit the decision there. I think I need to re-read the semantics document to see if I can get further enlightenment. At the least, I know that I can't entail a statement with a blank node as the predicate. Like the problem with literals, the semantics document appears to justify this sort of statement, but the RDF syntax doesn't allow for it. I know this is a particular bugbear for Andrae.
Posted by
Paula
at
Tuesday, December 13, 2005
0
comments
Catch Up
I've been wanting to write for nearly a week now. Every time I try to sit down for it I've had a work task, family needs, or packing to take priority over this blog. I ended up having to write little notes to myself to remind me of what I wanted to blog about.
JNI and Linux
Having made the Link library work on Mac OSX using JNI, I figured it would be easy to get it working on Linux as well. Unfortunately it didn't work out that way.
To start with, I got an error from the JVM saying that it could not find a symbol called "main" when loading the library. This sounded a little like dlopen loading an incorrectly linked file. I'm guessing that the dlopen procedure found what it thought was an executable, and therefore expected to see a main method. Googling confirmed this, but didn't really help me work out the appropriate flags for linking to fix this.
I had compiled the modules for the library using -fPIC (position independent code). I then used a -Wl,-shared flag to tell gcc to pass a -shared flag to the linker, in order to link the modules into a shared library. However, it turned out that I really needed to just use -shared directly on gcc. I've still to work out what the exact difference is, but that's not a big priority for me at the moment, since I have it working. According to DavidM there is something in the gcc man page about this, so at least I know where to look.
After linking correctly, the test code promptly gave a Hotspot error, due to a sigsegv. This meant that there was a problem with the C code. This had me a little confused, as it had run perfectly on OSX. Compiling everything in C and putting it all in a single executable demonstrated that the code worked fine on Linux, so I started suspecting that the problem might be across the JNI interface. This ended up being wrong. :-)
There are not many differences between the two systems, with the exception of the endianess of the CPUs. However, after looking at the problem carefully, I could not see this being the problem.
The initial error included the following stack trace:
C [libc.so.6+0xb1960]
C [libc.so.6+0xb4fcb] regexec+0x5b
C [libc.so.6+0xd0a98] advance+0x48
C [liblink.so+0x19f9d] read_dictionary+0x29
C [liblink.so+0x1d705]
C [liblink.so+0x1d914] dictionary_create+0x19
C [liblink.so+0x286c9] Java_com_link_Dictionary_create+0xc1The only code I had real control of was in Java_com_link_Dictionary_create, dictionary_create and read_dictionary. I started by looking in Java_com_link_Dictionary_create and printing the arguments, but everything looked fine. So then I went to the other end and looked in read_dictionary.I was a little curious about how
read_dictionary was calling advance, as I hadn't heard of this function before. Then I discovered that the function being called was from the Link library, and has a signature of advance(Dictionary). This didn't really make sense, as my reading of the stack trace above said that advance came from libc and not the Link library (liblink). This should have told me exactly what was happening, but instead I tried to justify what I was seeing. I convinced myself that the function name at the end of each line described the function that had called into that stack frame. In hindsight, it was a silly bit of reasoning. I was probably just tired.So to track the problem down I start putting
printf() statements through the code. The first thing that happened was that the hotspot errors changed, making the error appear a little later during execution. So that meant I had a stack smash. Obviously, one of the printf() invocations was leaving a parameter on the stack that helped the above stack trace avoid the sigsegv. OK, so now I'm getting some more info on the problem.It all came together when I discovered that I was seeing output from just before
read_dictionary() called advance(), and from just after it, but not from any of the code inside the advance() function. At that point I realised that the above stack trace didn't need a strange interpretation, and that the advance() that I was calling was coming from libc and not the local library.Unfortunately, doing a "man advance" on my Linux system showed up nothing. Was I wrong about this method? I decided to go straight to the source, and did a "nm -D /lib/libc.so.6 | grep advance". Sure enough, I found the following:
000b9220 W advanceSo what was this function? Obviously something internal to libc. I could download the source, but that wasn't going to make a difference to the problem or the solution. I just had to avoid calling it.My first approach was to change the function inside Link to
advance_dict(). This worked perfectly, and showed that I'd found the problem. However, when the modules were all linked into a single executable it had all worked correctly, and had picked up the local function, rather than the one found in libc. Why not?I decided that if I gave the compiler a hint that the method was local, then maybe that would be picked up by the linker. So rather than renaming the function to
advance_dict(), I changed its signature from: int advance(Dictionary dict)to: static int advance(Dictionary dict)I didn't know that this would work, but it seemed reasonable, and certainly cleaner since it's always a bad idea to presume that your name is unique (as demonstrated already). Fortunately, this solution worked just fine.DavidM explained to me that
static makes a symbol local to a compilation unit (which I knew) and was effectively a separate namespace (which I also knew). He also explained that this "namespace" has the highest priority... which I didn't know, but had suspected. So I learned something new. David and I also learnt that libc on Linux has an undocumented symbol in it called advance. This is worth noting, given how common a name that is. As shown here, it is likely to cause problems on any shared library that might want to use that name.There's more to write, but it's late, so I'll leave it for the morning.
Posted by
Paula
at
Tuesday, December 13, 2005
0
comments
Sunday, December 04, 2005
Blogging
I'm a little annoyed at myself for lack of blogging recently. This is particularly the case as I see mainstream media commenting on people's online presence more and more. I almost feel like I'm missing out on something. Yes, I know that's a ridiculous concern, but I'm allowed to worry about anything I want to. :-)
Other than the restrictions imposed on me by my recently expanded family, my main problem with blogging recently has been lack of material. I don't mean that I have nothing to say. Instead, I'm limited by what is appropriate to put into a public forum. It was much easier when I worked on Open Source software all the time.
For instance, this last week has had me reviewing software produced by a group of academics at another company. My review is for my employer, so I obviously can't publish it (otherwise, why would he be paying me?). Also, any review will naturally say both good and bad things. The good may be OK, but saying something bad in public is obviously inappropriate. After all, these guys are out to impress customers and make money too.
So I'm left having to write about what I do out of hours. That's all well and good, but having a young family reduces the time for that.
I could always write a few opinion pieces. Australian federal politics has had me feeling frustrated for some time now, and I definitely have things to say on the topic. But that's not what this particular blog is about. I could always start a parallel blog, but then, who would really want to know what I think about Brendan Nelson and higher education in Australia? It would be cathartic for me, but not so much that I think it's really worthwhile.
All the same, I might consider a second blog to contain random musings (like this one). Maybe one evening when I'm not feeling like going to bed, and I have something I feel I want to say. I could be a mix of my daily life, frustrations, and comments on the oft explored experience of fatherhood. I'm not sure it will be good reading, but I may have fun coming back to it in a few years to see just how naive I really was back in 2005. :-)
Grammar
Meanwhile, I'm back to grammar parsing, using Link. I was a little chuffed to get the JNI all working, particularly when I was able to rewrite some of the test code in Java and have it all run correctly. I still need to test that it runs fine on Linux, but I don't have any real concerns there. Making it run on Windows will be another story.
Ideally, I'll be able to use MingW as the compiler, as it should help keep the codebase and build process consistent. I just hope I won't have to jump through too many hoops to generate a DLL file.
I could always ask someone at work if we have an MS commercial compiler, but we may not. I have my own, but I'm notlicensedd to use it for work. It amazes me that people are concerned about the restrictions of Open Source licensing, when commercial licensing can be far worse.
Weather
I'm a little obsessed with the weather at the moment. I enjoy our sub-tropical climate here, and it's going to be a rude shock to land in Chicago in the middle of Winter. As a result, I'm enjoying every minute here that I can. I'm also comparing the weather between the two cities on a day-by-day basis. The huge difference fascinates me, but the guys at work are probably annoyed with me by now.
According to AccuWeather.com, Chicago is currently well below zero Celsius), and will be staying that way all week. The town I grew up in (Chinchilla) often goes below zero during Winter, but that only happens overnight. Chinchilla also hasn't had snow since the early 1900's (1915 rings a bell for some reason).
Brisbane has been my home for the last 17 years, and it has never been below freezing (at least, not in recorded history). So I really haven't experienced anything like Chicago before. Can you blame me for paying attention to the differences?
In the meantime, Brisbane is just starting on its first heat wave for the Summer. Fortunately, it's not supposed to get as high as 40C (104F) over the coming week, but it won't be far off. The prediction is 37C (99F). Not too bad, but unpleasant all the same. Overnight minimums are over 20C (68F), so Luc isn't sleeping too well. This is a far cry from Chicago, where the highest maximum for the coming week is -4C (24F).
This will certainly add some excitement to the move!
Posted by
Paula
at
Sunday, December 04, 2005
0
comments