• Home
  • About
  • Sample Apps
  • It’s all about the form…

    February 26th, 2008

    Based on the feedback we receive from our customers and our own experiences at customer sites, we learned that almost every application contains multiple forms. In business applications, forms are the basic building blocks that make up the essence of the application. Until now, UltraLightClient provided no special support for this central element. With UltraLightClient ‘08 this will change!

    UltraLightClient 08

    UltraLightClient ‘08 will provide an out-of-the-box form component that makes it ultra easy to implement your forms:

    What before was obfuscated by a lot of boilerplate code will now be reduced to some lines of clean code. What before offered lots of degrees of freedom (and lots of ways of getting lost as well) is now guided by best practices. As a result, form code is easier to write, easier to find, easier to read, easier to understand, and easier to maintain. Writing a form will become a very cost-effective task with UltraLightClient ‘08!

    Implementing a form basically means defining the following aspects of the form:

    • layout of the input components
    • value binding to a business object
    • input validation
    • status feedback: missing or invalid input, dirty state (i.e. not yet stored input)
    • calculation of dependent values (e.g. find corresponding city to entered ZIP)

    Let’s consider an example that shows how to express these aspects with help of the form component and how the form component simplifies your life (the programming one, not the real one ;-)). In this example I’ll show you how to implement the following form using the new features in UltraLightClient ‘08.

    Form

    The first step is to define the layout of the form. In the old days, this would mean creating tabs for the separate parts of the form, adding labels to the tabs, adding input fields to the tabs, connecting the labels to the input fields, adding layout constraints for each added component (e.g. that the last name input field is on the same line as the first name input field), … With UltraLightClient ‘08 this is just one line of code for each tab and each input field! The resulting code is easy to write, easy to understand, and easy to maintain:

    @Override
    protected void initForm() {
      startTab("General");
      addTextField("firstName", "Firstname, Lastname:");
      addTextField("lastName", new LayoutInfo(append()));  // append = add on same line
      addTextField("company", "Company:");
     
      startTab("Address");
      addTextField("street", "Street:");
      addTextField("zip", "ZIP, City:");
      addTextField("city", new LayoutInfo(append()));  // append = add on same line
      addTextField("country", "Country:");
    }

    And as an added bonus, you get the value binding for free! There’s no need to copy the property values from the business object (a person in this example) into the form when creating the form, and no need to write back the input component values into business object when storing the form. UltraLightClient ‘08 takes care of this for you for free.

    How about input validation? In UltraLightClient ‘08 this is ultra easy as well:

    @Override
    public String validateValue(String value) {
      char firstChar = value.charAt(0);
      if (Character.isDigit(firstChar)) {
        return "Field must not start with digit";
      }
     
      return null;
    }

    The previous code snippet adds error feedback to the form whenever the user input starts with a digit. UltraLightClient ‘08 takes care of invoking your validation code when necessary and displays the validation feedback to the user. So no need for you to add listeners to the input components and to update the form to display the validation feedback. See the red exclamation mark and the tooltip in the screenshot above, displaying the validation feedback.

    We talked about layout, value binding, input validation, and status feedback. In the last section of this post, we will tackle the calculation of dependent values. With UltraLightClient ‘08 this is ultra easy as well:

    @Override
    protected void calculate() {
      Person person = getBean();
     
      if (hasChanged("zip")) {
        String city = toCity(person.getZip());
        setProperty("city", city);
      }
    }

    As with input validation UltraLightClient ‘08 takes care of invoking your code when necessary. So there is no need for you to add listeners to the input components and to update the form here as well.

    Summary: With the new form component in UltraLightClient ‘08 implementing forms is an ultra easy task. No need to write stupid boilerplate code again and again. You can concentrate on the essential parts. Plus UltraLightClient ‘08 enforces best practices, which results in more uniform code. Form code will become ultra easy to write, ultra easy to read, and ultra easy to maintain in the upcoming release.

    We plan to publish an UltraLightClient ‘08 milestone release in early April. Stay tuned!


    Hierarchies

    February 26th, 2008

    Canoo’s CTO Bruno Schäffer is speaking at SD West 08 on “Design Patterns for Rich Internet Applications”.

    SD West 08

    The following blog post outlines some of the concepts that he will cover in his talk. This is part four of a series of blog posts:

    As we have seen in the previous posts of this blog post series, the presentation model clearly assigns responsibilities within the presentation layer. For simple user interfaces this approach is more than good enough. However, simple user interfaces are not really the domain of Rich Internet Applications (RIA). How can we tackle complex user interfaces using the presentation model approach? Let’s have a look at a non-trivial user interface:

    Screenshot

    It shows a typical master-detail view, further enhanced by a tree navigation on the left-hand side. The user can select different aspects of a person in the tree which brings up the corresponding form on the right hand side.
    A naïve approach would be to create a single presentation model for the entire view. While implementing the presentation model you will soon realize that there is just too much state and behaviour to be captured in a single presentation model.

    If a view is too complex, we have to split it up into manageable sub-views, each with a presentation model of its own. The combination of sub-view with its presentation model is called “application component”. An application component communicates with its environment only via the presentation model, i.e. the presentation model acts as an observer to other application components (resp. their presentation models).

    A complex user interface can now be decomposed into a number of fairly independent application components. Independence means, that these application components can be employed or reused in different contexts. Independence is facilitated by relying on the observer pattern for communication with other application components.
    How do you build a complex user interface from a set of application components. You simply arrange the application components in a hierarchy. Each application component is responsible for the creation of all directly known application components. Views and presentation models have to be aware of this hierarchy. An abstract base class for view resp. presentation model can factorize this.

    The component hierarchy for our example user interface shown above looks like this:

    Component hierarchy

    Views are marked red and presentation models are blue.

    As you can see not every view needs to come with a presentation model of its own. In this case the form view hooks up to the presentation model of the navigation view. A change in the tree selection will be broadcasted by the navigation presentation model. The form view updates itself accordingly by bringing the corresponding view to the front.

    In addition, application components are perfect candidates for testing. Each application component can be tested independently (as described in part three). Testing a user interface made up from a hierarchy of application components can be considered as integration testing. It still focuses on the behaviour of the presentation models, though. An integration test case first creates the presentation model hierarchy and then tests the behaviour of the model hierarchy. The view code in this hierarchy is still trivial and therefore rarely need dedicated test cases.

    Application components have another advantage. They are perfect candidates to be assigned as an independent task to a developer.

    There are still some challenges left, such as clean initialization for presentation models and views when creating a hierarchy of application components or distribution of update events in this hierarchy without ending up in infinite update cycles.

    In the next bog post, we will have a look at a simple framework which supports building user interfaces with application components. We will also see how easy it is to generically add undo/redo to an application.

    Part 1: MVC and the Brave New World of RIA
    Part 2: The World Needs More Models
    Part 3: A simple view on complex stuff


    How Widespread is the Use of RIA Plug-ins?

    February 19th, 2008

    Are there any studies or reports on the acceptance of plug-ins for Rich Internet Applications (RIA)? Are there any statistics available? Or any Gartner or Forrester reports?

    These are some questions we hear quite often. I tried to find out if there is an independent report on this. But most reports I found so far are based on vendor statistics.

    Adobe Flash

    Adobe claims over 750 million connected PCs and mobile devices worldwide have the Flash player installed. There’s a Adobe stats page that shows the current percentage of penetration for each version. Mike of RIApedia.com points to this same web page and concludes that 90% can view Flex 2 applications. The latest Flex framework requires Flash Player 9.0.

    Java Runtime Environment

    The Sun Microsystems website reports that over 91% of internet-connected PCs have Java enabled.

    Java Desktop

    Over 91% of Internet-connected PCs have Java enabled (Source: Omniture, April 2007).
    This includes over 63% of Sun JRE in the US, and over 65% of Sun JRE in Italy/Spain/UK (Nielsen//NetRatings, January 2007)

    92% (and growing) of JRE installs (Java.com, J.S.C.) are now Java SE 6 (April 2007, Sun)

    Estimated Worldwide Java SE penetration per Operating System and VM vendor (Source: Sun estimate, April 2007)

    • Sun JRE (Windows): 65%
    • Microsoft VM (Windows): 21%
    • Apple VM (Mac OS): 3.5%
    • Other (including Java SE on Linux and other OS: 1.5%

    PC OEMS representing over 60% of all shipped PCs in Q4 2006 have signed Java SE redistribution agreements with Sun. (Sun, based on IDC #206152, March 2007).

    9 of the top 10 PC OEM vendors have a JRE redistribution agreement with Sun. (Sun, based on IDC #206152, March 2007).

    Silverlight

    I would expect Microsoft’s Silverlight to be a lot lower (being newer to the market). Techcrunch reported in January 2008 that NBC will be streaming the Beijing Olympics using Silverlight.

    So far, all I have found are statistics on the number of downloads. I would be interested in how often the plug-ins are accessed per week and for what kind of applications (gaming vs. work-related applications).

    JavaScript

    For completion’s sake, let’s have a look at the stats for JavaScript, which is part and parcel of all standard web browsers and does not require a separate download. JavaScript needs to be enabled for AJAX applications.

    Javascript 1.2+: 3048722 (93%)
    Javascript <1.2: 5587 (0%)
    Javascript false: 214683 (6%)

    The Counter lists that 93% of all web browsers have JavaScript enabled.

    Nevertheless, statistics can often be misleading.

    Before deciding on a technology, consider the target audience. How often will a person use the application? Regular users will probably be more inclined to download a plugin if the corresponding web application improves their work experience or productivity.


    Canoo is Silver Sponsor of Jazoon 08

    February 18th, 2008

    Jazoon 08

    Canoo is sponsoring Jazoon, a Java conference taking place in Zürich, Switzerland from June 23 to 26, 2008. The initial speaker list looks very promising, with a number of renowned speakers.

    See also last year’s Jazoon blog posts written by Canoo attendees.

    Meet Canoo at these upcoming events:

    2G Experience

    Dierk König is speaking at this week’s 2G Experience in Reston, Virginia.

    SD West 08

    Bruno Schäffer is speaking at SD West 08 in Santa Clara, California on Friday, March 7.

    OpenExpo in Bern on 12th and 13th March, 2008

    And on March 12 and 13, Canoo will be exhibiting at the OpenExpo in Bern, Switzerland. Order a free entrance ticket here.

    An overview of all Canoo events is available here: http://canoo.com/events.html


    Podcast: Frank Westphal interviews Dierk König

    February 16th, 2008

    Groovy and Grails at Frankwestphal.de

    Listen to the podcast on Groovy and Grails (in German).


    RIA Better for Online Advertising

    February 13th, 2008

    I stumbled across Ryan Stewart ’s post on online advertising.

    His main argument: Rich Internet Applications (RIA) offer a richer experience and are thus better positioned to profit from the general move from TV to online advertising:

    One, the technology is richer and therefore more opportunities exist to create the kind of advertising that would benefit brands. This is both because of the audio/video capabilities but also because of the technical nature of RIAs. We can push data to clients, provide real-time collaboration and stay away from page refreshes that would ruin an experience. All that means that advertisers can control the experience all the way through and establish branding in a more strategic way. Secondly, rich Internet applications bring richness to a variety of touch points. We’re seeing RIAs on the desktop, on mobile devices, and set top boxes/video game consoles. Being able to take advantage of the same technology on a variety of devices and platforms means that advertisers can easily customize the experience so that they can provide the proper amount/type of advertising for the device using the exact same property. The same rich Internet application should have an interface customized to the small screen and the big screen and using RIAs to build brands means you can provide the right type of advertising for the medium and know that the experience will be consistent; something that doesn’t exist right now with regular HTML/banner ads.


    LIFT 08: Some observations

    February 11th, 2008

    Last week I attended LIFT in Geneva, Switzerland. LIFT is a conference that explores the challenges and opportunities of technology in society. The conference discusses new technologies and their impact on society from a user’s point of view.

    LIFT logo

    Here are some trends I observed:

    Disclaimer: this is my personal view and interpretation of LIFT. Please feel free to add a comment or point out any errors.

    Better Interfaces

    There are companies such as Headshift looking to create new web tools that will help to manage information overload and personal productivity in large networks or organizations. They held a workshop at LIFT to hear ideas and opinions about hybrid web interfaces for email, RSS feeds, and concepts such as Getting Things Done.

    I was in a parallel workshop called Forgetful Interfaces, discussing new ways to display the huge amounts of stored data we have accumulated. It was a very broad discussion and I went out of the workshop with more questions than answers. One proposal was to build interfaces like the human memory: data linked to recent events is available immediately, and as time flies, the data - i.e. the interface items related to the data - that you have not used over the past year fades away. For example, items in a to do list are important in the short term, but will tend to clutter search results one year from now without adding any added value.

    These two workshops highlight the need for better web interfaces for knowledge workers. The amount of information from various data streams is due to increase, and the challenge is to build business process, as well as knowledge management tools that will increase efficiency and productivity. As Web 2.0 moves into the corporate world, I’m expecting the need for richer, adaptable interfaces to grow.

    Scalability

    One of the most common questions asked by the Venture Night panel on Wednesday evening was: What about scalability? If your web app is successful and draws millions of users, will the architecture be able to handle this? How are you addressing the performance issue?

    Mobile computing

    Francesco Cara of Nokia described the evolution of mobile communication ecosystems. We are currently in the third stage where new features and services are being introduced rapidly, new players such as Apple and Google moving into the market, the complexity is increasing, and more mobile applications are accessing the Internet directly.

    Within this context, I couldn’t help but think of Canoo’s RIA for Mobiles project, that Christian wrote about in January 2008.

    Further links on LIFT 08:

    LIFT videos

    Bruno Giussani’s blog

    Stephanie Booth’s blog

    Hannes Gassert’s notes in the Liip blog


    A simple view on complex stuff

    February 11th, 2008

    Canoo’s CTO Bruno Schäffer is speaking at SD West 08 on “Design Patterns for Rich Internet Applications”.

    SD West 08

     

    The following blog post outlines some of the concepts that he will cover in his talk. This is part three of a series of blog posts:

    So far we discussed the deficiencies of plain MVC for complex user interfaces and how the presentation model approach can remedy this situation. The presentation model assumes most of the former responsibilities of the view/controller pair. What remains for the view/controller pair? Frankly spoken, not much:

    • The view is responsible to create the user interface components and arrange them in a layout.
    • All relevant events triggered by the user interface components are redirected to the appropriate methods of the presentation model
    • The view is an observer of the presentation model. It has to react to the relevant changes to the presentation model and update the user interface accordingly.

    Creating the user interface (besides design and ergonomical aspects) is trivial but cumbersome to code. However, we have the opportunity to employ some markup language for specifiying the UI. Markup language are not really suited to specify presentation logic, but since this is coded in the presentation model, views can easily be built this way. Examples for UI markup languages are SwiXml , ULC XML or XUL.

    Redirecting events to the presentation model and reacting to changes of the presentation model is also pretty straightforward in most cases. The standard scenarios can be covered by generic infrastructure known as binding. I will discuss some aspects of binding in a later blog post.

    Now let us have a look at a simple example to illustrate the concepts discussed so far.The example is based on the ULC component library, but the basic concepts can easily be transfered to most common component libraries. Here is a screenshot of the application to show what it looks like:

    Screenshot showing a simple view

    The application allows a user to load a record into the form, edit it and save it. There are two business objects involved, pertaining to the person and university. The presentation logic is simple: first name and last name must not be empty and the university id must relate to an existing university record. Validation is immediate, e.g. if the user enters the university id the university name field will be updated immediately. The presentation model captures the necessary state and logic. Below you can see the implementation stripped down to the properties personName and personFirstName (the observer infrastructure is left out too). It is fairly simple: since the presentation model is a Java Bean, we need to provide setters and getters which map to the person object referenced by the presentation model. The property personName has only a getter since it is a read only property. The setter validates the property and updates the errorList property accordingly.


    public class SimpleFormPresentationModel {
        private Person fPerson;
        private ErrorList fErrorList;
     
        public final static String PERSON_NAME = "personName";
        public final static String PERSON_FIRST_NAME = "personFirstName";
        public final static String ERROR_LIST = "errorList";
     
        public SimpleFormPresentationModel() {
            fireAllPropertiesChanged();
        }
     
        public String getPersonFirstName() {
            return getPerson().getFirstName();
        }
     
        public void setPersonFirstName(String firstName) {
            getPerson().setFirstName(firstName);
            validate(PERSON_FIRST_NAME);
            firePropertyChanged(PERSON_NAME, getPersonName(getPerson()));
        }
     
        public String getPersonName(Person person) {
            return person != null ? person.getFirstName() + " " + person.getLastName() : "";
        }
    }

    The view class is pretty straightforward. Basically, it creates the UI, hooks up the UI components to the presentation model and reacts to the changes of the presentation model. The implementation uses the UltraLightClient component library. The stripped down view class (incl. some convenience methods) looks like this:

    public class SimpleFormPane implements IPropertyChangeListener {
        private ULCBoxPane fFormPane;
        private ULCTextField fName;
        private ULCTextField fFirstName;
        private SimpleFormPresentationModel fFormPresentationModel;
        private Color fErrorColor = new Color(255, 0, 0, 192);
     
        private static final String[] UI_FIELDS = new String[]{"firstName"};
     
        public SimpleFormPane(SimpleFormPresentationModel formPresentationModel) {
            fFormPresentationModel = formPresentationModel;
        }
     
        public ULCComponent getPane() {
            if (fFormPane == null) {
                fFormPane = createForm();
                fFormPresentationModel.addPropertyChangeListener(PERSON_NAME, this);
                fFormPresentationModel.addPropertyChangeListener(PERSON_FIRST_NAME, this);
                addValueChangedListener(PERSON_FIRST_NAME, fFirstName);
            }
            return fFormPane;
        }
     
        private void addValueChangedListener(final String property, final ULCTextComponent textComponent) {
            textComponent.addValueChangedListener(new IValueChangedListener() {
                public void valueChanged(ValueChangedEvent event) {
                    if (textComponent instanceof ULCTextField &amp;&amp; ((ULCTextField)textComponent).getDataType() != null)  {
                        fFormPresentationModel.setProperty(property, ((ULCTextField)textComponent).getValue());
                    } else {
                        fFormPresentationModel.setProperty(property, textComponent.getText());
                    }
                }
            });
        }
     
        private ULCBoxPane createForm() {
            ULCBoxPane boxPane = new ULCBoxPane(2, 1, 5, 5);
            boxPane.add(2, "cc", new ULCLabel(HTMLUtilities.convertToHtml("<strong>Person Data</strong>")));
     
            boxPane.add("rc", new ULCLabel("Name:"));
            fName = new ULCTextField();
            fName.setEnabled(false);
            boxPane.add("ec", fName);
     
            boxPane.add("rc", new ULCLabel("First Name:"));
            fFirstName = new ULCTextField();
            boxPane.add("ec", fFirstName);
     
            boxPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
            return boxPane;
        }
     
        public void update(String property, Object oldValue, Object newValue) {
            if (property.equals(PERSON_NAME)) {
                fName.setText((String)newValue);
            } else if (property.equals(PERSON_FIRST_NAME)) {
                fFirstName.setText(((String)newValue));
            } else if (property.equals(ERROR_LIST)) {
                ErrorList errorList = (ErrorList)newValue;
                    for (at.diefaehre.argo.pm.util.Error error : errorList) {
                    ULCComponent component = getComponent(error.getProperty());
                    if (component != null) {
                        if (error.isError()) {
                            component.setBackground(fErrorColor);
                        } else {
                            component.setBackground(Color.white);
                        }
                    }
                }
                setFocusToFirstError(errorList);
            }
        }
     
        private void setFocusToFirstError(ErrorList errorList) {
            for (String field : UI_FIELDS) {
                if (errorList.containsError(field)) {
                    ULCComponent component = getComponent(field);
                    if (component != null) {
                        component.requestFocus();
                        break;
                    }
                }
            }
        }
     
        private ULCComponent getComponent(String name) {
            ULCComponent component = null;
            try {
                component = (ULCComponent)PropertyUtils.getProperty(this, name);
            } catch (Exception e) {
            }
            return component;
        }
     
        public ULCTextField getName() {
            return fName;
        }
     
        public ULCTextField getFirstName() {
            return fFirstName;
        }
    }

    What would test cases for this simple scenario look like? The view contains no real logic and therefore we do not need to write any test cases. However, we should make sure that the presentation model updates its properties correctly (incl. validation) and triggers the appropriate update events. Tests for our presentation model could look like this:


    @Test
    public void testValidFirstName() {
        attachPropertyChangeRecorder(fPresentationModel);
        fPresentationModel.setPerson(Service.getService().getPersonById(1));
        fPresentationModel.setProperty(PERSON_FIRST_NAME, "Bruno");
        assertFalse(fErrorList.hasErrors());
        testPropertyChangeMap(PERSON_NAME, PERSON_FIRST_NAME, ERROR_LIST);
    }
     
    @Test
    public void testInvalidFirstName() {
        attachPropertyChangeRecorder(fPresentationModel);
        fPresentationModel.setPerson(Service.getService().getPersonById(1));
        fPresentationModel.setProperty(PERSON_FIRST_NAME, "");
        assertTrue(fErrorList.hasErrors());
        assertEquals("firstName", fErrorList.getError().getProperty());
        assertEquals(1, fErrorList.getError().getErrorNr());
        testPropertyChangeMap(PERSON_NAME, PERSON_FIRST_NAME, ERROR_LIST);
    }

    The first test case starts with attaching a person to the presentation model and then sets the personFirstName property. There are two checks: one whether no errors have been produced and the other checks whether all expected update events have been triggered. For this an event recorder is attached (attachPropertyChangeRecorder()) and testPropertyChangeMap verifies the expected update events.

    As shown above, this blog post looked at simple views and how they are implemented with a presentation model running underneath. The above example demonstrated the concepts introduced so far. Obviously, there are still some drawbacks to this simple approach. It will not easily scale to more complex user interfaces (e.g. a master detail view with tabbed forms) and contains quite a lot of repetitive code. In the next blog post, we will investigate how more complex user interfaces can be tackled.

    See also:

    Part 2: The world needs more models

    Part 1: MVC and the Brave New World of RIA


    Dierk König on Groovy

    February 2nd, 2008

    Kirk Pepperdine interviews Canoo’s Dierk König.


    The Next Release of UltraLightClient: What to expect in 2008?

    February 1st, 2008

    UltraLightClient (ULC) is a development library for creating Rich Internet Applications, developed and maintained by Canoo. It is used to create robust and scalable web applications for the intranet, extranet, and internet. Knowledge workers - that use web applications on a daily basis and for extended periods of time - profit from better interfaces built with UltraLightClient.

    UltraLightClient 08

    Here are some questions I asked Daniel Grob, the technical lead of the UltraLightClient team, regarding the team’s plans:

    Interview with Daniel Grob

    SW> What is planned for 2008?

    We will continue to publish a maintenance release every 3 to 4 months. Maintenance releases contain minor bug fixes and feature requests. It is our policy to fix all minor issues reported to the support mailing lists in the next maintenance release. This means that maintenance releases are driven by the support mailing lists and that your posts on the support mailing lists have a great impact on the next maintenance release. So keep on posting!

    We plan to bring out one major release per year. And the topic of the major release for 2008 is all about productivity, productivity, and productivity.


    SW> What can developers expect in this release?

    UltraLightClient provides a very easy architecture for your Rich Internet Application, it does not enforce a client-server split on your application like most other RIA libraries do. From an architectural point of view, UltraLightClient applications are easier and faster to develop. But we learned from our customers that when building an UltraLightClient application you often need to build some initial application-independent, higher-level components like a form component or a sorted table. These missing high-level components somewhat mask the architectural benefit. You gain because of the easy architecture but you lose some of this gain because of the missing high-level components. In the major release for 2008 we want to address this issue. UltraLightClient will start to provide more than the basic components, such as buttons or text fields, and offer easy-to-use high-level components like a form component or a sorted table as well. This means your application developer team will not need to build high-level components themselves. They can just use the ones that are part of UltraLightClient and be productive from day one.


    SW> In October 2007 the UltraLightClient team posted a questionnaire on the product website, asking customers for feedback on the Canoo RIA library. What happened to that feedback?

    First, there was a draw and one lucky guy won an iPod Touch!

    The support mailing lists are a good source for maintenance release. However we feel that for innovations the postings on the support mailing lists are not adequate because they discuss minor issues in the current product. Support postings focus on the existing product. That is why we did the questionnaire last year: to get feedback for our major releases. And the questionnaire really gave us good feedback about what innovation our customers want to see in UltraLightClient. This feedback poured into our UltraLightClient 2008 release content: productivity, productivity, productivity.

    SW> Where can ULC developers find more information on the roadmap, the bugs that will be fixed, the release plan?

    Where planning is concerned we are quite open. We do not hide information from our customers. Our main planning tool is JIRA and customers can look at the release plans and the state of the releases in development in our JIRA road map.

    If you like to get more aggregated information you can subscribe to the news mailing list. In the news mailing list we inform about releases and about upcoming events.

    And we will start to do regular posts on this blog to keep you up-to-date on the latest development on UltraLightClient. So subscribe to this RSS feed to stay tuned.

    RSS feed