diff --git a/.gitmodules b/.gitmodules
index 582a9f9e..bd1bf063 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -677,3 +677,6 @@
 [submodule "vendor/grammars/sublime-pony"]
 	path = vendor/grammars/sublime-pony
 	url = https://github.com/CausalityLtd/sublime-pony
+[submodule "vendor/grammars/X10"]
+	path = vendor/grammars/X10
+	url = git@github.com:x10-lang/x10-highlighting.git
diff --git a/grammars.yml b/grammars.yml
index 0fcdf052..a42d7ae7 100644
--- a/grammars.yml
+++ b/grammars.yml
@@ -144,6 +144,8 @@ vendor/grammars/VBDotNetSyntax:
 - source.vbnet
 vendor/grammars/Vala-TMBundle:
 - source.vala
+vendor/grammars/X10:
+- source.x10
 vendor/grammars/abap.tmbundle:
 - source.abap
 vendor/grammars/actionscript3-tmbundle:
diff --git a/lib/linguist/heuristics.rb b/lib/linguist/heuristics.rb
index 7c523fa8..4d468bf0 100644
--- a/lib/linguist/heuristics.rb
+++ b/lib/linguist/heuristics.rb
@@ -65,7 +65,7 @@ module Linguist
     end
 
     # Common heuristics
-    ObjectiveCRegex = /^[ \t]*@(interface|class|protocol|property|end|synchronised|selector|implementation)\b/
+    ObjectiveCRegex = /^[ \t]*@(interface|class|protocol|property|end|synchronized|selector|implementation)\b/
 
     disambiguate ".bb" do |data|
       if /^\s*; /.match(data) || data.include?("End Function")
diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml
index 7ef4cebc..8e13bfda 100644
--- a/lib/linguist/languages.yml
+++ b/lib/linguist/languages.yml
@@ -1719,6 +1719,7 @@ LSL:
   ace_mode: lsl
   extensions:
   - .lsl
+  - .lslp
   interpreters:
   - lsl
   color: '#3d9970'
@@ -3574,6 +3575,16 @@ WebIDL:
   tm_scope: source.webidl
   ace_mode: text
 
+X10:
+  type: programming
+  aliases:
+  - xten
+  ace_mode: text
+  extensions:
+  - .x10
+  color: "#4B6BEF"
+  tm_scope: source.x10
+
 XC:
   type: programming
   color: "#99DA07"
diff --git a/lib/linguist/vendor.yml b/lib/linguist/vendor.yml
index ed89eda8..d5965bb2 100644
--- a/lib/linguist/vendor.yml
+++ b/lib/linguist/vendor.yml
@@ -78,6 +78,9 @@
 # Haxelib projects often contain a neko bytecode file named run.n
 - run.n$
 
+# Bootstrap Datepicker
+- bootstrap-datepicker/
+
 ## Commonly Bundled JavaScript frameworks ##
 
 # jQuery
@@ -88,6 +91,34 @@
 - (^|/)jquery\-ui(\-\d\.\d+(\.\d+)?)?(\.\w+)?\.(js|css)$
 - (^|/)jquery\.(ui|effects)\.([^.]*)\.(js|css)$
 
+# jQuery Gantt
+- jquery.fn.gantt.js
+
+# jQuery fancyBox
+- jquery.fancybox.js
+
+# Fuel UX
+- fuelux.js
+
+# jQuery File Upload
+- (^|/)jquery\.fileupload(-\w+)?\.js$
+
+# Slick
+- (^|/)slick\.\w+.js$
+
+# Leaflet plugins
+- (^|/)Leaflet\.Coordinates-\d+\.\d+\.\d+\.src\.js$
+- leaflet.draw-src.js
+- leaflet.draw.css
+- Control.FullScreen.css
+- Control.FullScreen.js
+- leaflet.spin.js
+- wicket-leaflet.js
+
+# Sublime Text workspace files
+- .sublime-project
+- .sublime-workspace
+
 # Prototype
 - (^|/)prototype(.*)\.js$
 - (^|/)effects\.js$
@@ -122,7 +153,7 @@
 - (^|/)Chart\.js$
 
 # Codemirror
-- (^|/)[Cc]ode[Mm]irror/(lib|mode|theme|addon|keymap|demo)
+- (^|/)[Cc]ode[Mm]irror/(\d+\.\d+/)?(lib|mode|theme|addon|keymap|demo)
 
 # SyntaxHighlighter - http://alexgorbatchev.com/
 - (^|/)shBrush([^.]*)\.js$
