/*
//////////////////////////////////////////////////////////
Stax2, Factory methods
//////////////////////////////////////////////////////////
10639
@Override
    public XMLValidationSchema createSchema(InputStream in, String encoding,
                                           String publicId, String systemId)
        throws XMLStreamException
    {
        InputSource src = new InputSource(in);
        src.setEncoding(encoding);
        src.setPublicId(publicId);
        src.setSystemId(systemId);
        return loadSchema(src, systemId);
    }
847337
public void generateXls(OutputStream out, List<Map<String, Object>> rows, List<ColumnDef> columns) {
        try {
            Workbook wb = new HSSFWorkbook();  // or new XSSFWorkbook();
            String safeName = WorkbookUtil.createSafeSheetName("Report"); // returns " O'Brien's sales   "
            Sheet reportSheet = wb.createSheet(safeName);

            short rowc = 0;
            Row nrow = reportSheet.createRow(rowc++);
            short cellc = 0;
            if (rows == null) return;
            if (columns == null && rows.size() > 0)
            {
                columns = new ArrayList<ColumnDef>(CollectionUtils.collect(rows.get(0).keySet(), new Transformer() {
                    @Override
                    public Object transform(final Object input) {
                        return new ColumnDef()
                        {{
                                setName((String)input);
                            }};
                    }
                }));
            }
            if (columns != null)
            {
                for (ColumnDef column : columns)
                {
                    Cell cell = nrow.createCell(cellc++);
                    cell.setCellValue(column.getName());
                }
            }
            for (Map<String, Object> row : rows)
            {
                nrow = reportSheet.createRow(rowc++);
                cellc = 0;
                for (ColumnDef column : columns)
                {
                    Cell cell = nrow.createCell(cellc++);
                    cell.setCellValue(String.valueOf(row.get(column.getName())));
                }
            }
            wb.write(out);
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

    }
333125
@SuppressWarnings("squid:S1166") //For the UnsupportedOperationException
    private Script build(CharStream cs) throws ScriptBuilderException {

        Script v = new Script();

        ANTLRBtrplaceSL2Lexer lexer = new ANTLRBtrplaceSL2Lexer(cs);

        ErrorReporter errorReporter = errBuilder.build(v);

        lexer.setErrorReporter(errorReporter);
        CommonTokenStream tokens = new CommonTokenStream(lexer);

        ANTLRBtrplaceSL2Parser parser = new ANTLRBtrplaceSL2Parser(tokens);
        parser.setErrorReporter(errorReporter);

        SymbolsTable t = new SymbolsTable();

        parser.setTreeAdaptor(new BtrPlaceTreeAdaptor(v, model, namingServiceNodes, namingServiceVMs, tpls, errorReporter, t, includes, catalog));

        try {
            BtrPlaceTree tree = (BtrPlaceTree) parser.script_decl().getTree();
            if (tree != null) {
                if (tree.token != null) {
                        tree.go(tree); //Single instruction
                } else {
                    for (int i = 0; i < tree.getChildCount(); i++) {
                            tree.getChild(i).go(tree);
                        }
                    }
            }
        } catch (RecognitionException e) {
            throw new ScriptBuilderException(e.getMessage(), e);
        } catch (UnsupportedOperationException e) {
            //We only keep the error message
            errorReporter.append(0, 0, e.getMessage());
        }
        if (!errorReporter.getErrors().isEmpty()) {
            throw new ScriptBuilderException(errorReporter);
        }
        return v;
    }
165055
@Override
  public final void make(final Map<String, Object> pReqVars) throws Exception {
    @SuppressWarnings("unchecked")
    AFactoryAppBeans<RS> factoryAppBeans =
      (AFactoryAppBeans<RS>) this.factoryAndServlet.getFactoryAppBeans();
    this.factoryAndServlet.getHttpServlet().getServletContext()
      .setAttribute("srvI18n", factoryAppBeans.lazyGet("ISrvI18n"));
    this.factoryAndServlet.getHttpServlet().getServletContext()
      .setAttribute("sessionTracker",
        factoryAppBeans.lazyGet("ISessionTracker"));
  }
875642
private void generateConstructor(
      ImmutableMap<TemplateParam, SoyExpression> defaultParamInitializers) {
    final Label start = new Label();
    final Label end = new Label();
    final LocalVariable thisVar = createThisVar(template.typeInfo(), start, end);
    final LocalVariable paramsVar = createLocal("params", 1, SOY_RECORD_TYPE, start, end);
    final LocalVariable ijVar = createLocal("ij", 2, SOY_RECORD_TYPE, start, end);
    final List<Statement> assignments = new ArrayList<>();
    assignments.add(paramsField.putInstanceField(thisVar, paramsVar));
    assignments.add(ijField.putInstanceField(thisVar, ijVar));
    for (TemplateParam param : templateNode.getAllParams()) {
      Expression paramProvider =
          getParam(paramsVar, ijVar, param, defaultParamInitializers.get(param));
      assignments.add(paramFields.get(param.name()).putInstanceField(thisVar, paramProvider));
    }
    Statement constructorBody =
        new Statement() {
          @Override
          protected void doGen(CodeBuilder ga) {
            ga.mark(start);
            // call super()
            thisVar.gen(ga);
            ga.invokeConstructor(OBJECT.type(), NULLARY_INIT);
            for (Statement assignment : assignments) {
              assignment.gen(ga);
            }
            ga.visitInsn(Opcodes.RETURN);
            ga.visitLabel(end);
            thisVar.tableEntry(ga);
            paramsVar.tableEntry(ga);
            ijVar.tableEntry(ga);
          }
        };
    constructorBody.writeMethod(Opcodes.ACC_PUBLIC, template.constructor().method(), writer);
  }
1006337
@Override
  public final synchronized void makeWith(final Map<String, Object> pReqVars,
    final FactoryAndServlet pFactoryAndServlet) throws Exception {
    @SuppressWarnings("unchecked")
    AFactoryAppBeans<RS> factoryAppBeans =
      (AFactoryAppBeans<RS>) pFactoryAndServlet.getFactoryAppBeans();
    File webAppPath = new File(pFactoryAndServlet.getHttpServlet().
      getServletContext().getRealPath(""));
    factoryAppBeans.setWebAppPath(webAppPath.getPath());
    String isShowDebugMessagesStr = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("isShowDebugMessages");
    factoryAppBeans.setIsShowDebugMessages(Boolean
      .valueOf(isShowDebugMessagesStr));
    String detailLevelStr = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("detailLevel");
    factoryAppBeans.setDetailLevel(Integer.parseInt(detailLevelStr));
    String newDatabaseIdStr = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("newDatabaseId");
    factoryAppBeans.setNewDatabaseId(Integer.parseInt(newDatabaseIdStr));
    String ormSettingsDir = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("ormSettingsDir");
    factoryAppBeans.setOrmSettingsDir(ormSettingsDir);
    String ormSettingsBaseFile = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("ormSettingsBaseFile");
    factoryAppBeans.setOrmSettingsBaseFile(ormSettingsBaseFile);
    String uvdSettingsDir = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("uvdSettingsDir");
    factoryAppBeans.setUvdSettingsDir(uvdSettingsDir);
    String uvdSettingsBaseFile = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("uvdSettingsBaseFile");
    factoryAppBeans.setUvdSettingsBaseFile(uvdSettingsBaseFile);
    String writeTi = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("writeTi");
    factoryAppBeans.setWriteTi(Integer.parseInt(writeTi));
    String readTi = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("readTi");
    factoryAppBeans.setReadTi(Integer.parseInt(readTi));
    String writeReTi = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("writeReTi");
    factoryAppBeans.setWriteReTi(Integer.parseInt(writeReTi));
    String wrReSpTr = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("wrReSpTr");
    factoryAppBeans.setWrReSpTr(Boolean.valueOf(wrReSpTr));
    String fastLoc = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("fastLoc");
    factoryAppBeans.setFastLoc(Boolean.parseBoolean(fastLoc));
    String jdbcUrl = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("databaseName");
    if (jdbcUrl != null && jdbcUrl.contains(ASrvOrm.WORD_CURRENT_DIR)) {
      jdbcUrl = jdbcUrl.replace(ASrvOrm.WORD_CURRENT_DIR,
        factoryAppBeans.getWebAppPath() + File.separator);
    } else if (jdbcUrl != null
      && jdbcUrl.contains(ASrvOrm.WORD_CURRENT_PARENT_DIR)) {
      File fcd = new File(factoryAppBeans.getWebAppPath());
      jdbcUrl = jdbcUrl.replace(ASrvOrm.WORD_CURRENT_PARENT_DIR,
        fcd.getParent() + File.separator);
    }
    String langCountriesStr = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("langCountries");
    List<String> lngCntLst = new ArrayList<String>();
    for (String str : langCountriesStr.split(",")) {
      lngCntLst.add(str);
    }
    String[] lngCntArr = new String[lngCntLst.size()];
    factoryAppBeans.lazyGetSrvI18n().add(lngCntLst.toArray(lngCntArr));
    LstnDbChanged<RS> lstnDbChanged = new LstnDbChanged<RS>();
    lstnDbChanged.setFactoryAndServlet(pFactoryAndServlet);
    factoryAppBeans.getListenersDbChanged().add(lstnDbChanged);
    factoryAppBeans.setDatabaseName(jdbcUrl);
    String databaseUser = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("databaseUser");
    factoryAppBeans.setDatabaseUser(databaseUser);
    String databasePassword = pFactoryAndServlet.getHttpServlet()
      .getInitParameter("databasePassword");
    factoryAppBeans.setDatabasePassword(databasePassword);
    pFactoryAndServlet.getHttpServlet().getServletContext()
      .setAttribute("srvI18n", factoryAppBeans.lazyGet("ISrvI18n"));
    pFactoryAndServlet.getHttpServlet().getServletContext()
      .setAttribute("sessionTracker",
        factoryAppBeans.lazyGet("ISessionTracker"));
    //to create/initialize database if need:
    factoryAppBeans.lazyGet("ISrvOrm");
  }
378194
@SuppressWarnings("unchecked")
	private <IN1, IN2, OUT> TypeInformation<OUT> createTypeInfoFromFactory(
			Type t, ArrayList<Type> typeHierarchy, TypeInformation<IN1> in1Type, TypeInformation<IN2> in2Type) {

		final ArrayList<Type> factoryHierarchy = new ArrayList<>(typeHierarchy);
		final TypeInfoFactory<? super OUT> factory = getClosestFactory(factoryHierarchy, t);
		if (factory == null) {
			return null;
		}
		final Type factoryDefiningType = factoryHierarchy.get(factoryHierarchy.size() - 1);

		// infer possible type parameters from input
		final Map<String, TypeInformation<?>> genericParams;
		if (factoryDefiningType instanceof ParameterizedType) {
			genericParams = new HashMap<>();
			final ParameterizedType paramDefiningType = (ParameterizedType) factoryDefiningType;
			final Type[] args = typeToClass(paramDefiningType).getTypeParameters();

			final TypeInformation<?>[] subtypeInfo = createSubTypesInfo(t, paramDefiningType, factoryHierarchy, in1Type, in2Type, true);
			assert subtypeInfo != null;
			for (int i = 0; i < subtypeInfo.length; i++) {
				genericParams.put(args[i].toString(), subtypeInfo[i]);
			}
		} else {
			genericParams = Collections.emptyMap();
		}

		final TypeInformation<OUT> createdTypeInfo = (TypeInformation<OUT>) factory.createTypeInfo(t, genericParams);
		if (createdTypeInfo == null) {
			throw new InvalidTypesException("TypeInfoFactory returned invalid TypeInformation 'null'");
		}
		return createdTypeInfo;
	}
1146935
@SuppressWarnings("resource")
    private XMLStreamWriter2 createSW(OutputStream out, Writer w, String enc,
                                      boolean requireAutoClose)
        throws XMLStreamException
    {
        /* Need to ensure that the configuration object is not shared
         * any more; otherwise later changes via factory could be
         * visible half-way through output...
         */
        WriterConfig cfg = mConfig.createNonShared();
        XmlWriter xw;

        boolean autoCloseOutput = requireAutoClose || mConfig.willAutoCloseOutput();

        if (w == null) {
            if (enc == null) {
                enc = WstxOutputProperties.DEFAULT_OUTPUT_ENCODING;
            } else {
                /* Canonical ones are interned, so we may have
                 * normalized encoding already...
                 */
                if (enc != CharsetNames.CS_UTF8
                    && enc != CharsetNames.CS_ISO_LATIN1
                    && enc != CharsetNames.CS_US_ASCII) {
                    enc = CharsetNames.normalize(enc);
                }
            }

            try {
                if (enc == CharsetNames.CS_UTF8) {
                    w = new UTF8Writer(cfg, out, autoCloseOutput);
                    xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, out, 16);
                } else if (enc == CharsetNames.CS_ISO_LATIN1) {
                    xw = new ISOLatin1XmlWriter(out, cfg, autoCloseOutput);
                } else if (enc == CharsetNames.CS_US_ASCII) {
                    xw = new AsciiXmlWriter(out, cfg, autoCloseOutput);
                } else {
                    w = new OutputStreamWriter(out, enc);
                    xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, out, -1);
                }
            } catch (IOException ex) {
                throw new XMLStreamException(ex);
            }
        } else {
            // we may still be able to figure out the encoding:
            if (enc == null) {
                enc = CharsetNames.findEncodingFor(w);
            }
            try {
                xw = new BufferingXmlWriter(w, cfg, enc, autoCloseOutput, null, -1);
            } catch (IOException ex) {
                throw new XMLStreamException(ex);
            }
        }

        return createSW(enc, cfg, xw);
    }
