Forum
Cookbook
Tutorials
Documentation
Blog
Sign in
Login
Lost password?
|
New user?
search
Developer Blog
SORT BY
Title
Date
FILTER BY USER
Error
com.nm.sdk.NmRuntimeException: Expression Data Source 'Label' Expression Evaluation Error: If $item == 'All' Then Return 'All'; Else Return JOIN(GetUser($item).getLastName(), ' ', SUBSTRING(GetUser($item).getFirstName(), 0, 1), '.'); End
NullPointerException: The method null.getLastName(0) can not be called on a null instance.
com.nm.sdk.NmRuntimeException: Expression Data Source 'Label' Expression Evaluation Error: If $item == 'All' Then
Return 'All';
Else
Return JOIN(GetUser($item).getLastName(), ' ', SUBSTRING(GetUser($item).getFirstName(), 0, 1), '.');
End
at com.nm.sdk.data.pages.views.options.ExpressionDataSource.getOptions(ExpressionDataSource.java:232)
at com.nm.sdk.data.pages.views.components.OptionList.getOptions(OptionList.java:56)
at com.nm.sdk.data.pages.html.renderer.SearchableDropdownListRenderer.render(SearchableDropdownListRenderer.java:38)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Control.renderComponent(Control.java:124)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:345)
at com.nm.sdk.data.pages.html.renderer.FlowLayoutRenderer.render(FlowLayoutRenderer.java:20)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Container.renderComponent(Container.java:333)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:345)
at com.nm.sdk.data.pages.html.renderer.AjaxUpdateAreaRenderer.render(AjaxUpdateAreaRenderer.java:36)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Container.renderComponent(Container.java:333)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:345)
at com.nm.sdk.data.pages.html.renderer.DivRenderer.render(DivRenderer.java:46)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Container.renderComponent(Container.java:333)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:349)
at com.nm.sdk.data.pages.views.components.LayoutContainer.renderChildren(LayoutContainer.java:25)
at com.nm.sdk.data.pages.views.components.View.renderComponent(View.java:19)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Include.renderComponent(Include.java:263)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:349)
at com.nm.sdk.data.pages.html.renderer.DivRenderer.render(DivRenderer.java:46)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Container.renderComponent(Container.java:333)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:349)
at com.nm.sdk.data.pages.views.components.LayoutContainer.renderChildren(LayoutContainer.java:25)
at com.nm.sdk.data.pages.views.components.TemplateArea.renderComponent(TemplateArea.java:46)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Placeholder.renderComponent(Placeholder.java:59)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:349)
at com.nm.sdk.data.pages.html.renderer.DivRenderer.render(DivRenderer.java:46)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Container.renderComponent(Container.java:333)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:349)
at com.nm.sdk.data.pages.html.renderer.DivRenderer.render(DivRenderer.java:46)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Container.renderComponent(Container.java:333)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:345)
at com.nm.sdk.data.pages.html.renderer.DivRenderer.render(DivRenderer.java:46)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Container.renderComponent(Container.java:333)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:349)
at com.nm.sdk.data.pages.html.renderer.DivRenderer.render(DivRenderer.java:46)
at com.nm.sdk.data.pages.html.HtmlRenderKit.render(HtmlRenderKit.java:54)
at com.nm.sdk.data.pages.views.components.Component.renderComponent(Component.java:448)
at com.nm.sdk.data.pages.views.components.Container.renderComponent(Container.java:333)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:349)
at com.nm.sdk.data.pages.views.components.LayoutContainer.renderChildren(LayoutContainer.java:25)
at com.nm.sdk.data.pages.views.components.View.renderComponent(View.java:19)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Template.renderComponent(Template.java:160)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.sdk.data.pages.views.components.Container.renderChildren(Container.java:345)
at com.nm.sdk.data.pages.views.components.LayoutContainer.renderChildren(LayoutContainer.java:25)
at com.nm.sdk.data.pages.views.components.View.renderComponent(View.java:19)
at com.nm.sdk.data.pages.views.components.Component.render(Component.java:387)
at com.nm.screenflow.PageServiceImpl.processPageRequest(PageServiceImpl.java:771)
at com.nm.sdk.data.workflow.model.ScreenTask.processHttpRequest(ScreenTask.java:426)
at com.nm.workspace.ProcessServlet.processWorkflowToken(ProcessServlet.java:590)
at com.nm.workspace.ProcessServlet.processWorkitem(ProcessServlet.java:308)
at com.nm.workspace.ProcessServlet.doPost(ProcessServlet.java:115)
at com.nm.workspace.ProcessServlet.doGet(ProcessServlet.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.nm.filter.AppwayServletsFilter.doFilter(AppwayServletsFilter.java:38)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:36)
at com.nm.extensions.patch20201204.PatchFilter.doFilter(PatchFilter.java:55)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.extensions.scriptbridgeservletpatch.ScriptBridgeServletFilter.doFilter(ScriptBridgeServletFilter.java:38)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.extensions.jspservletpatch.PatchFilter.doFilter(PatchFilter.java:39)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.VersioningFilter.doFilter(VersioningFilter.java:84)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.AccessControlFilter.doFilter(AccessControlFilter.java:66)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.ApplicationLockFilter.doFilter(ApplicationLockFilter.java:123)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.ContextPathFilter.doFilter(ContextPathFilter.java:45)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.CacheFilter.doFilter(CacheFilter.java:99)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.FileUploadFilter.doFilter(FileUploadFilter.java:71)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.UserFilter.doFilter(UserFilter.java:260)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.ErrorFilter.doFilter(ErrorFilter.java:37)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.DebugFilter.doFilter(DebugFilter.java:102)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.EncodingFilter.doFilter(EncodingFilter.java:67)
at com.nm.filter.AppwayFilterChain.doFilter(AppwayFilterChain.java:33)
at com.nm.filter.AppwayFiltersFilter.doFilter(AppwayFiltersFilter.java:39)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176)
at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:381)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:603)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:1025)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1137)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1780)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1739)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.nm.sdk.NmEvaluatorException: The method null.getLastName(0) can not be called on a null instance. [token:., line:4, charpos:29, scope:If:elseif, functionStack:LocationPath[ObjectRef-Workflow-DisplayNews,elements/5,ObjectRef-Screen-DisplayNews,components/2,ObjectRef-Screen-Templates_Support_Main_v2.0,components/219,ObjectRef-Screen-DisplayNews,components/156,ObjectRef-Screen-IncludeFilterByUser,components/31:dataSource/property/label]]
at com.nm.exprlang.functions.MethodCallFunction.calculate(MethodCallFunction.java:83)
at com.nm.sdk.data.expeval.MethodCallUtils.callScriptFunction(MethodCallUtils.java:111)
at com.nm.sdk.data.expeval.nodes.FunctionNode.execute(FunctionNode.java:464)
at com.nm.sdk.data.expeval.MethodCallUtils.callScriptFunction(MethodCallUtils.java:72)
at com.nm.sdk.data.expeval.nodes.FunctionNode.execute(FunctionNode.java:464)
at com.nm.sdk.data.expeval.nodes.ReturnNode.execute(ReturnNode.java:103)
at com.nm.sdk.data.expeval.nodes.ExpressionListNode.execute(ExpressionListNode.java:175)
at com.nm.sdk.data.expeval.nodes.ConditionalNode.execute(ConditionalNode.java:182)
at com.nm.sdk.data.expeval.nodes.ScriptBodyNode.execute(ScriptBodyNode.java:169)
at com.nm.exprlang.InterpreterImpl.execute(InterpreterImpl.java:380)
at com.nm.exprlang.InterpreterImpl.interpret(InterpreterImpl.java:348)
at com.nm.exprlang.InterpreterImpl.interpret(InterpreterImpl.java:336)
at com.nm.exprlang.InterpreterImpl.interpret(InterpreterImpl.java:291)
at com.nm.exprlang.InterpreterImpl.interpretObject(InterpreterImpl.java:142)
at com.nm.sdk.data.pages.views.options.ExpressionDataSource.getOptions(ExpressionDataSource.java:221)
... 144 more
Caused by: java.lang.NullPointerException: The method null.getLastName(0) can not be called on a null instance.
at com.nm.sdk.data.expeval.FunctionPointer.<init>(FunctionPointer.java:47)
at com.nm.sdk.data.expeval.FunctionPointer.<init>(FunctionPointer.java:36)
at com.nm.exprlang.functions.MethodCallFunction.getMethodCallTarget(MethodCallFunction.java:71)
at com.nm.exprlang.functions.MethodCallFunction.calculate(MethodCallFunction.java:77)
... 158 more
Workspace Design Notes #18: Don't Play Hide and Seek
Published June 27, 2016 by
Lukas Mathis
Screen Design
Usability
Previous Design Notes tackling the topic of "why" – "
Why the Flow Bar is at the Bottom
" and "
Why Use the Border Layout Manager
", for example – have taken a deep dive into one specific design decision taken by the Appway Product and UX teams. This post continues that approach, examining why there's no "collapsible section" component within Appway.
You've probably seen a form like this before:
In this form, the user can click on the small "+" or "-" buttons to the right of each header to expand or collapse the corresponding section.
While it's technically possible to implement this feature in Appway using built-in components, Appway intentionally does not have a "collapsible section" component, or any kind of high-level feature specifically for creating collapsible sections.
Why?
Collapsible sections cause confusion.
I actually had trouble finding screenshots of a form with collapsible sections for this post, because these collapsible sections have fallen out of favor recently - and for good reason: They make form usability worse in 99% of all situations.
Note: All of the issues that collapsible sections have also apply to tabs. This is why we also strongly recommend against using tabs to organize forms.
Reason 1: Users don't really want them
It's true that people often request collapsible sections. But they request them because collapsible sections are a simple, "obvious" feature to request - not because they are actually going to be used.
When you measure how many people actually collapse the sections, you'll end up with numbers close to zero.
The simple fact is that in 99% of all cases, there is no reason to have collapsible sections. They don't solve any problems. There is no real use case for them. So people don't use them.
Collapsible sections make sense in theory, but think about it: How common is it that you use a form with collapsible sections, and actually collapse these sections? Does it happen in 50% of cases where you encounter a form with collapsible sections? Or do you collapse the sections just 10% of the time? More to the point: Have you ever collapsed one of these sections?
Now think about this: If you did once encounter a form with collapsible sections, and did collapse a section, why did you do it? What problem did you solve? Can you think of a better way of solving that problem? (Note: Hold that thought!)
Reason 2: Users use them by accident, and get confused
When we measure whether people actually use collapsible sections, we find that very, very few people (if any) use them. Interestingly, the people who do use them often do so by accident. Perhaps they were looking for a different feature, and clicked on the little [-] button just to see what it did. Or they touched it by accident on their phone.
In these situations, people often don't realize what has happened. To them, suddenly, part of the form is missing, and there may be no obvious way of getting it back.
In those situations, collapsible sections are indistinguishable from a bug in your solution.
Part of the form is missing, and users don't know why, or how to get it back? That's a support nightmare.
Reason 3: Users don't understand what they imply
But let's assume that your users understand how to expand and collapse sections, and that you've implemented the feature such that people don't get confused by accidentally collapsed sections.
Collapsible sections are still bad usability.
The
Baymard Institute
ran a usability test and found out that people did not understand what it meant for a section of a form to be closed. To quote:
"The issue arises when users can’t figure out which form fields will be submitted – whether it is only the fields in the currently active inline accordion or tab "sheet", or whether the collapsed "sheets" will be submitted as well."
When designing user-friendly form layouts it’s key to ensure that the user always instinctively knows which form fields will be submitted. Now, typically this is a non-issue since users assume all form fields will be submitted - and on most sites they are.
However, tab-style and inline accordion form layouts can muddy this relationship, making it unclear if the fields in each "sheet" are mutually exclusive or if switching between them simply toggles their visibility but not the actual form. This can make users uncertain as to which fields in the form will actually be submitted. As you can imagine, this is highly problematic as it leads to a sense of unpredictability and the fear of potential data loss.
Here's an actual quote from a user:
"Is it only the options that I’m currently seeing that will be submitted or will it submit all sections (including the 'collapsed' ones)?"
Collapsible sections make it look as if only part of the form is actually being submitted to the server. This means that users might accidentally submit bad information to the server, not understanding that the "hidden" data in the collapsible section is also being persisted.
Other Problems
When screens start out with collapsed sections, people can't scan them anymore to get an immediate understanding of what they're looking at.
When people use the browser's search function, and sections of the screen are collapsed, they won't be able to find text even if it's technically on the current screen.
If you have anchor links inside your screen, and link inside a collapsed section, these links won't work when the sections are collapsed.
This article lists more problems
.
What to do instead
The most common case where collapsible sections are used is in long screens. It's tempting to allow people to shorten these screens by allowing them to collapse sections. Unfortunately, collapsible sections don't really solve that problem; they just add additional complexity to already complex screens, and shift the burden of managing that complexity to the user.
If you have long screens, you should instead use the Table of Contents component, and put it in the left sidebar. This allows users to immediately see what a screen contains, and then to easily navigate between different sections of the screen at any time.
For more information, see
Navigating through Long Screens Using the Adaptive Table Of Contents Component
.
If you
must
If you are being asked for collapsible sections – or if you're the one asking for collapsible sections – first identify the problem you're trying to solve. What's the actual use case? Make sure that collapsible sections are not simply being requested out of habit.
If there is an actual problem to solve, collapsible sections are most likely still not the answer. In this case, please contact our team of
UX consultants
who will work together with you to find a good design solution for the problem.
While collapsible sections may seem like a good idea, they in fact aren't: they will cause usability and support problems.
Collapsible sections: The jetpack of UX
We all have an intuitive understanding of what makes a good user interface. This understanding is often partly based on customs we've gotten used to. A lot of the time, our intuition serves us well: If a lot of people do something, it's often a good idea to do the same thing. If everybody puts the search field into the header, putting your own search field into the header is a good starting point; even if it's not the best place within the context of your solution, at least it's no worse than what everybody else is doing.
Relying on intuition alone, however, is not a great idea because we're often mistaken about our own needs and about our users' needs. We don't think through all of the implications of a design decision, and we do something just because we've seen it before – not because it's actually a good idea.
Here's a secret: people are peculiar. Users behave in odd ways, have strange quirks, and in general rarely do what we want or expect them to do. And that's wonderful: that's what makes design so interesting.
That's why the field of UX design exists, why we do user research, and why we don't just go with our gut feeling: People are surprising, and our gut is often wrong.
Collapsible sections fall squarely into this category: You often see them on other websites, and intuitively, they seem to make sense. When you really do the research, though, you end up noticing that most people might think that they want them, but won't actually use them. Instead of making the user interface easier to understand and organize, they just add needless clutter.
Collapsible sections are like jet packs: a great idea in theory. In reality, you're just strapping a ton of unstable fuel to your back and waiting for it to explode while you're 200 feet up in the air. While user confusion and frustration are not quite so dramatic, they're still painful. Rethink the requirement, taking reality into consideration.
Comments (2)
Christian Estler
replied on 28.06.2016
Great read, thanks!
It seems that collapsable forms are worse than screens which are displaying information. Would you say they should be avoided for the latter too?
Lukas Mathis
replied on 28.06.2016
My personal inclination is to always avoid collapsible sections, unless there's a really compelling reason to consider them, and even then, to do real-world usability tests to validate whether they actually *are* a good idea (in my experience, it usually turns out that they're not).
Whenever you're faced with the idea of adding collapsible sections, it's a good idea to take a step back and as yourself: why do people want to hide stuff that's on the screen? Quite often, there's a deeper underlying design problem that causes people to ask for collapsible sections (e.g. the visual design of the screen is cluttered, so people are overwhelmed by it - the solution there is to simplify the visual design of the screen, not to just hide parts of it).
Please log in to add a comment.
Latest Posts
Subscribe to the latest blog posts
Announcement: The Community Blog Has a New Home
April 10, 2017
Appway Ecosystem: Meet Our Partners!
April 3, 2017
An Introduction to Digital Signatures
March 27, 2017
Patch Release: Appway 6.2.31
March 22, 2017
Behind the Scenes at community.appway.com
March 20, 2017
Terms of use
|
Privacy statement
|
Support
|
Academy
|
About Appway
|
Contact us
© 2013 Appway | Numcom Software AG. All Rights Reserved.