diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6789e7a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+*~
+target/
+*dependency-reduced-pom.xml
+.idea
+*.iml
+*.iws
+.DS_Store
+*.project
+*.classpath
+*.settings
+*.metadata
+*hbase-site.xml
+*.log
+*.swp
+*.tmp
+*.bak
+*.class
+
+tmp/**
+tmp/**/*
+temp/**
+temp/**/*
+
+repodata/
diff --git a/demo_loader/README.md b/demo_loader/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/demo_loader/pom.xml b/demo_loader/pom.xml
new file mode 100644
index 0000000..addae33
--- /dev/null
+++ b/demo_loader/pom.xml
@@ -0,0 +1,81 @@
+
+
+
+
+ 4.0.0
+ com.hortonworks.metron
+ demo-loader
+ 0.4.0
+ Demo CSV Loader
+
+
+ org.apache.metron
+ metron-data-management
+ 0.4.0
+
+
+
+
+
+ maven-assembly-plugin
+
+ src/main/assembly/assembly.xml
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.5.1
+
+ javac-with-errorprone
+ true
+
+ -Xlint:unchecked
+ 1.8
+ true
+
+
+
+ org.codehaus.plexus
+ plexus-compiler-javac-errorprone
+ 2.8
+
+
+
+ com.google.errorprone
+ error_prone_core
+ 2.0.14
+
+
+
+
+
+
+ src/main/resources
+
+
+
+
+
diff --git a/demo_loader/src/main/assembly/assembly.xml b/demo_loader/src/main/assembly/assembly.xml
new file mode 100644
index 0000000..0b36f9d
--- /dev/null
+++ b/demo_loader/src/main/assembly/assembly.xml
@@ -0,0 +1,42 @@
+
+
+
+ archive
+
+ tar.gz
+
+ false
+
+
+ ${project.basedir}/src/main/scripts
+ /bin
+ true
+
+ **/*.formatted
+ **/*.filtered
+
+ 0755
+ unix
+ true
+
+
+ ${project.basedir}/target
+
+ ${project.artifactId}-${project.version}.jar
+
+ /lib
+ true
+
+
+
diff --git a/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DegreeAnalyzer.java b/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DegreeAnalyzer.java
new file mode 100644
index 0000000..cbdaa21
--- /dev/null
+++ b/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DegreeAnalyzer.java
@@ -0,0 +1,140 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.hortonworks.metron.loader.csv;
+
+
+import org.apache.metron.guava.base.Splitter;
+import org.apache.metron.guava.collect.Iterables;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+
+public class DegreeAnalyzer {
+
+ public static void processRecords(File f, Function, Void> op) throws IOException {
+ BufferedReader reader = Files.newBufferedReader(f.toPath(), Charset.defaultCharset());
+ for(String line = null;(line = reader.readLine()) != null;) {
+ Iterable tokens = Splitter.on(",").split(line);
+ String left = Iterables.getFirst(tokens, "").trim();
+ String right = Iterables.getLast(tokens, "").trim();
+ if(left.length() > 0 && right.length() > 0) {
+ Map.Entry lr = new AbstractMap.SimpleEntry(left.trim(), right.trim());
+ op.apply(lr);
+ }
+ }
+ }
+
+ public static void main(String... argv) throws IOException {
+ final ArrayList hosts = new ArrayList<>();
+ final Map hostToIndex = new HashMap<>();
+ File inputFile = new File(argv[0]);
+ List importantHosts = new ArrayList<>();
+ for(int i = 1;i < argv.length;++i) {
+ importantHosts.add(argv[i].trim());
+ }
+
+ Progress progress = new Progress(System.err);
+ AtomicInteger numRecs = new AtomicInteger(0);
+ processRecords(inputFile
+ , entry -> {
+ if(!hostToIndex.containsKey(entry.getKey())) {
+ int idx = hosts.size();
+ hosts.add(entry.getKey());
+ hostToIndex.put(entry.getKey(), idx);
+ }
+ if(!hostToIndex.containsKey(entry.getValue())) {
+ int idx = hosts.size();
+ hosts.add(entry.getValue());
+ hostToIndex.put(entry.getValue(), idx);
+ }
+ numRecs.incrementAndGet();
+ progress.update();
+ return null;
+ }
+ );
+ progress.reset();
+ int tenPercent = numRecs.get()/10;
+ System.err.println("Preprocessed " + numRecs.get() + " records.");
+ final boolean[][] adjacencyMatrix = new boolean[hosts.size()][hosts.size()];
+ for(int i = 0;i < hosts.size();++i) {
+ for(int j = 0;j < hosts.size();++j) {
+ adjacencyMatrix[i][j] = i == j;
+ }
+ }
+ final AtomicInteger proc = new AtomicInteger(0);
+ processRecords( inputFile
+ , entry -> {
+ int row = hostToIndex.get(entry.getKey());
+ int col = hostToIndex.get(entry.getValue());
+ adjacencyMatrix[row][col] = true;
+ int numProcessed = proc.incrementAndGet();
+ progress.update();
+ if(tenPercent > 0 && numProcessed % tenPercent == 0) {
+ System.err.println(" -- " + (numProcessed / tenPercent) + " %");
+ }
+ return null;
+ }
+ );
+ System.err.println("\nSquaring adjacency matrix (" + adjacencyMatrix.length + "x" + adjacencyMatrix.length + ") to make transitive links...");
+ List rowIds = new ArrayList<>();
+ for(String importantHost : importantHosts) {
+ Integer idx = hostToIndex.get(importantHost);
+ if(idx != null) {
+ rowIds.add(idx);
+ }
+ }
+ boolean[][] transitiveMatrix = squareMatrix(adjacencyMatrix, rowIds);
+ Set ret = new HashSet<>();
+ for(Integer idx : rowIds) {
+ boolean[] connectedHosts = transitiveMatrix[idx];
+ for(int i = 0;i < connectedHosts.length;++i) {
+ if(connectedHosts[i]) {
+ ret.add(hosts.get(i));
+ }
+ }
+ }
+ for(String s : ret) {
+ System.out.println(s);
+ }
+ }
+
+ private static boolean innerProduct(boolean[][] adjacencyMatrix, int rowId, int colId) {
+ boolean ret = false;
+ for(int i = 0;i < adjacencyMatrix.length;++i) {
+ boolean lhs = adjacencyMatrix[rowId][i];
+ boolean rhs = adjacencyMatrix[i][colId];
+ ret = ret | (rhs && lhs);
+ }
+ return ret;
+ }
+
+ private static boolean[][] squareMatrix(boolean[][] adjacencyMatrix, List rowIds) {
+ boolean[][] ret = new boolean[adjacencyMatrix.length][adjacencyMatrix.length];
+ for(Integer i : rowIds) {
+ for(int j = 0;j < adjacencyMatrix.length;++j) {
+ ret[i][j] = innerProduct(adjacencyMatrix, i, j);
+ }
+ }
+ return ret;
+ }
+
+}
diff --git a/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DemoConfig.java b/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DemoConfig.java
new file mode 100644
index 0000000..4a9e02b
--- /dev/null
+++ b/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DemoConfig.java
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.hortonworks.metron.loader.csv;
+
+import org.apache.metron.common.csv.CSVConverter;
+
+import java.util.List;
+import java.util.Map;
+
+public class DemoConfig {
+
+ public static class DataSource {
+ public String outputTopic;
+ public String inputFile;
+ public String filter;
+ public CSVConverter converter;
+
+ public String getOutputTopic() {
+ return outputTopic;
+ }
+
+ public void setOutputTopic(String outputTopic) {
+ this.outputTopic = outputTopic;
+ }
+
+ public String getInputFile() {
+ return inputFile;
+ }
+
+ public void setInputFile(String inputFile) {
+ this.inputFile = inputFile;
+ }
+
+ public CSVConverter getConverter() {
+ return converter;
+ }
+
+ public void setConfig(Map config) {
+ converter = new CSVConverter();
+ converter.initialize(config);
+ }
+
+ public String getFilter() {
+ return filter;
+ }
+
+ public void setFilter(String filter) {
+ this.filter = filter;
+ }
+ }
+
+ public int stepTimeMs;
+ public Long timeOffset;
+ public List sources;
+
+ public int getStepTimeMs() {
+ return stepTimeMs;
+ }
+
+ public void setStepTimeMs(int stepTimeMs) {
+ this.stepTimeMs = stepTimeMs;
+ }
+
+ public Long getTimeOffset() {
+ return timeOffset;
+ }
+
+ public void setTimeOffset(Long timeOffset) {
+ this.timeOffset = timeOffset;
+ }
+
+ public List getSources() {
+ return sources;
+ }
+
+ public void setSources(List sources) {
+ this.sources = sources;
+ }
+}
diff --git a/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DemoLoader.java b/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DemoLoader.java
new file mode 100644
index 0000000..03bde3c
--- /dev/null
+++ b/demo_loader/src/main/java/com/hortonworks/metron/loader/csv/DemoLoader.java
@@ -0,0 +1,417 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.hortonworks.metron.loader.csv;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.commons.cli.*;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.apache.metron.common.dsl.Context;
+import org.apache.metron.common.dsl.MapVariableResolver;
+import org.apache.metron.common.dsl.StellarFunctions;
+import org.apache.metron.common.dsl.VariableResolver;
+import org.apache.metron.common.stellar.StellarPredicateProcessor;
+import org.apache.metron.common.utils.JSONUtils;
+import org.apache.metron.common.utils.KafkaUtils;
+import org.apache.metron.common.utils.cli.OptionHandler;
+import org.apache.metron.dataloads.nonbulk.flatfile.importer.LocalImporter;
+
+import javax.annotation.Nullable;
+import java.io.*;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.zip.GZIPInputStream;
+
+public class DemoLoader {
+ public enum LoadOptions {
+ HELP("h", new OptionHandler() {
+
+ @Nullable
+ @Override
+ public Option apply(@Nullable String s) {
+ return new Option(s, "help", false, "Generate Help screen");
+ }
+ }),
+ CONFIG("c", new OptionHandler() {
+ @Nullable
+ @Override
+ public Option apply(@Nullable String s) {
+ Option o = new Option(s, "config", true, "The demo config.");
+ o.setArgName("CONFIG_FILE");
+ o.setRequired(true);
+ return o;
+ }
+
+ @Override
+ public Optional