Ultra Light Client Logo

Release Notes

September 12, 2007

 

About UltraLightClient 6.2

Release 6.2 includes the following new features:

Feature Description
Test Framework The test framework is a tool to enable functional testing of UltraLightClient applications. It shields the test developer from all UltraLightClient specifics.
  • Fast and reliable: No need to write complex synchronization code.
  • Easy to use: No need to write test specific infrastructure code.
  • Real end-to-end: Use your launcher and container adapters in your tests.
  • Monitor production: Use the test framework to test the availability and response time of your UltraLightClient applications in production.
QuickTest Professional Integration Use the popular record & replay tool to define your functional tests. The QuickTest Professional integration saves you from writing complex synchronization code and therefore enables fast and reliable functional tests for your UltraLightClient applications.
Support Fixes This release contains a lot of fixes and features that were reported to the support mailing list.
Cell Based Pop Up Menus Some components are built out of smaller sub-elements. These sub-elements are usually referred to as cells. UltraLightClient supports the following cell-based widgets: ULCList, ULCTable, ULCTree, and ULCTableTree. For these widgets it is now possible to define a component pop-up menu that shows different menu items for each cell.

Cell Based Popup Menus

Custom Blocking Feedback UltraLightClient blocks the user interface during a synchronous server round-trip. By default, UltraLightClient indicates a blocking user interface by means of a special mouse cursor. It is now possible to define a custom blocking feedback.

Custom Blocking Feedback

Multi File Selection UltraLightClient's file chooser dialog is now able to select more than one file at once.
Swing API This release contains almost 100 new properties and methods for existing components plus one completely new component. You can find detailed information for the most important features in the next sections.
ULCSpinner ULCSpinner is a new control that enables an easy selection for numbers, dates and list elements.

ULCSpinner

ComponentOrientation All components now support left-to-right and the right-to-left component orientation.

Component Orientation

Full Mnemonic Support It is now possible to set mnemonics, as well as the exact mnemonic index on labels, buttons, and tabs.

Full Mnemoni Support

L&F Window Decoration Dialogs and frames now support look & feel window decoration. Therefore dialogs and frames can now inherit the window decoration from the installed look & feel and not from the underlying host operating system, e.g. Windows.

L&F Window Decoration

Slider Labels The labels in ULCSlider can now be defined in detail to show their various values.

Slider Labels

Progress Bar String ULCProgressBar can now contain an information string, e.g. to display the percentage completed or the time required for an operation.

Progress Bar String

Tab Layout Policy A ULCTabbedPane with a lot of tabs can now display scroll buttons for faster tab navigation.

Tab Layout Policy

The sections Fixed Bugs and Implemented Feature Requests give an overview of the most important differences between UltraLightClient 6.1.3 and UltraLightClient 6.2.

To migrate from UltraLightClient 6.1.3 to UltraLightClient 6.2, please see the migration notes.

 

Version Notes

UltraLightClient 6.2 requires the Java Runtime Environment (JRE) 1.4.2 or later on the server and on the client.

To deploy an UltraLightClient application in a J2EE server the server needs to support either at least the Servlet 2.4 specification or at least the EJB 2.1 specification.

 

Modules, Parts and Release Structure

The UltraLightClient release includes all components required to successfully develop and deploy UltraLightClient applications. The UltraLightClient modules, parts, packages, and the structure of the current release are described in the following sections.

 

Modules

The UltraLightClient release is split into modules. Each module belongs to exactly one of five categories:

The category and module names are reflected in the directory structure of the release, e.g. environment/applet for the applet module that belongs to the environement category.

A module directory contains subdirectories with the following contents:

 

Parts

Each of these modules can contain up to four parts:

The part names are reflected in the filename of the jar files in the lib and src directory of the corresponding module, e.g. ulc-applet-client.jar and ulc-applet-client-src.jar for the classes and source stubs of the applet module that have to be deployed on the client side.

 

Release Structure

ulc-6.2 UltraLightClient 6.2 home directory
   addon
      testframework
      qtpintegration
Add-ons to the UltraLightClient base framework
   base UltraLightClient base framework
   container
      ejb
      servlet
