docs: public static void checkVersions(){
          boolean doCheck = Boolean.parseBoolean(System.getProperty(ND4JSystemProperties.VERSION_CHECK_PROPERTY, "true"));
  
          if(!doCheck){
              return;
          }
  
          if(classExists(ND4J_JBLAS_CLASS)) {
              //nd4j-jblas is ancient and incompatible
              log.error("Found incompatible/obsolete backend and version (nd4j-jblas) on classpath. ND4J is unlikely to"
                      + " function correctly with nd4j-jblas on the classpath. JVM will now exit.");
              System.exit(1);
          }
  
          if(classExists(CANOVA_CLASS)) {
              //Canova is ancient and likely to pull in incompatible dependencies
              log.error("Found incompatible/obsolete library Canova on classpath. ND4J is unlikely to"
                      + " function correctly with this library on the classpath. JVM will now exit.");
              System.exit(1);
          }
  
          List<VersionInfo> dependencies = getVersionInfos();
          if(dependencies.size() <= 2){
              //No -properties.git files were found on the classpath. This may be due to a misconfigured uber-jar
              // or maybe running in IntelliJ with "dynamic.classpath" set to true (in workspace.xml). Either way,
              // we can't check versions and don't want to log an error, which will more often than not be wrong
              if(dependencies.size() == 0){
                  return;
              }
  
              //Another edge case: no -properties.git files were found, but DL4J and/or DataVec were inferred
              // by class names. If these "inferred by opName" versions were the only things found, we should also
              // not log a warning, as we can't check versions in this case
  
              boolean dl4jViaClass = false;
              boolean datavecViaClass = false;
              for(VersionInfo vi : dependencies ){
                  if(DL4J_GROUPID.equals(vi.getGroupId()) && DL4J_ARTIFACT.equals(vi.getArtifactId())
                          && (UNKNOWN_VERSION.equals(vi.getBuildVersion()))){
                      dl4jViaClass = true;
                  } else if(DATAVEC_GROUPID.equals(vi.getGroupId()) && DATAVEC_ARTIFACT.equals(vi.getArtifactId())
                          && (UNKNOWN_VERSION.equals(vi.getBuildVersion()))){
                      datavecViaClass = true;
                  }
              }
  
              if(dependencies.size() == 1 && (dl4jViaClass || datavecViaClass)){
                  return;
              } else if(dependencies.size() == 2 && dl4jViaClass && datavecViaClass){
                  return;
              }
          }
  
          Set<String> foundVersions = new HashSet<>();
          for(VersionInfo vi : dependencies){
              String g = vi.getGroupId();
              if(g != null && GROUPIDS_TO_CHECK.contains(g)){
                  String version = vi.getBuildVersion();
  
                  if(version.contains("_spark_")){
                      //Normalize spark versions:
                      // "0.9.1_spark_1" to "0.9.1" and "0.9.1_spark_1-SNAPSHOT" to "0.9.1-SNAPSHOT"
                      version = version.replaceAll("_spark_1","");
                      version = version.replaceAll("_spark_2","");
                  }
  
                  foundVersions.add(version);
              }
          }
  
          boolean logVersions = false;
  
          if(foundVersions.size() > 1){
              log.warn("*** ND4J VERSION CHECK FAILED - INCOMPATIBLE VERSIONS FOUND ***");
              log.warn("Incompatible versions (different version number) of DL4J, ND4J, RL4J, DataVec, Arbiter are unlikely to function correctly");
              logVersions = true;
          }
  
          //Also: check for mixed scala versions - but only for our dependencies... These are in the artifact ID,
          // scored like dl4j-spack_2.10 and deeplearning4j-ui_2.11
          //And check for mixed spark versions (again, just DL4J/DataVec etc dependencies for now)
          boolean scala210 = false;
          boolean scala211 = false;
          boolean spark1 = false;
          boolean spark2 = false;
          for(VersionInfo vi : dependencies){
              String artifact = vi.getArtifactId();
              if(!scala210 && artifact.contains(SCALA_210_SUFFIX)){
                  scala210 = true;
              }
              if(!scala211 && artifact.contains(SCALA_211_SUFFIX)){
                  scala211 = true;
              }
  
              String version = vi.getBuildVersion();
              if(!spark1 && version.contains(SPARK_1_VER_STRING)){
                  spark1 = true;
              }
              if(!spark2 && version.contains(SPARK_2_VER_STRING)){
                  spark2 = true;
              }
          }
  
          if(scala210 && scala211){
              log.warn("*** ND4J VERSION CHECK FAILED - FOUND BOTH SCALA VERSION 2.10 AND 2.11 ARTIFACTS ***");
              log.warn("Projects with mixed Scala versions (2.10/2.11) are unlikely to function correctly");
              logVersions = true;
          }
  
          if(spark1 && spark2){
              log.warn("*** ND4J VERSION CHECK FAILED - FOUND BOTH SPARK VERSION 1 AND 2 ARTIFACTS ***");
              log.warn("Projects with mixed Spark versions (1 and 2) are unlikely to function correctly");
              logVersions = true;
          }
  
          if(logVersions){
              log.info("Versions of artifacts found on classpath:");
              logVersionInfo();
          }
      }