542293
@PostConstruct
	protected void postConstruct() throws GeomajasException {
		if (null != crsDefinitions) {
			for (CrsInfo crsInfo : crsDefinitions.values()) {
				try {
					CoordinateReferenceSystem crs = CRS.parseWKT(crsInfo.getCrsWkt());
					String code = crsInfo.getKey();
					crsCache.put(code, CrsFactory.getCrs(code, crs));
				} catch (FactoryException e) {
					throw new GeomajasException(e, ExceptionCode.CRS_DECODE_FAILURE_FOR_MAP, crsInfo.getKey());
				}
			}
		}
		if (null != crsTransformDefinitions) {
			for (CrsTransformInfo crsTransformInfo : crsTransformDefinitions.values()) {
				String key = getTransformKey(crsTransformInfo);
				transformCache.put(key, getCrsTransform(key, crsTransformInfo));
			}
		}
		GeometryFactory factory = new GeometryFactory();
		EMPTY_GEOMETRIES.put(Point.class, factory.createPoint((Coordinate) null));
		EMPTY_GEOMETRIES.put(LineString.class, factory.createLineString((Coordinate[]) null));
		EMPTY_GEOMETRIES.put(Polygon.class, factory.createPolygon(null, null));
		EMPTY_GEOMETRIES.put(MultiPoint.class, factory.createMultiPoint((Coordinate[]) null));
		EMPTY_GEOMETRIES.put(MultiLineString.class, factory.createMultiLineString((LineString[]) null)); // cast needed!
		EMPTY_GEOMETRIES.put(MultiPolygon.class, factory.createMultiPolygon((Polygon[]) null)); // cast needed!
		EMPTY_GEOMETRIES.put(Geometry.class, factory.createGeometryCollection(null));
	}