J2EE server integration including EJB container integration and Servlet container integration.
   doc
      addon
       ULCQTPIntegrationGuide.pdf
       ULCTestFrameworkGuide.pdf
      apidoc
      ULCArchitectureGuide.pdf
      ULCDeploymentGuide.pdf
      ULCEssentialsGuide.pdf
      ULCExtensionGuide.pdf
      ULCInstallGuide.pdf
      ULCReferenceGuide.pdf
      ULCTestFramework.pdf
      ULCWhitePaper.pdf
UltraLightClient documentation
   environment
      applet
      jnlp
      standalone
Client environment integration for applet deployment, JNLP deployment, and standalone deployment.
   license the jar file with the deployment license key
   previous_releasenotes Previous release notes
   sample
      hello
      onlineshop
      pie
      teammembers
      tomcat
      trusted
      ulcdndset
      ulcset
Sample applications with ready to run Tomcat Servlet container
   build.txt Contains the build number
   LicenseAgreement.pdf The license Agreement
   releasenotes.html This document

 

 

Fixed Bugs

PR Description Comments
UBA-7220 UISession.waitForIdle() does not respect low priority events  
UBA-7221 UISession.waitForIdle() does not respect multi cycle round trips  
UBA-7222 UISession.waitForIdle() may lead to a deadlock  
UBA-7183 Multiple client-side sessions in one VM / AppContext may lead to a deadlock  
UBA-7248 DefaultTableModel.isCellEditable javadoc is missing  
UBA-1101 Drag & Drop triggers an exception when dropping on fields with data type set  
UBA-6920 It is not possible to set ULCCheckBox as a cell editor on ULCTree  
UBA-6967 DnD does not work in ULCInternalFrame  
UBA-6989 ULCTextArea.append : the appended value is lost  
UBA-7154 ULCAlert.setInitialValue doesn't work  
UBA-7163 DevelopmentRunnerGui: NullpointerException while setting the connetion type  
UBA-7217 Disabling of the swing DnD feature is not possible  
UBA-7232 ULCLayeredPane.setLayer() method causes reset of defaultButton for ULCInternalFrame  
UBA-7246 ULCPollingTimer's ActionListener should not be fired once the timer is stopped on the server  
UBA-7247 Infinite loop when there are many users trying to start a session  
UBA-7252 Focus handling of ULCTable is not the same as in JTable  
UBA-7259 ULCScrollBar.setPosition(0.0 ) when it is not in sync with the client side value does not work and issue with adjustment event and client'server synch  
UBA-7260 ULCTextComponent.setCaretPosition(0 ) when it is not in sync with the client side value does not work.  
UBA-7265 JTable#setSurrendersFocusOnKeystroke(true) does not work when a custom cell editor has been installed  
UBA-7270 Implementation of addNotify and removeNotify methods should be as per Swing  
UBA-7049 DefaultTableTreeHeaderCellRenderer does not display background color unless it's opaque property is set to true.  
UBA-7173 DefaultTableTreeHeaderRenderer is not using the default look and feel border  
UBA-7201 Removing a listener that has not yet been added to a ULCProxy results in removal of the event category from optional events list.  
UBA-7102 ULCFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE) removes WindowListener.  
UBA-7135 Removing the selected card from a ULCCardPane should update the selection state and fire the corresponding event.  
UBA-7172 In ULCCombobox with a SelectionManager, Registered key event is consumed on the client side  
UBA-7185 IDnDComponent.restoreDnDSourceData() is never called  
UBA-7211 UITree does not load / paint TreeNodes  
UBA-7212 No data (nodes) are fetched on AbstractTreeModel.nodeStructureChanged(rootNode) if setRootVisible(false)  
UBA-7213 Mac OSX JDK 1.5: the mouse released event is not played on the right component if a mouse click triggers a popup menu  
UBA-7218 The input blocker filters mouse dragged events - this leads to errors on MAC OSX  
UBA-7224 Lazy loading is broken if ULCTable / ULCTableTree / ULCTree / ULCList is not direct child of ULCScrollPane  
UBA-920 ULCTree is not updated when changing the root node's value  
UBA-7228 componentPopupMenu property is ignored if inheritsPopupMenu property is true  
UBA-7231 ULCInternalFrame.pack() should reset isIcon and isMaximum flags just like JInternalFrame.pack()  
UBA-985 Link to bundled sample tomcat does not work on Linux  
UBA-7249 No selection events while expanding a table tree node the first time  
UBA-7283 LCTableTree.setShowsRootHandles() has no immediate visual effect but shows up only after repaint  
UBA-7284 ULCTable.fTable.setDefaultRenderer() has no immediate visual effect but shows up only after repaint  

 

