| package kellegous.client; | 
 |  | 
 | import com.google.gwt.core.client.Duration; | 
 | import com.google.gwt.core.client.EntryPoint; | 
 | import com.google.gwt.core.client.GWT; | 
 | import com.google.gwt.dom.client.DivElement; | 
 | import com.google.gwt.dom.client.Document; | 
 | import com.google.gwt.user.client.Command; | 
 | import com.google.gwt.user.client.Event; | 
 | import com.google.gwt.user.client.EventListener; | 
 |  | 
 | public class Dispatch implements EntryPoint { | 
 |   private static native Event createMockEvent() /*-{ | 
 |     return { type: "click" }; | 
 |   }-*/; | 
 |  | 
 |   private static double[] runTrial(int numberOfObservers, | 
 |       int numberOfIterations, int numberOfSamples) { | 
 |     final double[] results = new double[numberOfSamples]; | 
 |     final EventListener subject = Subject.create(numberOfObservers); | 
 |     final Event event = createMockEvent(); | 
 |     for (int j = 0; j < numberOfSamples; ++j) { | 
 |       final Duration d = new Duration(); | 
 |       for (int i = 0; i < numberOfIterations; ++i) { | 
 |         subject.onBrowserEvent(event); | 
 |       } | 
 |       results[j] = d.elapsedMillis(); | 
 |     } | 
 |     return results; | 
 |   } | 
 |  | 
 |   private static native void schedule(Command command) /*-{ | 
 |     $wnd.setTimeout(function() { | 
 |       command.@com.google.gwt.user.client.Command::execute()(); | 
 |     }, 0); | 
 |   }-*/; | 
 |  | 
 |   // t-distribution for p = 0.05 (used to compute 95% confidence intervals). | 
 |   // This table is based at df = 2. | 
 |   private final static double[] TDIST = new double[] { | 
 |       4.3027, 3.1824, 2.7765, 2.5706, 2.4469, 2.3646, 2.3060, 2.2622, 2.2281, | 
 |       2.2010, 2.1788, 2.1604, 2.1448, 2.1315, 2.1199, 2.1098, 2.1009, 2.0930, | 
 |       2.0860, 2.0796, 2.0739, 2.0687, 2.0639, 2.0595, 2.0555, 2.0518, 2.0484, | 
 |       2.0452, 2.0423, 2.0395, 2.0369, 2.0345, 2.0322, 2.0301, 2.0281, 2.0262, | 
 |       2.0244, 2.0227, 2.0211, 2.0195, 2.0181, 2.0167, 2.0154, 2.0141, 2.0129, | 
 |       2.0117, 2.0106, 2.0096, 2.0086, 2.0076, 2.0066, 2.0057, 2.0049, 2.0040, | 
 |       2.0032, 2.0025, 2.0017, 2.0010, 2.0003, 1.9996, 1.9990, 1.9983, 1.9977, | 
 |       1.9971, 1.9966, 1.9960, 1.9955, 1.9949, 1.9944, 1.9939, 1.9935, 1.9930, | 
 |       1.9925, 1.9921, 1.9917, 1.9913, 1.9908, 1.9905, 1.9901, 1.9897, 1.9893, | 
 |       1.9890, 1.9886, 1.9883, 1.9879, 1.9876, 1.9873, 1.9870, 1.9867, 1.9864, | 
 |       1.9861, 1.9858, 1.9855, 1.9852, 1.9850, 1.9847, 1.9845, 1.9842, 1.9840}; | 
 |  | 
 |   private static double computeT(int df) { | 
 |     return TDIST[df - 2]; | 
 |   } | 
 |  | 
 |   private static double computeMean(double[] s) { | 
 |     double sum = 0.0; | 
 |     final int n = s.length; | 
 |     for (int i = 0; i < n; ++i) { | 
 |       sum += s[i]; | 
 |     } | 
 |     return sum / n; | 
 |   } | 
 |  | 
 |   private static double computeStandardError(double[] data, double mean) { | 
 |     final int n = data.length; | 
 |     double sum = 0.0; | 
 |     for (int i = 0; i < n; ++i) { | 
 |       final double d = data[i] - mean; | 
 |       sum += d * d; | 
 |     } | 
 |  | 
 |     return Math.sqrt(sum / n) / Math.sqrt(n); | 
 |   } | 
 |  | 
 |   private static class Stats { | 
 |     private final double mean, upper, lower; | 
 |  | 
 |     Stats(double[] data) { | 
 |       mean = computeMean(data); | 
 |       final double error = computeStandardError(data, mean); | 
 |       final double t = computeT(data.length - 1); | 
 |       upper = mean + t * error; | 
 |       lower = mean - t * error; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public String toString() { | 
 |       return mean + ", " + lower + ", " + upper; | 
 |     } | 
 |   } | 
 |  | 
 |   public static class Runner { | 
 |     private int n; | 
 |     private final int max, numIterations, numSamples; | 
 |     private Stats[] results; | 
 |  | 
 |     Runner(int min, int max, int numIterations, int numSamples) { | 
 |       n = min; | 
 |       this.max = max; | 
 |       this.numIterations = numIterations; | 
 |       this.numSamples = numSamples; | 
 |       results = new Stats[max - min + 1]; | 
 |     } | 
 |  | 
 |     void finish() { | 
 |       final Document document = Document.get(); | 
 |       final DivElement root = document.createDivElement(); | 
 |       document.getBody().appendChild(root); | 
 |       for (int i = 0, n = results.length; i < n; ++i) { | 
 |         final DivElement div = document.createDivElement(); | 
 |         root.appendChild(div); | 
 |         div.setInnerText("" + results[i].toString()); | 
 |       } | 
 |     } | 
 |  | 
 |     void next() { | 
 |       schedule(new Command() { | 
 |         public void execute() { | 
 |           final double[] results = runTrial(n, numIterations, numSamples); | 
 |           Runner.this.results[n] = new Stats(results); | 
 |           if (++n <= max) { | 
 |             next(); | 
 |           } else { | 
 |             finish(); | 
 |           } | 
 |         } | 
 |       }); | 
 |     } | 
 |  | 
 |     void run() { | 
 |       next(); | 
 |     } | 
 |   } | 
 |  | 
 |   public void onModuleLoad() { | 
 |     // Don't run this in hosted mode. | 
 |     if (GWT.isScript()) { | 
 |       new Runner(0, 10, 10000, 20).run(); | 
 |     } | 
 |   } | 
 | } |