code: function cluster(points) {
      // number of clusters has to be smaller or equal the number of data points
      if (points.length < k) {
        throw 'Too many clusters';
      }
  
      // create the initial clusters
      var clusters = chooseInitialCenters(points);
  
      // create an array containing the latest assignment of a point to a cluster
      // no need to initialize the array, as it will be filled with the first assignment
      var assignments = new Int32Array(points.length);
      assignPointsToClusters(clusters, points, assignments);
      // iterate through updating the centers until we're done
      var max = (maxIterations < 0) ? Number.MAX_VALUE : maxIterations;
      for (var count = 0; count < max; count++) {
        var emptyCluster = false;
        var newClusters = [];
        for (var clusterIndex = 0; clusterIndex < clusters.length; clusterIndex++) {
          var cluster = clusters[clusterIndex];
          var newCenter;
          if (cluster.getPoints().length === 0) {
            newCenter = getPointFromLargestVarianceCluster(clusters);
            emptyCluster = true;
          } else {
            newCenter = centroidOf(cluster.getPoints(), cluster.getCenter().getPoint().size());
          }
          newClusters.push(new CentroidCluster(newCenter));
        }
        var changes = assignPointsToClusters(newClusters, points, assignments);
        clusters = newClusters;
  
        // if there were no more changes in the point-to-cluster assignment
        // and there are no empty clusters left, return the current clusters
        if (changes === 0 && !emptyCluster) {
          return clusters;
        }
      }
      return clusters;
    }
docs: Runs the K-means++ clustering algorithm.
  
  @param points the points to cluster
  @return a list of clusters containing the points