> Fred pretty much iterated things correctly. > > The ResolvePackageNamePass I haven't to get back to. I was in the middle of > implementing something when I got it to work in another place. > > There is a pattern to how things are parsed so most of the time it's better > to set state as nodes/references are being added to the model. In the case > of imports, I don't see any problems right now with checking during the > emit phase but, if the model was more interactive during the session, this > type of logic should happen during the resolve phase so the model with it's > references has a correct state if there is any logic happening between two > references.
Thanks for the explanation, I will take the time to do some debug spins to understand when the phases are called, what they do and what classes are involved. Given it is a fairly small transpiler and despite the recursive visitor pattern, I guess I can do it. > How much are you working on right now Fred? I just ask because I don't want > to create any conflicts. Go ahead Mike, I'm done with that at the moment, I did my last cleanup already. Anyway, better I work on a branch and commit the branch instead for review next time. Frédéric THOMAS ---------------------------------------- > Date: Sun, 28 Jun 2015 13:23:15 -0400 > Subject: Re: [Externs] jasmine-2.0.js > From: teotigraphix...@gmail.com > To: dev@flex.apache.org > > Fred pretty much iterated things correctly. > > The ResolvePackageNamePass I haven't to get back to. I was in the middle of > implementing something when I got it to work in another place. > > There is a pattern to how things are parsed so most of the time it's better > to set state as nodes/references are being added to the model. In the case > of imports, I don't see any problems right now with checking during the > emit phase but, if the model was more interactive during the session, this > type of logic should happen during the resolve phase so the model with it's > references has a correct state if there is any logic happening between two > references. > > How much are you working on right now Fred? I just ask because I don't want > to create any conflicts. > > Mike > . > > On Sat, Jun 27, 2015 at 5:58 PM, Michael Schmalle <teotigraphix...@gmail.com >> wrote: > >> Hey Fred, I was out all day. I will have some time in the morning to look >> at what you did and comment. :) >> >> Mike >> >> On Sat, Jun 27, 2015 at 5:27 PM, Frédéric THOMAS <webdoubl...@hotmail.com> >> wrote: >> >>> Just to explain what I did, especially to folks who would like to get >>> their hand dirty on the compiler but like me, don't know how it works :-) >>> >>> I was adding jasmine-2.0.js [1], a file that contains only jsDoc >>> (parameters and return type descriptions) and declarations, no >>> implementations. >>> When I say "adding jasmine-2.0.js" I mean, transpile this .js file to .as >>> and then compile it to a .swc. >>> >>> The transpilation part is done by EXTERNC >>> >>> You call it like that: >>> >>> <java jar="${basedir}/compiler.jx/lib/externc.jar" fork="true" >>> failonerror="false"> >>> <arg value="+flexlib=${env.ASJS_HOME}/frameworks" /> >>> <arg value="-debug" /> >>> <arg >>> value="-load-config=${basedir}/externs/jasmine/jasmine-compile-config.xml" >>> /> >>> >>> In the jasmine-compile-config.xml, you can exclude classes and member, >>> for example, in the jasmine.Spec class, I excluded the variable $injector >>> as its type was coming from the Angular library that is not yet transpiled. >>> >>> <field-exclude> >>> <class>jasmine.Spec</class> >>> <field>$injector</field> >>> </field-exclude> >>> >>> You can also exclude classes and functions. >>> >>> The compile part is done by the falcon compc as follow: >>> >>> <java jar="${basedir}/compiler/generated/dist/sdk/lib/falcon-compc.jar" >>> fork="true" >>> failonerror="true"> >>> <arg value="+flexlib=${env.ASJS_HOME}/frameworks" /> >>> <arg value="-debug" /> >>> <arg >>> value="-load-config=${basedir}/externs/jasmine/compile-config.xml" /> >>> <arg >>> value="-output=${basedir}/externs/jasmine/out/bin/jasmine-2.0.swc" /> >>> </java> >>> >>> The problem was that this last part was failing with an NPE a Type of >>> something: >>> >>> org.apache.flex.compiler.internal.scopes.TypeScope.getPropertyForMemberAccess(TypeScope.java:344) >>> >>> Even looking closely at the code, I didn't get why it was failing but for >>> sure, because it was trying to compile one of the transpiled .as file, this >>> transpiled code was wrong. >>> Looking at those .as, it was easy to see that some import were missing. >>> >>> So, why the 2 others externs (js and jquery) had no issues ? >>> It is always surprising to see something working on all the things except >>> of yours, but it can help you too :-) >>> >>> So, I've been looking at those other transpiled .as files from existing >>> externs to see if they had imports and they were some. >>> I then created a mini jasmine.js containing only the faulty case only, >>> that, from what I've been able to determinate, was that the import was not >>> generated when a static function had a return type of a class created via a >>> function constructor, so, I filled this mini jasmine.js with the equivalent >>> of a static function like this: >>> >>> /** >>> * @return {!jasmine.Clock} >>> */ >>> jasmine.clock = function() {}; >>> >>> Which should transpile in AS3, something like: >>> >>> import jasmine.Clock; >>> public static function clock():Clock {} >>> >>> and a function constructor like this: >>> >>> /** @constructor */ >>> jasmine.Clock = function() {}; >>> >>> which transpile: >>> >>> package jasmine { >>> public class Clock {} >>> } >>> >>> Created a test class based on those Mike created for the previous externs >>> doing: >>> >>> // jasmine, the main jasmine class. >>> ClassReference jasmine = model.getClassReference("jasmine"); >>> assertNotNull(jasmine); >>> >>> assertTrue(jasmine.hasImport("jasmine.Clock")); >>> >>> The hasImport method didn't exist on ClassReference but it was a >>> addImport(), I follow to where it was called in ResolvePackagesPass hoping >>> to find a missing case but after debug spin I wasn't able to do what I >>> expected, I'm not sure I understood all the logic in this class but it >>> looked like the Node of my return type was never visited and therefore >>> wasn't able to add my import here. >>> >>> But wait, in the ClassReference, I have a >>> >>> public MethodReference addMethod(Node node, String functionName, >>> JSDocInfo comment, boolean isStatic) >>> >>> To me it would be enough to add the import to the list of imports to be >>> emitted when the MethodReference is to be added, I just had to determinate >>> if the return type given in the jsDoc was not from the current package, the >>> given method not excluded, the given return type neither ! >>> >>> My test was passing was I was able to compile with this new code the old >>> externs. >>> >>> The only thing I had to do to finish to compile the jasmine extern was to >>> emit the imports for the global functions too as they shown to be faulty >>> for the same reasons. >>> >>> Mike will probably tell me now where my logic was wrong now :-) >>> >>> Frédéric THOMAS >>> >>> >>> ---------------------------------------- >>>> From: webdoubl...@hotmail.com >>>> To: dev@flex.apache.org >>>> Subject: RE: [Externs] jasmine-2.0.js >>>> Date: Sat, 27 Jun 2015 20:43:43 +0100 >>>> >>>> Ok, done ! >>>> >>>> I forgot to uncomment the externc build of jasmine and print the global >>> function imports ! >>>> >>>> Frédéric THOMAS >>>> >>>> >>>> ---------------------------------------- >>>>> From: webdoubl...@hotmail.com >>>>> To: dev@flex.apache.org >>>>> Subject: RE: [Externs] jasmine-2.0.js >>>>> Date: Sat, 27 Jun 2015 20:12:16 +0100 >>>>> >>>>>> I pushed the changes which are ready to be reviewed. >>>>> >>>>> oups, hold on, I had some things commented that hidden other problems, >>> I will continue on it. >>>>> >>>>> Frédéric THOMAS >>>>> >>>>> >>>>> ---------------------------------------- >>>>>> From: webdoubl...@hotmail.com >>>>>> To: dev@flex.apache.org >>>>>> Subject: RE: [Externs] jasmine-2.0.js >>>>>> Date: Sat, 27 Jun 2015 18:31:32 +0100 >>>>>> >>>>>> Hi Mike, >>>>>> >>>>>> I pushed the changes which are ready to be reviewed. >>>>>> >>>>>> Note: The jasmine-2.0.js is not committed as it should be downloaded >>> with the unpack-externs target of the download.xml, I followed the model. >>>>>> >>>>>> Thanks, >>>>>> Frédéric THOMAS >>>>>> >>>>>> >>>>>> ---------------------------------------- >>>>>>> Date: Sat, 27 Jun 2015 05:31:50 -0400 >>>>>>> Subject: Re: [Externs] jasmine-2.0.js >>>>>>> From: teotigraphix...@gmail.com >>>>>>> To: dev@flex.apache.org >>>>>>> >>>>>>> I just noticed you said today or tomorrow, whatever man. doesn't >>> matter. >>>>>>> >>>>>>> Mike >>>>>>> >>>>>>> On Sat, Jun 27, 2015 at 5:17 AM, Michael Schmalle < >>> teotigraphix...@gmail.com >>>>>>>> wrote: >>>>>>> >>>>>>>> Well its the practice. I know the pattern I am using so if I have to >>>>>>>> adjust it to fit I will. You can tell that with AST type stuff, it >>> has to >>>>>>>> follow a specific pattern or everything turns to crap when trying >>> to add >>>>>>>> stuff down the road. >>>>>>>> >>>>>>>> Commit it sooner than later as I have a couple hours to check it >>> out this >>>>>>>> morning. >>>>>>>> >>>>>>>> Mike >>>>>>>> >>>>>>>> On Sat, Jun 27, 2015 at 3:15 AM, Frédéric THOMAS < >>> webdoubl...@hotmail.com> >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Hi Mike, >>>>>>>>> >>>>>>>>> I can now compile jasmine, I'm not sure my fix is very clean but it >>>>>>>>> works, I've been able to compile all the externs with. >>>>>>>>> I will commit it later today or tomorrow as I need to clean a bit >>> before >>>>>>>>> and it would be nice if you can review it. >>>>>>>>> >>>>>>>>> Thanks, >>>>>>>>> Frédéric THOMAS >>>>>>>>> >>>>>>>>> >>>>>>>>> ---------------------------------------- >>>>>>>>>> From: webdoubl...@hotmail.com >>>>>>>>>> To: dev@flex.apache.org >>>>>>>>>> Subject: RE: [Externs] jasmine-2.0.js >>>>>>>>>> Date: Fri, 26 Jun 2015 22:43:30 +0100 >>>>>>>>>> >>>>>>>>>> Hey Mike, it looks like "import jasmine.Clock;" is missing in the >>>>>>>>> generated jasmine.as, that's it ! >>>>>>>>>> >>>>>>>>>> Frédéric THOMAS >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> ---------------------------------------- >>>>>>>>>>> From: webdoubl...@hotmail.com >>>>>>>>>>> To: dev@flex.apache.org >>>>>>>>>>> Subject: RE: [Externs] jasmine-2.0.js >>>>>>>>>>> Date: Fri, 26 Jun 2015 22:26:32 +0100 >>>>>>>>>>> >>>>>>>>>>>> HAHA, ah that is a hard one man, thanks for the offer but I >>> think I am >>>>>>>>>>>> going to need to get this one. There are a couple places it >>> could be >>>>>>>>> though >>>>>>>>>>>> if you are curious. >>>>>>>>>>>> >>>>>>>>>>>> First you really need to understand the problem, I am typing >>> this >>>>>>>>> stuff in >>>>>>>>>>>> between installing a bathroom vanity and sink, so I haven't >>> looked at >>>>>>>>> the >>>>>>>>>>>> code yet. :) >>>>>>>>>>>> >>>>>>>>>>>> So I can't really give you an answer since I don't quite know >>> the >>>>>>>>> problem >>>>>>>>>>>> yet. >>>>>>>>>>> >>>>>>>>>>> Ok, I will check your solution :-) >>>>>>>>>>> >>>>>>>>>>> Frédéric THOMAS >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> ---------------------------------------- >>>>>>>>>>>> Date: Fri, 26 Jun 2015 16:59:58 -0400 >>>>>>>>>>>> Subject: Re: [Externs] jasmine-2.0.js >>>>>>>>>>>> From: teotigraphix...@gmail.com >>>>>>>>>>>> To: dev@flex.apache.org >>>>>>>>>>>> >>>>>>>>>>>> On Fri, Jun 26, 2015 at 4:39 PM, Frédéric THOMAS < >>>>>>>>> webdoubl...@hotmail.com> >>>>>>>>>>>> wrote: >>>>>>>>>>>> >>>>>>>>>>>>>> Yeah, this "jasmine.Clock" >>>>>>>>>>>>>> >>>>>>>>>>>>>> The error means that the Falcon compiler is trying to resolve >>> a >>>>>>>>> member >>>>>>>>>>>>>> expression and it can't resolve it. >>>>>>>>>>>>>> >>>>>>>>>>>>>> So this means there is a bug in the AST resolver. You are >>> using the >>>>>>>>>>>>> extern >>>>>>>>>>>>>> in the GCC project correct? >>>>>>>>>>>>> >>>>>>>>>>>>> Yes, >>>>>>>>>>>>> >>>>>>>>> >>> https://raw.githubusercontent.com/google/closure-compiler/master/contrib/externs/jasmine-2.0.js >>>>>>>>>>>>> >>>>>>>>>>>>>> If so, I need to take a look at it. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Everyone, I did one pass and tests on packages and class >>> creation, >>>>>>>>> so >>>>>>>>>>>>> these >>>>>>>>>>>>>> types of bugs are to be expected as the AST/Type resolver is >>>>>>>>> "asked" to >>>>>>>>>>>>> do >>>>>>>>>>>>>> more work then my initial implementation. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Make sense? >>>>>>>>>>>>> >>>>>>>>>>>>> Well, kind of :-) >>>>>>>>>>>>> What classes would you check for this ? >>>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> HAHA, ah that is a hard one man, thanks for the offer but I >>> think I am >>>>>>>>>>>> going to need to get this one. There are a couple places it >>> could be >>>>>>>>> though >>>>>>>>>>>> if you are curious. >>>>>>>>>>>> >>>>>>>>>>>> First you really need to understand the problem, I am typing >>> this >>>>>>>>> stuff in >>>>>>>>>>>> between installing a bathroom vanity and sink, so I haven't >>> looked at >>>>>>>>> the >>>>>>>>>>>> code yet. :) >>>>>>>>>>>> >>>>>>>>>>>> So I can't really give you an answer since I don't quite know >>> the >>>>>>>>> problem >>>>>>>>>>>> yet. >>>>>>>>>>>> >>>>>>>>>>>> Mike >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> Thanks, >>>>>>>>>>>>> Frédéric THOMAS >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> ---------------------------------------- >>>>>>>>>>>>>> Date: Fri, 26 Jun 2015 16:32:16 -0400 >>>>>>>>>>>>>> Subject: Re: [Externs] jasmine-2.0.js >>>>>>>>>>>>>> From: teotigraphix...@gmail.com >>>>>>>>>>>>>> To: dev@flex.apache.org >>>>>>>>>>>>>> >>>>>>>>>>>>>> Yeah, this "jasmine.Clock" >>>>>>>>>>>>>> >>>>>>>>>>>>>> The error means that the Falcon compiler is trying to resolve >>> a >>>>>>>>> member >>>>>>>>>>>>>> expression and it can't resolve it. >>>>>>>>>>>>>> >>>>>>>>>>>>>> So this means there is a bug in the AST resolver. You are >>> using the >>>>>>>>>>>>> extern >>>>>>>>>>>>>> in the GCC project correct? >>>>>>>>>>>>>> >>>>>>>>>>>>>> If so, I need to take a look at it. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Everyone, I did one pass and tests on packages and class >>> creation, >>>>>>>>> so >>>>>>>>>>>>> these >>>>>>>>>>>>>> types of bugs are to be expected as the AST/Type resolver is >>>>>>>>> "asked" to >>>>>>>>>>>>> do >>>>>>>>>>>>>> more work then my initial implementation. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Make sense? >>>>>>>>>>>>>> >>>>>>>>>>>>>> Mike >>>>>>>>>>>>>> >>>>>>>>>>>>>> On Fri, Jun 26, 2015 at 3:27 PM, Frédéric THOMAS < >>>>>>>>>>>>> webdoubl...@hotmail.com> >>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>> >>>>>>>>>>>>>>> Hi Mike, >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> Any idea why ? >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> U:\sources\asf\flex\falcon\externs\jasmine\out\as\classes\ >>>>>>>>> jasmine.as:26 >>>>>>>>>>>>>>> Erreur interne : java.lang.NullPointerException >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.scopes.TypeScope.getPropertyForMemberAccess(TypeScope.java:344) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.scopes.ScopeView.getPropertyForMemberAccess(ScopeView.java:81) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.scopes.ASScope.getPropertyFromDef(ASScope.java:879) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.scopes.ASScope.getPropertyFromDef(ASScope.java:841) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.scopes.ASScope.getPropertyFromDef(ASScope.java:760) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.tree.as.IdentifierNode.resolveMemberRef(IdentifierNode.java:829) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.tree.as.IdentifierNode.resolve(IdentifierNode.java:377) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.tree.as.IdentifierNode.getMName(IdentifierNode.java:432) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.tree.as.MemberAccessExpressionNode.getMName(MemberAccessExpressionNode.java:158) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.as.codegen.ABCGeneratingReducer.dottedName(ABCGeneratingReducer.java:840) >>>>>>>>>>>>>>> at >>>>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>> >>> org.apache.flex.compiler.internal.as.codegen.CmcEmitter.action_321(CmcEmitter.java:5236) >>>>>>>>>>>>>>> ... >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> public static function clock():jasmine.Clock { return null; } >>>>>>>>>>>>>>> ^ >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> ----------------------------- >>>>>>>>>>>>>>> In the jasmine extern file >>>>>>>>>>>>>>> ----------------------------- >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** >>>>>>>>>>>>>>> * @return {!jasmine.Clock} >>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>> jasmine.clock = function() {}; >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** @constructor */ >>>>>>>>>>>>>>> jasmine.Clock = function() {}; >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** */ >>>>>>>>>>>>>>> jasmine.Clock.prototype.install = function() {}; >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** */ >>>>>>>>>>>>>>> jasmine.Clock.prototype.uninstall = function() {}; >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** @param {number} ms */ >>>>>>>>>>>>>>> jasmine.Clock.prototype.tick = function(ms) {}; >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** @param {!Date} date */ >>>>>>>>>>>>>>> jasmine.Clock.prototype.mockDate = function(date) {}; >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> ----------------------------- >>>>>>>>>>>>>>> In jasmine.as >>>>>>>>>>>>>>> ----------------------------- >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** >>>>>>>>>>>>>>> * @see [jasmine-2.0] >>>>>>>>>>>>>>> * @returns {jasmine.Clock} >>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>> public static function clock():jasmine.Clock { return null; } >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> ----------------------------- >>>>>>>>>>>>>>> clock.as >>>>>>>>>>>>>>> ----------------------------- >>>>>>>>>>>>>>> package jasmine { >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** >>>>>>>>>>>>>>> * @see [jasmine-2.0] >>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>> public class Clock { >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** >>>>>>>>>>>>>>> * @see [jasmine-2.0] >>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>> public function Clock() { >>>>>>>>>>>>>>> super(); >>>>>>>>>>>>>>> } >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** >>>>>>>>>>>>>>> * Generated doc for missing method JSDoc. >>>>>>>>>>>>>>> * >>>>>>>>>>>>>>> * @see [jasmine-2.0] >>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>> public function install():void { } >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** >>>>>>>>>>>>>>> * @param ms [number] >>>>>>>>>>>>>>> * @see [jasmine-2.0] >>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>> public function tick(ms:Number):void { } >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** >>>>>>>>>>>>>>> * Generated doc for missing method JSDoc. >>>>>>>>>>>>>>> * >>>>>>>>>>>>>>> * @see [jasmine-2.0] >>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>> public function uninstall():void { } >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> /** >>>>>>>>>>>>>>> * @param date [Date] >>>>>>>>>>>>>>> * @see [jasmine-2.0] >>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>> public function mockDate(date:Date):void { } >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> } >>>>>>>>>>>>>>> } >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> Thanks, >>>>>>>>>>>>>>> Frédéric THOMAS >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>> >>>>> >>>> >>> >>> >> >>