<div dir="ltr"><p style="box-sizing:border-box;margin-bottom:16px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px;margin-top:0px">Hi everyone,<br style="box-sizing:border-box">i generate a rta spark-callgraph starting from some entrypoints that i pass to Soot scene.<br style="box-sizing:border-box">So, i have this type of situation:</p><p style="box-sizing:border-box;margin-bottom:16px;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px"><a target="_blank" rel="noopener noreferrer" href="https://user-images.githubusercontent.com/15249587/54478020-0f99f200-480e-11e9-8bca-093900689166.jpg" style="box-sizing:border-box;background-color:transparent;color:rgb(3,102,214);text-decoration-line:none"><img src="https://user-images.githubusercontent.com/15249587/54478020-0f99f200-480e-11e9-8bca-093900689166.jpg" alt="call-graph" style="box-sizing: content-box; border-style: none; max-width: 100%;"></a></p><p style="box-sizing:border-box;margin-bottom:16px;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px">Obviously there some other methods, this is only an example.</p><p style="box-sizing:border-box;margin-bottom:16px;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px">Now i call "sub-callgraph" of entry point X, that part of callgraph that start from entry point X.<br style="box-sizing:border-box">So, in our example we have N sub-callgraph.</p><p style="box-sizing:border-box;margin-bottom:16px;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px">I need to start from each entry points and analyze the sub-callgraph, when i meet a specific methods, i can stop the visit of that sub-callgraph and start to analyze the next sub-callgraph.<br style="box-sizing:border-box">It's important for me know, during all visit of the sub-callgraph, which is the entry-point of the sub-callgraph that i analyzing.</p><p style="box-sizing:border-box;margin-bottom:16px;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px">I have find a way to do this, but it's very slowly, and i can't understand if the cause is that the call-graph is very big, or my algorithm.</p><p style="box-sizing:border-box;margin-bottom:16px;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px">My algorithm work as this:</p><pre style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:11.9px;margin-bottom:16px;margin-top:0px;background-color:rgb(246,248,250);border-radius:3px;line-height:1.45;overflow:auto;padding:16px;color:rgb(36,41,46)"><code style="box-sizing:border-box;font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:11.9px;background:transparent;border-radius:3px;margin:0px;padding:0px;border:0px;word-break:normal;display:inline;line-height:inherit;overflow:visible">for each entrypoint {
call callgraph.edgesOutOf(entrypoint)
while(callgraph.edgesOutOf(entrypoint).hasNext()){
callgraphAnalyzer(callgraph.edgesOutOf(entrypoint).next())
}
callgraphAnalyzer(Edge next){
retrieve the src method
retrieve the tgt method
do something with them
call callgraph.edgesOutOf(tgt)
while(callgraph.edgesOutOf(tgt).hasNext()){
callgraphAnalyzer(callgraph.edgesOutOf(tgt).next())
}
}
</code></pre><p style="box-sizing:border-box;margin-bottom:16px;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px">Obviously i have for each entry point a structure to memorize the edges already analyze, to skip them. To semplify i don't insert this in the code up.</p><p style="box-sizing:border-box;margin-top:0px;color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px;margin-bottom:0px">There are some other way to do this better?<br style="box-sizing:border-box"></p><span style="color:rgb(36,41,46);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px">I have tried multi-threading, so each thread analyze X entrypoint, but it's slow anyway.<br></span><br>P.S<br>i'm sure that the problem it'snt in part of code that do something with src and tgt methof <br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Il giorno mer 13 mar 2019 alle ore 15:30 Dario Amoroso d'Aragona <<a href="mailto:darioamorosodaragona@gmail.com">darioamorosodaragona@gmail.com</a>> ha scritto:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">Hi everyone,<br>i'm a little confusing and i want to understand how use soot correctly.<br>I need to use soot to compare two java project, (so one version of a project with the next version of the same project).<br>I would like to the body of each SootMethod is a DavaBody but if use Dava i have some problem, so for now i use Baf.<br><div>For the first project: <br>1. I set soot options with a String Array and i call Options.v().parse(options).<br>The options that i set are:<br><div> List<String> argsList = new ArrayList<>();</div><div> argsList.add("-w"); // whole program mode</div><div> argsList.add("-no-bodies-for-excluded"); //don't load bodies for excluded classes, so for non-application-classes</div><div> argsList.add("-allow-phantom-refs"); // allow to don't load some classes (it's necessary for "no-bodies-for-excluded" option)</div><div> argsList.add("-f");</div><div> argsList.add("baf");</div><div> argsList.add("-cp");// Soot class-paths</div></div><div> argsList.add(classpath);</div><div><div> argsList.add("-process-dir");</div><div> argsList.add(target);</div></div><div>2. call Scene.v().loadNecessaryClasses();</div><div>4. call PackManager.v().runPacks();</div><div><br></div><div>Than i call soot.G.reset();</div><div> For second project the first and second previous point are the same:<br><br></div><div><div>3 i add this:</div><div> Transform preprocessingTransfrom = new Transform("wjtp.refresolve", new SceneTransformer() {</div><div> @Override</div><div> protected void internalTransform(String phaseName, Map options) {</div><div> LOGGER.info("rta call graph building...");</div><div> Transform sparkTranform = new Transform("cg.spark", null);</div><div> PhaseOptions.v().setPhaseOption(sparkTranform, "enabled:true"); //enable spark transformation</div><div> PhaseOptions.v().setPhaseOption(sparkTranform, "apponly:true");</div><div> PhaseOptions.v().setPhaseOption(sparkTranform, "rta:true"); //enable rta mode for call-graph</div><div> PhaseOptions.v().setPhaseOption(sparkTranform, "verbose:false");</div><div> PhaseOptions.v().setPhaseOption(sparkTranform, "on-fly-cg:false"); //disable default call-graph construction mode (soot not permitted to use rta and on-fly-cg options together)</div><div> PhaseOptions.v().setPhaseOption(sparkTranform, "force-gc:true"); //force call a System.cg() to increase tue available space on garbage collector</div><div><br></div><div> // Map<String, String> opt = PhaseOptions.v().getPhaseOptions(sparkTranform);</div><div> // sparkTransform(sparkTranform, opt);</div><div> CallGraph c = Scene.v().getCallGraph(); //take the call-graph builded</div><div> setCallGraph(c); //set the callgraph as call-graph of this project</div><div><br></div><div> }</div><div> });</div><div> Pack wjpppack = PackManager.v().getPack("wjtp");</div><div> wjpppack.add(preprocessingTransfrom);</div></div><div><br></div><div><br></div><div><br></div><div>4. and then i call, as before, PackManager.v().runPacks();<br><br></div><div>Obviously i save all SootMethods and SootClass of the first and second project in two different data structure.<br><br>it's all right?<br><br>If yes, i can't understand why if have two SootMethod, one of the first project and one of the second project, in java file are identical (and i pass to soot class file compiled with the same jre), but they in Baf have two different representation, in particular all in the two methods are equal except some variables name, so i have in one "$r14 := @caughtexception" and in the other "$r15 := @caughtexception", or "load $r16" and "load $r10". There are some representation that it's better? With Jimple and Shimple i have the same problem. <br>If i try to use dava, that have a renamer pack, setting "-f dava db.renamer enabled:true" soot option, i have some exception (it's indifferent if i enable db.renamer or not), in particular with inner class, for example: </div><div><br></div><div><div>15:22:23.835 [main] DEBUG s.j.t.c.OnFlyCallGraphBuilder - [Call Graph] For information on where the call graph may be incomplete,use the verbose option to the cg phase.</div><div>15:22:27.983 [Thread-6] DEBUG soot.PackManager - Decompiling org.apache.commons.configuration.AbstractConfiguration$2...</div><div>15:22:27.986 [Thread-7] DEBUG soot.PackManager - Decompiling org.apache.commons.configuration.AbstractConfiguration...</div><div>15:22:27.985 [Thread-8] DEBUG soot.PackManager - Decompiling org.apache.commons.configuration.AbstractFileConfiguration...</div><div>15:22:27.982 [Thread-5] DEBUG soot.PackManager - Decompiling org.apache.commons.configuration.AbstractConfiguration$1...</div><div>Setting declaring class of methodint <init>(org.apache.commons.configuration.AbstractConfiguration,DavaSuperHandler)</div><div>Setting declaring class of methodint <init>(org.apache.commons.configuration.AbstractConfiguration,DavaSuperHandler)</div><div>15:22:28.263 [Thread-6] ERROR h.solver.CountingThreadPoolExecutor - Worker thread execution failed: Attempting to add method DavaSuperHandler preInit(org.apache.commons.configuration.AbstractConfiguration) to class org.apache.commons.configuration.AbstractConfiguration$2, but the class already has a method with that signature.</div><div>java.lang.RuntimeException: Attempting to add method DavaSuperHandler preInit(org.apache.commons.configuration.AbstractConfiguration) to class org.apache.commons.configuration.AbstractConfiguration$2, but the class already has a method with that signature.</div><div><span style="white-space:pre-wrap"> </span>at soot.SootClass.addMethod(SootClass.java:707) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1052) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source) ~[na:na]</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_40]</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_40]</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745) [na:1.8.0_40]</div><div>Exception in thread "Thread-6" java.lang.RuntimeException: Attempting to add method DavaSuperHandler preInit(org.apache.commons.configuration.AbstractConfiguration) to class org.apache.commons.configuration.AbstractConfiguration$2, but the class already has a method with that signature.</div><div><span style="white-space:pre-wrap"> </span>at soot.SootClass.addMethod(SootClass.java:707)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1052)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745)</div><div>Exception in thread "main" 15:22:28.265 [Thread-5] ERROR h.solver.CountingThreadPoolExecutor - Worker thread execution failed: already declared: preInit</div><div>java.lang.RuntimeException: already declared: preInit</div><div><span style="white-space:pre-wrap"> </span>at soot.SootClass.addMethod(SootClass.java:693) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1052) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source) ~[na:na]</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_40]</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_40]</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745) [na:1.8.0_40]</div><div>Exception in thread "Thread-5" java.lang.RuntimeException: already declared: preInit</div><div><span style="white-space:pre-wrap"> </span>at soot.SootClass.addMethod(SootClass.java:693)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1052)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745)</div><div>java.lang.RuntimeException: already declared: preInit</div><div><span style="white-space:pre-wrap"> </span>at soot.SootClass.addMethod(SootClass.java:693)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1052)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745)</div><div>15:22:28.288 [Thread-7] ERROR h.solver.CountingThreadPoolExecutor - Worker thread execution failed: null</div><div>java.util.ConcurrentModificationException: null</div><div><span style="white-space:pre-wrap"> </span>at soot.util.HashChain$LinkIterator.hasNext(HashChain.java:563) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.toolkits.base.finders.ExceptionFinder.preprocess(ExceptionFinder.java:105) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.DavaBody.<init>(DavaBody.java:324) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.Dava.newBody(Dava.java:87) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1039) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source) ~[na:na]</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_40]</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_40]</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745) [na:1.8.0_40]</div><div>Exception in thread "Thread-7" java.util.ConcurrentModificationException</div><div><span style="white-space:pre-wrap"> </span>at soot.util.HashChain$LinkIterator.hasNext(HashChain.java:563)</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.toolkits.base.finders.ExceptionFinder.preprocess(ExceptionFinder.java:105)</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.DavaBody.<init>(DavaBody.java:324)</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.Dava.newBody(Dava.java:87)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1039)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745)</div><div>15:22:28.293 [Thread-8] ERROR h.solver.CountingThreadPoolExecutor - Worker thread execution failed: null</div><div>java.util.ConcurrentModificationException: null</div><div><span style="white-space:pre-wrap"> </span>at soot.util.HashChain$LinkIterator.hasNext(HashChain.java:563) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.toolkits.base.finders.ExceptionFinder.preprocess(ExceptionFinder.java:105) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.DavaBody.<init>(DavaBody.java:324) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.Dava.newBody(Dava.java:87) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1039) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660) ~[soot-3.3.0.jar:na]</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source) ~[na:na]</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_40]</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_40]</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745) [na:1.8.0_40]</div><div>Exception in thread "Thread-8" java.util.ConcurrentModificationException</div><div><span style="white-space:pre-wrap"> </span>at soot.util.HashChain$LinkIterator.hasNext(HashChain.java:563)</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.toolkits.base.finders.ExceptionFinder.preprocess(ExceptionFinder.java:105)</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.DavaBody.<init>(DavaBody.java:324)</div><div><span style="white-space:pre-wrap"> </span>at soot.dava.Dava.newBody(Dava.java:87)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.runBodyPacks(PackManager.java:1039)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager.lambda$runBodyPacks$0(PackManager.java:660)</div><div><span style="white-space:pre-wrap"> </span>at soot.PackManager$$Lambda$1/302869695.run(Unknown Source)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)</div><div><span style="white-space:pre-wrap"> </span>at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)</div><div><span style="white-space:pre-wrap"> </span>at java.lang.Thread.run(Thread.java:745)</div><div><br></div>Somebody can help me?!</div><div><br></div><div>-- <br><div dir="ltr" class="gmail-m_-7609227639717233314gmail_signature"><div dir="ltr"><a href="https://www.facebook.com/scattiperanima?ref=hl" target="_blank">https://www.facebook.com/scattiperanima</a> - Il mio compito è arduo, si tratta di fermare un istante con un click... <br></div></div></div></div></div></div></div></div></div></div></div></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><a href="https://www.facebook.com/scattiperanima?ref=hl" target="_blank">https://www.facebook.com/scattiperanima</a> - Il mio compito è arduo, si tratta di fermare un istante con un click... <br></div></div>