Implemented Feature Requests

PR Description Comments
UBA-7227 Provide ULC Test Framework  
UBA-7274 Provide support for QuickTest Professional  
UBA-6943 Support JSpinner New API:
  • ULCSpinner
  • ULCSpinnerDateModel
  • ULCSpinnerListModel
  • ULCSpinnerNumberModel
UBA-715 Support for Cell Based Popup Menus New behavior:
  • IRendererComponent.componentPopupMenu property is now respected when displaying a component popup menu
UBA-7255 Provide ULCSlider.labelTable property New API:
  • ULCSlider.getLabelTable()
  • ULCSlider.setLabelTable(Map)
  • ULCSlider.createStandardLabels(int increment)
  • ULCSlider.createStandardLabels(int increment, int start)
UBA-6946 Add a popup menu listener to ULCComboBox much as for JComboBox New API:
  • IPopupMenuListener.popupMenuHasBecomeVisible(PopupMenuEvent event)
  • IPopupMenuListener.popupMenuHasBecomeInvisible(PopupMenuEvent event)
  • IPopupMenuListener.popupMenuCanceled(PopupMenuEvent event)
  • ULCComboBox.addPopupMenuListener(IPopupMenuListener listener)
  • ULCComboBox.removePopupMenuListener(IPopupMenuListener listener)
  • ULCPopupMenu.addPopupMenuListener(IPopupMenuListener listener)
  • ULCPopupMenu.removePopupMenuListener(IPopupMenuListener listener)
UBA-886 Provide a TableColumnModelListener as in Swing New API:
  • IColumnModelListener.columnAdded(ColumnModelEvent event)
  • IColumnModelListener.columnRemoved(ColumnModelEvent event)
  • IColumnModelListener.columnMoved(ColumnModelEvent event)
  • ULCTableColumnModel.addColumnModelListener(IColumnModelListener listener)
  • ULCTableColumnModel.removeColumnModelListener(IColumnModelListener listener)
  • ULCTableTreeColumnModel.addColumnModelListener(IColumnModelListener listener)
  • ULCTableTreeColumnModel.removeColumnModelListener(IColumnModelListener listener)
UBA-7134 Provide ULCDialog#setUndecorated(boolean) API New API:
  • ULCDialog.setUndecorated(boolean)
  • ULCDialog.isUndecorated(boolean)
  • ULCFrame.setUndecorated(boolean)
  • ULCFrame.isUndecorated(boolean)
  • ULCRootPane.setWindowDecorationStyle(int windowDecorationStyle)
  • ULCRootPane.NONE
  • ULCRootPane.FRAME
  • ULCRootPane.PLAIN_DIALOG
  • ULCRootPane.INFORMATION_DIALOG
  • ULCRootPane.ERROR_DIALOG
  • ULCRootPane.COLOR_CHOOSER_DIALOG
  • ULCRootPane.FILE_CHOOSER_DIALOG
  • ULCRootPane.QUESTION_DIALOG
  • ULCRootPane.WARNING_DIALOG
UBA-7240 Provide ULCTabbedPane.setTabLayoutPolicy() API New API:
  • ULCTabbedPane.setTabLayoutPolicy()
  • ULCTabbedPane.getTabLayoutPolicy()
  • ULCTabbedPane.WRAP_TAB_LAYOUT
  • ULCTabbedPane.SCROLL_TAB_LAYOUT
UBA-7238 Provide ULCProgressBar.setStringPainted() API New API:
  • ULCProgressBar.setStringPainted()
  • ULCProgressBar.isStringPainted()
  • ULCProgressBar.setString()
  • ULCProgressBar.getString()
UBA-7239 Provide ULCLabel.setDisplayedMnemonicIndex() API New API:
  • ULCAbstractButton.setDisplayedMnemonicIndex()
  • ULCAbstractButton.getDisplayedMnemonicIndex()
  • ULCLabel.setDisplayedMnemonicIndex()
  • ULCLabel.getDisplayedMnemonicIndex()
  • ULCTabbedPane.getMnemonicAt(int)
  • ULCTabbedPane.setMnemonicAt(int, int)
  • ULCTabbedPane.getDisplayedMnemonicIndex(int)
  • ULCTabbedPane.setDisplayedMnemonicIndexAt(int, int)
