← Back to team overview

dhis2-devs team mailing list archive

Re: Bulk Deletion of ProgramDataElements

 

Hi Morten,

Sure. Does this mean that both of those should be possible? Here are the
tickets:

https://jira.dhis2.org/browse/DHIS2-1241
https://jira.dhis2.org/browse/DHIS2-1242

Thanks,

Lorill

On Thu, Mar 9, 2017 at 3:40 PM, Morten Olav Hansen <morten@xxxxxxxxx> wrote:

> Hi Lorill
>
> Would you mind filing an issue in JIRA?
>
> --
> Morten Olav Hansen
> Senior Engineer, DHIS 2
> University of Oslo
> http://www.dhis2.org
>
> On Fri, Mar 10, 2017 at 4:16 AM, Lorill Crees <lcrees@xxxxxxxxxx> wrote:
>
>> Hi,
>>
>> Just following up on this. I similarly would like to bulk delete Options,
>> but am not successful in this either.
>>
>> When POSTing to api/25/options?strategy=DELETE
>>
>> with this payload:
>>
>> {
>> "options": [
>>       {
>>           "id": "GNJOoVg1CdI"
>>       },
>>       {
>>           "id": "ZPRArfldlqK"
>>       }
>>   ]
>> }
>>
>> I get this returned:
>>
>> {
>>     "httpStatus": "Conflict",
>>     "httpStatusCode": 409,
>>     "status": "WARNING",
>>     "message": "One more more errors occurred, please see full details in
>> import report.",
>>     "response": {
>>         "responseType": "ObjectReport",
>>         "uid": "ySD4jtmXNrG",
>>         "klass": "org.hisp.dhis.option.Option",
>>         "errorReports": [
>>             {
>>                 "message": "Missing required property `name`.",
>>                 "mainKlass": "org.hisp.dhis.option.Option",
>>                 "errorKlass": "java.lang.String",
>>                 "errorCode": "E4000"
>>             }
>>         ]
>>     }
>> }
>>
>> and POSTING to
>>
>> api/25/metadata?strategy=DELETE
>>
>> with this payload:
>>
>> {
>> "options": [
>>   {
>>     "id": "GNJOoVg1CdI"
>>     },
>>     {
>>     "id": "ZPRArfldlqK"
>>     }
>> ]
>> }
>>
>> returns this:
>>
>> {"status":"ERROR","stats":{"created":0,"updated":0,"deleted"
>> :0,"ignored":2,"total":2},"typeReports":[{"klass":"org.
>> hisp.dhis.option.Option","stats":{"created":0,"updated":0,"
>> deleted":0,"ignored":2,"total":2},"objectReports":[{"klass":
>> "org.hisp.dhis.option.Option","index":0,"uid":"GNJOoVg1CdI",
>> "errorReports":[{"message":"Missing required property
>> `name`.","mainKlass":"org.hisp.dhis.option.Option","errorKla
>> ss":"java.lang.String","errorCode":"E4000"}]},{"klass"
>> :"org.hisp.dhis.option.Option","index":1,"uid":"ZPRArfldlqK"
>> ,"errorReports":[{"message":"Missing required property
>> `name`.","mainKlass":"org.hisp.dhis.option.Option","errorKla
>> ss":"java.lang.String","errorCode":"E4000"}]}]}]}
>>
>> On Tue, Mar 7, 2017 at 12:55 PM, Lorill Crees <lcrees@xxxxxxxxxx> wrote:
>>
>>> Hi,
>>>
>>> I am attempting to do a bulk deletion of ProgramDataElements via the Web
>>> API. I am able to delete one by one by using Http DELETE:
>>>
>>> api/25/programDataElements/s3L7Qamxs0s
>>>
>>> I am not successful when attempting to POST to:
>>>
>>> api/25/programDataElements?strategy=DELETE
>>>
>>> with the payload:
>>>
>>> {
>>>    "programDataElements":[
>>>       {
>>>          "id":"B6GVF8xN0QL"
>>>       },
>>>       {
>>>          "id":"VvLbQPQH4xs"
>>>       }
>>>    ]
>>> }
>>>
>>> or
>>>
>>> {
>>>    "programDataElements":[
>>>       {
>>>          "programDataElement":"B6GVF8xN0QL"
>>>       },
>>>       {
>>>          "programDataElement":"VvLbQPQH4xs"
>>>       }
>>>    ]
>>> }
>>>
>>> A nullpointer is thrown in the logs (pasted below).
>>>
>>> I was unable to find documentation specifically for programDataElements.
>>> Is bulk deletion even possible? If so, do I need to be doing something
>>> differently or is this a bug?
>>>
>>> Thanks,
>>>
>>> Lorill
>>>
>>> Version:
>>> 2.25
>>> Build revision:
>>> 910b13a
>>> Build date:
>>> 2017-03-07 08:39
>>>
>>>
>>> * INFO  2017-03-07 12:53:13,559 (admin) Import:Start
>>> (DefaultMetadataImportService.java [http-nio-8090-exec-10])
>>>
>>> * INFO  2017-03-07 12:53:13,570 (admin) Import:Preheat[REFERENCE] took
>>> 0.01 seconds (DefaultPreheatService.java [http-nio-8090-exec-10])
>>>
>>> java.lang.NullPointerException
>>>
>>> at org.hisp.dhis.program.ProgramDataElement.getName(ProgramData
>>> Element.java:79)
>>>
>>> at org.hisp.dhis.common.BaseIdentifiableObject.getDisplayName(B
>>> aseIdentifiableObject.java:266)
>>>
>>> at org.hisp.dhis.common.IdentifiableObjectUtils.getDisplayName(
>>> IdentifiableObjectUtils.java:341)
>>>
>>> at org.hisp.dhis.dxf2.metadata.objectbundle.DefaultObjectBundle
>>> ValidationService.validateBySchemas(DefaultObjectBundleValid
>>> ationService.java:491)
>>>
>>> at org.hisp.dhis.dxf2.metadata.objectbundle.DefaultObjectBundle
>>> ValidationService.validate(DefaultObjectBundleValidationServ
>>> ice.java:156)
>>>
>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>
>>> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAcce
>>> ssorImpl.java:62)
>>>
>>> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMe
>>> thodAccessorImpl.java:43)
>>>
>>> at java.lang.reflect.Method.invoke(Method.java:483)
>>>
>>> at org.springframework.aop.support.AopUtils.invokeJoinpointUsin
>>> gReflection(AopUtils.java:302)
>>>
>>> at org.springframework.aop.framework.ReflectiveMethodInvocation
>>> .invokeJoinpoint(ReflectiveMethodInvocation.java:190)
>>>
>>> at org.springframework.aop.framework.ReflectiveMethodInvocation
>>> .proceed(ReflectiveMethodInvocation.java:157)
>>>
>>> at org.springframework.transaction.interceptor.TransactionInter
>>> ceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
>>>
>>> at org.springframework.transaction.interceptor.TransactionAspec
>>> tSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
>>>
>>> at org.springframework.transaction.interceptor.TransactionInter
>>> ceptor.invoke(TransactionInterceptor.java:96)
>>>
>>> at org.springframework.aop.framework.ReflectiveMethodInvocation
>>> .proceed(ReflectiveMethodInvocation.java:179)
>>>
>>> at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(
>>> JdkDynamicAopProxy.java:208)
>>>
>>> at com.sun.proxy.$Proxy187.validate(Unknown Source)
>>>
>>> at org.hisp.dhis.dxf2.metadata.DefaultMetadataImportService.imp
>>> ortMetadata(DefaultMetadataImportService.java:119)
>>>
>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>
>>> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAcce
>>> ssorImpl.java:62)
>>>
>>> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMe
>>> thodAccessorImpl.java:43)
>>>
>>> at java.lang.reflect.Method.invoke(Method.java:483)
>>>
>>> at org.springframework.aop.support.AopUtils.invokeJoinpointUsin
>>> gReflection(AopUtils.java:302)
>>>
>>> at org.springframework.aop.framework.ReflectiveMethodInvocation
>>> .invokeJoinpoint(ReflectiveMethodInvocation.java:190)
>>>
>>> at org.springframework.aop.framework.ReflectiveMethodInvocation
>>> .proceed(ReflectiveMethodInvocation.java:157)
>>>
>>> at org.springframework.transaction.interceptor.TransactionInter
>>> ceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
>>>
>>> at org.springframework.transaction.interceptor.TransactionAspec
>>> tSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
>>>
>>> at org.springframework.transaction.interceptor.TransactionInter
>>> ceptor.invoke(TransactionInterceptor.java:96)
>>>
>>> at org.springframework.aop.framework.ReflectiveMethodInvocation
>>> .proceed(ReflectiveMethodInvocation.java:179)
>>>
>>> at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(
>>> JdkDynamicAopProxy.java:208)
>>>
>>> at com.sun.proxy.$Proxy188.importMetadata(Unknown Source)
>>>
>>> at org.hisp.dhis.webapi.controller.AbstractCrudController.postJ
>>> sonObject(AbstractCrudController.java:589)
>>>
>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>
>>> at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAcce
>>> ssorImpl.java:62)
>>>
>>> at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMe
>>> thodAccessorImpl.java:43)
>>>
>>> at java.lang.reflect.Method.invoke(Method.java:483)
>>>
>>> at org.springframework.web.method.support.InvocableHandlerMetho
>>> d.doInvoke(InvocableHandlerMethod.java:221)
>>>
>>> at org.springframework.web.method.support.InvocableHandlerMetho
>>> d.invokeForRequest(InvocableHandlerMethod.java:136)
>>>
>>> at org.springframework.web.servlet.mvc.method.annotation.Servle
>>> tInvocableHandlerMethod.invokeAndHandle(ServletInvocableHand
>>> lerMethod.java:110)
>>>
>>> at org.springframework.web.servlet.mvc.method.annotation.Reques
>>> tMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHan
>>> dlerAdapter.java:817)
>>>
>>> at org.springframework.web.servlet.mvc.method.annotation.Reques
>>> tMappingHandlerAdapter.handleInternal(RequestMappingHandlerA
>>> dapter.java:731)
>>>
>>> at org.springframework.web.servlet.mvc.method.AbstractHandlerMe
>>> thodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
>>>
>>> at org.springframework.web.servlet.DispatcherServlet.doDispatch
>>> (DispatcherServlet.java:959)
>>>
>>> at org.springframework.web.servlet.DispatcherServlet.doService(
>>> DispatcherServlet.java:893)
>>>
>>> at org.springframework.web.servlet.FrameworkServlet.processRequ
>>> est(FrameworkServlet.java:968)
>>>
>>> at org.springframework.web.servlet.FrameworkServlet.doPost(Fram
>>> eworkServlet.java:870)
>>>
>>> at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
>>>
>>> at org.springframework.web.servlet.FrameworkServlet.service(Fra
>>> meworkServlet.java:844)
>>>
>>> at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi
>>> lter(ApplicationFilterChain.java:291)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App
>>> licationFilterChain.java:206)
>>>
>>> at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilte
>>> r.java:52)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi
>>> lter(ApplicationFilterChain.java:239)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App
>>> licationFilterChain.java:206)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:330)
>>>
>>> at org.springframework.security.web.access.intercept.FilterSecu
>>> rityInterceptor.invoke(FilterSecurityInterceptor.java:118)
>>>
>>> at org.springframework.security.web.access.intercept.FilterSecu
>>> rityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.access.ExceptionTranslation
>>> Filter.doFilter(ExceptionTranslationFilter.java:113)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.session.SessionManagementFi
>>> lter.doFilter(SessionManagementFilter.java:103)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.authentication.AnonymousAut
>>> henticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.servletapi.SecurityContextH
>>> olderAwareRequestFilter.doFilter(SecurityContextHolderAwareR
>>> equestFilter.java:154)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.savedrequest.RequestCacheAw
>>> areFilter.doFilter(RequestCacheAwareFilter.java:45)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.authentication.www.BasicAut
>>> henticationFilter.doFilter(BasicAuthenticationFilter.java:201)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.hisp.dhis.security.filter.CorsFilter.doFilter(CorsFilter.java:98)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.authentication.AbstractAuth
>>> enticationProcessingFilter.doFilter(AbstractAuthenticationPr
>>> ocessingFilter.java:199)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.authentication.AbstractAuth
>>> enticationProcessingFilter.doFilter(AbstractAuthenticationPr
>>> ocessingFilter.java:199)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.hisp.dhis.security.filter.CustomAuthenticationFilter.doF
>>> ilter(CustomAuthenticationFilter.java:64)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.oauth2.provider.authentication.
>>> OAuth2AuthenticationProcessingFilter.doFilter(OAuth2Authenti
>>> cationProcessingFilter.java:140)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.authentication.logout.Logou
>>> tFilter.doFilter(LogoutFilter.java:110)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.hisp.dhis.security.filter.AutomaticAccessFilter.doFilter
>>> (AutomaticAccessFilter.java:115)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.header.HeaderWriterFilter.d
>>> oFilterInternal(HeaderWriterFilter.java:57)
>>>
>>> at org.springframework.web.filter.OncePerRequestFilter.doFilter
>>> (OncePerRequestFilter.java:107)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.context.request.async.WebAs
>>> yncManagerIntegrationFilter.doFilterInternal(WebAsyncManager
>>> IntegrationFilter.java:50)
>>>
>>> at org.springframework.web.filter.OncePerRequestFilter.doFilter
>>> (OncePerRequestFilter.java:107)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.context.SecurityContextPers
>>> istenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
>>>
>>> at org.springframework.security.web.FilterChainProxy$VirtualFil
>>> terChain.doFilter(FilterChainProxy.java:342)
>>>
>>> at org.springframework.security.web.FilterChainProxy.doFilterIn
>>> ternal(FilterChainProxy.java:192)
>>>
>>> at org.springframework.security.web.FilterChainProxy.doFilter(F
>>> ilterChainProxy.java:160)
>>>
>>> at org.springframework.web.filter.DelegatingFilterProxy.invokeD
>>> elegate(DelegatingFilterProxy.java:346)
>>>
>>> at org.springframework.web.filter.DelegatingFilterProxy.doFilte
>>> r(DelegatingFilterProxy.java:262)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi
>>> lter(ApplicationFilterChain.java:239)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App
>>> licationFilterChain.java:206)
>>>
>>> at org.hisp.dhis.servlet.filter.HttpUrlPatternFilter.doFilter(H
>>> ttpUrlPatternFilter.java:105)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi
>>> lter(ApplicationFilterChain.java:239)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App
>>> licationFilterChain.java:206)
>>>
>>> at org.springframework.web.filter.ShallowEtagHeaderFilter.doFil
>>> terInternal(ShallowEtagHeaderFilter.java:87)
>>>
>>> at org.hisp.dhis.servlet.filter.ExcludableShallowEtagHeaderFilt
>>> er.doFilterInternal(ExcludableShallowEtagHeaderFilter.java:110)
>>>
>>> at org.springframework.web.filter.OncePerRequestFilter.doFilter
>>> (OncePerRequestFilter.java:107)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi
>>> lter(ApplicationFilterChain.java:239)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App
>>> licationFilterChain.java:206)
>>>
>>> at org.springframework.orm.hibernate5.support.OpenSessionInView
>>> Filter.doFilterInternal(OpenSessionInViewFilter.java:151)
>>>
>>> at org.springframework.web.filter.OncePerRequestFilter.doFilter
>>> (OncePerRequestFilter.java:107)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi
>>> lter(ApplicationFilterChain.java:239)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App
>>> licationFilterChain.java:206)
>>>
>>> at org.springframework.web.filter.CharacterEncodingFilter.doFil
>>> terInternal(CharacterEncodingFilter.java:121)
>>>
>>> at org.springframework.web.filter.OncePerRequestFilter.doFilter
>>> (OncePerRequestFilter.java:107)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.internalDoFi
>>> lter(ApplicationFilterChain.java:239)
>>>
>>> at org.apache.catalina.core.ApplicationFilterChain.doFilter(App
>>> licationFilterChain.java:206)
>>>
>>> at org.apache.catalina.core.StandardWrapperValve.invoke(Standar
>>> dWrapperValve.java:219)
>>>
>>> at org.apache.catalina.core.StandardContextValve.invoke(Standar
>>> dContextValve.java:106)
>>>
>>> at org.apache.catalina.authenticator.AuthenticatorBase.invoke(A
>>> uthenticatorBase.java:502)
>>>
>>> at org.apache.catalina.core.StandardHostValve.invoke(StandardHo
>>> stValve.java:142)
>>>
>>> at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorRepo
>>> rtValve.java:79)
>>>
>>> at org.apache.catalina.valves.AbstractAccessLogValve.invoke(Abs
>>> tractAccessLogValve.java:610)
>>>
>>> at org.apache.catalina.core.StandardEngineValve.invoke(Standard
>>> EngineValve.java:88)
>>>
>>> at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAd
>>> apter.java:518)
>>>
>>> at org.apache.coyote.http11.AbstractHttp11Processor.process(Abs
>>> tractHttp11Processor.java:1091)
>>>
>>> at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler
>>> .process(AbstractProtocol.java:668)
>>>
>>> at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionH
>>> andler.process(Http11NioProtocol.java:223)
>>>
>>> at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun
>>> (NioEndpoint.java:1517)
>>>
>>> at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(N
>>> ioEndpoint.java:1474)
>>>
>>> at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPool
>>> Executor.java:1142)
>>>
>>> at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoo
>>> lExecutor.java:617)
>>>
>>> at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.r
>>> un(TaskThread.java:61)
>>>
>>> at java.lang.Thread.run(Thread.java:745)
>>>
>>>
>>> --
>>> Lorill Crees
>>> Project Leader / Senior Developer
>>> 2Paths Solutions Ltd. <http://www.2paths.com>
>>>
>>> lcrees@xxxxxxxxxx
>>> skype: lorill2paths
>>> (604) 689-4123 x 15 <(604)%20689-4123>
>>>
>>
>>
>>
>> --
>> Lorill Crees
>> Project Leader / Senior Developer
>> 2Paths Solutions Ltd. <http://www.2paths.com>
>>
>> lcrees@xxxxxxxxxx
>> skype: lorill2paths
>> (604) 689-4123 x 15 <(604)%20689-4123>
>>
>> _______________________________________________
>> Mailing list: https://launchpad.net/~dhis2-devs
>> Post to     : dhis2-devs@xxxxxxxxxxxxxxxxxxx
>> Unsubscribe : https://launchpad.net/~dhis2-devs
>> More help   : https://help.launchpad.net/ListHelp
>>
>>
>


-- 
Lorill Crees
Project Leader / Senior Developer
2Paths Solutions Ltd. <http://www.2paths.com>

lcrees@xxxxxxxxxx
skype: lorill2paths
(604) 689-4123 x 15

Follow ups

References