diff --git a/samples/LSL/LSL.lslp b/samples/LSL/LSL.lslp
new file mode 100644
index 00000000..5d281b95
--- /dev/null
+++ b/samples/LSL/LSL.lslp
@@ -0,0 +1,74 @@
+/*
+    Testing syntax highlighting
+    for the Linden Scripting Language
+*/
+
+integer someIntNormal       = 3672;
+integer someIntHex          = 0x00000000;
+integer someIntMath         = PI_BY_TWO;
+
+integer event               = 5673;// 'event' is invalid.illegal
+
+key someKeyTexture          = TEXTURE_DEFAULT;
+string someStringSpecial    = EOF;
+
+some_user_defined_function_without_return_type(string inputAsString)
+{
+    llSay(PUBLIC_CHANNEL, inputAsString);
+}
+
+string user_defined_function_returning_a_string(key inputAsKey)
+{
+    return (string)inputAsKey;
+}
+
+default
+{
+    state_entry()
+    {
+        key someKey = NULL_KEY;
+        someKey = llGetOwner();
+
+        string someString = user_defined_function_returning_a_string(someKey);
+
+        some_user_defined_function_without_return_type(someString);
+    }
+
+    touch_start(integer num_detected)
+    {
+        list agentsInRegion = llGetAgentList(AGENT_LIST_REGION, []);
+        integer numOfAgents = llGetListLength(agentsInRegion);
+
+        integer index;                                                          // defaults to 0
+        for (; index <= numOfAgents - 1; index++)                               // for each agent in region
+        {
+            llRegionSayTo(llList2Key(agentsInRegion, index), PUBLIC_CHANNEL, "Hello, Avatar!");
+        }
+    }
+
+    touch_end(integer num_detected)
+    {
+        someIntNormal       = 3672;
+        someIntHex          = 0x00000000;
+        someIntMath         = PI_BY_TWO;
+
+        event               = 5673;// 'event' is invalid.illegal
+
+        someKeyTexture      = TEXTURE_DEFAULT;
+        someStringSpecial   = EOF;
+
+        llSetInventoryPermMask("some item", MASK_NEXT, PERM_ALL);// 'llSetInventoryPermMask' is reserved.godmode
+
+        llWhisper(PUBLIC_CHANNEL, "Leaving \"default\" now...");
+        state other;
+    }
+}
+
+state other
+{
+    state_entry()
+    {
+        llWhisper(PUBLIC_CHANNEL, "Entered \"state other\", returning to \"default\" again...");
+        state default;
+    }
+}
diff --git a/samples/X10/ArraySum.x10 b/samples/X10/ArraySum.x10
new file mode 100644
index 00000000..389d0e87
--- /dev/null
+++ b/samples/X10/ArraySum.x10
@@ -0,0 +1,72 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.io.Console;
+
+/**
+ * A simple illustration of loop parallelization within a single place.
+ */
+public class ArraySum {
+
+    var sum:Long;
+    val data:Rail[Long];
+
+    public def this(n:Long) {
+	// Create a Rail with n elements (0..(n-1)), all initialized to 1.
+        data = new Rail[Long](n, 1);
+        sum = 0;
+    }
+
+    def sum(a:Rail[Long], start:Long, last:Long) {
+        var mySum: Long = 0;
+        for (i in start..(last-1)) { 
+        	mySum += a(i);
+        }
+        return mySum;
+    }
+
+    def sum(numThreads:Long) {
+        val mySize = data.size/numThreads;
+        finish for (p in 0..(numThreads-1)) async {
+            val mySum = sum(data, p*mySize, (p+1)*mySize);
+            // Multiple activities will simultaneously update
+            // this location -- so use an atomic operation.
+            atomic sum += mySum;
+        }
+    }
+    
+    public static def main(args:Rail[String]) {
+        var size:Long = 5*1000*1000;
+        if (args.size >=1)
+            size = Long.parse(args(0));
+
+        Console.OUT.println("Initializing.");
+        val a = new ArraySum(size);
+        val P = [1,2,4];
+
+        //warmup loop
+        Console.OUT.println("Warming up.");
+        for (numThreads in P)
+            a.sum(numThreads);
+        
+        for (numThreads in P) {
+            Console.OUT.println("Starting with " + numThreads + " threads.");
+            a.sum=0;
+            var time: long = - System.nanoTime();
+            a.sum(numThreads);
+            time += System.nanoTime();
+            Console.OUT.println("For p=" + numThreads
+                    + " result: " + a.sum 
+                    + ((size==a.sum)? " ok" : "  bad") 
+                    + " (time=" + (time/(1000*1000)) + " ms)");
+        }
+    }
+}
diff --git a/samples/X10/Cancellation.x10 b/samples/X10/Cancellation.x10
new file mode 100644
index 00000000..1e13bea1
--- /dev/null
+++ b/samples/X10/Cancellation.x10
@@ -0,0 +1,50 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.xrx.Runtime;
+
+/**
+ * Demonstrate how to instantiate the X10 runtime as an executor service
+ * submit jobs to the runtime, wait jobs to complete and cancel all jobs
+ * 
+ * Compile with: x10c -O -EXECUTOR_MODE=true Cancellation.x10
+ * Run with:     X10_CANCELLABLE=true X10_NPLACES=4 x10 -DX10RT_IMPL=JavaSockets Cancellation
+ */
+class Cancellation {
+    static def job(id:Long, iterations:Long) = ()=>{
+        at (Place.places().next(here)) async {
+            for (i in 1..iterations) {
+                finish for (p in Place.places()) { 
+                    at (p) async Console.OUT.println(here+" says hello (job " + id + ", iteration " + i + ")");
+                }
+                Console.ERR.println();
+                System.sleep(200);
+            }
+        }
+    };
+
+    public static def main(args:Rail[String]):void {
+        val w1 = Runtime.submit(job(1, 5));
+        w1.await(); Console.ERR.println("Job 1 completed\n");
+        val w2 = Runtime.submit(job(2, 1000));
+        System.threadSleep(1000);
+        val c1 = Runtime.cancelAll();
+        try { w2.await(); } catch (e:Exception) { Console.ERR.println("Job 2 aborted with exception " + e +"\n"); }
+        c1.await(); // waiting for cancellation to be processed
+        System.threadSleep(1000);
+        Runtime.submit(job(3, 1000));
+        Runtime.submit(job(4, 1000));
+        System.threadSleep(1000);
+        val c2 = Runtime.cancelAll();
+        c2.await();
+        Console.ERR.println("Goodbye\n");
+    }
+}
diff --git a/samples/X10/Fibonacci.x10 b/samples/X10/Fibonacci.x10
new file mode 100644
index 00000000..fc1466f1
--- /dev/null
+++ b/samples/X10/Fibonacci.x10
@@ -0,0 +1,52 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.io.Console;
+
+/**
+ * This is a small program to illustrate the use of 
+ * async and finish in a 
+ * prototypical recursive divide-and-conquer algorithm.  
+ * It is obviously not intended to show a efficient way to
+ * compute Fibonacci numbers in X10.
+ *
+ * The heart of the example is the run method,
+ * which directly embodies the recursive definition of 
+ * 
+ * fib(n) = fib(n-1)+fib(n-2); + *+ * by using an
async to compute fib(n-1) while
+ * the current activity computes fib(n-2).  A finish
+ * is used to ensure that both computations are complete before 
+ * their results are added together to compute fib(n)
+ */
+public class Fibonacci {
+
+  public static def fib(n:long) {
+    if (n<=2) return 1;
+    
+    val f1:long;
+    val f2:long;
+    finish {
+      async { f1 = fib(n-1); }
+      f2 = fib(n-2);
+    }
+    return f1 + f2;
+  }
+
+  public static def main(args:Rail[String]) {
+    val n = (args.size > 0) ? Long.parse(args(0)) : 10;
+    Console.OUT.println("Computing fib("+n+")");
+    val f = fib(n);
+    Console.OUT.println("fib("+n+") = "+f);
+  }
+}
+
diff --git a/samples/X10/HeatTransfer_v0.x10 b/samples/X10/HeatTransfer_v0.x10
new file mode 100644
index 00000000..5546fae8
--- /dev/null
+++ b/samples/X10/HeatTransfer_v0.x10
@@ -0,0 +1,86 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.array.*;
+import x10.compiler.Foreach;
+import x10.compiler.Inline;
+
+
+/**
+ * This is a sample program illustrating how to use
+ * X10's array classes.  It also illustrates the use
+ * of foreach to acheive intra-place parallelism.
+ *
+ * The program solves a set of 2D partial differential
+ * equations by iteratively applying a 5-point stencil
+ * operation until convergence is reached.
+ */
+public class HeatTransfer_v0 {
+    static val EPSILON = 1.0e-5;
+
+    val N:Long;
+    val A:Array_2[Double]{self!=null};
+    val Tmp:Array_2[Double]{self!=null};
+
+    public def this(size:Long) {
+        N = size;
+        A = new Array_2[Double](N+2, N+2);  // zero-initialized N+2 * N+2 array of doubles
+        for (j in 1..N) A(0, j) = 1;     // set one border row to 1 
+        Tmp = new Array_2[Double](A);
+    }
+
+    final @Inline def stencil(x:Long, y:Long):Double {
+        return (A(x-1,y) + A(x+1,y) + A(x,y-1) + A(x,y+1)) / 4;
+    }
+
+    def run() {
+        val is = new DenseIterationSpace_2(1,1,N,N);
+        var delta:Double;
+        do {
+            // Compute new values, storing in tmp
+            delta = Foreach.blockReduce(is,
+                (i:Long, j:Long)=>{
+                    Tmp(i,j) = stencil(i,j);
+                    // Reduce max element-wise delta (A now holds previous values)
+                    return Math.abs(Tmp(i,j) - A(i,j));
+                },
+                (a:Double, b:Double)=>Math.max(a,b), 0.0
+            );
+
+            // swap backing data of A and Tmp
+            Array.swap(A, Tmp);
+        } while (delta > EPSILON);
+    }
+
+    def prettyPrintResult() {
+       for (i in 1..N) {
+           for (j in 1..N) {
+                Console.OUT.printf("%1.4f ",A(i,j));
+            }
+            Console.OUT.println();
+        }
+    }
+
+    public static def main(args:Rail[String]) {
+        val n = args.size > 0 ? Long.parse(args(0)) : 8;
+        Console.OUT.println("HeatTransfer example with N="+n+" and epsilon="+EPSILON);
+        Console.OUT.println("Initializing data structures");
+        val ht = new HeatTransfer_v0(n);
+        Console.OUT.println("Beginning computation...");
+        val start = System.nanoTime();
+        ht.run();
+        val stop = System.nanoTime();
+        Console.OUT.printf("...completed in %1.3f seconds.\n", ((stop-start) as double)/1e9);
+        if (n <= 10) {
+            ht.prettyPrintResult();
+        }
+    }
+}
diff --git a/samples/X10/HeatTransfer_v1.x10 b/samples/X10/HeatTransfer_v1.x10
new file mode 100644
index 00000000..feeeebe6
--- /dev/null
+++ b/samples/X10/HeatTransfer_v1.x10
@@ -0,0 +1,114 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.array.*;
+import x10.compiler.Foreach;
+import x10.util.Team;
+
+/**
+ * This is a sample program illustrating how to use
+ * X10's distributed array classes.  It also illustrates the use
+ * of foreach to achieve intra-place parallelism and the mixture
+ * of APGAS finish/async/at with Team collective operations.
+ *
+ * This version of the program uses a vanilla DistArray without
+ * ghost regions.  As a result, the stencil function does
+ * inefficient fine-grained neighbor communication to get individual values.
+ * Compare this to HeatTransfer_v2 which utilizes ghost regions and
+ * bulk ghost-region exchange functions.
+ * 
+ * The program solves a set of 2D partial differential
+ * equations by iteratively applying a 5-point stencil
+ * operation until convergence is reached.
+ */
+public class HeatTransfer_v1 {
+    static val EPSILON = 1.0e-5;
+
+    val N:Long;
+    val A:DistArray_BlockBlock_2[Double]{self!=null};
+    val Tmp:DistArray_BlockBlock_2[Double]{self!=null};
+
+    public def this(size:Long) {
+        N = size;
+        val init = (i:Long, j:Long)=>i==0 ? 1.0 : 0.0;
+        A = new DistArray_BlockBlock_2[Double](N+2, N+2, init);
+        Tmp = new DistArray_BlockBlock_2[Double](N+2, N+2, init);
+    }
+
+    final def stencil(x:Long, y:Long):Double {
+        val cls = (dx:Long, dy:Long)=>{
+            val p = A.place(x+dx, y+dy);
+            p == here ? A(x+dx,y+dy) : at (p) A(x+dx,y+dy)
+        };
+        val tmp = cls(-1,0) + cls(1,0) + cls(0,-1) + cls(0,1);
+        return tmp / 4; 
+    }
+
+    def run() {
+        val myTeam = new Team(A.placeGroup());
+        finish for (p in A.placeGroup()) at (p) async {
+            // Compute the subset of the local indices on which
+            // we want to apply the stencil (the interior points of the N+2 x N+2 grid)
+            val li = A.localIndices();
+            val interior = new DenseIterationSpace_2(li.min(0) == 0 ? 1 : li.min(0),
+                                                     li.min(1) == 0 ? 1 : li.min(1),
+                                                     li.max(0) == N+1 ? N : li.max(0),
+                                                     li.max(1) == N+1 ? N : li.max(1));
+            var delta:Double;
+            do {
+                // Compute new values, storing in tmp
+                val myDelta = Foreach.blockReduce(interior,
+                    (i:Long, j:Long)=>{
+                        Tmp(i,j) = stencil(i,j);
+                        // Reduce max element-wise delta (A now holds previous values)
+                        return Math.abs(Tmp(i,j) - A(i,j));
+                    },
+                    (a:Double, b:Double)=>Math.max(a,b), 0.0
+                );
+
+                myTeam.barrier();
+
+                // Unlike Array, DistArray doesn't provide an optimized swap.
+                // So, until it does, we have to copy the data elements.
+                Foreach.block(interior, (i:Long, j:Long)=>{
+                    A(i,j) = Tmp(i,j);
+                });
+
+                delta = myTeam.allreduce(myDelta, Team.MAX);
+            } while (delta > EPSILON);
+        }
+    }
+ 
+   def prettyPrintResult() {
+       for (i in 1..N) {
+           for (j in 1..N) {
+                val x = at (A.place(i,j)) A(i,j);
+                Console.OUT.printf("%1.4f ", x);
+            }
+            Console.OUT.println();
+        }
+    }
+
+    public static def main(args:Rail[String]) {
+        val n = args.size > 0 ? Long.parse(args(0)) : 8;
+        Console.OUT.println("HeatTransfer example with N="+n+" and epsilon="+EPSILON);
+        Console.OUT.println("Initializing data structures");
+        val ht = new HeatTransfer_v1(n);
+        Console.OUT.println("Beginning computation...");
+        val start = System.nanoTime();
+        ht.run();
+        val stop = System.nanoTime();
+        Console.OUT.printf("...completed in %1.3f seconds.\n", ((stop-start) as double)/1e9);
+        if (n <= 10) {
+            ht.prettyPrintResult();
+        }
+    }
+}
diff --git a/samples/X10/HelloWholeWorld.x10 b/samples/X10/HelloWholeWorld.x10
new file mode 100644
index 00000000..4017ef9d
--- /dev/null
+++ b/samples/X10/HelloWholeWorld.x10
@@ -0,0 +1,44 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.io.Console;
+
+/**
+ * The classic hello world program, with a twist - prints a message
+ * from the command line at every Place. 
+ * The messages from each Place may appear in any order, but the
+ * finish ensures that the last message printed will be "Goodbye"
+ * + * Typical output: + * [dgrove@linchen samples]$ ./HelloWholeWorld 'best wishes' + * Place(1) says hello and best wishes + * Place(2) says hello and best wishes + * Place(3) says hello and best wishes + * Place(0) says hello and best wishes + * Goodbye + * [dgrove@linchen samples]$ + *+ */ +class HelloWholeWorld { + public static def main(args:Rail[String]):void { + if (args.size < 1) { + Console.OUT.println("Usage: HelloWholeWorld message"); + return; + } + + finish for (p in Place.places()) { + at (p) async Console.OUT.println(here+" says hello and "+args(0)); + } + Console.OUT.println("Goodbye"); + } +} + + diff --git a/samples/X10/HelloWorld.x10 b/samples/X10/HelloWorld.x10 new file mode 100644 index 00000000..06743b4c --- /dev/null +++ b/samples/X10/HelloWorld.x10 @@ -0,0 +1,23 @@ +/* + * This file is part of the X10 project (http://x10-lang.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * (C) Copyright IBM Corporation 2006-2014. + */ + +import x10.io.Console; + +/** + * The classic hello world program, shows how to output to the console. + */ +class HelloWorld { + public static def main(Rail[String]) { + Console.OUT.println("Hello World!" ); + } +} + + diff --git a/samples/X10/Histogram.x10 b/samples/X10/Histogram.x10 new file mode 100644 index 00000000..bf6ad2b1 --- /dev/null +++ b/samples/X10/Histogram.x10 @@ -0,0 +1,45 @@ +/* + * This file is part of the X10 project (http://x10-lang.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * (C) Copyright IBM Corporation 2006-2014. + */ + +public class Histogram { + public static def compute(data:Rail[Int], numBins:Int) { + val bins = new Rail[Int](numBins); + finish for (i in data.range) async { + val b = data(i) % numBins; + atomic bins(b)++; + } + return bins; + } + + public static def run(N:Int, S:Int):Boolean { + val a = new Rail[Int](N, (i:long)=> i as int); + val b = compute(a, S); + val v = b(0); + var ok:Boolean = true; + for (x in b.range) ok &= (b(x)==v); + return ok; + } + + public static def main(args:Rail[String]) { + if (args.size != 2L) { + Console.OUT.println("Usage: Histogram SizeOfArray NumberOfBins"); + return; + } + val N = Int.parse(args(0)); + val S = Int.parse(args(1)); + val ok = run(N,S); + if (ok) { + Console.OUT.println("Test ok."); + } else { + Console.OUT.println("Test failed."); + } + } +} diff --git a/samples/X10/Integrate.x10 b/samples/X10/Integrate.x10 new file mode 100644 index 00000000..accf31b9 --- /dev/null +++ b/samples/X10/Integrate.x10 @@ -0,0 +1,55 @@ +/* + * This file is part of the X10 project (http://x10-lang.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * (C) Copyright IBM Corporation 2006-2014. + */ + +/** + * This is a slightly more realistic example of the + * basic computational pattern of using async/finish + * to express recursive divide-and-conquer algorithms. + * The program does integration via Guassian Quadrature. + *
+ * It also can serve as an example of using a closure. + */ +public class Integrate { + static val epsilon = 1.0e-9; + + val fun:(double)=>double; + + public def this(f:(double)=>double) { fun = f; } + + public def computeArea(left:double, right:double) { + return recEval(left, fun(left), right, fun(right), 0); + } + + private def recEval(l:double, fl:double, r:double, fr:double, a:double) { + val h = (r - l) / 2; + val hh = h / 2; + val c = l + h; + val fc = fun(c); + val al = (fl + fc) * hh; + val ar = (fr + fc) * hh; + val alr = al + ar; + if (Math.abs(alr - a) < epsilon) return alr; + val expr1:double; + val expr2:double; + finish { + async { expr1 = recEval(c, fc, r, fr, ar); }; + expr2 = recEval(l, fl, c, fc, al); + } + return expr1 + expr2; + } + + public static def main(args:Rail[String]) { + val obj = new Integrate((x:double)=>(x*x + 1.0) * x); + val xMax = args.size > 0 ? Long.parse(args(0)) : 10; + val area = obj.computeArea(0, xMax); + Console.OUT.println("The area of (x*x +1) * x from 0 to "+xMax+" is "+area); + } +} diff --git a/samples/X10/KMeans.x10 b/samples/X10/KMeans.x10 new file mode 100644 index 00000000..475732b7 --- /dev/null +++ b/samples/X10/KMeans.x10 @@ -0,0 +1,151 @@ +/* + * This file is part of the X10 project (http://x10-lang.org). + * + * This file is licensed to You under the Eclipse Public License (EPL); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.opensource.org/licenses/eclipse-1.0.php + * + * (C) Copyright IBM Corporation 2006-2014. + */ + +import x10.io.Console; +import x10.util.Random; + +/** + * A KMeans object o can compute K means of a given set of + * points of dimension o.myDim. + *
 
+ * This class implements a sequential program, that is readily parallelizable.
+ *
+ * For a scalable, high-performance version of this benchmark see
+ * KMeans.x10 in the X10 Benchmarks (separate download from x10-lang.org)
+ */
+public class KMeans(myDim:Long) {
+
+    static val DIM=2;
+    static val K=4;
+    static val POINTS=2000;
+    static val ITERATIONS=50;
+    static val EPS=0.01F;
+    
+    static type ValVector(k:Long) = Rail[Float]{self.size==k};
+    static type ValVector = ValVector(DIM);
+    
+    static type Vector(k:Long) = Rail[Float]{self.size==k};
+    static type Vector = Vector(DIM);
+    
+    static type SumVector(d:Long) = V{self.dim==d};
+    static type SumVector = SumVector(DIM);
+
+    /**
+     * V represents the sum of 'count' number of vectors of dimension 'dim'.
+     */
+    static class V(dim:Long) implements (Long)=>Float {
+        var vec: Vector(dim);
+        var count:Int;
+        def this(dim:Long, init:(Long)=>Float): SumVector(dim) {
+           property(dim);
+           vec = new Rail[Float](this.dim, init);
+           count = 0n;
+        }
+        public operator this(i:Long) = vec(i);
+        def makeZero() {
+            for (i in 0..(dim-1))
+                vec(i) =0.0F;
+            count=0n;
+        }
+        def addIn(a:ValVector(dim)) {
+            for (i in 0..(dim-1))
+                vec(i) += a(i);
+            count++;
+        }
+        def div(f:Int) {
+            for (i in 0..(dim-1))
+                vec(i) /= f;
+        }
+        def dist(a:ValVector(dim)):Float {
+            var dist:Float=0.0F;
+            for (i in 0..(dim-1)) {
+                val tmp = vec(i)-a(i);
+                dist += tmp*tmp;
+            }
+            return dist;
+        }
+        def dist(a:SumVector(dim)):Float {
+            var dist:Float=0.0F;
+            for (i in 0..(dim-1)) {
+                val tmp = vec(i)-a(i);
+                dist += tmp*tmp;
+            }
+            return dist;
+        }
+        def print() {
+            Console.OUT.println();
+            for (i in 0..(dim-1)) {
+                Console.OUT.print((i>0? " " : "") + vec(i));
+            }
+        }
+        def normalize() { div(count);}
+        def count() = count;
+    }
+    
+    
+    def this(myDim:Long):KMeans{self.myDim==myDim} {
+        property(myDim);
+    }
+    static type KMeansData(myK:Long, myDim:Long)= Rail[SumVector(myDim)]{self.size==myK};
+
+    /**
+     * Compute myK means for the given set of points of dimension myDim.
+     */
+    def computeMeans(myK:Long, points:Rail[ValVector(myDim)]):KMeansData(myK, myDim) {
+        var redCluster : KMeansData(myK, myDim) =
+            new Rail[SumVector(myDim)](myK, (i:long)=> new V(myDim, (j:long)=>points(i)(j)));
+        var blackCluster: KMeansData(myK, myDim) =
+            new Rail[SumVector(myDim)](myK, (i:long)=> new V(myDim, (j:long)=>0.0F));
+        for (i in 1..ITERATIONS) {
+            val tmp = redCluster;
+            redCluster = blackCluster;
+            blackCluster=tmp;
+            for (p in 0..(POINTS-1)) { 
+                var closest:Long = -1;
+                var closestDist:Float = Float.MAX_VALUE;
+                val point = points(p);
+                for (k in 0..(myK-1)) { // compute closest mean in cluster.
+                    val dist = blackCluster(k).dist(point);
+                    if (dist < closestDist) {
+                        closestDist = dist;
+                        closest = k;
+                    }
+                }
+                redCluster(closest).addIn(point);
+            }
+            for (k in 0..(myK-1))
+                redCluster(k).normalize(); 
+            
+            var b:Boolean = true;
+                for (k in 0..(myK-1)) {
+                    if (redCluster(k).dist(blackCluster(k)) > EPS) {
+                        b=false;
+                        break;
+                    }
+                }
+            if (b) 
+                break;
+            for (k in 0..(myK-1))
+                blackCluster(k).makeZero(); 
+        }
+        return redCluster;  
+    }
+  
+    public static def main (Rail[String]) {
+        val rnd = new Random(0);
+        val points = new Rail[ValVector](POINTS, 
+                        (long)=>new Rail[Float](DIM, (long)=>rnd.nextFloat()));
+        val result = new KMeans(DIM).computeMeans(K, points);
+        for (k in 0..(K-1)) result(k).print();
+    }
+}
+
+// vim: shiftwidth=4:tabstop=4:expandtab
diff --git a/samples/X10/KMeansDist.x10 b/samples/X10/KMeansDist.x10
new file mode 100644
index 00000000..069cc374
--- /dev/null
+++ b/samples/X10/KMeansDist.x10
@@ -0,0 +1,147 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.array.*;
+import x10.io.Console;
+import x10.util.Random;
+
+/**
+ * A low performance formulation of distributed KMeans using fine-grained asyncs.
+ *
+ * For a highly optimized and scalable, version of this benchmark see
+ * KMeans.x10 in the X10 Benchmarks (separate download from x10-lang.org)
+ */
+public class KMeansDist {
+
+    static val DIM=2;
+    static val CLUSTERS=4;
+    static val POINTS=2000;
+    static val ITERATIONS=50;
+
+    public static def main (Rail[String]) {
+        val world = Place.places();
+        val local_curr_clusters = 
+            PlaceLocalHandle.make[Array_2[Float]](world, () => new Array_2[Float](CLUSTERS, DIM));
+        val local_new_clusters = 
+            PlaceLocalHandle.make[Array_2[Float]](world, () =>  new Array_2[Float](CLUSTERS, DIM));
+        val local_cluster_counts = 
+            PlaceLocalHandle.make[Rail[Int]](world, ()=> new Rail[Int](CLUSTERS));
+
+        val rnd = PlaceLocalHandle.make[Random](world, () => new Random(0));
+        val points = new DistArray_Block_2[Float](POINTS, DIM, world, (Long,Long)=>rnd().nextFloat());
+
+        val central_clusters = new Array_2[Float](CLUSTERS, DIM, (i:Long, j:Long) => {
+            at (points.place(i,j)) points(i,j)
+        });
+
+	val old_central_clusters = new Array_2[Float](CLUSTERS, DIM);
+
+        val central_cluster_counts = new Rail[Int](CLUSTERS);
+
+        for (iter in 1..ITERATIONS) {
+
+            Console.OUT.println("Iteration: "+iter);
+
+            finish {
+                // reset state
+                for (d in world) at (d) async {
+                    for ([i,j] in central_clusters.indices()) {
+                        local_curr_clusters()(i, j) = central_clusters(i, j);
+                        local_new_clusters()(i, j) = 0f;
+                    }
+            
+                    local_cluster_counts().clear();
+                }
+            }
+
+            finish {
+                // compute new clusters and counters
+                for (p in 0..(POINTS-1)) {
+                    at (points.place(p,0)) async {
+                        var closest:Long = -1;
+                        var closest_dist:Float = Float.MAX_VALUE;
+                        for (k in 0..(CLUSTERS-1)) { 
+                            var dist : Float = 0;
+                            for (d in 0..(DIM-1)) { 
+                                val tmp = points(p,d) - local_curr_clusters()(k, d);
+                                dist += tmp * tmp;
+                            }
+                            if (dist < closest_dist) {
+                                closest_dist = dist;
+                                closest = k;
+                            }
+                        }
+			atomic {
+                            for (d in 0..(DIM-1)) { 
+                                local_new_clusters()(closest,d) += points(p,d);
+                            }
+                            local_cluster_counts()(closest)++;
+                        }
+                    }
+                }
+            }
+
+            for ([i,j] in old_central_clusters.indices()) {
+                old_central_clusters(i, j) = central_clusters(i, j);
+                central_clusters(i, j) = 0f;
+            }
+           
+            central_cluster_counts.clear();
+
+            finish {
+                val central_clusters_gr = GlobalRef(central_clusters);
+                val central_cluster_counts_gr = GlobalRef(central_cluster_counts);
+                val there = here;
+                for (d in world) at (d) async {
+                    // access PlaceLocalHandles 'here' and then data will be captured by at and transfered to 'there' for accumulation
+                    val tmp_new_clusters = local_new_clusters();
+                    val tmp_cluster_counts = local_cluster_counts();
+                    at (there) atomic {
+                        for ([i,j] in tmp_new_clusters.indices()) {
+                            central_clusters_gr()(i,j) += tmp_new_clusters(i,j);
+                        }
+                        for (j in 0..(CLUSTERS-1)) {
+                            central_cluster_counts_gr()(j) += tmp_cluster_counts(j);
+                        }
+                    }
+                }
+            }
+
+            for (k in 0..(CLUSTERS-1)) { 
+                for (d in 0..(DIM-1)) { 
+                    central_clusters(k, d) /= central_cluster_counts(k);
+                }
+            }
+
+            // TEST FOR CONVERGENCE
+            var b:Boolean = true;
+            for ([i,j] in old_central_clusters.indices()) { 
+                if (Math.abs(old_central_clusters(i, j)-central_clusters(i, j))>0.0001) {
+                    b = false;
+                    break;
+                }
+            }
+            if (b) break;
+
+        }
+
+        for (d in 0..(DIM-1)) { 
+            for (k in 0..(CLUSTERS-1)) { 
+                if (k>0)
+                    Console.OUT.print(" ");
+                Console.OUT.print(central_clusters(k,d));
+            }
+            Console.OUT.println();
+        }
+    }
+}
+
+// vim: shiftwidth=4:tabstop=4:expandtab
diff --git a/samples/X10/KMeansDistPlh.x10 b/samples/X10/KMeansDistPlh.x10
new file mode 100644
index 00000000..ca16aa59
--- /dev/null
+++ b/samples/X10/KMeansDistPlh.x10
@@ -0,0 +1,144 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2015.
+ */
+
+import x10.array.Array;
+import x10.array.Array_2;
+import x10.compiler.Foreach;
+import x10.util.Random;
+
+/**
+ * A better formulation of distributed KMeans using coarse-grained asyncs to
+ * implement an allreduce pattern for cluster centers and counts.
+ *
+ * For a highly optimized and scalable, version of this benchmark see
+ * KMeans.x10 in the X10 Benchmarks (separate download from x10-lang.org)
+ */
+public class KMeansDistPlh {
+
+    static val DIM=2;
+    static val CLUSTERS=4;
+
+    static class ClusterState {
+        val clusters = new Array_2[Float](CLUSTERS, DIM);
+        val clusterCounts = new Rail[Int](CLUSTERS);
+    }
+
+    public static def main(args:Rail[String]) {
+        val numPoints = args.size > 0 ? Long.parse(args(0)) : 2000;
+        val iterations = args.size > 1 ? Long.parse(args(1)) : 50;
+        val world = Place.places();
+
+        val clusterStatePlh = PlaceLocalHandle.make[ClusterState](world, () => new ClusterState());
+        val currentClustersPlh = PlaceLocalHandle.make[Array_2[Float]](world, () => new Array_2[Float](CLUSTERS, DIM));
+        val pointsPlh = PlaceLocalHandle.make[Array_2[Float]](world, () => {
+            val rand = new Random(here.id);
+            return new Array_2[Float](numPoints/world.size(), DIM, (Long,Long)=>rand.nextFloat());
+        });
+
+        val centralCurrentClusters = new Array_2[Float](CLUSTERS, DIM);
+        val centralNewClusters = new Array_2[Float](CLUSTERS, DIM);
+        val centralClusterCounts = new Rail[Int](CLUSTERS);
+
+        // arbitrarily initialize central clusters to first few points
+        for ([i,j] in centralCurrentClusters.indices()) {
+            centralCurrentClusters(i,j) = pointsPlh()(i,j);
+        }
+
+        for (iter in 1..iterations) {
+            Console.OUT.println("Iteration: "+iter);
+
+            finish {
+                for (place in world) async {
+                    val placeClusters = at(place) {
+                        val currentClusters = currentClustersPlh();
+                        Array.copy(centralCurrentClusters, currentClusters);
+
+                        val clusterState = clusterStatePlh();
+                        val newClusters = clusterState.clusters;
+                        newClusters.clear();
+                        val clusterCounts = clusterState.clusterCounts;
+                        clusterCounts.clear();
+
+                        // compute new clusters and counters
+                        val points = pointsPlh();
+
+                        for (p in 0..(points.numElems_1-1)) {
+                            var closest:Long = -1;
+                            var closestDist:Float = Float.MAX_VALUE;
+                            for (k in 0..(CLUSTERS-1)) { 
+                                var dist : Float = 0;
+                                for (d in 0..(DIM-1)) { 
+                                    val tmp = points(p,d) - currentClusters(k, d);
+                                    dist += tmp * tmp;
+                                }
+                                if (dist < closestDist) {
+                                    closestDist = dist;
+                                    closest = k;
+                                }
+                            }
+
+                            atomic {
+                                for (d in 0..(DIM-1)) { 
+                                    newClusters(closest,d) += points(p,d);
+                                }
+                                clusterCounts(closest)++;
+                            }
+                        }
+                        clusterState
+                    };
+
+                    // combine place clusters to central
+                    atomic {
+                        for ([i,j] in centralNewClusters.indices()) {
+                            centralNewClusters(i,j) += placeClusters.clusters(i,j);
+                        }
+                        for (j in 0..(CLUSTERS-1)) {
+                            centralClusterCounts(j) += placeClusters.clusterCounts(j);
+                        }
+                    }
+                }
+            }
+
+            for (k in 0..(CLUSTERS-1)) { 
+                for (d in 0..(DIM-1)) { 
+                    centralNewClusters(k, d) /= centralClusterCounts(k);
+                }
+            }
+
+            // TEST FOR CONVERGENCE
+            var b:Boolean = true;
+            for ([i,j] in centralCurrentClusters.indices()) { 
+                if (Math.abs(centralCurrentClusters(i, j)-centralNewClusters(i, j)) > 0.0001) {
+                    b = false;
+                    break;
+                }
+            }
+
+            Array.copy(centralNewClusters, centralCurrentClusters);
+
+            if (b) break;
+
+            centralNewClusters.clear();
+            centralClusterCounts.clear();
+        }
+
+        for (d in 0..(DIM-1)) { 
+            for (k in 0..(CLUSTERS-1)) { 
+                if (k > 0)
+                    Console.OUT.print(" ");
+                Console.OUT.print(centralCurrentClusters(k,d));
+            }
+            Console.OUT.println();
+        }
+    }
+}
+
+// vim: shiftwidth=4:tabstop=4:expandtab
diff --git a/samples/X10/KMeansSPMD.x10 b/samples/X10/KMeansSPMD.x10
new file mode 100644
index 00000000..f6530f24
--- /dev/null
+++ b/samples/X10/KMeansSPMD.x10
@@ -0,0 +1,192 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.io.Console;
+import x10.io.File;
+import x10.io.Marshal;
+import x10.io.IOException;
+import x10.util.OptionsParser;
+import x10.util.Option;
+import x10.util.Team;
+
+/**
+ * An SPMD formulation of KMeans.
+ *
+ * For a highly optimized and scalable version of this benchmark see
+ * KMeans.x10 in the X10 Benchmarks (separate download from x10-lang.org)
+ */
+public class KMeansSPMD {
+
+    public static def printClusters (clusters:Rail[Float], dims:long) {
+        for (d in 0..(dims-1)) { 
+            for (k in 0..(clusters.size/dims-1)) { 
+                if (k>0)
+                    Console.OUT.print(" ");
+                Console.OUT.print(clusters(k*dims+d).toString());
+            }
+            Console.OUT.println();
+        }
+    }
+
+    public static def main (args:Rail[String]) {here == Place.FIRST_PLACE } {
+
+        val opts = new OptionsParser(args, [
+            Option("q","quiet","just print time taken"),
+            Option("v","verbose","print out each iteration"),
+            Option("h","help","this information")
+        ], [
+            Option("p","points","location of data file"),
+            Option("i","iterations","quit after this many iterations"),
+            Option("c","clusters","number of clusters to find"),
+            Option("d","dim","number of dimensions"),
+            Option("s","slices","factor by which to oversubscribe computational resources"),
+            Option("n","num","quantity of points")
+        ]);
+        if (opts.filteredArgs().size!=0L) {
+            Console.ERR.println("Unexpected arguments: "+opts.filteredArgs());
+            Console.ERR.println("Use -h or --help.");
+            System.setExitCode(1n);
+            return;
+        }
+        if (opts("-h")) {
+            Console.OUT.println(opts.usage(""));
+            return;
+        }
+
+        val fname = opts("-p", "points.dat");
+        val num_clusters=opts("-c",4);
+        val num_slices=opts("-s",1);
+        val num_global_points=opts("-n", 2000);
+        val iterations=opts("-i",50);
+        val dim=opts("-d", 4);
+        val verbose = opts("-v");
+        val quiet = opts("-q");
+
+        if (!quiet)
+            Console.OUT.println("points: "+num_global_points+" clusters: "+num_clusters+" dim: "+dim);
+
+        // file is dimension-major
+        val file = new File(fname);
+        val fr = file.openRead();
+        val init_points = (long) => Float.fromIntBits(Marshal.INT.read(fr).reverseBytes());
+        val num_file_points = (file.size() / dim / 4) as Int;
+        val file_points = new Rail[Float](num_file_points*dim, init_points);
+
+        val team = Team.WORLD;
+
+        val num_slice_points = num_global_points / num_slices / Place.numPlaces();
+
+        finish {
+            for (h in Place.places()) at(h) async {
+                var compute_time:Long = 0;
+                var comm_time:Long = 0;
+                var barrier_time:Long = 0;
+
+                val host_clusters  = new Rail[Float](num_clusters*dim, (i:long)=>file_points(i));
+                val host_cluster_counts = new Rail[Int](num_clusters);
+
+                for (slice in 0..(num_slices-1)) {
+                    // carve out local portion of points (point-major)
+                    val offset = (slice*Place.numPlaces() + here.id) * num_slice_points;
+                    if (verbose)
+                        Console.OUT.println(h.toString()+" gets "+offset+" len "+num_slice_points);
+                    val init = (i:long) => {
+                        val p=i%num_slice_points;
+                        val d=i/num_slice_points;
+                        return file_points(offset+p+d*num_file_points);
+                    };
+
+                    // these are pretty big so allocate up front
+                    val host_points = new Rail[Float](num_slice_points*dim, init);
+                    val host_nearest = new Rail[Float](num_slice_points);
+
+                    val start_time = System.currentTimeMillis();
+
+                    barrier_time -= System.nanoTime();
+                    team.barrier();
+                    barrier_time += System.nanoTime();
+
+                    main_loop: for (iter in 0..(iterations-1)) {
+
+                        //if (offset==0) Console.OUT.println("Iteration: "+iter);
+
+                        val old_clusters = new Rail[Float](host_clusters.size);
+                        Rail.copy(host_clusters, 0L, old_clusters, 0L, host_clusters.size);
+
+                        host_clusters.clear();
+                        host_cluster_counts.clear();
+
+                        compute_time -= System.nanoTime();
+                        for (p in 0..(num_slice_points-1)) {
+                            var closest:Long = -1;
+                            var closest_dist:Float = Float.MAX_VALUE;
+                            for (k in 0..(num_clusters-1)) { 
+                                var dist : Float = 0;
+                                for (d in 0..(dim-1)) { 
+                                    val tmp = host_points(p+d*num_slice_points) - old_clusters(k*dim+d);
+                                    dist += tmp * tmp;
+                                }
+                                if (dist < closest_dist) {
+                                    closest_dist = dist;
+                                    closest = k;
+                                }
+                            }
+                            for (d in 0..(dim-1)) { 
+                                host_clusters(closest*dim+d) += host_points(p+d*num_slice_points);
+                            }
+                            host_cluster_counts(closest)++;
+                        }
+                        compute_time += System.nanoTime();
+
+                        comm_time -= System.nanoTime();
+                        team.allreduce(host_clusters, 0L, host_clusters, 0L, host_clusters.size, Team.ADD);
+                        team.allreduce(host_cluster_counts, 0L, host_cluster_counts, 0L, host_cluster_counts.size, Team.ADD);
+                        comm_time += System.nanoTime();
+
+                        for (k in 0..(num_clusters-1)) {
+                            for (d in 0..(dim-1)) host_clusters(k*dim+d) /= host_cluster_counts(k);
+                        }
+
+                        if (offset==0 && verbose) {
+                            Console.OUT.println("Iteration: "+iter);
+                            printClusters(host_clusters,dim);
+                        }
+
+                        // TEST FOR CONVERGENCE
+                        for (j in 0..(num_clusters*dim-1)) {
+                            if (true/*||Math.abs(clusters_old(j)-host_clusters(j))>0.0001*/) continue main_loop;
+                        }
+
+                        break;
+
+                    } // main_loop
+
+                } // slice
+
+                Console.OUT.printf("%d: computation %.3f s communication %.3f s (barrier %.3f s)\n", 
+                    here.id, compute_time/1E9, comm_time/1E9, barrier_time/1E9);
+
+                team.barrier();
+
+                if (here.id == 0) {
+                    Console.OUT.println("\nFinal results:");
+                    printClusters(host_clusters,dim);
+                }
+
+            } // async
+
+        } // finish
+
+    }
+
+}
+
+// vim: shiftwidth=4:tabstop=4:expandtab
diff --git a/samples/X10/MontyPi.x10 b/samples/X10/MontyPi.x10
new file mode 100644
index 00000000..951161ee
--- /dev/null
+++ b/samples/X10/MontyPi.x10
@@ -0,0 +1,42 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.array.DistArray_Unique;
+import x10.io.Console;
+import x10.util.Random;
+
+/**
+ * Calculation of an approximation to pi by using a Monte Carlo simulation
+ * (throwing darts into the unit square and determining the fraction that land
+ * in the unit circle).
+ */
+public class MontyPi {
+    public static def main(args:Rail[String]) {
+        if (args.size != 1L) {
+            Console.OUT.println("Usage: MontyPi j
+         * on the next rank after the last fixed position.
+         */
+        def safe(j:Long) {
+            for (k in 0..(fixed-1)) {
+                if (j == q(k) || Math.abs(fixed-k) == Math.abs(j-q(k)))
+                    return false;
+            }
+            return true;
+        }
+
+        /** Search all positions for the current board. */
+        def search() {
+            for (k in R) searchOne(k);
+        }
+
+        /**
+         * Modify the current board by adding a new queen
+         * in file k on rank fixed,
+         * and search for all safe positions with this prefix.
+         */
+        def searchOne(k:Long) {
+            if (safe(k)) {
+                if (fixed==(N-1)) {
+                    // all ranks safely filled
+                    atomic NQueensDist.this.results(here.id)++;
+                } else {
+                    q(fixed++) = k;
+                    search();
+                    fixed--;
+                }
+            }
+        }
+
+        /**
+         * Search this board, dividing the work between all places
+         * using a block distribution of the current free rank.
+         */
+        def distSearch()  {
+            val work = R.split(Place.numPlaces());
+            finish for (p in Place.places()) {
+                val myPiece = work(p.id);
+                at (p) async {
+                    // implicit copy of 'this' made across the at divide
+                    for (k in myPiece) {
+                        searchOne(k);
+                    }
+                }
+            }
+        }
+    }
+
+    public static def main(args:Rail[String])  {
+        val n = args.size > 0 ? Long.parse(args(0)) : 8;
+        Console.OUT.println("N=" + n);
+        //warmup
+        //finish new NQueensPar(12, 1).start();
+        val P = Place.numPlaces();
+        val nq = new NQueensDist(n,P);
+        var start:Long = -System.nanoTime();
+        val answer = nq.run();
+        val result = answer==EXPECTED_SOLUTIONS(n);
+        start += System.nanoTime();
+        start /= 1000000;
+        Console.OUT.println("NQueensDist " + nq.N + "(P=" + P +
+                            ") has " + answer + " solutions" +
+                            (result? " (ok)." : " (wrong).") + 
+                            "time=" + start + "ms");
+    }
+}
diff --git a/samples/X10/NQueensPar.x10 b/samples/X10/NQueensPar.x10
new file mode 100644
index 00000000..bb841e13
--- /dev/null
+++ b/samples/X10/NQueensPar.x10
@@ -0,0 +1,117 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ *  (C) Copyright Australian National University 2011.
+ */
+
+/**
+ * Compute the number of solutions to the N queens problem.
+ */
+public class NQueensPar {
+    public static val EXPECTED_SOLUTIONS =
+        [0, 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, 73712, 365596, 2279184, 14772512];
+
+    val N:Int;
+    val P:Int;
+    var nSolutions:Int = 0n;
+    val R:IntRange;
+
+    def this(N:Int, P:Int) { 
+       this.N=N;
+       this.P=P;
+       this.R = 0n..(N-1n);
+    }
+
+    def start() {
+        new Board().parSearch();
+    }
+
+    class Board {
+        val q: Rail[Int];
+        /** The number of low-rank positions that are fixed in this board for the purposes of search. */
+        var fixed:Int;
+        def this() {
+            q = new Rail[Int](N);
+            fixed = 0n;
+        }
+
+        def this(b:Board) {
+            this.q = new Rail[Int](b.q);
+            this.fixed = b.fixed;
+        }
+
+        /** 
+         * @return true if it is safe to put a queen in file j
+         * on the next rank after the last fixed position.
+         */
+        def safe(j:Int) {
+            for (k in 0n..(fixed-1n)) {
+                if (j == q(k) || Math.abs(fixed-k) == Math.abs(j-q(k)))
+                    return false;
+            }
+            return true;
+        }
+
+        /** Search all positions for the current board. */
+        def search() {
+            for (k in R) searchOne(k);
+        }
+
+        /**
+         * Modify the current board by adding a new queen
+         * in file k on rank fixed,
+         * and search for all safe positions with this prefix.
+         */
+        def searchOne(k:Int) {
+            if (safe(k)) {
+                if (fixed==(N-1n)) {
+                    // all ranks safely filled
+                    atomic NQueensPar.this.nSolutions++;
+                } else {
+                    q(fixed++) = k;
+                    search();
+                    fixed--;
+                }
+            }
+        }
+
+        /**
+         * Search this board, dividing the work between threads
+         * using a block distribution of the current free rank.
+         */
+        def parSearch()  {
+            for (work in R.split(P)) async {
+                val board = new Board(this);
+                for (w in work) {
+                    board.searchOne(w);
+                }
+            }
+        }
+    }
+
+    public static def main(args:Rail[String])  {
+        val n = args.size > 0 ? Int.parse(args(0)) : 8n;
+        Console.OUT.println("N=" + n);
+        //warmup
+        //finish new NQueensPar(12, 1).start();
+        val ps = [1n,2n,4n];
+        for (numTasks in ps) {
+            Console.OUT.println("starting " + numTasks + " tasks");
+            val nq = new NQueensPar(n,numTasks);
+            var start:Long = -System.nanoTime();
+            finish nq.start();
+            val result = (nq.nSolutions as Long)==EXPECTED_SOLUTIONS(nq.N);
+            start += System.nanoTime();
+            start /= 1000000;
+            Console.OUT.println("NQueensPar " + nq.N + "(P=" + numTasks +
+                    ") has " + nq.nSolutions + " solutions" +
+                    (result? " (ok)." : " (wrong).") + "time=" + start + "ms");
+        }
+    }
+}
diff --git a/samples/X10/QSort.x10 b/samples/X10/QSort.x10
new file mode 100644
index 00000000..d96983b6
--- /dev/null
+++ b/samples/X10/QSort.x10
@@ -0,0 +1,73 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+
+/**
+ * Straightforward quicksort implementation using
+ * naive partition-in-the-middle and not bothering with
+ * well-known optimizations such as using insertion sort
+ * once the partitions get small.  This is only intended
+ * as a simple example of an array-based program that 
+ * combines a recirsive divide and conquer algorithm 
+ * with async and finish, not as a highly efficient 
+ * sorting procedure..
+ */
+public class QSort {
+
+  private static def partition(data:Rail[int], left:long, right:long) {
+      var i:long = left;
+      var j:long = right;
+      var tmp:int;
+      var pivot:long = data((left + right) / 2);
+
+      while (i <= j) {
+          while (data(i) < pivot) i++;
+          while (data(j) > pivot) j--;
+          if (i <= j) {
+              tmp = data(i);
+              data(i) = data(j);
+              data(j) = tmp;
+              i++;
+              j--;
+          }
+      }
+
+      return i;
+  }
+
+  public static def qsort(data:Rail[int], left:long, right:long) {
+      index:long = partition(data, left, right);
+      finish {
+          if (left < index - 1)
+              async qsort(data, left, index - 1);
+
+          if (index < right)
+              qsort(data, index, right);
+      }
+  }
+
+  public static def main(args:Rail[String]) {
+      val N = args.size>0 ? Long.parse(args(0)) : 100;
+      val r = new x10.util.Random();
+      val data = new Rail[int](N, (long)=>r.nextInt(9999n));
+      qsort(data, 0, N-1);
+      for (i in 0..(N-1)) {
+          Console.OUT.print(data(i)); 
+          if (i%10 == 9) {
+	      Console.OUT.println();
+          } else {
+              Console.OUT.print(", ");
+          }
+      }
+      Console.OUT.println();
+  }
+}
+
diff --git a/samples/X10/StructSpheres.x10 b/samples/X10/StructSpheres.x10
new file mode 100644
index 00000000..6d833633
--- /dev/null
+++ b/samples/X10/StructSpheres.x10
@@ -0,0 +1,123 @@
+/*
+ *  This file is part of the X10 project (http://x10-lang.org).
+ *
+ *  This file is licensed to You under the Eclipse Public License (EPL);
+ *  You may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *      http://www.opensource.org/licenses/eclipse-1.0.php
+ *
+ *  (C) Copyright IBM Corporation 2006-2014.
+ */
+
+import x10.io.Console;
+import x10.util.Random;
+
+/**
+ * This class represents a real-world problem in graphics engines --
+ * determining which objects in a large sprawling world are close enough to the
+ * camera to be considered for rendering.  
+ *
+ * It illustrates the usage of X10 structs to define new primitive types.
+ * In Native X10, structs are allocated within their containing object/stack frame
+ * and thus using structs instead of classes for Vector3 and WorldObject greatly
+ * improves the memory efficiency of the computation.
+ *
+ * @Author Dave Cunningham
+ * @Author Vijay Saraswat
+ */
+class StructSpheres {
+    static type Real = Float;
+
+    static struct Vector3(x:Real, y:Real, z:Real) {
+        public def getX () = x; 
+        public def getY () = y;
+        public def getZ () = z;
+
+        public def add (other:Vector3)
+            = Vector3(this.x+other.x, this.y+other.y, this.z+other.z);
+
+        public def neg () = Vector3(-this.x, -this.y, -this.z);
+
+        public def sub (other:Vector3) = add(other.neg());
+
+        public def length () = Math.sqrtf(length2());
+
+        public def length2 () = x*x + y*y + z*z;
+    }
+
+
+    static struct WorldObject {
+
+        def this (x:Real, y:Real, z:Real, r:Real) {
+            pos = Vector3(x,y,z);
+            renderingDistance = r;
+        }
+
+        public def intersects (home:Vector3)
+            = home.sub(pos).length2() < renderingDistance*renderingDistance;
+
+        protected val pos:Vector3;
+        protected val renderingDistance:Real;
+    }
+
+
+    public static def compute():boolean {
+
+        val reps = 7500;
+
+        // The following correspond to a modern out-door computer game:
+        val num_objects = 50000;
+        val world_size = 6000;
+        val obj_max_size = 400;
+
+        val ran = new Random(0);
+
+        // the array can go on the heap
+        // but the elements ought to be /*inlined*/ in the array
+        val spheres =
+            new Rail[WorldObject](num_objects, (i:long) => {
+                val x = (ran.nextDouble()*world_size) as Real;
+                val y = (ran.nextDouble()*world_size) as Real;
+                val z = (ran.nextDouble()*world_size) as Real;
+                val r = (ran.nextDouble()*obj_max_size) as Real;
+                return WorldObject(x,y,z,r);
+            });
+
+        val time_start = System.nanoTime();
+
+        var counter : Long = 0;
+
+        // HOT LOOP BEGINS
+        for (c in 1..reps) {
+
+            val x = (ran.nextDouble()*world_size) as Real;
+            val y = (ran.nextDouble()*world_size) as Real;
+            val z = (ran.nextDouble()*world_size) as Real;
+
+            val pos = Vector3(x,y,z);
+
+            for (i in spheres.range()) {
+                if (spheres(i).intersects(pos)) {
+                    counter++;
+                }
+            }
+        }
+        // HOT LOOP ENDS
+
+        val time_taken = System.nanoTime() - time_start;
+        Console.OUT.println("Total time: "+time_taken/1E9);
+
+        val expected = 109702;
+        val ok = counter == expected;
+        if (!ok) {
+            Console.ERR.println("number of intersections: "+counter
+                                +" (expected "+expected+")");
+        }
+        return ok;
+    }
+
+    public static def main (Rail[String]) {
+        compute();
+    }
+
+}
diff --git a/test/test_blob.rb b/test/test_blob.rb
index 0a1cefe9..ca9640c4 100644
--- a/test/test_blob.rb
+++ b/test/test_blob.rb
@@ -301,6 +301,7 @@ class TestBlob < Minitest::Test
 
     # Codemirror deps
     assert sample_blob("codemirror/mode/blah.js").vendored?
+    assert sample_blob("codemirror/5.0/mode/blah.js").vendored?
 
     # Debian packaging
     assert sample_blob("debian/cron.d").vendored?
@@ -361,6 +362,26 @@ class TestBlob < Minitest::Test
     assert sample_blob("ui/minified/jquery.effects.blind.min.js").vendored?
     assert sample_blob("ui/minified/jquery.ui.accordion.min.js").vendored?
 
+    # jQuery Gantt
+    assert sample_blob("web-app/jquery-gantt/js/jquery.fn.gantt.js").vendored?
+
+    # jQuery fancyBox
+    assert sample_blob("web-app/fancybox/jquery.fancybox.js").vendored?
+
+    # Fuel UX
+    assert sample_blob("web-app/fuelux/js/fuelux.js").vendored?
+
+    # jQuery File Upload
+    assert sample_blob("fileupload-9.0.0/jquery.fileupload-process.js").vendored?
+
+    # Slick
+    assert sample_blob("web-app/slickgrid/controls/slick.columnpicker.js").vendored?
+
+    # Leaflet plugins
+    assert sample_blob("leaflet-plugins/Leaflet.Coordinates-0.5.0.src.js").vendored?
+    assert sample_blob("leaflet-plugins/leaflet.draw-src.js").vendored?
+    assert sample_blob("leaflet-plugins/leaflet.spin.js").vendored?
+
     # MooTools
     assert sample_blob("public/javascripts/mootools-core-1.3.2-full-compat.js").vendored?
     assert sample_blob("public/javascripts/mootools-core-1.3.2-full-compat-yc.js").vendored?
diff --git a/test/test_grammars.rb b/test/test_grammars.rb
index 65a7e6de..569da5c9 100644
--- a/test/test_grammars.rb
+++ b/test/test_grammars.rb
@@ -83,17 +83,23 @@ class TestGrammars < Minitest::Test
   def test_submodules_have_recognized_licenses
     unrecognized = submodule_licenses.select { |k,v| v.nil? && Licensee::Project.new(k).license_file }
     unrecognized.reject! { |k,v| PROJECT_WHITELIST.include?(k) }
-    assert_equal Hash.new, unrecognized, "The following submodules have unrecognized licenses:\n* #{unrecognized.keys.join("\n* ")}"
+    message = "The following submodules have unrecognized licenses:\n* #{unrecognized.keys.join("\n* ")}\n"
+    message << "Please ensure that the project's LICENSE file contains the full text of the license."
+    assert_equal Hash.new, unrecognized, message
   end
 
   def test_submodules_have_licenses
     unlicensed = submodule_licenses.select { |k,v| v.nil? }.reject { |k,v| PROJECT_WHITELIST.include?(k) }
-    assert_equal Hash.new, unlicensed, "The following submodules don't have licenses:\n* #{unlicensed.keys.join("\n* ")}"
+    message = "The following submodules don't have licenses:\n* #{unlicensed.keys.join("\n* ")}\n"
+    message << "Please ensure that the project has a LICENSE file, and that the LICENSE file contains the full text of the license."
+    assert_equal Hash.new, unlicensed, message
   end
 
   def test_submodules_have_approved_licenses
     unapproved = submodule_licenses.reject { |k,v| LICENSE_WHITELIST.include?(v) || PROJECT_WHITELIST.include?(k) }.map { |k,v| "#{k}: #{v}"}
-    assert_equal [], unapproved, "The following submodules have unapproved licenses:\n* #{unapproved.join("\n* ")}"
+    message = "The following submodules have unapproved licenses:\n* #{unapproved.join("\n* ")}\n"
+    message << "The license must be added to the LICENSE_WHITELIST in /test/test_grammars.rb once approved."
+    assert_equal [], unapproved, message
   end
 
   def test_submodules_whitelist_has_no_extra_entries
diff --git a/vendor/grammars/X10 b/vendor/grammars/X10
new file mode 160000
index 00000000..2bae6e77
--- /dev/null
+++ b/vendor/grammars/X10
@@ -0,0 +1 @@
+Subproject commit 2bae6e77fabcdceff753823477390c37305ca76c