636604
private synchronized static XPathFactory createXPathFactory() {
        XPathFactory factory = null;

        // read system property and see if there is a factory set
        Properties properties = System.getProperties();
        for (Map.Entry<Object, Object> prop : properties.entrySet()) {
            String key = (String) prop.getKey();
            if (key.startsWith(XPathFactory.DEFAULT_PROPERTY_NAME)) {
                String uri = key.indexOf(":") > 0 ? key.substring(key.indexOf(":") + 1) : null;
                if (uri != null) {
                    try {
                        factory = XPathFactory.newInstance(uri);
                    } catch (XPathFactoryConfigurationException e) {
                        log.warn("Failed to instantiate xpath factory", e);
                        factory = XPathFactory.newInstance();
                    }
                    log.info("Created xpath factory {} using system property {} with value {}", factory, key, uri);
                }
            }
        }

        if (factory == null) {
            factory = XPathFactory.newInstance();
            log.info("Created default xpath factory {}", factory);
        }

        return factory;
    }
931978
function createPlatformFactory(parentPlatformFactory, name, providers) {
    if (providers === void 0) { providers = []; }
    var desc = "Platform: " + name;
    var marker = new InjectionToken(desc);
    return function (extraProviders) {
        if (extraProviders === void 0) { extraProviders = []; }
        var platform = getPlatform();
        if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
            if (parentPlatformFactory) {
                parentPlatformFactory(providers.concat(extraProviders).concat({ provide: marker, useValue: true }));
            }
            else {
                var injectedProviders = providers.concat(extraProviders).concat({ provide: marker, useValue: true });
                createPlatform(Injector.create({ providers: injectedProviders, name: desc }));
            }
        }
        return assertPlatform(marker);
    };
}
178156
public static synchronized void initializeDXF_SCHEMA( CoordinateReferenceSystem crs ) {
        if (DXF_POINTSCHEMA != null && DXF_POINTSCHEMA.getAttributeCount() != 0)
            return;

        SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
        b.setName("dxfpointfile");
        b.setCRS(crs);
        b.add("the_geom", Point.class);
        b.add("LAYER", String.class);
        b.add("LTYPE", String.class);
        b.add("ELEVATION", Double.class);
        b.add("THICKNESS", Double.class);
        b.add("COLOR", Integer.class);
        b.add("TEXT", String.class);
        b.add("TEXT_HEIGHT", Double.class);
        b.add("TEXT_STYLE", String.class);
        DXF_POINTSCHEMA = b.buildFeatureType();

        b = new SimpleFeatureTypeBuilder();
        b.setName("dxflinefile");
        b.setCRS(crs);
        b.add("the_geom", LineString.class);
        b.add("LAYER", String.class);
        b.add("LTYPE", String.class);
        b.add("ELEVATION", Double.class);
        b.add("THICKNESS", Double.class);
        b.add("COLOR", Integer.class);
        b.add("TEXT", String.class);
        b.add("TEXT_HEIGHT", Double.class);
        b.add("TEXT_STYLE", String.class);
        DXF_LINESCHEMA = b.buildFeatureType();

        b = new SimpleFeatureTypeBuilder();
        b.setName("dxfpolygonfile");
        b.setCRS(crs);
        b.add("the_geom", Polygon.class);
        b.add("LAYER", String.class);
        b.add("LTYPE", String.class);
        b.add("ELEVATION", Double.class);
        b.add("THICKNESS", Double.class);
        b.add("COLOR", Integer.class);
        b.add("TEXT", String.class);
        b.add("TEXT_HEIGHT", Double.class);
        b.add("TEXT_STYLE", String.class);
        DXF_POLYGONSCHEMA = b.buildFeatureType();

    }