UBA-1030 Add ULCComponent.setComponentOrientation() API as in Swing New API:
  • ComponentOrientation
  • ULCComponent.setComponentOrientation(ComponentOrientation)
  • ULCComponent.getComponentOrientation()
  • ULCComponent.applyComponentOrientation(ComponentOrientation)
UBA-6929 Support Swing API of JDK 1.4 on the ULCComponents New API:
  • ULCAbstractButton.setDisabledSelectedIcon(ULCIcon)
  • ULCAbstractButton.getDisabledSelectedIcon()
  • ULCAbstractButton.setMultiClickThreshhold(long)
  • ULCAbstractButton.getMultiClickThreshhold()
  • ULCAbstractButton.setRolloverSelectedIcon(ULCIcon)
  • ULCAbstractButton.getRolloverSelectedIcon()
  • ULCAbstractButton.setContentAreaFilled(boolean)
  • ULCAbstractButton.isContentAreaFilled()
  • ULCAbstractButton.setRolloverEnabled(boolean)
  • ULCAbstractButton.isRolloverEnabled()
  • ULCAbstractButton.setSelected(boolean)
  • ULCAbstractButton.isSelected()
  • ULCButton.isDefaultButton()
  • ULCButton.setDefaultCapable(boolean)
  • ULCButton.isDefaultCapable()
  • ULCComponent.setRequestFocusEnabled(boolean)
  • ULCComponent.isDisplayable()
  • ULCComponent.setRequestFocusEnabled(boolean)
  • ULCComponent.isRequestFocusEnabled()
  • ULCComponent.setFocusCycleRoot(boolean)
  • ULCComponent.isFocusCycleRoot()
  • ULCComponent.transferFocus()
  • ULCComponent.transferFocusBackward()
  • ULCComponent.transferFocusUpCycle()
  • ULCComponent.transferFocusDownCycle()
  • ULCDesktopPane.setDragMode(int)
  • ULCDesktopPane.getDragMode()
  • ULCDesktopPane.LIVE_DRAG_MODE
  • ULCDesktopPane.OUTLINE_DRAG_MODE
  • ULCInternalFrame.dispose()
  • ULCInternalFrame.getDesktopPane()
  • ULCLayeredPane.getLayererdPaneAbove()
  • ULCMenu.setDelay(int)
  • ULCMenu.getDelay()
  • ULCMenu.isTopLevelMenu()
  • ULCPasswordField.getPassword()
  • ULCProgressBar.getPercentComplete()
  • ULCProxy.getListeners(Class)
  • ULCScrollPane.setWheelScrollingEnabled(boolean)
  • ULCScrollPane.isWheelScrollingEnabled()
  • ULCSlider.setPaintTrack(boolean)
  • ULCSlider.getPaintTrack()
  • ULCSlider.setInverted(boolean)
  • ULCSlider.getInverted()
  • ULCSplitPane.getLastDividerLocation()
  • ULCSplitPane.resetToPreferredSizes()
  • ULCTabbedPane.setDisabledIconAt(int, ULCIcon)
  • ULCTabbedPane.getDisabledIconAt(int)
  • ULCTabbedPane.indexOfTab(String)
  • ULCTabbedPane.indexOfTab(ULCIcon)
  • ULCTabbedPane.indexOfComponent(ULCComponent)
  • ULCTableHeader.getColumnModel()
  • ULCTableHeader.getTable()
  • ULCTableTreeHeader.getColumnModel()
  • ULCTableTreeHeader.getTable()
  • ULCTextArea.setTabSize(int)
  • ULCTextArea.getTabSize()
  • ULCTextArea.DEFAULT_TAB_SIZE
  • ULCTextArea.insert(String, int)
  • ULCTextArea.replaceRange(String, int, int)
  • ULCTextComponent.setCaretColor(Color)
  • ULCTextComponent.getCaretColor()
  • ULCTextComponent.setFocusAccelerator(char)
  • ULCTextComponent.getFocusAccelerator()
  • ULCTextComponent.replaceSelection(String)
  • ULCTextComponent.setSelectionEnd(int)
  • ULCTextComponent.setSelectionStart(int)
  • ULCToolBar.setRollover(boolean)
  • ULCToolBar.isRollover()
  • ULCTree.setLargeModel(boolean)
  • ULCTree.isLargeModel()
  • ULCTree.getMaxSelectionRow()
  • ULCTree.getMinSelectionRow()
  • ULCTree.isFixedRowHeight()
