short addition: with a custom MockFilter you can exclude specific parts of your application- and/or test-code directly, however, since you have a mixed test-setup it might not be that easy. (-> the @Alternative implementation for DynamicMockManager + MockFilter might be easier for you.)
regards, gerhard 2017-10-31 10:28 GMT+01:00 Gerhard Petracek <[email protected]>: > hi bruno, > > i just had time to check the issue with an @Alternative implementation for > DynamicMockManager (/SimpleMockManager). > > everything i wrote about it is valid, however, since you have your own > package (with a custom mock-manager), you have to provide an own > implementation of org.apache.deltaspike.testcontrol.spi.mock.MockFilter > and register it via the std. spi-config (-> /META-INF/services/org.apache. > deltaspike.testcontrol.spi.mock.MockFilter). > -> just exclude your mock-manager (you can have a look e.g. at > org.apache.deltaspike.testcontrol.impl.mock.DefaultMockFilter to get an > idea about the required steps). > without such a filter ds tries to mock your custom mock-manager. > > i'll add a corresponding hint to our documentation. > > regards, > gerhard > > > > 2017-10-19 16:17 GMT+02:00 Gerhard Petracek <[email protected]>: > >> hi bruno, >> >> agreed. >> -> the only topic we have to check (in owb) is the issue with a custom >> mock-manager (replacing the SimpleMockManager via @Specializes or >> @Alternative). >> (that's the only part which shouldn't be as you described it.) >> >> regards, >> gerhard >> >> >> >> 2017-10-19 15:50 GMT+02:00 Bruno Boissard <[email protected]>: >> >>> Hello Gerhard, >>> >>> Deactivating MockExtension for a single test class only while >>> stop_container=false is used appears impossible. >>> MockExtension seems to put some MockAwareInjectionTargetWrapper and >>> MockAwareProducerWrapper instances everywhere before the very first test. >>> >>> So what I finally done is to deactivate MockExtension for all tests and >>> replace it with my own CustomMockExtension. >>> This CustomMockExtension inherit from MockExtension but wrap >>> MockAwareInjectionTargetWrapper and MockAwareProducerWrapper into my own >>> CustomMockAwareInjectionTargetWrapper and CustomMockAwareProducerWrapper >>> . >>> >>> If mocking is activated (A static flag) these implementations delegate to >>> the "MockAware" implementations. >>> If mocking is deactivated these implementations delegate to the original >>> Producer/InjectionTarget. >>> >>> That way I do not impact production code. >>> >>> Thanks. >>> >>> >>> >>> 2017-10-18 18:56 GMT+02:00 Gerhard Petracek <[email protected] >>> >: >>> >>> > hi bruno, >>> > >>> > you don't need to use reflection - see [1] (or for more dynamic cases >>> [2]). >>> > >>> > in view of AmbiguousResolutionException (and the other effects): >>> > i'll have a look at owb, you shouldn't face such cases. >>> > >>> > regards, >>> > gerhard >>> > >>> > [1] >>> > https://deltaspike.apache.org/documentation/core.html# >>> > DeactivateDeactivatable-ClassesviaConfig >>> > [2] https://deltaspike.apache.org/documentation/core.html#Deacti >>> vatable >>> > >>> > >>> > >>> > 2017-10-18 18:24 GMT+02:00 Bruno Boissard <[email protected]>: >>> > >>> > > Hello Gerhard, >>> > > >>> > > The threads are created when a web-service published using >>> > > javax.xml.ws.Endpoint.publish is called. >>> > > They might come from some jvm thread pool. >>> > > Instead of customizing the thread creation, I modified directly the >>> > > production code to call an implementation of an interface that I >>> called >>> > > RequestContextManager. >>> > > The default implementation for production does nothing but the test >>> > injects >>> > > manually (Static setter) an implementation that start/stop the >>> DeltaSpike >>> > > request context. >>> > > It is quite ugly but good enough. >>> > > >>> > > I investigated your interesting approach of replacing >>> SimpleMockManager. >>> > > I tried with @Specializes and ended up with >>> AmbiguousResolutionException. >>> > > Then I tried with @Alternative and I am facing a stack overflow: >>> > > MockAwareInjectionTargetWrapper.produce calls >>> > > BeanProvider.getContextualReference and retrieve a proxy of my >>> > > CustomSimpleMockManager. >>> > > Then it calls the getMock on that proxy. At that time, DeltaSpike >>> tries >>> > to >>> > > find the instance behind the proxy to call the actual getMock so it >>> > results >>> > > in a recursive call to MockAwareInjectionTargetWrapper.produce... >>> > > >>> > > I also found MockExtension service from DeltaSpike and tried to >>> > deactivate >>> > > it temporarily using reflection on its isActivated private field but >>> with >>> > > no luck. >>> > > >>> > > Regards. >>> > > >>> > > >>> > > 2017-10-17 17:58 GMT+02:00 Gerhard Petracek <[email protected]>: >>> > > >>> > > > hi bruno, >>> > > > >>> > > > you mentioned that you can't create the thread-instances, maybe >>> you can >>> > > > customize/extend the part which is doing it. >>> > > > >>> > > > or extend SimpleMockManager + use e.g. @Specializes. your custom >>> > > > implementation would only delegate to ApplicationMockManager. >>> > > > (-> remove it again once the rest is refactored...) >>> > > > >>> > > > regards, >>> > > > gerhard >>> > > > >>> > > > >>> > > > >>> > > > 2017-10-17 17:29 GMT+02:00 Bruno Boissard < >>> [email protected]>: >>> > > > >>> > > > > That is a solution and we are already using @Alternative >>> sometimes >>> > but >>> > > > > there are currently too many tests with too many mocks for me to >>> > > > transform >>> > > > > them all. >>> > > > > >>> > > > > Thanks. >>> > > > > >>> > > > > 2017-10-17 16:48 GMT+02:00 Gerhard Petracek < >>> [email protected]>: >>> > > > > >>> > > > > > hi bruno, >>> > > > > > >>> > > > > > if a cdi-bean only gets replaced by one mocked bean (for all >>> > involved >>> > > > > > tests), you don't need the mock-support from deltaspike. >>> > > > > > just use (global) alternatives or @Specializes (for beans >>> which are >>> > > > only >>> > > > > in >>> > > > > > your test-classpath and change the default behavior). >>> > > > > > >>> > > > > > or use a cdi-producer for such beans (-> you can use an >>> alternative >>> > > > > > producer in the test-classpath). >>> > > > > > >>> > > > > > regards, >>> > > > > > gerhard >>> > > > > > >>> > > > > > >>> > > > > > >>> > > > > > 2017-10-17 14:09 GMT+02:00 Bruno Boissard < >>> > [email protected] >>> > > >: >>> > > > > > >>> > > > > > > John -> I do not use the allow_mocked_beans in the exact test >>> > that >>> > > > > fails >>> > > > > > > but it is used in some other tests like this: >>> > > > > > > ======================= >>> > > > > > > ApplicationMockManager mockManager = >>> > > > > > > getContextualReference(ApplicationMockManager.class); >>> > > > > > > mockManager.addMock(Mockito.mock(SomeClass.class)); >>> > > > > > > ======================= >>> > > > > > > >>> > > > > > > Documentation is here: >>> > > > > > > https://deltaspike.apache.org/documentation/test-control. >>> > > > > > > html#MockFrameworks >>> > > > > > > >>> > > > > > > Currently only application scoped beans are mocked and >>> > > > > DynamicMockManager >>> > > > > > > is not used but it can evolve. >>> > > > > > > As stop_container is also set to false, I assume there is no >>> > > chances >>> > > > > > that I >>> > > > > > > could deactivate the mock management for my particular test. >>> > > > > > > >>> > > > > > > Regards. >>> > > > > > > >>> > > > > > > >>> > > > > > > >>> > > > > > > 2017-10-17 13:37 GMT+02:00 John D. Ament < >>> [email protected] >>> > >: >>> > > > > > > >>> > > > > > > > Bruno, >>> > > > > > > > >>> > > > > > > > It seems that your example isn't complete enough. You >>> > > > > > > > have deltaspike.testcontrol.mock-su >>> pport.allow_mocked_beans= >>> > true >>> > > > > > > enabled, >>> > > > > > > > however you're not using it (in the example). How are you >>> > using >>> > > > > mocked >>> > > > > > > > beans in your real test? >>> > > > > > > > >>> > > > > > > > John >>> > > > > > > > >>> > > > > > > > On Tue, Oct 17, 2017 at 6:56 AM Bruno Boissard < >>> > > > > > [email protected] >>> > > > > > > > >>> > > > > > > > wrote: >>> > > > > > > > >>> > > > > > > > > John -> Yes you found the sources and reproduced my >>> issue. >>> > > > > > > > > Gerhard -> It's a pity that the mock functionality >>> implies to >>> > > > have >>> > > > > a >>> > > > > > > > > request context. >>> > > > > > > > > Using your code proposal make cdi-test work but in the >>> real >>> > > thing >>> > > > > the >>> > > > > > > > > threads are not created explicitely by me so it will be >>> > harder >>> > > to >>> > > > > > have >>> > > > > > > > them >>> > > > > > > > > creating the request context, and only in case of tests. >>> > > > > > > > > >>> > > > > > > > > It would have been nice to have the mock functionality >>> > working >>> > > > > > without >>> > > > > > > > > request context but I will implement your workaround and >>> > create >>> > > > the >>> > > > > > > > request >>> > > > > > > > > context in the separated thread. >>> > > > > > > > > >>> > > > > > > > > Thanks. >>> > > > > > > > > >>> > > > > > > > > >>> > > > > > > > > 2017-10-17 12:26 GMT+02:00 Gerhard Petracek < >>> > > > [email protected] >>> > > > > >: >>> > > > > > > > > >>> > > > > > > > > > hi bruno, >>> > > > > > > > > > >>> > > > > > > > > > you don't have a request-scoped bean, but the >>> > > > mock-functionality >>> > > > > > you >>> > > > > > > > > > enabled (via config) is based on the request-scoped >>> bean >>> > you >>> > > > > > > mentioned. >>> > > > > > > > > > it's needed to support different mocks (across tests). >>> > > > > > > > > > >>> > > > > > > > > > -> if MyThread is part of your test-code, just add the >>> > parts >>> > > > i've >>> > > > > > > > > mentioned >>> > > > > > > > > > in my previous answer. >>> > > > > > > > > > (otherwise use MyTestThread which extends MyThread for >>> your >>> > > > > tests + >>> > > > > > > add >>> > > > > > > > > the >>> > > > > > > > > > additional behavior there...) >>> > > > > > > > > > >>> > > > > > > > > > regards, >>> > > > > > > > > > gerhard >>> > > > > > > > > > >>> > > > > > > > > > >>> > > > > > > > > > >>> > > > > > > > > > 2017-10-17 11:58 GMT+02:00 John D. Ament < >>> > > > [email protected] >>> > > > > >: >>> > > > > > > > > > >>> > > > > > > > > > > Bruno, >>> > > > > > > > > > > >>> > > > > > > > > > > When I run your project (assuming you meant : >>> > > > > > > > > > > https://github.com/rt15/cdi-test ) This is the >>> > exception I >>> > > > > get, >>> > > > > > > > which >>> > > > > > > > > > > matches to what Gerhard is describing to you: >>> > > > > > > > > > > >>> > > > > > > > > > > javax.enterprise.context.ContextNotActiveException: >>> > > WebBeans >>> > > > > > > context >>> > > > > > > > > > with >>> > > > > > > > > > > scope type annotation @RequestScoped does not exist >>> > within >>> > > > > > current >>> > > > > > > > > thread >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.container. >>> > BeanManagerImpl.getContext( >>> > > > > > > > > > > BeanManagerImpl.java:331) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.intercept. >>> > > NormalScopedBeanInterceptorHan >>> > > > > > > > > > > dler.getContextualInstance( >>> > NormalScopedBeanInterceptorHan >>> > > > > > > > dler.java:88) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.intercept. >>> > > RequestScopedBeanInterceptorHa >>> > > > > > > > > > > >>> > > > > > > > > ndler.getContextualInstance(Re >>> questScopedBeanInterceptorHa >>> > > > > > > ndler.java:76) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.intercept. >>> > > NormalScopedBeanInterceptorHan >>> > > > > > > > dler.get( >>> > > > > > > > > > > NormalScopedBeanInterceptorHandler.java:70) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.deltaspike.testcontrol.impl.mock. >>> > > > > SimpleMockManager$$ >>> > > > > > > > > > > OwbNormalScopeProxy0.getMock(org/apache/deltaspike/ >>> > > > > > > > > > testcontrol/impl/mock/ >>> > > > > > > > > > > SimpleMockManager.java) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.deltaspike.testcontrol.impl.mock. >>> > > > > > > > > > MockAwareInjectionTargetWrappe >>> > > > > > > > > > > r.produce(MockAwareInjectionTargetWrapper.java:59) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.component. >>> AbstractOwbBean.create( >>> > > > > > > > > > > AbstractOwbBean.java:122) >>> > > > > > > > > > > at >>> > > > > > > > > org.apache.webbeans.component.ManagedBean.create( >>> > > > > > ManagedBean.java:67) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.context.cr >>> eational.BeanInstanceBag. >>> > > > > > > > > > > create(BeanInstanceBag.java:76) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.context.Ab >>> stractContext.getInstance( >>> > > > > > > > > > > AbstractContext.java:159) >>> > > > > > > > > > > at org.apache.webbeans.context.AbstractContext.get( >>> > > > > > > > > > > AbstractContext.java:125) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.intercept. >>> > > NormalScopedBeanInterceptorHan >>> > > > > > > > > > > dler.getContextualInstance( >>> > NormalScopedBeanInterceptorHan >>> > > > > > > > dler.java:100) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.intercept. >>> > > ApplicationScopedBeanIntercept >>> > > > > > > > orHandler. >>> > > > > > > > > > > getContextualInstance(ApplicationScopedBeanIntercept >>> > > > > > > > orHandler.java:65) >>> > > > > > > > > > > at >>> > > > > > > > > > > org.apache.webbeans.intercept. >>> > > NormalScopedBeanInterceptorHan >>> > > > > > > > dler.get( >>> > > > > > > > > > > NormalScopedBeanInterceptorHandler.java:70) >>> > > > > > > > > > > at fr.rt15.MyBean$$OwbNormalScopeProxy0.foo(fr/ >>> > > > > rt15/MyBean.java) >>> > > > > > > > > > > at fr.rt15.MyThread.run(MyThread.java:13) >>> > > > > > > > > > > >>> > > > > > > > > > > On Tue, Oct 17, 2017 at 5:04 AM Bruno Boissard < >>> > > > > > > > > [email protected] >>> > > > > > > > > > > >>> > > > > > > > > > > wrote: >>> > > > > > > > > > > >>> > > > > > > > > > > > Hi Gerhard, >>> > > > > > > > > > > > >>> > > > > > > > > > > > It would make sense to start a request context in >>> order >>> > > to >>> > > > be >>> > > > > > > able >>> > > > > > > > to >>> > > > > > > > > > > > access a @RequestScoped bean but my bean is >>> > > > > @ApplicationScoped. >>> > > > > > > > > Should >>> > > > > > > > > > it >>> > > > > > > > > > > > not be accessible without starting a request >>> context? >>> > > > > > > > > > > > >>> > > > > > > > > > > > But while searching for my bean, in deltaspike >>> > > > > > > > > > > > MockAwareInjectionTargetWrapper, a >>> DynamicMockManager >>> > is >>> > > > > > > searched: >>> > > > > > > > > > > > >>> > > > > > > > > > > > DynamicMockManager mockManager = >>> > > > > > > > > > > > BeanProvider.getContextualRefe >>> rence(this.beanManager, >>> > > > > > > > > > > > DynamicMockManager.class, false); >>> > > > > > > > > > > > >>> > > > > > > > > > > > It returns a SimpleMockManager that is >>> @RequestScoped >>> > so >>> > > it >>> > > > > > > cannot >>> > > > > > > > be >>> > > > > > > > > > > used >>> > > > > > > > > > > > without a created request context. >>> > > > > > > > > > > > >>> > > > > > > > > > > > Maybe MockAwareInjectionTargetWrapper should use >>> > > > > > > > > > > > SimpleApplicationMockManager (Which is >>> > > @ApplicationScoped) >>> > > > > when >>> > > > > > > we >>> > > > > > > > > ask >>> > > > > > > > > > > for >>> > > > > > > > > > > > an @ApplicationScoped bean? >>> > > > > > > > > > > > >>> > > > > > > > > > > > Regards. >>> > > > > > > > > > > > >>> > > > > > > > > > > > 2017-10-17 10:20 GMT+02:00 Gerhard Petracek < >>> > > > > > > [email protected] >>> > > > > > > > >: >>> > > > > > > > > > > > >>> > > > > > > > > > > > > hi bruno, >>> > > > > > > > > > > > > >>> > > > > > > > > > > > > if you start your own threads, you have to >>> control >>> > some >>> > > > > > scopes >>> > > > > > > > like >>> > > > > > > > > > the >>> > > > > > > > > > > > > request-scope on your own (>within< those new >>> > threads). >>> > > > > > > > > > > > > (that isn't specific to deltaspike) >>> > > > > > > > > > > > > >>> > > > > > > > > > > > > see a similar part [1] in our documentation. >>> > > > > > > > > > > > > >>> > > > > > > > > > > > > regards, >>> > > > > > > > > > > > > gerhard >>> > > > > > > > > > > > > >>> > > > > > > > > > > > > [1] >>> > > > > > > > > > > > > http://deltaspike.apache.org/ >>> > documentation/container- >>> > > > > > > > control.html# >>> > > > > > > > > > > > > AttachaRequestContexttoaNewThreadinEE >>> > > > > > > > > > > > > >>> > > > > > > > > > > > > >>> > > > > > > > > > > > > >>> > > > > > > > > > > > > 2017-10-17 9:55 GMT+02:00 Bruno Boissard < >>> > > > > > > > [email protected] >>> > > > > > > > > >: >>> > > > > > > > > > > > > >>> > > > > > > > > > > > > > Hello, >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > I am using deltaspike 1.8.0 and owb version >>> 1.6.3. >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > My test which has to be executed with >>> > CdiTestRunner, >>> > > is >>> > > > > > > > starting >>> > > > > > > > > a >>> > > > > > > > > > > new >>> > > > > > > > > > > > > > thread. >>> > > > > > > > > > > > > > This thread retrieves an instance of MyBean >>> from >>> > CDI >>> > > > and >>> > > > > > try >>> > > > > > > to >>> > > > > > > > > use >>> > > > > > > > > > > it. >>> > > > > > > > > > > > > > MyBean is @ApplicationScoped. >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > It works fine unless I add in >>> > > > > apache-deltaspike.properties: >>> > > > > > > > > > > > > > deltaspike.testcontrol.mock- >>> > > > support.allow_mocked_beans= >>> > > > > > true >>> > > > > > > > > > > > > > (It is necessary for some other tests. As well >>> as >>> > > > > > > > > > > stop_container=false >>> > > > > > > > > > > > is >>> > > > > > > > > > > > > > also necessary). >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > With allow_mocked_beans=true I have following >>> > > > exception: >>> > > > > > > > > > > > > > javax.enterprise.context. >>> > ContextNotActiveException: >>> > > > > > WebBeans >>> > > > > > > > > > context >>> > > > > > > > > > > > > with >>> > > > > > > > > > > > > > scope type annotation @RequestScoped does not >>> exist >>> > > > > within >>> > > > > > > > > current >>> > > > > > > > > > > > thread >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > It appears that while searching for MyBean, it >>> is >>> > > > > searching >>> > > > > > > for >>> > > > > > > > > > > > > > SimpleMockManager bean. >>> > > > > > > > > > > > > > SimpleMockManager is @RequestScoped, so >>> deltaspike >>> > > does >>> > > > > not >>> > > > > > > > find >>> > > > > > > > > it >>> > > > > > > > > > > > > > (Logical, there is no request context as we >>> are in >>> > a >>> > > > new >>> > > > > > > > thread). >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > A very ugly workaround is to use MyBean in >>> MyTest: >>> > > once >>> > > > > it >>> > > > > > is >>> > > > > > > > > > > created, >>> > > > > > > > > > > > it >>> > > > > > > > > > > > > > become accessible in the other thread... >>> > > > > > > > > > > > > > Is there a better solution? >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > A maven project corresponding to this >>> available in >>> > > > > github, >>> > > > > > > > please >>> > > > > > > > > > > > search >>> > > > > > > > > > > > > > for rt15/cdi-test. >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > Otherwise here is the source code: >>> > > > > > > > > > > > > > ============================== >>> > > > ========================= >>> > > > > > > > > > > > > > @RunWith(CdiTestRunner.class) >>> > > > > > > > > > > > > > public class MyTest { >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > @Inject >>> > > > > > > > > > > > > > private MyBean myBean; >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > @Test >>> > > > > > > > > > > > > > public void test() throws Exception { >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > // Ugly workaround: uncomment next >>> line. >>> > > > > > > > > > > > > > // this.myBean.foo(); >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > MyThread myThread = new MyThread(); >>> > > > > > > > > > > > > > myThread.start(); >>> > > > > > > > > > > > > > myThread.join(); >>> > > > > > > > > > > > > > if (myThread.exception != null) { >>> > > > > > > > > > > > > > throw myThread.exception; >>> > > > > > > > > > > > > > } >>> > > > > > > > > > > > > > } >>> > > > > > > > > > > > > > } >>> > > > > > > > > > > > > > ============================== >>> > > > ========================= >>> > > > > > > > > > > > > > public class MyThread extends Thread { >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > public Exception exception; >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > @Override >>> > > > > > > > > > > > > > public void run() { >>> > > > > > > > > > > > > > try { >>> > > > > > > > > > > > > > MyBean myBean = >>> > > > CDI.current().select(MyBean. >>> > > > > > > > > > > class).get(); >>> > > > > > > > > > > > > > myBean.foo(); >>> > > > > > > > > > > > > > } catch (Exception e) { >>> > > > > > > > > > > > > > this.exception = e; >>> > > > > > > > > > > > > > } >>> > > > > > > > > > > > > > } >>> > > > > > > > > > > > > > } >>> > > > > > > > > > > > > > ============================== >>> > > > ========================= >>> > > > > > > > > > > > > > @ApplicationScoped >>> > > > > > > > > > > > > > public class MyBean { >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > public void foo() { >>> > > > > > > > > > > > > > System.out.println("foo"); >>> > > > > > > > > > > > > > } >>> > > > > > > > > > > > > > } >>> > > > > > > > > > > > > > ============================== >>> > > > ========================= >>> > > > > > > > > > > > > > deltaspike.testcontrol.mock- >>> > > > support.allow_mocked_beans= >>> > > > > > true >>> > > > > > > > > > > > > > ============================== >>> > > > ========================= >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > > Regards. >>> > > > > > > > > > > > > > >>> > > > > > > > > > > > > >>> > > > > > > > > > > > >>> > > > > > > > > > > >>> > > > > > > > > > >>> > > > > > > > > >>> > > > > > > > >>> > > > > > > >>> > > > > > >>> > > > > >>> > > > >>> > > >>> > >>> >> >> > >