827293
@SuppressWarnings("unchecked")
	public T create(Object[] args)
	{
		for(int i=0, n=args.length; i<n; i++)
		{
			if(arguments[i] instanceof FactoryDefinition.InjectedArgument)
			{
				args[i] = arguments[i].getValue(null);
			}
		}

		try
		{
			return (T) raw.newInstance(args);
		}
		catch(IllegalArgumentException e)
		{
			throw new SerializationException("Unable to create; " + e.getMessage(), e);
		}
		catch(InstantiationException e)
		{
			throw new SerializationException("Unable to create; " + e.getMessage(), e);
		}
		catch(IllegalAccessException e)
		{
			throw new SerializationException("Unable to create; " + e.getMessage(), e);
		}
		catch(InvocationTargetException e)
		{
			throw new SerializationException("Unable to create; " + e.getCause().getMessage(), e.getCause());
		}
	}
1248444
static void constructR( DMatrixRMaj R, DMatrixRMaj R_v , DMatrix2x2 R22 ,
							double b1 , double b2 , Vector3D_F64 ca ,
							double sign , DMatrixRMaj tmp )
	{
		tmp.data[0]= R22.a11;
		tmp.data[1]= R22.a12;
		tmp.data[2]= sign*ca.x;

		tmp.data[3]= R22.a21;
		tmp.data[4]= R22.a22;
		tmp.data[5]= sign*ca.y;

		tmp.data[6]= sign*b1;
		tmp.data[7]= sign*b2;
		tmp.data[8]= ca.z;

		CommonOps_DDRM.mult(R_v,tmp,R);
	}