UBA-6863 Align the ULCInternalFrame API with Swing. New API:
  • ULCInternalFrame.getDesktopPane()
  • ULCInternalFrame.dispose()
UBA-7241 Provide ULCTable.setSurrenderOnKeyStroke() API New API:
  • ULCTable.setSurrenderOnKeyStroke()
  • ULCTable.getSurrenderOnKeyStroke()
  • ULCTableTree.setSurrenderOnKeyStroke()
  • ULCTableTree.getSurrenderOnKeyStroke()
UBA-6865 Provide ULCComboBox.setPrototypeDisplayValue(String) API as in Swing New API:
  • ULCComboBox.setPrototypeDisplayValue()
  • ULCComboBox.getPrototypeDisplayValue()
UBA-1097 ULCAppletPane should offer getSize() API New API:
  • ULCRootPane.getSize()
  • ULCRootPane.setSize()
  • ULCRootPane.getLocation()
  • ULCRootPane.setLocation()
UBA-7257 Uninstall does not uninstall all files  
UBA-6653 Unable to find out if a table popup menu has been opened over the empty area Changed behavior:
  • Selection is now cleared when opening a popup menu over the empty area
UBA-6854 Package the interfaces that have a serializable and non-serializable version in different JARs. Changed API:
  • All listeners in com.ulcjava.base.application.event package are now serializable, e.g. IActionListener, IFocusListener
UBA-781 ULC's FileChooserConfig does not support selection of multiple files. Changed/New API:
  • FileChooserConfig.setMultiSelectionEnabled()
  • FileChooserConfig.isMultiSelectionEnabled()
  • FileChooserConfig.setControlButtonsAreShown(boolean)
  • FileChooserConfig.getControlButtonsAreShown()
  • IFileChooseHandler.onSuccess(String[] filePaths, String[] fileNames)
  • IFileLoadHandler.onSuccess(InputStream[] ins, String[] filePaths, String[] fileNames)
See migration notes .
UBA-6884 ULCAbstractButton does not provide setSelected(), isSelected() New API:
  • ULCAbstractButton.setSelected()
  • ULCAbstractButton.isSelected()
UBA-7188 JNLP File Service returns null for file path, but it can return filename. Should a new API be provided which returns file path and file name? Changed API:
  • IFileChooseHandler.onSuccess(String[] filePaths, String[] fileNames)
  • IFileLoadHandler.onSuccess(InputStream[] ins, String[] filePaths, String[] fileNames)
  • IFileStoreHandler.onSuccess(String filePath, String fileName)
See migration notes.
UBA-7137 Make AllPermissionsFileService extensible - for example, w.r.t. FileFilter New API:
  • AllPermissionsFileService.createFileChooser()
  • AllPermissionsFileService.createFileFilter()
UBA-7206 Improve reflection performance  
UBA-7253 Component popup menus should only be inherited if all ancestors have the inheritsPopupMenu flag set  
UBA-7205 Model adapters should not be hard coded New API:
  • IModelAdapterProvider
  • DefaultModelAdapterProvider
  • IContainerServices.MODEL_ADAPTER_PROVIDER_KEY
A custom model adapter provider can be configured with the IContainerServices.MODEL_ADAPTER_PROVIDER_KEY init parameter. Please see the corresponding section in the ULC Extension Guide for a more detailed description.
UBA-665 API to get type of deployment container New API:
  • ApplicationContext.getContainerAdapterClassName()
UBA-976 The feedback during long lasting server round trips should be configurable New API:
  • IUserFeedbackStrategy
  • DefaultUserFeedbackStrategy
  • InputBlocker.setUserFeedbackStrategy()
  • InputBlocker.getUserFeedbackStrategy()
UBA-6860 Implement toString() on Insets class Added implementations to Rectangle and SystemColor class as well.
UBA-6918 ULCPercentDataType cannot enter / display negative percent values  
UBA-7276 ULCPercentDataType shoulld allow input / display of exponential (E) values  
UBA-6945 IBlockedSessionListener should provide callback for session unblock New API:
  • IBlockedSessionListener.sessionUnblocked()
