JCategory User Guide

Contents

    Overview

    JCategory is a lightweight categorization framework for Java.

    Since ancient times, conceptual grouping has been a natural human way to create abstract models of the world 1 . In computer science, the notion of categories plays a major role in computer programming 2 . Particularly, different categorization mechanisms are often implicit in most programming languages (e.g., classes and packages). However, for statically-typed languages it is often not trivial (or not possible at all) to modify at runtime the properties of existing categories, or creating new categories on the fly. Furthermore, a programmer may intend to create or modify the properties of categories in a certain well-scoped context, isolating category properties, or the categories themselves, from the rest of the application.

    JCategory provides support for defining complex taxonomies of categories into a particular context. With JCategory, a programmer can define and manipulate ad hoc categorizations, as well as easily organize categories relying on existing Java categorization mechanisms, such as classes and packages.

    Having Fun with Categories (or a Short Introduction to log4j)

    This section illustrates a typical usage of custom categories in everyday programming by means of reviewing common logging practices using a well known Java library.

    Name Hierarchies

    Popular logging libraries such as log4j allow fine-grained control on which kind of logging message (e.g., warning or error) should be processed at runtime. This control is enabled since programmers can easily categorize a logging space 3 according to some developer-chosen criteria. Loggers are organized hierarchically following a naming rule. For example, a logger named "org" is the parent of a logger named "org.jcategory", and the ancestor of a logger named "org.jcategory.JCategory". If a logger property (e.g., a logging level) is not defined for a given logger, it should be resolved according to the corresponding property value of its parent.

    Loggers are typically defined by means of configuration files. The following fragment of a log4j configuration file configures a logger named org.jcategory with the level WARN.

    # Set the logger level to WARN for the "org.jcategory" logger
    log4j.logger.org.jcategory=WARN

    Although loggers can have any name, a practical convention is to name them according to the fully qualified name of the class where they are used. For example, a logger used in the org.jcategory.JCategory class may be named "org.jcategory.JCategory". Such logger can be instantiated with:

    Logger jcategoryLogger = Logger.getLogger(org.jcategory.JCategory.class); //instantiates a logger named "org.jcategory.JCategory"

    Since this logger is a descendant from the "org.jcategory" logger defined in the configuration file, it inherits from its parent the level property, set to WARN. This is illustrated by the figure below.
    Name category properties.
    Fig 1. - A name categorization for loggers.

    Note that in order to keep our example simple some details of log4j have been omitted. Particularly, the actual implementation of log4j defines level and other properties with default values in the root category. For a detailed explanation on the semantic meaning of logger properties please refer to the log4j manual.

    This section has illustrated how a popular logging library makes use of name hierarchies to create a categorization of loggers. The core idea of a name based categorization is to infer hierarchical relationships between labeled categories based on a given naming convention. As we will see, JCategory provides high level support for dealing with this categorization pattern.

    The following section motivates another kind of categorization based on the existing type hierarchies of a programming language.

    Type Hierarchies

    Back to our logging example, this section illustrates how log4j renders objects in logging messages.

    Since generating readable messages is a core objective of logging, log4j allows to associate custom renderers with certain classes. The renderers are responsible to convert instances of such classes to a convenient string representation for logging purposes.

    Quoting the log4j manual: Object rendering follows the class hierarchy. For example, assuming oranges are fruits, if you register a FruitRenderer, all fruits including oranges will be rendered by the FruitRenderer, unless of course you registered an orange specific OrangeRenderer . Following this example, we would like to associate a property (a renderer) with the category identified by the Fruit class. However, in this setting we require a different categorization heuristic: instead of categorizing a class according to its fully qualified name as in the previous section, we want to do it according to its position in a class hierarchy. This categorization is illustrated by the figure below.
    Type category properties.
    Fig 2. - A type categorization for renderers.
    Therefore, this categorization relies on an existing categorization already provided by the language (a hierarchy of classes). As in the previous categorization based on name hierarchies, JCategory factorizes out this categorization pattern as a general mechanism to associate properties to classes and interfaces. As before, this association is limited to the scope of a certain context.

    The JCategory Context

    JCategory allows to create and maintain categorizations associated with a context. A JCategory context can be regarded as a register for categorizations and a store of preferences. A default JCategory context can be instantiated as follows:

    JCategory context = new JCategory();

    Categorizations can be registered and retrieved as follows:

    Categorization<CategoryClass> myCategorization = ...;
    context.register("my-categorization", myCategorization); //registering a categorization under the identifier "my-categorization"
    context.getCategorization("my-categorization"); //retrieving the categorization identified by "my-categorization"

    This context also provides high-level methods to deal with name and type categorizations, as it will be illustrated in the next section.

    JCategory Categories

    The notion of category is a core aspect of the JCategory implementation. A JCategory category is defined by a group of properties shared by the objects belonging to such a category. Categories can also be defined in terms of other categories, in which case they inherit the properties of their ancestor categories. Therefore, categories define parents-children relationships with other categories.

    JCategory categories may be associated with an identifying label. According to the chosen categorization, this label may determine the position of the category in a hierarchy (e.g., named hierarchies), or just serve as a human aid facilitating reasoning over the category and its extension 4 .

    In addition to offer a framework for creating and maintaining custom hierarchies of categories, JCategory provides special classes and routines for dealing with two common categorization mechanisms. The rest of this section overviews the JCategory support for name and type categorizations.

    Name Categorizations

    JCategory allows to define name categorizations that structure their hierarchy according to the naming convention described in our loggers categorization example. This categorization approach can be used to associate properties with Java packages, classes (by means of their fully qualified name) or any artifact following a similar hierarchical naming convention.

    The example below creates a name categorization with the same properties that our logging example.

    final Object LEVEL = "level"; //the property identifier
    JCategory context = new JCategory();
    NameCategory parent = context.forPackage(JCategory.class.getPackage()); //name category for "org.jcategory"
    NameCategory child = context.forName(JCategory.class.getName()); //name category for "org.jcategory.JCategory"
    parent.setProperty(LEVEL, "WARN"); //"level" property set to "WARN" for "org.jcategory"
    assertEquals("WARN", parent.getProperty(LEVEL).get()); //"level" property is "WARN" for "org.jcategory"
    assertEquals("WARN", child.getProperty(LEVEL).get()); //"level" property is also "WARN" for "org.jcategory.JCategory"
    assertFalse(context.forName("org").getProperty(LEVEL).isPresent()); //"level" property has not been set for "org"

    First we obtain categories corresponding to the names "org.jcategory" (line 3) and "org.jcategory.JCategory" (line 4). We set the level property to WARN in the "org.jcategory" category (line 5). We verify that the property is set for both this category (line 6) and a child category that should inherit that property (line 7). In line 8 we verify that the property is undefined for the category "org", since it is before in the hierarchy of the only category defining this property.

    Type Categorizations

    JCategory facilitates the creation of type categorizations based on the Java class hierarchy. Back to our renderers categorization example, consider the classes Fruit, Orange and FruitRenderer as:

    public class Fruit  {...}
    public class Orange extends Fruit{...}
    
    public class FruitRenderer implements ObjectRenderer {
    	@Override
    	public String doRender(Object fruit) {
    		...
    	}
    }

    The code below shows how the categorization illustrated in our rendering example can be implemented in few lines of code.

    final Object OBJECT_RENDERER_KEY = ObjectRenderer.class; //the property identifier
    JCategory context = new JCategory();
    TypeCategory<Fruit> fruitCategory = context.forClass(Fruit.class); //type category for Fruit
    TypeCategory<Orange> orangeCategory = context.forClass(Orange.class); //type category for Orange
    fruitCategory.setProperty(OBJECT_RENDERER_KEY, FruitRenderer.class); //ObjectRenderer property set to FruitRenderer for Fruit
    assertEquals(FruitRenderer.class, fruitCategory.getProperty(OBJECT_RENDERER_KEY).get()); //ObjectRenderer property is FruitRenderers for Fruit
    assertEquals(FruitRenderer.class, orangeCategory.getProperty(OBJECT_RENDERER_KEY).get()); //ObjectRenderer property is also FruitRenderer for Orange
    assertFalse(context.forClass(Object.class).getProperty(OBJECT_RENDERER_KEY).isPresent()); //ObjectRenderer property has not been set for Object

    First we obtain categories corresponding to the classes Fruit (line 3) and Orange (line 4). Note that a property identifier can be any object, in this case the property is identified by the ObjectRenderer class (line 1). We set the ObjectRenderer property to FruitRenderer in the Fruit category (line 5). We verify that the property is set for both this category (line 6) and a child category that should inherit that property (line 7). In line 8 we verify that the property is undefined for the category Object, since it is an ancestor of the only category defining this property.

    Dealing with Multi-Inheritance

    Previous examples showed categories inheriting the properties of a single parent category, creating tree-structured category hierarchies. However, other categories may be better modelled as inheriting from more than one single parent. Although powerful in expressiveness 5 , multi-inheritance introduces many conceptual and technical problems 6 .

    The following section illustrates this with one common problematic scenario in multi-inheritance categorizations.

    The Diamond Inheritance Problem

    The figure below illustrates a known problem referred to as diamond inheritance 7 with a simple example. Categories B and C inherit from A. They define different values for the property p. If category D inherits from both B and C, the value of the property p is ambiguous in D .
    Diamond inheritance.
    Fig 3. - Diamond inheritance.
    Although there are many different alternatives to solve conflicts for ambiguous properties, unfortunately there is not a perfect one-fit-all solution 8 . The following section illustrates the approach followed by JCategory.

    Linearization Functions

    Linearization is a common approach for solving multi-inheritance conflicts 9 . In order to illustrate this approach, let's consider the following classes and interfaces defining a taxonomy of animals (example adapted from a popular Scala book 10 ) :

    public class Animal {}
    public interface HasLegs {}
    public interface FourLegged extends HasLegs {}
    public interface Furry {}
    public class Cat extends Animal implements Furry, FourLegged {}
    public class Fish extends Animal {}

    Figure 4 illustrates a JCategory type categorization based on this class hierarchy.

    Animal hierarchy example.
    Fig 4. - Animal hierarchy example.

    First note that JCategory adds the special class Any at the root of the hierarchy. This design decision allows to have a common root for both class and interface type categories and this presents various advantages. One of those is being able to set global properties that are inherited by both class and interface categories in the hierarchy.

    The figure also illustrates a type-based categorization of renderers according to this class hierarchy (note the renderer property associated to certain classes). Observe that JCategory considers, in many aspects, both classes and interfaces as same-level categorization units. For example, one of the two renderers shown in the figure (AnimalRenderer) is a property of the Animal class. The other (HasLegsRenderer) is a property of the HasLegs interface. In order to associate those renderers with the categories Animal and HasLegs, we can write:

    final Object OBJECT_RENDERER_KEY = ObjectRenderer.class;
    JCategory context = new JCategory();
    TypeCategory<Animal> animalCategory = context.forClass(Animal.class); //type category for Animal
    TypeCategory<HasLegs> hasLegsCategory = context.forClass(HasLegs.class); //type category for HasLegs
    animalCategory.setProperty(OBJECT_RENDERER_KEY, AnimalRenderer.class); //setting property ObjectRenderer to AnimalRenderer in Animal
    hasLegsCategory.setProperty(OBJECT_RENDERER_KEY, HasLegsRenderer.class); //setting property ObjectRenderer to HasLegsRenderer in HasLegs

    This example provides for both non-conflictive and conflictive property resolution scenarios. In the simplest case, let's consider we would like to query the render property for the Fish category. Since there is only single inheritance in the category hierarchy of Fish, its renderer is trivially found from the first ancestor defining such a property (i.e., Animal), as the following test illustrates:

    ...
    TypeCategory<Fish> fishCategory = context.forClass(Fish.class); //type category for Fish
    assertEquals(AnimalRenderer.class, fishCategory.getProperty(OBJECT_RENDERER_KEY).get()); //ObjectRenderer property is AnimalRenderer for Fish

    However, if we ask which is the appropriate renderer for instances of Cat, different property resolution strategies may result in different values. For example, some may think that categories from super interfaces should be looked up first. In this case HasLegRenderer should be returned. Others may prefer to query first categories corresponding to the super class. In that case AnimalRenderer should be returned.

    Linearization helps to solve this conflict unambiguously defining a lineal order in which (super-)categories should be visited when querying a property. In JCategory, linearization is considered a function mapping a category to a list of categories creating a search path.

    The default JCategory type linearization function is, to certain extent, inspired by the linearization function used by Scala 11 when solving conflicts between classes and traits. JCategory uses a left-first depth-first search, before eliminating all but the last occurrence of each category in the resulting list (the main difference with the Scala algorithm is that the later uses a right-first depth-first search). Figure 5 illustrates the resolution order of a property starting from the category Cat.
    Linearization: traversing classes first.
    Fig 5. - Linearization: Left to right (classes first).

    The linearization function first finds this resolution order (left-first depth-first search): [Cat, Animal, Object, Any, Furry, Any, FourLegged, HasLegs, Any] which is reduced down to: [Cat, Animal, Object, Furry, FourLegged, HasLegs, Any] (eliminating all but the last occurrence of a redundant category). As the figure shows, this algorithm has the particularity that an ancestor category will not be reached until all the descendants leading to it have been explored.

    The following example verifies that the ObjectRenderer property is AnimalRenderer for Cat, according to our default linearization function:

    ...	
    TypeCategory<Cat> catCategory = context.forClass(Cat.class); //type category for Cat
    assertEquals(AnimalRenderer.class, catCategory.getProperty(OBJECT_RENDERER_KEY).get()); //ObjectRenderer property is AnimalRenderer for Cat

    Given that a custom linearization function may be not that trivial to implement, JCategory provides simple abstractions for creating those functions from a set of parameters. In order to associate a type linearization function with a JCategory context we can write:

    Function<TypeCategory<?>, List<TypeCategory<?>>> linearizationFunction = 
    		new BottomUpTypeTraversalPolicy(
    		SearchStrategy.PRE_ORDER, //pre-order search
    		Priority.CLASSES_FIRST, //look first at classes, then interfaces
    		InterfaceOrder.DECLARATION, //traverse the interfaces from left to right (declaration order)
    		RedundancyCheck.KEEP_LAST); //if a category appears more than once in the linearization, keep the last found and discard the previous ones.
    JCategory context = new JCategory(linearizationFunction);

    The previous linearization function is the same as the default linearization function for type categories: left to right search, looking at classes first. Alternatively, we could have configured a different linearization function, say a right to left search, looking at interfaces first:

    Function<TypeCategory<?>, List<TypeCategory<?>>> linearizationFunction = 
    		new BottomUpTypeTraversalPolicy( 
    		SearchStrategy.PRE_ORDER, //pre-order search
    		Priority.INTERFACES_FIRST, //look first at interfaces, then classes
    		InterfaceOrder.REVERSE, //traverse the interfaces from right to left (reverse declaration order)
    		RedundancyCheck.KEEP_LAST); //if a category appears more than once in the linearization, keep the last found and discard the previous ones.
    JCategory context = new JCategory(linearizationFunction);

    Figure 6 illustrates the alternative resolution order defined by our custom linearization function.
    Linearization: traversing interfaces first.
    Fig 6. - Linearization: Right to left (interfaces first).
    This function first finds this resolution order: [Cat, FourLegged, HasLegs, Any, Furry, Any, Animal, Object, Any] which is reduced down to: [Cat, FourLegged, HasLegs, Furry, Animal, Object, Any]. In this setting, the renderer for instances of Cat is HasLegsRenderer, since it is found earlier in the list of categories returned by the linearization function.

    Ad Hoc Categorizations

    Of course, you can always create simple ad hoc categorizations if you do not care about name and type categorizations. For ad hoc categorizations, the default linearization function makes use of a left-first depth-first search. Conflicts are solved keeping the last redundant category in the linearization and dropping the rest.

    The example below implements a simple diamond inheritance hierarchy.

    //creating a simple hierarchy
    Categorization mySimpleCategorization = new Categorization();
    Category grandFather = new Category(mySimpleCategorization); //the root of the hierarchy
    Category parent1 = new Category(asList(grandFather)); //parent1 inherits from grandFather
    Category parent2 = new Category(asList(grandFather)); //parent2 also inherits from grandFather
    Category child = new Category(asList(parent1, parent2)); //child inherits from both parent1 and parent2
    		
    //setting properties
    Object p1 = new Object();
    Object p2 = new Object();
    grandFather.setProperty(p1, "x"); //setting property p1 to "x" in grandFather
    parent1.setProperty(p1, "y"); //overriding property p1 as "y" in parent1
    parent2.setProperty(p1, "z"); //overriding property p1 as "z" in parent2
    parent2.setProperty(p2, "x"); //setting property p2 to "x" in parent2
    		
    //testing
    assertEquals("y", child.getProperty(p1).get()); //p1 property found in parent1
    assertEquals("x", child.getProperty(p2).get()); //p2 property found in parent2
    		
    //optionally registering the previous categorization in a JCategory context
    JCategory context = new JCategory();
    context.register("my-categorization", mySimpleCategorization);

    Strategies

    Categories may be associated with strategies. A JCategory strategy is just an object which class implements one or more interfaces. Multiple strategies can be located in a categorization, forming an implicit chain of responsibility.

    In order to illustrate this, we come back to the animal renderers showed in a previous example. The following classes provide a simple implementation of such renderers:

    public class AnimalRenderer implements ObjectRenderer {
    	@Override
    	public String doRender(Object animal) {
    		return "animal";
    	}
    }
    
    
    public class HasLegsRenderer implements ObjectRenderer {
    	@Override
    	public String doRender(Object hasLegs) {
    		return "has-legs";
    	}
    }

    For this example, we will make use of type categories to associate classes with instances of our renderers, as it is showed in the example below:

    final Object OBJECT_RENDERER_KEY = ObjectRenderer.class;
    JCategory context = new JCategory();
    //instantiating categories
    TypeCategory animalCategory = context.forClass(Animal.class); //type category for Animal
    TypeCategory hasLegsCategory = context.forClass(HasLegs.class); //type category for HasLegs
    TypeCategory catCategory = context.forClass(Cat.class); //type category for Cat
    		
    //setting properties
    animalCategory.setProperty(OBJECT_RENDERER_KEY, new AnimalRenderer()); //ObjectRenderer property is an instance of AnimalRenderer for Animal
    hasLegsCategory.setProperty(OBJECT_RENDERER_KEY, new HasLegsRenderer()); //ObjectRenderer property is an instance of HasLegsRenderer for HasLegs

    We can obtain an instance of a strategy by means of the getStrategy() method in the Category class. The returned strategy is in fact a composition of other strategies (specifically, a chain of responsibility) in the upper hierarchy of a category. Note that the class of this strategy is generated at runtime (at the moment, by means of dynamic proxies).

    The code below verifies that the result of rendering a cat by means of the strategy ObjectRenderer at the Cat category is delegated to the first renderer found in the hierarchy (according to the default linearization function). This is the instance of AnimalRenderer found at the Animal class.

    ...
    ObjectRenderer renderer = catCategory.getStrategy(ObjectRenderer.class);
    assertEquals("animal", renderer.doRender(new Cat()));

    Finally, in case a strategy requires to delegate to the next strategy in the chain of responsibility, it just needs to throw a NoMyResponsibilityException exception. If this happens, the next strategy in the chain will be employed. If all the strategies in the chain are exhausted, a NoMyResponsibilityException exception is thrown to the caller.

    To illustrate this, let's consider the following alternative animal renderer:

    class DelegationAnimalRenderer implements ObjectRenderer {
    	@Override
    	public String doRender(Object animal) {
    		throw new NoMyResponsibilityException();
    	}
    }

    The code below verifies that the renderer of a cat is now the instance of HasLegsRenderer found at the HasLegs class, which is second in the hierarchy (again, according to the default linearization function). This is given to the fact that the renderer instance of AnimalRenderer, although found first in the hierarchy, throws a NoMyResponsibilityException exception.

    ...
    //overridding property
    animalCategory.setProperty(OBJECT_RENDERER_KEY, new DelegationAnimalRenderer()); //ObjectRenderer property is an instance of DelegationAnimalRenderer for Animal
    //testing
    ObjectRenderer renderer = catCategory.getStrategy(ObjectRenderer.class);
    assertEquals("has-legs", renderer.doRender(new Cat()));

    Limitations and Future Work

    This section highlights certain limitations of JCategory. In certain cases, future work directions to overcome these limitations are outlined.

    Name Categorizations Limitations

    JCategory provides support for only one pattern of name categorizations: hierarchies specified by means of category names implicitly containing a list of ancestors using dots as token separator. However, many other alternatives are possible (e.g., structuring hierarchies based on a numeric pattern present in the name of a category). The current mechanism was chosen because it is well known and understood. Other strategies should not be difficult to implement.

    Type Categorizations Limitations

    JCategory type categories currently do not take into consideration implicit reflective properties (e.g., fields and methods declarations) of the wrapped classes that define a type categorization. Instead, existing classes are just considered category identifiers and provide a hierarchical organization for type categorizations. This may change in the future if a good use-case appears.

    Alternative Conflict Resolution Mechanisms

    As mentioned before, linearization is only one mechanism to solve conflicts in multi-inheritance scenarios. For example, an alternative mechanism allowing to rename one of the conflictive properties in a descendant type category may be implemented, or somehow given the possibility to the programmer to explicitly decide which inherited property to choose.

    At the moment, there are no plans to implement any of these alternative conflict resolution mechanisms since they are not part of the requirements that motivated the implementation of JCategory.

    Performance Issues

    A potential performance issue may occur in scenarios with many categories deep in a hierarchy. For example, if many of those categories do not contain properties (or only contain properties that are not queried often), the property look up algorithm has to continuously traverse a long list of non interesting nodes. This may be solved by adding to each category references not only to its parents, but to the next ancestors actually containing properties. In this line, it may also make sense to implement a sort of indexing based on certain frequently queried properties. In other words, a category may keep a reference to the next category with a particular often-queried property. This optimization algorithms may make the querying of properties more efficient despite a small overhead in the addition of new properties.

    Alternatively, for a rather static categorization that do not modify much its properties, it may also make sense to pre-process its categories, in such a way that a category has a local copy of all its inherited properties according to a linearization function.

    Conclusions

    This tutorial has described a lightweight Java library for creating different kinds of categorizations: 1) name, 2) type and 3) ad hoc categorizations.

    Not all the JCategory features have been discussed here. Features such as top-down traversing of hierarchies, registration of listeners in categorizations and the description of utility classes facilitating common tasks have been left out for timing constraints.

    Particularly, top-down search has interesting applications. For example, with JCategory it is easy to find, given a type categorization, the first implementor of an interface (say using breadth-first search) that has certain desired characteristics (e.g., it is associated with a particular JCategory property). This feature may be described in the next version of this tutorial.

    If you are interested to learn more about such features, or would like to know how to extend JCategory to support other user-defined categorizations, please contact the author.

    License

    JCategory is open source, distributed under the terms of this license.

    Try it !

    JCategory sources are available at GitHub.

    In case you are using Maven, it is also available at the Maven Central repository. Just add this dependency to your POM to include JCategory into your project.

    <dependency>
      <groupId>com.github.jcategory</groupId>
      <artifactId>jcategory</artifactId>
      <version>0.0.1</version>
    </dependency>

    You may also find interesting taking a look at the JCategory API documentation.

    Contact

    Constructive feedback and criticism, questions or a wish list can be sent to [sergioc78 (that symbol for emails) gmail(dot)com]. Or just drop me a line if you want to say hello ! :-)

    Footnotes

    1. The complete works of Aristotle. Barnes, J. (ed). Volume 1. (the revised Oxford translation), Princeton University Press. 1984.
    2. Classes vs. Prototypes - Some Philosophical and Historical Observations. Antero Taivalsaari. Journal of Object-Oriented Programming. 1996.
    3. Short introduction to log4j. Ceki Gülcü, March 2002.
    4. The conceptual grouping effect: Categories matter (and named categories matter more). Gary Lupyan. Cognition, Vol. 108, No. 2. August 2008.
    5. Object Oriented Software Construction. Bertrand Meyer. August 1997.
    6. On the Notion of Inheritance. Antero Taivalsaari. ACM Computing Surveys, Vol. 28, pages 438 - 479. 1996.
    7. The programming language Jigsaw: Mixins, modularity and multiple inheritance. Bracha, G. Ph.D. thesis, Univ. of Utah, March 1992.
    8. Name Collision in Multiple Classification Hierarchies. Knudsen. European Conference on Object-Oriented Programming, Oslo, Norway. August 1988.
    9. Proposal for a Monotonic Multiple Inheritance Linearization. Roland Ducournau, Michel Habib, Marianne Huchard, and Marie-Laure Mugnier. OOPSLA, page 164-175. ACM. 1994.
    10. Programming in Scala. Martin Odersky, Lex Spoon and Bill Venners. Artima Press, Mountain View, CA. 2 edition. January 2011.
    11. An Overview of the Scala Programming Language. Martin Odersky, and al.. IC/2004/64. EPFL Lausanne, Switzerland. 2004.