56504
static final CompactSketch createCompactSketch(final long[] compactCache, boolean empty,
      final short seedHash, final int curCount, long thetaLong, final boolean dstOrdered,
      final WritableMemory dstMem) {
    thetaLong = thetaOnCompact(empty, curCount, thetaLong);
    empty = emptyOnCompact(curCount, thetaLong);

    CompactSketch sketchOut = null;
    final int sw = (dstOrdered ? 2 : 0) | ((dstMem != null) ? 1 : 0);
    switch (sw) {
      case 0: { //dst not ordered, dstMem == null
        sketchOut = HeapCompactUnorderedSketch.compact(compactCache, empty, seedHash, curCount,
            thetaLong); //converts to SingleItem if curCount == 1
        break;
      }
      case 1: { //dst not ordered, dstMem == valid
        sketchOut = DirectCompactUnorderedSketch.compact(compactCache, empty, seedHash, curCount,
            thetaLong, dstMem); //converts to SingleItem format if curCount == 1
        break;
      }
      case 2: { //dst ordered, dstMem == null
        sketchOut = HeapCompactOrderedSketch.compact(compactCache, empty, seedHash, curCount,
            thetaLong); //converts to SingleItem format if curCount == 1
        break;
      }
      case 3: { //dst ordered, dstMem == valid
        sketchOut = DirectCompactOrderedSketch.compact(compactCache, empty, seedHash, curCount,
            thetaLong, dstMem); //converts to SingleItem format if curCount == 1
        break;
      }
      //default: //This cannot happen and cannot be tested
    }
    return sketchOut;
  }
1242282
Expression XreadExplicitRowValueConstructorOrNull() {

        Expression e;

        switch (token.tokenType) {

            case Tokens.OPENBRACKET : {
                read();

                int position = getPosition();
                int brackets = readOpenBrackets();

                switch (token.tokenType) {

                    case Tokens.TABLE :
                    case Tokens.VALUES :
                    case Tokens.SELECT :
                        rewind(position);

                        SubQuery sq = XreadSubqueryBody(false,
                                                        OpTypes.ROW_SUBQUERY);

                        readThis(Tokens.CLOSEBRACKET);

                        return new Expression(OpTypes.ROW_SUBQUERY, sq);

                    default :
                        rewind(position);

                        e = XreadRowElementList(true);

                        readThis(Tokens.CLOSEBRACKET);

                        return e;
                }
            }
            case Tokens.ROW : {
                read();
                readThis(Tokens.OPENBRACKET);

                e = XreadRowElementList(false);

                readThis(Tokens.CLOSEBRACKET);

                return e;
            }
        }

        return null;
    }