UBA-7030 Writing a custom container still depends on Anything API  
UBA-7042 ULC session id used in Servlet deployment should only be valid within specific HTTP session context  
UBA-7067 ULCDataInputSteam / ULCDataOutputStream should not be final  
UBA-7079 ULCMenuBar#add(ULCComponent, Object) should support Integer constraints New API:
  • ULCMenuBar.add(ULCComponent, int)
UBA-7128 Open up private API ULCSession.processRequest(ICallable callable, Request request)  
UBA-7242 ULCMandatoryAndenabler shoud restore the current backgrond color on input to mandatory text field  
UBA-7243 ULCMandatoryAndEnabler should set the highlight color on a textfield irrespective of whether it is enabled or disabled New API:
  • ULCMandatoryAndEnabler.setShowHighLightColorWhenDisabled(boolean)
  • ULCMandatoryAndEnabler.getShowHighLightColorWhenDisabled()
UBA-7244 Add new API: ULCEnablerNode.getEnablers()  
UBA-7245 UserInteractionMonitor should check for null component in addMonitoredComponent  
UBA-7251 ULCStringDataType should ignore too long texts completely New API:
  • ULCStringDataType.setIgnoreLongStringCompeletely(boolean)
  • ULCStringDataType.setIgnoreLongStringCompeletely()
UBA-7256 ClientContext.storeFile should also take maxSize parameter New API:
  • ClientContext.storeFile(IFileStoreHandler handler, FileChooserConfig config, ULCComponent parent, long maximumFileSize)
  • ClientContext.storeFile(IFileStoreHandler handler, String clientFilePath, long maximumFileSize)
UBA-7258 Provide a public method that is equivalent to handleRequest() from the old extension API New API:
  • ULCProxy.processInvokeULC(String methodName, Object[] arguments)
  • ULCProxy.invokeUI(String methodName, Object[] arguments)
  • UIProxy.processInvokeUI(String methodName, Object[] arguments)
  • UIProxy.invokeULC(int deliveryMode, String methodName, Object[] arguments)
UBA-7266 ULCTable/ULCTableTree should support the use case where cell editor pops up a window.  
UBA-1125 Make com.ulcjava.base.application.util.Font immutable  
UBA-7158 Deprecate session state listener methods in launchers  
UBA-7170 Make 'targets' available to subclasses of UIHasChangedEnabler  
UBA-7203 Better null-handling and error reporting  
UBA-7223 Improve error message on lmethod client-side call  
UBA-7233 It should be possible to configure the DevelopmentRunner with help of init parameters  
UBA-7139 com.ulcjava.base.client.Registry.findByBasicObject(Object basicObject) should check that input parameter is not null.  
UBA-6953 Document how to pass ClientCoderRegisteryProvider to an EJBConnetcor and also Javadoc for EJBConnector  
UBA-576 DevGuide: do not use renderer/editor models for retrieval of data etc.  
UBA-627 ULCComponent.requestFocus() only works when widget is uploaded Added clarification to JavaDoc.
UBA-7075 ClientContext.getAvailableFontFamilyNames() has no elements Added clarification to JavaDoc.
UBA-581 Allow events to be sent deferred Added clarification to JavaDoc.
UBA-602 How to Implement IRendererComponent and IEditorComponent Interfaces  
UBA-6800 Improve Javadoc how to find the keys for the ClientContext.getXXX() methods.  
UBA-6949 ULC Extension Guide  
UBA-7025 Add informations concerning coders and streams to the architecture guide  
UBA-7153 Document how to deploy ULC applications in standalone off-line mode using LocalContainerAdapter  

 

Migration Notes

Enhancements for Client File Access

The enhancements for client file access made it necessary to change the API:

Removal of deprecated ULCComponent.setPopupMenu() methods

The methods ULCComponent.setPopupMenu() / ULCComponent.getPopupMenu() have been removed. Use ULCComponent.setComponentPopupMenu() / ULCComponent.getComponentPopupMenu() instead.

 

Known Problems and Limitations

You can find known problems and limitations in our issue database.

Product and company names herein may be trademarks of their respective owners.


Copyright (c) 2000-2015 Canoo Engineering AG