dlr-eoc / proseo Goto Github PK
View Code? Open in Web Editor NEWprosEO – A Processing System for Earth Observation Data
License: GNU General Public License v3.0
prosEO – A Processing System for Earth Observation Data
License: GNU General Public License v3.0
The Production Planner currently does not write log messages stating the operations performed and their outcome.
Log entries like the following should be written before returning from a REST call:
(I2939) Order with identifier L2_orbits_3000-3002 deleted
(E1022) Order identifier L2_orbits_3000-3002 already exists
After planning and before releasing an order, the associated jobs and job steps should be in status INITIAL. This is OK for the jobs, but not for the job steps:
prosEO> job show L2_orbits_3000-3002
80 2020-03-25T09:00:00 2020-03-25T10:41:10 INITIAL
99 2020-03-25T10:41:10 2020-03-25T12:22:20 INITIAL
118 2020-03-25T12:22:20 2020-03-25T14:03:30 INITIAL
prosEO> job step show 118
128 PTM_L2B WAITING_INPUT
131 L1B_______ WAITING_INPUT
119 PTM_L2A WAITING_INPUT
122 L1B_______ WAITING_INPUT
prosEO> job step show 80
81 PTM_L2A WAITING_INPUT
84 L1B_______ WAITING_INPUT
90 PTM_L2B WAITING_INPUT
93 L1B_______ WAITING_INPUT
prosEO> job step show 99
112 L1B_______ WAITING_INPUT
100 PTM_L2A WAITING_INPUT
103 L1B_______ WAITING_INPUT
109 PTM_L2B WAITING_INPUT
what shall prosEO do?
Testing parameters
User Login: no user login
Mission : no mission
Context:
Executing the proseo command returns that the command is illegal.
Output:
prosEO> proseo
(E2916) Illegal command proseo
Testing parameters:
User Login: no user login
Mission : no mission
Context:
It seems that the user needs to be logged in before the help page for the command [mission show -h], which requires login, can be displayed. This could be problematic for some users, if they wanted to understand what this command does. [Mission show -h] functions, on the contrary, so this behavior should be universal. Finally, based on the current output, the user cannot understand what could be missing from the command to show the help page, so the documentation could be updated to reflect its usage.
Example output:
prosEO> mission spacecraft -h
(E2802) User not logged in
(E2801) Subcommand missing for command mission
Mission show works on the other hand:
prosEO> mission show -h
(E2802) User not logged in
List all configured missions or only the given one
Options:
...
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The command [mission -h spacecraft] returns an exception and terminates the interface.
Example output:
prosEO> mission -h spacecraft
prosEO Command Line Interface terminated by exception!
More in detail: parsing of datetime results in Exception.
Example:
prosEO> login PTM
Username (empty field cancels): melchinger
Password for user melchinger:
(I2821) User melchinger logged in
prosEO> order show --from=2019-11-04T08:30:00
(E2925) prosEO Command Line Interface terminated by exception: Failed to execute CommandLineRunner
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The 2 commands [product delete] and [product update] are terminating the CLI. They should have returned a message that the commands are not allowed while not terminating the CLI.
Example outputs:
prosEO> product delete
(E2802) User not logged in
prosEO Command Line Interface terminated by exception!
prosEO> product update
(E2802) User not logged in
prosEO Command Line Interface terminated by exception!
Testing parameters:
User Login: no user login
Mission : no mission
Context:
When the user executes the command login without defining a username, a prompt asks the user to input the username. If the user uses ENTER without writing the username first, there is an error message that cancels the login but a password is still requested nonetheless. This implies that the null user is taken as input after the cancelled login and a password for the null user is requested. This could be a cause of security concern but from the user's safety/security point of view but also the user experience point of view.
Example output:
prosEO> login ptm
Username:
(I2824) No username given, login cancelled
Password for user :
Further information:
There is no indication of how to cancel a login. This could be an enhancement.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
Trying out the command ingest resulted into the termination of the CLI. Please refer to the example output.
Example output:
prosEO> ingest -fabc
(E2918) Required parameter processingFacility not found for command ingest
prosEO> ingest -fabc abc
(E2802) User not logged in
prosEO Command Line Interface terminated by exception!
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The help documentation ('help') for the command 'login' is a bit ambiguous. It could infer that all commands are valid to be used with login apart from 'mission show'.
Example output:
login Log in to a mission in prosEO. A login is required prior to executing any other command except "mission show".
Further information:
A potential enhancement would be to write "any valid command except..."
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The user needs to use the ENTER button several times in order to have some space between outputs/texts. This might be a good addition from the UX point of view.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
When the user chooses to login to a mission, the user is prompted to input the password and system informs the user that it needs the password for a specific username, the one it was used for the login. At the same time, the system does not verify to the user that the login is done for a specific mission as per their request.
Example output:
prosEO> login -uuser1 ptm
Password for user user1:
Further information:
The output could be: Password for user user1 in mission ptm
It could be even more beneficial if the mission is stated explicitly: Password for user user1 in mission ExampleMission1
The command "order approve " deletes at least requestedProductClasses.
Before:
requestedProductClasses:
After:
requestedProductClasses: []
See complete output in attachment.
Currently to copy users with their passwords from one mission to another first the user must be exported ("user show" into a file), then the file must be edited to change the mission code in the user name (and to remove excess lines, e. g. the CLI banner), and then the new user must be created with "user create --file=xxx".
It would be easier to have a command "user copy --with-authorities ". Obviously, copying group memberships in this way would not be possible, because the groups may be different.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
Positional parameters and subcommands are empty. This could mean that indeed there are none but it could also infer not yet written/documented.
Example output:
prosEO> help -h
Show the prosEO Command Line Interface help information (this page; for subcommand help, type " --help")
Options:
-h, --help Show help information for the current command level (top level commands, when called from the shell command line)
Positional parameters:
Subcommands:
prosEO>
Further information:
The CLI should include an output message indicating that the specific command has no associated positional parameters/subcommands when there are indeed none associated.
This command failed:
prosEO> ingest --file=PTM_LO_ingest.json Lerchenhof
(E2806) Command failed (cause: (E2810) HTTP request failed (cause: 500 ); nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 )
The input file is attached.
The log is:
2020-03-27 15:58:14.583 TRACE 19684 --- [nio-8081-exec-3] d.d.p.i.rest.IngestControllerImpl : >>> ingestProducts(Lerchenhof, IngestorProduct[15])
2020-03-27 15:58:14.590 TRACE 19684 --- [nio-8081-exec-3] d.d.p.ingestor.rest.ProductIngestor : >>> ingestProduct(Lerchenhof, L0________)
2020-03-27 15:58:14.590 TRACE 19684 --- [nio-8081-exec-3] d.d.proseo.ingestor.rest.ProductManager : >>> createProduct(L0________)
2020-03-27 15:58:14.591 TRACE 19684 --- [nio-8081-exec-3] d.d.p.ingestor.rest.model.ProductUtil : >>> toModelProduct(L0________)
2020-03-27 15:58:14.629 INFO 19684 --- [nio-8081-exec-3] d.d.proseo.ingestor.rest.ProductManager : (I2007) Product of type L0________ created for mission PTM
2020-03-27 15:58:14.629 TRACE 19684 --- [nio-8081-exec-3] d.d.p.ingestor.rest.model.ProductUtil : >>> toRestProduct(104)
2020-03-27 15:58:14.632 DEBUG 19684 --- [nio-8081-exec-3] d.d.p.ingestor.rest.ProductIngestor : Calling Storage Manager with URL http://192.168.20.159:8083/proseo/storage-mgr/v0.1/storage/products/register and data {targetStorageType=S3, sourceFilePaths=[http://192.168.20.159:9000\proseo-data-002/input\PTM_L0_20191104090000_20191104094500_20191104120000.RAW], productId=104, sourceStorageType=S3}
2020-03-27 15:58:14.700 ERROR 19684 --- [nio-8081-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at de.dlr.proseo.ingestor.rest.ProductIngestor.ingestProduct(ProductIngestor.java:211) ~[classes!/:0.1.0]
at de.dlr.proseo.ingestor.rest.ProductIngestor$$FastClassBySpringCGLIB$$b135ddd6.invoke() ~[classes!/:0.1.0]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) ~[spring-tx-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at de.dlr.proseo.ingestor.rest.ProductIngestor$$EnhancerBySpringCGLIB$$1ca8f49d.ingestProduct() ~[classes!/:0.1.0]
at de.dlr.proseo.ingestor.rest.IngestControllerImpl.ingestProducts(IngestControllerImpl.java:153) ~[classes!/:0.1.0]
at de.dlr.proseo.ingestor.rest.IngestControllerDecorator.ingestProducts(IngestControllerDecorator.java:43) ~[classes!/:0.1.0]
at de.dlr.proseo.ingestor.rest.IngestControllerDecorator$$FastClassBySpringCGLIB$$da96d37b.invoke() ~[classes!/:0.1.0]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:119) ~[spring-context-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at de.dlr.proseo.ingestor.rest.IngestControllerDecorator$$EnhancerBySpringCGLIB$$f8ba3d4d.ingestProducts() ~[classes!/:0.1.0]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) ~[spring-webmvc-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:88) ~[spring-boot-actuator-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:215) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:114) ~[spring-boot-actuator-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:104) ~[spring-boot-actuator-2.1.6.RELEASE.jar!/:2.1.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109) ~[spring-web-5.1.8.RELEASE.jar!/:5.1.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.21.jar!/:9.0.21]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The command 'exit -h' / 'exit --help' exits the CLI. The user would expect information on the command, based on what is written in the help documentation.
For example, does the user remain logged in? Using "exit -h" would help answer this question.
If a processing facility is created after startup of the production planner, and then an attempt to plan an order for this facility is made, the Production Planner returns an error:
2020-03-31 16:58:38.551 INFO 1 --- [ main] de.dlr.proseo.planner.ProductionPlanner : Started ProductionPlanner in 64.892 seconds (JVM running for 69.274)
...
2020-04-01 13:56:29.039 INFO 9684 --- [main] d.d.proseo.ui.cli.FacilityCommandRunner : (I2746) Processing facility telekom-otc created (database ID 49)
...
2020-04-01 13:56:36.814 INFO 9684 --- [main] de.dlr.proseo.ui.cli.OrderCommandRunner : (I2934) Order with identifier L2_orbits_3000-3002 created (database ID 80)
2020-04-01 13:56:37.071 INFO 9684 --- [main] de.dlr.proseo.ui.cli.OrderCommandRunner : (I2934) Order with identifier L3_products_9:30-17:30 created (database ID 81)
...
2020-04-01 14:11:08.879 INFO 9700 --- [main] de.dlr.proseo.ui.cli.OrderCommandRunner : (I2942) Order with identifier L3_products_9:30-17:30 approved (new version 2)
...
2020-04-01 14:11:20.033 TRACE 9700 --- [main] de.dlr.proseo.ui.cli.parser.CLIParser : >>> parse(order plan L3_products_9:30-17:30 telekom-otc)
2020-04-01 14:11:20.033 TRACE 9700 --- [main] de.dlr.proseo.ui.cli.OrderCommandRunner : >>> executeCommand(order)
2020-04-01 14:11:20.261 TRACE 9700 --- [main] d.d.proseo.ui.backend.ServiceConnection : ... calling service URL https://proseo.proseo-bcm.de/proseo/planner/v0.1/orders/plan/81?facility=telekom-otc with GET
2020-04-01 14:11:20.985 ERROR 9700 --- [main] d.d.proseo.ui.backend.ServiceConnection : (E2811) Service request failed with status 404 (404 NOT_FOUND), cause: 199 proseo-planner Processing facility 'telekom-otc' does not exist (3046)
Expected behaviour: Once started the Production Planner may run indefinitely. Therefore new facilities created during runtime must be recognized.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
When the user tries a command which requires login, [mission show] in this case, the error messages show that the user is not logged in which is a normal output message but as a second message the system shows to the user that it tries to revert to a null user for privileges. From the system design point of view, this could be a security concern, in case by mistake the null user gains such privileges. The nature of this error message causes confusion as well and is a security concern by itself.
Example output:
prosEO> mission show
(E2802) User not logged in
(E2803) User null not authorized to manage missions for mission null
Examples with other commands:
example for the command [product show]
prosEO> product show abc
(E2802) User not logged in
(E2803) User null not authorized to manage products for mission null
example for the command [productclass show]
prosEO> productclass show
(E2802) User not logged in
(E2803) User null not authorized to manage product classes for mission null
example for the command [productclass delete]
prosEO> productclass delete abc
(E2802) User not logged in
(E2803) User null not authorized to manage product classes for mission null
example for the command [productclass update]
prosEO> productclass update abc
(E2802) User not logged in
(E2803) User null not authorized to manage product classes for mission null
Similar issues occur with the commands [orbit], [order] and [configuration]
When showing the list of orders for an empty database, an empty list is returned:
prosEO> order show
--- []
prosEO>
In line with other services, an error message should be returned, based on a 404 NOT_FOUND return code from the Order Manager service; compare to:
prosEO> processor class show
(E2970) No processor classes found for given search criteria
prosEO>
Testing parameters:
User Login: no user login
Mission : no mission
Context:
Executing the command [order update] returns a confusing error message, requesting a product database ID. Retrieving the help page mentions the parameter orderID that might be what the system is asking for but this is not very clear from a UX perspective as the user does not understand if this is indeed what is missing, or if there is another problem. On the contrary, order delete/approve/plan/release/suspend/resume/cancel/close/reset return an error message mentioning the orderID
Example output:
prosEO> order update
(E2802) User not logged in
(E2936) No product database ID given
prosEO> order update -h
(E2802) User not logged in
Update a processing order (only allowed in status initial)
Options:
-f, --file Path to file to read the order definition from
--format The file format (one of { JSON, XML, YAML }; default value JSON)
--delete-attributes Delete attributes not given in the order definition file and/or the command parameters
-h, --help Show help information for the current command level (top level commands, when called from the shell command line)
Positional parameters:
orderId The order identifier for user reference (mandatory if not read from file)
attribute An order attribute to update in the form "=", overrides values given in the order definition file
Subcommands:
prosEO> order update 123
(E2802) User not logged in
(E2803) User null not authorized to manage orders for mission null
Authentication is required to get a list of the missions configured in prosEO:
prosEO> mission show
(E2802) User not logged in
(E2803) User null not authorized to manage missions for mission null
According to the help text, the command "mission show" shall be executable without prior login.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
When the user executes the command product create, the system returns that the user is not logged but then allows the user to enter mandatory attributes. On top of that, there seems to be a security concern when the system gets the final input attribute: the HTTP request seems to be actually sent with no response but also no explanation on what went wrong.
It is a security concern and should not be allowed to enter the attributes if the users are not logged in. The system should return to the default prompt if the user is not loggen in returning a relevant message for the need of logging in.
Example output:
prosEO> product create
(E2802) User not logged in
Checking for missing mandatory attributes ...
Product class (empty field cancels): abc
File class (empty field cancels): abc
Sensing start time (empty field cancels): 2020-02-01T14:00:00
Sensing stop time (empty field cancels): 2020-02-01T14:50:00
Product generation time (empty field cancels): 2020-02-01T14:52:00
(E2806) Command failed (cause: (E2810) HTTP request failed (cause: Could not extract response: no suitable HttpMessageConverter found for response type [class de.dlr.proseo.model.rest.model.RestProduct] and content type [text/html]); nested exception is org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class de.dlr.proseo.model.rest.model.RestProduct] and content type [text/html])
prosEO>
Similarly with the command [productclass create]:
prosEO> productclass create
(E2802) User not logged in
Checking for missing mandatory attributes ...
Product class name (empty field cancels): abc
Mission product type (empty field cancels): abc
(E2806) Command failed (cause: (E2810) HTTP request failed (cause: Could not extract response: no suitable HttpMessageConverter found for response type [class de.dlr.proseo.model.rest.model.RestProductClass] and content type [text/html]); nested exception is org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class de.dlr.proseo.model.rest.model.RestProductClass] and content type [text/html])
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The documentation seems to be missing some information on the required inputs for the subcommand configuration > delete. ClassName and ConfigurationVersion are not mentioned in the 'help' documentation. Moreover, an example could prove to be a welcome addition for the users of the CLI, from the UX point of view.
Extract from the 'help':
delete Remove a configuration from the current mission and processor class
Example output:
prosEO> configuration delete
(E2918) Required parameter className not found for command delete
prosEO> configuration delete abc
(E2918) Required parameter configurationVersion not found for command delete
prosEO> configuration delete abc 1
(E2802) User not logged in
(E2803) User null not authorized to manage configurations for mission null
prosEO>
The command "order suspend ..." has to be applicable in state "RELEASED" too.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The subcommands of the command 'order' in their help documentation references statuses: Initial, Planned, etc. It could be of added value to the users of the CLI to understand what theses statuses are about, while reading the documentation.
The processor was created by command
processor create --file=PTM_PTML2_0.1.0.json
Now there was the intention to change an attribute, but these comannds failed:
prosEO> processor update --file=PTM_PTML1B_0.1.0.json
(E2806) Command failed (cause: org.springframework.web.client.HttpClientErrorException: 500 )
prosEO> processor create --file=PTM_PTML2_0.1.0.json
Checking for missing mandatory attributes ...
(E2806) Command failed (cause: (E2810) HTTP request failed (cause: 500 ); nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 )
prosEO> processor delete PTML2 0.1.0
(E2988) Deletion of processor PTML2 with version 0.1.0 failed (cause: 199 proseo-processor-mgr could not execute statement; SQL [n/a]; constraint [fkloteyhnalc56x161f4inujyt5]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement)
The log of processor-mgr is attached.
proc-mgr.log
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The system includes the command 'configuration' which is about "Commands for managing configurations" and it also include the subcommand processor>configuration which is about "Commands to manage configured processors". This could be a cause of confusion.
Further information:
Could the command 'configuration' be renamed or the documentation be updated to include some more information on what those configurations are?
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The subcommand mission > spacecraft indicates that there might be more information to be added in the documentation.
Extract from the help page:
spacecraft Commands to manage the spacecrafts for a mission
Testing parameters:
User Login: no user login
Mission : no mission
Context:
It seems that either there is a need to enhance the documentation of the subcommand processor>class or the development is not complete. The subcommand class seems to not be recognized by the system.
Example output:
prosEO> processor class
(E2802) User not logged in
(E2801) Subcommand missing for command processor
prosEO> processor class a
(E2917) Illegal subcommand a
prosEO> processor class 1
(E2917) Illegal subcommand 1
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The command [productclass rule] seems to either not be developed or the documentation needs an update or needs to be added. Calling the help page of the sub-command seems not to function either.
Example output:
prosEO> productclass rule
(E2802) User not logged in
(E2801) Subcommand missing for command productclass
prosEO> productclass rule -h
(E2802) User not logged in
(E2801) Subcommand missing for command productclass
Similar issue for [processor class]:
prosEO> processor class -h
(E2802) User not logged in
(E2801) Subcommand missing for command processor
On the contrary, [processor delete -h] seems to function:
prosEO> processor delete -h
(E2802) User not logged in
Delete a processor version from the current mission
After login, all commands are directed at a specific mission, but the user is not informed, which mission that would be. Add the mission, to which the user is currently logged in, to the command prompt.
Currently only a user with privilege ROLE_USERMGR can change passwords. This shall extend to all users, and passwords entered shall be validated against password rules.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The documentation for the subcommand mission>show might be a bit confusing. It indicates that the user can invoke information for other missions and processor classes. What could be beneficial is the addition of an example or syntax of how this can be done.
Extract from the help:
show Show all configurations for the current mission and processor class or a named one
Further information:
Apart from adding a specific example on how to retrieve information for other missions/processor classes, the actual text could be re-written: Show all configurations for the current mission and processor class. The user can also define to show all the configurations for other missions/processor classes with the syntax … For example:
Existing order not found.
Example:
prosEO> order show --format=JSON L2orbits3000-3002
[ {
"id" : 223,
"version" : 2,
"missionCode" : "PTM",
"identifier" : "L2orbits3000-3002",
...
}]
prosEO> order plan L2orbits3000-3002 Lerchenhof
(E2935) Order with identifier L2orbits3000-3002 not found
prosEO>
Potential enhancement
Adding some specific examples/use cases on the usage and input structure of the commands/subcommands/options/parameters could be of help to the users of the CLI. This is currently missing from the help pages and it could prove to be a good enhancement from a UX perspective.
Move OrderUtil definition to Model for common use in OrderManager and Planner
Call the delete function of Planner (at least in state "CLOSED") to delete also the dependend objects (like jobs, job steps, ...).
Testing parameters:
User Login: no user login
Mission : no mission
Context:
Executing just "-v" does not return any error message or result.
Output:
prosEO> -v
prosEO>
Further information:
Shouldn't typing -v alone return an output of some sort? If there is no version associated with proseo, then shouldn't the output/error message indicate this with a message similar to "no version was found", or, 'This option can only be used from a shell command line', as per the indication from the help page? Contrary to but relative to this, -u is taken as input and executes but because it is missing a username it fails. Shouldn't -v return something, along the same line of output? Example output:
prosEO> -u
(E2913) Illegal option value null for option user of type string
Creating a mission with an already existing code returns HTTP status 500 from Order Manager component:
prosEO> mission create --file=PTM.json
(E2806) Command failed (cause: (E2810) HTTP request failed (cause: 500 ); nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 )
The same happens, if orbits are created with an already existing orbit number.
In both cases the Order Manager component should return HTTP status 400 (BAD REQUEST) and a meaningful error message in the Warning header.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
With reference to issues 19 and 23, it was observed that there seems to be a different logic between subcommands when calling subcommand + option or subcommand + option + parameter
Example from issue 23:
Example output:
prosEO> orbit update
(E2802) User not logged in
(E2853) Spacecraft code and/or orbit number missing
prosEO> orbit update abc
(E2802) User not logged in
(E2853) Spacecraft code and/or orbit number missing
prosEO> orbit update abc 10
(E2802) User not logged in
(E2803) User null not authorized to manage orbits for mission null
Example from issue 19:
prosEO> configuration delete
(E2918) Required parameter className not found for command delete
prosEO> configuration delete abc
(E2918) Required parameter configurationVersion not found for command delete
prosEO> configuration delete abc 1
(E2802) User not logged in
(E2803) User null not authorized to manage configurations for mission null
prosEO>
Difference:
When executing orbit update, the system returns the error message "Spacecraft code and/or orbit number missing", realizing at the same time that both the option and the parameter are missing. On the contrary during the execution of configuration delete, the system seems to only focus on the missing option and then exiting.
Questions:
While, understandably, both commands require a username and a mission, is this difference in logic expected? The parameters seem mandatory in both cases, so why does the system behave differently?
Testing parameters:
User Login: no user login
Mission : no mission
Context:
The welcome screen is missing a welcome message indicating that the user can type 'help' to retrieve the help page.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
When reading the help documentation for option -u, information is presented to the user that might prove confusing not only based on what is written but also of what this information might infer from a security point of view.
Extract from the help:
-u, --user The user name for login to prosEO. If a command is given upon program invocation, but no username, login is attempted using the default user name and password stored in the application configuration file.
Further information:
The users expect to login based on their own username and password credentials. They do not expect to see a default username/password that the system automatically tries to use. Moreover, it is implied that this username/password is saved somewhere, in a configuration file, and from a distant point of view it is seems to be a sort of a master username/password that the system automatically reverts to. This could be a security concern but also problematic from the UX point of view.
Real world example: what is happening when a user tries login to an online website with their account, e.g. on GitHub?
Testing parameters:
User Login: no user login
Mission : no mission
Context:
Executing 'orbit update' indicates that more information is needed as input. This information might not be very well documented in the 'help'.
Example output:
prosEO> orbit update
(E2802) User not logged in
(E2853) Spacecraft code and/or orbit number missing
prosEO> orbit update abc
(E2802) User not logged in
(E2853) Spacecraft code and/or orbit number missing
prosEO> orbit update abc 10
(E2802) User not logged in
(E2803) User null not authorized to manage orbits for mission null
Extract from the help:
prosEO> orbit -h
Commands for managing orbits for a given spacecraft
Options:
-h, --help Show help information for the current command level (top level commands, when called from the shell command line)
UX Enhancement:
Restructure information in 'help' so that the inputs 'command -h' and 'command subcommand -h' are both more visible to the users as valid inputs. While it is written in the command section that -h can be used with the commands, it is easy to be missed that this can also be used on the sub-command level.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
Typing [space]help results in an error message with no indication of what the problem is. On the contrary, help[space] functions. The same issue is occuring for all other commands.
Example output:
prosEO> help
(E2916) Illegal command
prosEO> help
Commands can be invoked...
Enhancement:
Typing [space]help functions. This could be an enhancement to the user experience as this is a functionality already in place in internet search engines, for example.
When updating a ProcessingOrder, the Production Planner does not increment the object version number:
prosEO> order show L2_orbits_3000-3002
---
- id: 87
version: 1
missionCode: "PTM"
identifier: "L2_orbits_3000-3002"
[...]
prosEO> order approve L2_orbits_3000-3002
(I2942) Order with identifier L2_orbits_3000-3002 approved (new version 2)
prosEO> order plan L2_orbits_3000-3002 telekom-otc
(I2943) Order with identifier L2_orbits_3000-3002 planned (new version 2)
The "new version" should have been 3 after approve and 4 after plan.
Testing parameters:
User Login: no user login
Mission : no mission
Context:
If a user utilizes CTRL+C by accident, the CLI is terminated and the user does not know what was the reason. There is no prompt to indicate to the user what happened, what are the results of the termination of the CLI, if previous work was lost, etc. CTRL+C is an actionable shortcut used in a operating system terminal, for example, but prosEO represents a different user experience environment and has a different scope. As such, a message/prompt could prove beneficial to the users of the prosEO CLI.
Correct display if requested orbits.
There are multiple objects of same definition and gaps in orbit numbers are not supported.
Example:
"orbits" : [ {
"spacecraftCode" : "PTS",
"orbitNumberFrom" : 3000,
"orbitNumberTo" : 3002
}, {
"spacecraftCode" : "PTS",
"orbitNumberFrom" : 3000,
"orbitNumberTo" : 3002
}, {
"spacecraftCode" : "PTS",
"orbitNumberFrom" : 3000,
"orbitNumberTo" : 3002
} ],
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.