510073
function forceAtlas2Worker() {
    var vec2 = {
        create: function() {
            return new Float32Array(2);
        },
        dist: function(a, b) {
            var x = b[0] - a[0];
            var y = b[1] - a[1];
            return Math.sqrt(x*x + y*y);
        },
        len: function(a) {
            var x = a[0];
            var y = a[1];
            return Math.sqrt(x*x + y*y);
        },
        scaleAndAdd: function(out, a, b, scale) {
            out[0] = a[0] + b[0] * scale;
            out[1] = a[1] + b[1] * scale;
            return out;
        },
        scale: function(out, a, b) {
            out[0] = a[0] * b;
            out[1] = a[1] * b;
            return out;
        },
        add: function(out, a, b) {
            out[0] = a[0] + b[0];
            out[1] = a[1] + b[1];
            return out;
        },
        sub: function(out, a, b) {
            out[0] = a[0] - b[0];
            out[1] = a[1] - b[1];
            return out;
        },
        normalize: function(out, a) {
            var x = a[0];
            var y = a[1];
            var len = x*x + y*y;
            if (len > 0) {
                //TODO: evaluate use of glm_invsqrt here?
                len = 1 / Math.sqrt(len);
                out[0] = a[0] * len;
                out[1] = a[1] * len;
            }
            return out;
        },
        negate: function(out, a) {
            out[0] = -a[0];
            out[1] = -a[1];
            return out;
        },
        copy: function(out, a) {
            out[0] = a[0];
            out[1] = a[1];
            return out;
        },
        set: function(out, x, y) {
            out[0] = x;
            out[1] = y;
            return out;
        }
    }

    /****************************
     * Class: Region
     ***************************/

    function Region() {

        this.subRegions = [];

        this.nSubRegions = 0;

        this.node = null;

        this.mass = 0;

        this.centerOfMass = null;

        this.bbox = new Float32Array(4);

        this.size = 0;
    }

    var regionProto = Region.prototype;

    // Reset before update
    regionProto.beforeUpdate = function() {
        for (var i = 0; i < this.nSubRegions; i++) {
            this.subRegions[i].beforeUpdate();
        }
        this.mass = 0;
        if (this.centerOfMass) {
            this.centerOfMass[0] = 0;
            this.centerOfMass[1] = 0;
        }
        this.nSubRegions = 0;
        this.node = null;
    };
    // Clear after update
    regionProto.afterUpdate = function() {
        this.subRegions.length = this.nSubRegions;
        for (var i = 0; i < this.nSubRegions; i++) {
            this.subRegions[i].afterUpdate();
        }
    };

    regionProto.addNode = function(node) {
        if (this.nSubRegions === 0) {
            if (this.node == null) {
                this.node = node;
                return;
            }
            // Already have node, subdivide self.
            else {
                this._addNodeToSubRegion(this.node);
                this.node = null;
            }
        }
        this._addNodeToSubRegion(node);

        this._updateCenterOfMass(node);
    };

    regionProto.findSubRegion = function(x, y) {
        for (var i = 0; i < this.nSubRegions; i++) {
            var region = this.subRegions[i];
            if (region.contain(x, y)) {
                return region;
            }
        }
    };

    regionProto.contain = function(x, y) {
        return this.bbox[0] <= x
            && this.bbox[2] >= x
            && this.bbox[1] <= y
            && this.bbox[3] >= y;
    };

    regionProto.setBBox = function(minX, minY, maxX, maxY) {
        // Min
        this.bbox[0] = minX;
        this.bbox[1] = minY;
        // Max
        this.bbox[2] = maxX;
        this.bbox[3] = maxY;

        this.size = (maxX - minX + maxY - minY) / 2;
    };

    regionProto._newSubRegion = function() {
        var subRegion = this.subRegions[this.nSubRegions];
        if (!subRegion) {
            subRegion = new Region();
            this.subRegions[this.nSubRegions] = subRegion;
        }
        this.nSubRegions++;
        return subRegion;
    };

    regionProto._addNodeToSubRegion = function(node) {
        var subRegion = this.findSubRegion(node.position[0], node.position[1]);
        var bbox = this.bbox;
        if (!subRegion) {
            var cx = (bbox[0] + bbox[2]) / 2;
            var cy = (bbox[1] + bbox[3]) / 2;
            var w = (bbox[2] - bbox[0]) / 2;
            var h = (bbox[3] - bbox[1]) / 2;

            var xi = node.position[0] >= cx ? 1 : 0;
            var yi = node.position[1] >= cy ? 1 : 0;

            var subRegion = this._newSubRegion();
            // Min
            subRegion.setBBox(
                // Min
                xi * w + bbox[0],
                yi * h + bbox[1],
                // Max
                (xi + 1) * w + bbox[0],
                (yi + 1) * h + bbox[1]
            );
        }

        subRegion.addNode(node);
    };

    regionProto._updateCenterOfMass = function(node) {
        // Incrementally update
        if (this.centerOfMass == null) {
            this.centerOfMass = new Float32Array(2);
        }
        var x = this.centerOfMass[0] * this.mass;
        var y = this.centerOfMass[1] * this.mass;
        x += node.position[0] * node.mass;
        y += node.position[1] * node.mass;
        this.mass += node.mass;
        this.centerOfMass[0] = x / this.mass;
        this.centerOfMass[1] = y / this.mass;
    };

    /****************************
     * Class: Graph Node
     ***************************/
    function GraphNode() {
        this.position = new Float32Array(2);

        this.force = vec2.create();
        this.forcePrev = vec2.create();

        // If repulsionByDegree is true
        //  mass = inDegree + outDegree + 1
        // Else
        //  mass is manually set
        this.mass = 1;

        this.inDegree = 0;
        this.outDegree = 0;

        // Optional
        // this.size = 1;
    }

    /****************************
     * Class: Graph Edge
     ***************************/
    function GraphEdge(source, target) {
        this.source = source;
        this.target = target;

        this.weight = 1;
    }

    /****************************
     * Class: ForceStlas2
     ***************************/
    function ForceAtlas2() {
        //-------------
        // Configs

        // If auto settings is true
        //  barnesHutOptimize,
        //  barnesHutTheta,
        //  scaling,
        //  jitterTolerence
        // Will be set by the system automatically
        //  preventOverlap will be set false
        //  if node size is not given
        this.autoSettings = true;

        // Barnes Hut
        // http://arborjs.org/docs/barnes-hut
        this.barnesHutOptimize = true;
        this.barnesHutTheta = 1.5;

        // Force Atlas2 Configs
        this.repulsionByDegree = true;

        this.linLogMode = false;

        this.strongGravityMode = false;
        this.gravity = 1.0;

        this.scaling = 1.0;

        this.edgeWeightInfluence = 1.0;
        this.jitterTolerence = 0.1;

        // TODO
        this.preventOverlap = false;
        this.dissuadeHubs = false;

        //
        this.rootRegion = new Region();
        this.rootRegion.centerOfMass = vec2.create();

        this.nodes = [];

        this.edges = [];

        this.bbox = new Float32Array(4);

        this.gravityCenter = null;

        this._massArr = null;

        this._swingingArr = null;

        this._sizeArr = null;

        this._globalSpeed = 0;
    }

    var forceAtlas2Proto = ForceAtlas2.prototype;

    forceAtlas2Proto.initNodes = function(positionArr, massArr, sizeArr) {
        var nNodes = massArr.length;
        this.nodes.length = 0;
        var haveSize = typeof(sizeArr) != 'undefined';
        for (var i = 0; i < nNodes; i++) {
            var node = new GraphNode();
            node.position[0] = positionArr[i * 2];
            node.position[1] = positionArr[i * 2 + 1];
            node.mass = massArr[i];
            if (haveSize) {
                node.size = sizeArr[i];
            }
            this.nodes.push(node);
        }

        this._massArr = massArr;
        this._swingingArr = new Float32Array(nNodes);

        if (haveSize) {
            this._sizeArr = sizeArr;
        }
    };

    forceAtlas2Proto.initEdges = function(edgeArr, edgeWeightArr) {
        var nEdges = edgeArr.length / 2;
        this.edges.length = 0;
        for (var i = 0; i < nEdges; i++) {
            var sIdx = edgeArr[i * 2];
            var tIdx = edgeArr[i * 2 + 1];
            var sNode = this.nodes[sIdx];
            var tNode = this.nodes[tIdx];

            if (!sNode || !tNode) {
                console.error('Node not exists, try initNodes before initEdges');
                return;
            }
            sNode.outDegree++;
            tNode.inDegree++;
            var edge = new GraphEdge(sNode, tNode);

            if (edgeWeightArr) {
                edge.weight = edgeWeightArr[i];
            }

            this.edges.push(edge);
        }
    }

    forceAtlas2Proto.updateSettings = function() {
        if (this.repulsionByDegree) {
            for (var i = 0; i < this.nodes.length; i++) {
                var node = this.nodes[i];
                node.mass = node.inDegree + node.outDegree + 1;
            }
        }
        else {
            for (var i = 0; i < this.nodes.length; i++) {
                var node = this.nodes[i];
                node.mass = this._massArr[i];
            }
        }
    };

    forceAtlas2Proto.update = function() {
        var nNodes = this.nodes.length;

        this.updateSettings();

        this.updateBBox();

        // Update region
        if (this.barnesHutOptimize) {
            this.rootRegion.setBBox(
                this.bbox[0], this.bbox[1],
                this.bbox[2], this.bbox[3]
            );

            this.rootRegion.beforeUpdate();
            for (var i = 0; i < nNodes; i++) {
                this.rootRegion.addNode(this.nodes[i]);
            }
            this.rootRegion.afterUpdate();
        }

        // Reset forces
        for (var i = 0; i < nNodes; i++) {
            var node = this.nodes[i];
            vec2.copy(node.forcePrev, node.force);
            vec2.set(node.force, 0, 0);
        }

        // Compute forces
        // Repulsion
        for (var i = 0; i < nNodes; i++) {
            var na = this.nodes[i];
            if (this.barnesHutOptimize) {
                this.applyRegionToNodeRepulsion(this.rootRegion, na);
            }
            else {
                for (var j = i + 1; j < nNodes; j++) {
                    var nb = this.nodes[j];
                    this.applyNodeToNodeRepulsion(na, nb, false);
                }
            }

            // Gravity
            if (this.gravity > 0) {
                if (this.strongGravityMode) {
                    this.applyNodeStrongGravity(na);
                }
                else {
                    this.applyNodeGravity(na);
                }
            }
        }

        // Attraction
        for (var i = 0; i < this.edges.length; i++) {
            this.applyEdgeAttraction(this.edges[i]);
        }

        // Handle swinging
        var swingWeightedSum = 0;
        var tractionWeightedSum = 0;
        var tmp = vec2.create();
        for (var i = 0; i < nNodes; i++) {
            var node = this.nodes[i];
            var swing = vec2.dist(node.force, node.forcePrev);
            swingWeightedSum += swing * node.mass;

            vec2.add(tmp, node.force, node.forcePrev);
            var traction = vec2.len(tmp) * 0.5;
            tractionWeightedSum += traction * node.mass;

            // Save the value for using later
            this._swingingArr[i] = swing;
        }
        var globalSpeed = this.jitterTolerence * this.jitterTolerence
                        * tractionWeightedSum / swingWeightedSum;
        // NB: During our tests we observed that an excessive rise of the global speed could have a negative impact.
        // That’s why we limited the increase of global speed s(t)(G) to 50% of the previous step s(t−1)(G).
        if (this._globalSpeed > 0) {
            globalSpeed = Math.min(globalSpeed / this._globalSpeed, 1.5) * this._globalSpeed;
        }
        this._globalSpeed = globalSpeed;

        // Apply forces
        for (var i = 0; i < nNodes; i++) {
            var node = this.nodes[i];
            var swing = this._swingingArr[i];

            var speed = 0.1 * globalSpeed / (1 + globalSpeed * Math.sqrt(swing));

            // Additional constraint to prevent local speed gets too high
            var df = vec2.len(node.force);
            if (df > 0) {
                speed = Math.min(df * speed, 10) / df;
                vec2.scaleAndAdd(node.position, node.position, node.force, speed);
            }
        }
    };

    forceAtlas2Proto.applyRegionToNodeRepulsion = (function() {
        var v = vec2.create();
        return function applyRegionToNodeRepulsion(region, node) {
            if (region.node) { // Region is a leaf
                this.applyNodeToNodeRepulsion(region.node, node, true);
            }
            else {
                vec2.sub(v, node.position, region.centerOfMass);
                var d2 = v[0] * v[0] + v[1] * v[1];
                if (d2 > this.barnesHutTheta * region.size * region.size) {
                    var factor = this.scaling * node.mass * region.mass / d2;
                    vec2.scaleAndAdd(node.force, node.force, v, factor);
                }
                else {
                    for (var i = 0; i < region.nSubRegions; i++) {
                        this.applyRegionToNodeRepulsion(region.subRegions[i], node);
                    }
                }
            }
        }
    })();

    forceAtlas2Proto.applyNodeToNodeRepulsion = (function() {
        var v = vec2.create();
        return function applyNodeToNodeRepulsion(na, nb, oneWay) {
            if (na == nb) {
                return;
            }
            vec2.sub(v, na.position, nb.position);
            var d2 = v[0] * v[0] + v[1] * v[1];

            // PENDING
            if (d2 === 0) {
                return;
            }

            var factor;
            if (this.preventOverlap) {
                var d = Math.sqrt(d2);
                d = d - na.size - nb.size;
                if (d > 0) {
                    factor = this.scaling * na.mass * nb.mass / (d * d);
                }
                else if (d < 0) {
                    // A stronger repulsion if overlap
                    factor = this.scaling * 100 * na.mass * nb.mass;
                }
                else {
                    // No repulsion
                    return;
                }
            }
            else {
                // Divide factor by an extra `d` to normalize the `v`
                factor = this.scaling * na.mass * nb.mass / d2;
            }

            vec2.scaleAndAdd(na.force, na.force, v, factor);
            vec2.scaleAndAdd(nb.force, nb.force, v, -factor);
        }
    })();

    forceAtlas2Proto.applyEdgeAttraction = (function() {
        var v = vec2.create();
        return function applyEdgeAttraction(edge) {
            var na = edge.source;
            var nb = edge.target;

            vec2.sub(v, na.position, nb.position);
            var d = vec2.len(v);

            var w;
            if (this.edgeWeightInfluence === 0) {
                w = 1;
            }
            else if (this.edgeWeightInfluence === 1) {
                w = edge.weight;
            }
            else {
                w = Math.pow(edge.weight, this.edgeWeightInfluence);
            }

            var factor;

            if (this.preventOverlap) {
                d = d - na.size - nb.size;
                if (d <= 0) {
                    // No attraction
                    return;
                }
            }

            if (this.linLogMode) {
                // Divide factor by an extra `d` to normalize the `v`
                factor = - w * Math.log(d + 1) / (d + 1);
            }
            else {
                factor = - w;
            }
            vec2.scaleAndAdd(na.force, na.force, v, factor);
            vec2.scaleAndAdd(nb.force, nb.force, v, -factor);
        }
    })();

    forceAtlas2Proto.applyNodeGravity = (function() {
        var v = vec2.create();
        return function(node) {
            vec2.sub(v, this.gravityCenter, node.position);
            var d = vec2.len(v);
            vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass / (d + 1));
        }
    })();

    forceAtlas2Proto.applyNodeStrongGravity = (function() {
        var v = vec2.create();
        return function(node) {
            vec2.sub(v, this.gravityCenter, node.position);
            vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass);
        }
    })();

    forceAtlas2Proto.updateBBox = function() {
        var minX = Infinity;
        var minY = Infinity;
        var maxX = -Infinity;
        var maxY = -Infinity;
        for (var i = 0; i < this.nodes.length; i++) {
            var pos = this.nodes[i].position;
            minX = Math.min(minX, pos[0]);
            minY = Math.min(minY, pos[1]);
            maxX = Math.max(maxX, pos[0]);
            maxY = Math.max(maxY, pos[1]);
        }
        this.bbox[0] = minX;
        this.bbox[1] = minY;
        this.bbox[2] = maxX;
        this.bbox[3] = maxY;
    };

    forceAtlas2Proto.getGlobalSpeed = function () {
        return this._globalSpeed;
    }

    /****************************
     * Main process
     ***************************/

    var forceAtlas2 = null;

    self.onmessage = function(e) {
        switch(e.data.cmd) {
            case 'init':
                forceAtlas2 = new ForceAtlas2();
                forceAtlas2.initNodes(e.data.nodesPosition, e.data.nodesMass, e.data.nodesSize);
                forceAtlas2.initEdges(e.data.edges, e.data.edgesWeight);
                break;
            case 'updateConfig':
                if (forceAtlas2) {
                    for (var name in e.data.config) {
                        forceAtlas2[name] = e.data.config[name];
                    }
                }
                break;
            case 'update':
                var steps = e.data.steps;
                if (forceAtlas2) {
                    for (var i = 0; i < steps; i++) {
                        forceAtlas2.update();
                    }

                    var nNodes = forceAtlas2.nodes.length;
                    var positionArr = new Float32Array(nNodes * 2);
                    // Callback
                    for (var i = 0; i < nNodes; i++) {
                        var node = forceAtlas2.nodes[i];
                        positionArr[i * 2] = node.position[0];
                        positionArr[i * 2 + 1] = node.position[1];
                    }
                    self.postMessage({
                        buffer: positionArr.buffer,
                        globalSpeed: forceAtlas2.getGlobalSpeed()
                    }, [positionArr.buffer]);
                }
                else {
                    // Not initialzied yet
                    var emptyArr = new Float32Array();
                    // Post transfer object
                    self.postMessage({
                        buffer: emptyArr.buffer,
                        globalSpeed: forceAtlas2.getGlobalSpeed()
                    }, [emptyArr.buffer]);
                }
                break;
        }
    }
}