From a95014ed1e145f9133dd95dcbfbf7e9212401fef Mon Sep 17 00:00:00 2001 From: cstella Date: Tue, 19 Dec 2017 17:26:03 -0500 Subject: [PATCH 01/28] METRON-1377: Stellar function to generate typosquatted domains (similar to dnstwist) --- .../common/typosquat/AdditionStrategy.java | 38 +++ .../typosquat/BitsquattingStrategy.java | 58 ++++ .../common/typosquat/HomoglyphStrategy.java | 84 ++++++ .../common/typosquat/HyphenationStrategy.java | 38 +++ .../common/typosquat/InsertionStrategy.java | 53 ++++ .../metron/common/typosquat/Keyboards.java | 147 ++++++++++ .../common/typosquat/OmissionStrategy.java | 38 +++ .../common/typosquat/OriginalStrategy.java | 35 +++ .../common/typosquat/RepetitionStrategy.java | 45 +++ .../common/typosquat/ReplacementStrategy.java | 49 ++++ .../common/typosquat/SubdomainStrategy.java | 45 +++ .../typosquat/TranspositionStrategy.java | 46 ++++ .../typosquat/TyposquattingStrategies.java | 105 +++++++ .../typosquat/TyposquattingStrategy.java | 25 ++ .../common/typosquat/VowelSwapStrategy.java | 54 ++++ .../TyposquattingStrategiesTest.java | 124 +++++++++ .../src/test/resources/typosquat/amazon.csv | 259 ++++++++++++++++++ .../src/test/resources/typosquat/github.csv | 227 +++++++++++++++ .../dsl/functions/FunctionalFunctions.java | 9 +- 19 files changed, 1474 insertions(+), 5 deletions(-) create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/AdditionStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/BitsquattingStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HyphenationStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/InsertionStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/Keyboards.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OmissionStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OriginalStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/RepetitionStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/ReplacementStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/SubdomainStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TranspositionStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategy.java create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/VowelSwapStrategy.java create mode 100644 metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java create mode 100644 metron-platform/metron-common/src/test/resources/typosquat/amazon.csv create mode 100644 metron-platform/metron-common/src/test/resources/typosquat/github.csv diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/AdditionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/AdditionStrategy.java new file mode 100644 index 0000000000..423f976e34 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/AdditionStrategy.java @@ -0,0 +1,38 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class AdditionStrategy implements TyposquattingStrategy { + @Override + public Set generateCandidates(String domain) { + Set ret = new HashSet<>(); + for(int i = 97;i < 123;++i) { + char c = Character.toChars(i)[0]; + ret.add(domain + c); + } + return ret; + } + + @Override + public String name() { + return "Addition"; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/BitsquattingStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/BitsquattingStrategy.java new file mode 100644 index 0000000000..004c2cacc1 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/BitsquattingStrategy.java @@ -0,0 +1,58 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class BitsquattingStrategy implements TyposquattingStrategy { + public static int[] MASK = new int[] { 1, 2, 4, 8, 16, 32, 64, 128}; + @Override + public Set generateCandidates(String originalString) { + Set ret = new HashSet<>(); + char[] str = originalString.toCharArray(); + for(int i = 0;i < str.length;++i) { + char c = str[i]; + for(int j : MASK) { + int maskedNum = (int)c ^ j; + char maskedChar = (char)maskedNum; + if((maskedNum >= 48 && maskedNum <= 57) || (maskedNum >= 97 && maskedNum <= 122) || maskedNum == 45) { + ret.add(pasteTogether(str, i, maskedChar)); + } + } + } + return ret; + } + + @Override + public String name() { + return "Bitsquatting"; + } + + private static String pasteTogether(char[] str, int replacementPoint, char maskedChar) { + String ret = ""; + for(int i = 0;i < replacementPoint;++i) { + ret += str[i]; + } + ret += maskedChar; + for(int i = replacementPoint+1;i < str.length;++i) { + ret += str[i]; + } + return ret; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java new file mode 100644 index 0000000000..39d8bcbeca --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java @@ -0,0 +1,84 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import com.google.common.collect.ImmutableList; + +import java.net.IDN; +import java.util.*; + +public class HomoglyphStrategy implements TyposquattingStrategy{ public static final Map> glyphs = new HashMap>() + {{ + put('a', ImmutableList.of("à", "á", "â", "ã", "ä", "å", "ɑ", "а", "ạ", "ǎ", "ă", "ȧ", "ӓ")); + put('b', ImmutableList.of("d", "lb", "ib", "ʙ", "Ь", "b̔", "ɓ", "Б")); + put('c', ImmutableList.of("ϲ", "с", "ƈ", "ċ", "ć", "ç")); + put('d', ImmutableList.of("b", "cl", "dl", "di", "ԁ", "ժ", "ɗ", "đ")); + put('e', ImmutableList.of("é", "ê", "ë", "ē", "ĕ", "ě", "ė", "е", "ẹ", "ę", "є", "ϵ", "ҽ")); + put('f', ImmutableList.of("Ϝ", "ƒ", "Ғ")); + put('g', ImmutableList.of("q", "ɢ", "ɡ", "Ԍ", "Ԍ", "ġ", "ğ", "ց", "ǵ", "ģ")); + put('h', ImmutableList.of("lh", "ih", "һ", "հ", "Ꮒ", "н")); + put('i', ImmutableList.of("1", "l", "Ꭵ", "í", "ï", "ı", "ɩ", "ι", "ꙇ", "ǐ", "ĭ")); + put('j', ImmutableList.of("ј", "ʝ", "ϳ", "ɉ")); + put('k', ImmutableList.of("lk", "ik", "lc", "κ", "ⲕ", "κ")); + put('l', ImmutableList.of("1", "i", "ɫ", "ł")); + put('m', ImmutableList.of("n", "nn", "rn", "rr", "ṃ", "ᴍ", "м", "ɱ")); + put('n', ImmutableList.of("m", "r", "ń")); + put('o', ImmutableList.of("0", "Ο", "ο", "О", "о", "Օ", "ȯ", "ọ", "ỏ", "ơ", "ó", "ö", "ӧ")); + put('p', ImmutableList.of("ρ", "р", "ƿ", "Ϸ", "Þ")); + put('q', ImmutableList.of("g", "զ", "ԛ", "գ", "ʠ")); + put('r', ImmutableList.of("ʀ", "Г", "ᴦ", "ɼ", "ɽ")); + put('s', ImmutableList.of("Ⴝ", "Ꮪ", "ʂ", "ś", "ѕ")); + put('t', ImmutableList.of("τ", "т", "ţ")); + put('u', ImmutableList.of("μ", "υ", "Ս", "ս", "ц", "ᴜ", "ǔ", "ŭ")); + put('v', ImmutableList.of("ѵ", "ν", "v̇")); + put('w', ImmutableList.of("vv", "ѡ", "ա", "ԝ")); + put('x', ImmutableList.of("х", "ҳ", "ẋ")); + put('y', ImmutableList.of("ʏ", "γ", "у", "Ү", "ý")); + put('z', ImmutableList.of("ʐ", "ż", "ź", "ʐ", "ᴢ")); + }}; + + @Override + public Set generateCandidates(String originalString) { + Set result = new HashSet<>(); + for(int ws = 0;ws < originalString.length();ws++) { + for(int i = 0;i < originalString.length() - ws + 1;++i) { + String win = originalString.substring(i, i+ws); + for(int j = 0;j < ws;j++) { + char c = win.charAt(j); + if( glyphs.containsKey(c)) { + for( String g : glyphs.get(c)) { + String winNew = win.replaceAll("" + c, g); + String d = originalString.substring(0, i) + winNew + originalString.substring(i + ws); + String dAscii = IDN.toASCII(d, IDN.ALLOW_UNASSIGNED); + result.add(d); + if(!d.equals(dAscii)) { + result.add(dAscii); + } + } + } + } + } + } + return result; + } + + @Override + public String name() { + return "Homoglyph"; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HyphenationStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HyphenationStrategy.java new file mode 100644 index 0000000000..08a2583919 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HyphenationStrategy.java @@ -0,0 +1,38 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class HyphenationStrategy implements TyposquattingStrategy { + @Override + public Set generateCandidates(String originalString) { + Set ret = new HashSet<>(); + for(int i = 1;i < originalString.length();++i) { + ret.add(originalString.substring(0, i) + "-" + originalString.substring(i)); + } + return ret; + } + + @Override + public String name() { + return "Hyphenation"; + } + +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/InsertionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/InsertionStrategy.java new file mode 100644 index 0000000000..d6a644d057 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/InsertionStrategy.java @@ -0,0 +1,53 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class InsertionStrategy implements TyposquattingStrategy { + @Override + public Set generateCandidates(String domain) { + Set ret = new HashSet<>(); + for(int i = 1;i < domain.length() - 1;++i) { + for(Keyboards keyboard : Keyboards.values()) { + String mapping = keyboard.getMapping().get(domain.charAt(i)); + if(mapping != null) { + for(Character c : mapping.toCharArray()) { + ret.add(domain.substring(0, i) + + c + + domain.charAt(i) + + domain.substring(i+1, domain.length()) + ); + ret.add(domain.substring(0, i) + + domain.charAt(i) + + c + + domain.substring(i+1, domain.length()) + ); + } + } + } + } + return ret; + } + + @Override + public String name() { + return "Insertion"; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/Keyboards.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/Keyboards.java new file mode 100644 index 0000000000..3cc70a787f --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/Keyboards.java @@ -0,0 +1,147 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashMap; +import java.util.Map; + +public enum Keyboards { + QWERTY(new HashMap() + {{ + put('j', "ikmnhu"); + put('w', "3esaq2"); + put('v', "cfgb"); + put('l', "kop"); + put('y', "7uhgt6"); + put('x', "zsdc"); + put('r', "5tfde4"); + put('u', "8ijhy7"); + put('a', "qwsz"); + put('q', "12wa"); + put('c', "xdfv"); + put('b', "vghn"); + put('e', "4rdsw3"); + put('d', "rfcxse"); + put('g', "yhbvft"); + put('p', "lo0"); + put('i', "9okju8"); + put('h', "ujnbgy"); + put('k', "olmji"); + put('f', "tgvcdr"); + put('m', "njk"); + put('s', "edxzaw"); + put('o', "0plki9"); + put('n', "bhjm"); + put('1', "2q"); + put('0', "po9"); + put('3', "4ew2"); + put('2', "3wq1"); + put('5', "6tr4"); + put('4', "5re3"); + put('7', "8uy6"); + put('6', "7yt5"); + put('9', "0oi8"); + put('8', "9iu7"); + put('z', "asx"); + put('t', "6ygfr5"); + }}), + QWERTZ(new HashMap() {{ + put('j', "ikmnhu"); + put('w', "3esaq2"); + put('v', "cfgb"); + put('l', "kop"); + put('y', "asx"); + put('x', "ysdc"); + put('r', "5tfde4"); + put('u', "8ijhz7"); + put('a', "qwsy"); + put('q', "12wa"); + put('c', "xdfv"); + put('b', "vghn"); + put('e', "4rdsw3"); + put('d', "rfcxse"); + put('g', "zhbvft"); + put('p', "lo0"); + put('i', "9okju8"); + put('h', "ujnbgz"); + put('k', "olmji"); + put('f', "tgvcdr"); + put('m', "njk"); + put('s', "edxyaw"); + put('o', "0plki9"); + put('n', "bhjm"); + put('1', "2q"); + put('0', "po9"); + put('3', "4ew2"); + put('2', "3wq1"); + put('5', "6tr4"); + put('4', "5re3"); + put('7', "8uz6"); + put('6', "7zt5"); + put('9', "0oi8"); + put('8', "9iu7"); + put('z', "7uhgt6"); + put('t', "6zgfr5"); + }}), + AZERTY(new HashMap() {{ + put('j', "iknhu"); + put('w', "sxq"); + put('v', "cfgb"); + put('l', "kopm"); + put('y', "7uhgt6"); + put('x', "zsdc"); + put('r', "5tfde4"); + put('u', "8ijhy7"); + put('a', "2zq1"); + put('q', "zswa"); + put('c', "xdfv"); + put('b', "vghn"); + put('e', "4rdsz3"); + put('d', "rfcxse"); + put('g', "yhbvft"); + put('p', "lo0m"); + put('i', "9okju8"); + put('h', "ujnbgy"); + put('k', "olji"); + put('f', "tgvcdr"); + put('m', "lp"); + put('s', "edxwqz"); + put('o', "0plki9"); + put('n', "bhj"); + put('1', "2a"); + put('0', "po9"); + put('3', "4ez2"); + put('2', "3za1"); + put('5', "6tr4"); + put('4', "5re3"); + put('7', "8uy6"); + put('6', "7yt5"); + put('9', "0oi8"); + put('8', "9iu7"); + put('z', "3esqa2"); + put('t', "6ygfr5"); + }}) + ; + private Map mapping; + Keyboards(Map mapping) { + this.mapping = mapping; + } + public Map getMapping() { + return mapping; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OmissionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OmissionStrategy.java new file mode 100644 index 0000000000..be3a49a812 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OmissionStrategy.java @@ -0,0 +1,38 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class OmissionStrategy implements TyposquattingStrategy { + + @Override + public Set generateCandidates(String domain) { + HashSet ret = new HashSet<>(); + for(int i = 0;i < domain.length();++i) { + ret.add(domain.substring(0, i) + domain.substring(i+1, domain.length())); + } + return ret; + } + + @Override + public String name() { + return "Omission"; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OriginalStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OriginalStrategy.java new file mode 100644 index 0000000000..d700792ef4 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OriginalStrategy.java @@ -0,0 +1,35 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class OriginalStrategy implements TyposquattingStrategy { + @Override + public Set generateCandidates(String domain) { + Set ret = new HashSet<>(); + ret.add(domain); + return ret; + } + + @Override + public String name() { + return "Original*"; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/RepetitionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/RepetitionStrategy.java new file mode 100644 index 0000000000..81de290260 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/RepetitionStrategy.java @@ -0,0 +1,45 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class RepetitionStrategy implements TyposquattingStrategy { + @Override + public Set generateCandidates(String domain) { + Set ret = new HashSet<>(); + for(int i = 0;i < domain.length();++i) { + Character c = domain.charAt(i); + if(Character.isLetter(c)) { + ret.add( domain.substring(0, i) + + c + + c + + domain.substring(i+1, domain.length()) + ); + } + } + return ret; + } + + @Override + public String name() { + return "Repetition"; + } + +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/ReplacementStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/ReplacementStrategy.java new file mode 100644 index 0000000000..78254d9713 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/ReplacementStrategy.java @@ -0,0 +1,49 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class ReplacementStrategy implements TyposquattingStrategy { + @Override + public Set generateCandidates(String domain) { + Set ret = new HashSet<>(); + for(int i = 0;i < domain.length();++i) { + for(Keyboards keyboard : Keyboards.values()) { + String mapping = keyboard.getMapping().get(domain.charAt(i)); + if(mapping != null) { + for(Character c : mapping.toCharArray()) { + ret.add( domain.substring(0, i) + + c + + domain.substring(i+1, domain.length()) + ); + } + } + } + } + return ret; + } + + @Override + public String name() { + return "Replacement"; + } + + +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/SubdomainStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/SubdomainStrategy.java new file mode 100644 index 0000000000..be342c2f4f --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/SubdomainStrategy.java @@ -0,0 +1,45 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class SubdomainStrategy implements TyposquattingStrategy{ + + @Override + public Set generateCandidates(String domain) { + Set ret = new HashSet<>(); + for(int i = 1;i < domain.length();++i) { + Character c = domain.charAt(i); + Character prevC = domain.charAt(i-1); + if(c != '-' && c != '.' + && prevC != '-' && prevC != '.' + ) + { + ret.add(domain.substring(0, i) + "." + domain.substring(i, domain.length())); + } + } + return ret; + } + + @Override + public String name() { + return "Subdomain"; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TranspositionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TranspositionStrategy.java new file mode 100644 index 0000000000..7962553e0d --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TranspositionStrategy.java @@ -0,0 +1,46 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class TranspositionStrategy implements TyposquattingStrategy { + @Override + public Set generateCandidates(String domain) { + + Set ret = new HashSet<>(); + for(int i = 0; i < domain.length()-1;++i) { + char nextC = domain.charAt(i+1); + char c = domain.charAt(i); + if(nextC != c) { + ret.add( domain.substring(0, i) + + nextC + + c + + domain.substring(i+2) + ); + } + } + return ret; + } + + @Override + public String name() { + return "Transposition"; + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java new file mode 100644 index 0000000000..a8fa9e42ed --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java @@ -0,0 +1,105 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import org.apache.metron.stellar.dsl.Context; +import org.apache.metron.stellar.dsl.ParseException; +import org.apache.metron.stellar.dsl.Stellar; +import org.apache.metron.stellar.dsl.StellarFunction; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public enum TyposquattingStrategies implements TyposquattingStrategy { + ADDITION(new AdditionStrategy()), + BITSQUATTING(new BitsquattingStrategy()), + HOMOGLYPH(new HomoglyphStrategy()), + HYPHENATION(new HyphenationStrategy()), + INSERTION(new InsertionStrategy()), + OMISSION(new OmissionStrategy()), + REPETITION(new RepetitionStrategy()), + REPLACEMENT(new ReplacementStrategy()), + SUBDOMAIN(new SubdomainStrategy()), + TRANSPOSITION(new TranspositionStrategy()), + VOWELSWAP(new VowelSwapStrategy()), + ORIGINAL(new OriginalStrategy()) + ; + TyposquattingStrategy strategy; + TyposquattingStrategies(TyposquattingStrategy strategy) { + this.strategy = strategy; + } + + @Override + public Set generateCandidates(String originalString) { + return strategy.generateCandidates(originalString); + } + + public static Set generateAllCandidates(String originalString) { + Set ret = new HashSet<>(); + for(TyposquattingStrategy s : values() ) { + ret.addAll(s.generateCandidates(originalString)); + } + return ret; + } + + public static TyposquattingStrategies byName(String name) { + for(TyposquattingStrategies s : values()) { + if(s.strategy.name().equals(name)) { + return s; + } + } + return null; + } + + @Stellar(namespace="DOMAIN" + ,name="TYPOSQUAT" + ,description="Generate potential typosquatted domain from a passed domain. Strategies largely match https://github.com/elceef/dnstwist" + ,params = { + "domain - Domain (without subdomains or TLD) to generate typosquatted domains for." + } + ,returns = "A set of potential typosquatted domains." + ) + public static class Generate implements StellarFunction{ + + @Override + public Object apply(List args, Context context) throws ParseException { + if(args.size() == 0) { + return null; + } + Object dnObj = args.get(0); + if(dnObj == null) { + return null; + } + if(!(dnObj instanceof String)) { + throw new IllegalStateException("Expected a domain without subdomains or a TLD, but got " + dnObj); + } + return TyposquattingStrategies.generateAllCandidates((String)dnObj); + } + + @Override + public void initialize(Context context) { + + } + + @Override + public boolean isInitialized() { + return true; + } + } +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategy.java new file mode 100644 index 0000000000..37e3f16160 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategy.java @@ -0,0 +1,25 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.Set; + +public interface TyposquattingStrategy { + Set generateCandidates(String domain); + String name(); +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/VowelSwapStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/VowelSwapStrategy.java new file mode 100644 index 0000000000..538acf9bec --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/VowelSwapStrategy.java @@ -0,0 +1,54 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import java.util.HashSet; +import java.util.Set; + +public class VowelSwapStrategy implements TyposquattingStrategy { + private static Set VOWELS = new HashSet() {{ + add('a'); + add('e'); + add('i'); + add('o'); + add('u'); + }}; + + @Override + public Set generateCandidates(String domain) { + + HashSet ret = new HashSet<>(); + for(int i = 0;i < domain.length();++i) { + char c = domain.charAt(i); + for(char vowel : VOWELS) { + if(VOWELS.contains(c)) { + ret.add( domain.substring(0, i) + + vowel + + domain.substring(i+1) + ); + } + } + } + return ret; + } + + @Override + public String name() { + return "Vowel-swap"; + } +} diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java new file mode 100644 index 0000000000..b3d3de22a0 --- /dev/null +++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java @@ -0,0 +1,124 @@ +/** + * 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 org.apache.metron.common.typosquat; + +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; +import org.apache.metron.stellar.common.utils.StellarProcessorUtils; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.*; + +@RunWith(Parameterized.class) +public class TyposquattingStrategiesTest { + + /* + Skipping the miscellaneous typosquatted domains as they rely on the TLD. + */ + static Set typesToSkip = new HashSet() {{ + add("Various"); + }}; + + //These are the output from DNS Twist ( https://github.com/elceef/dnstwist ). We want to ensure we match their output at minimum + static Map>> expected = new HashMap>>() + {{ + put("amazon", new EnumMap<>(TyposquattingStrategies.class)); + put("github", new EnumMap<>(TyposquattingStrategies.class)); + }}; + + @BeforeClass + public static void setup() throws Exception { + for(Map.Entry>> kv : expected.entrySet()) { + try(BufferedReader br = new BufferedReader(new FileReader( "src/test/resources/typosquat/" + kv.getKey() + ".csv") ) ) + { + for(String line = null;(line = br.readLine()) != null;) { + if(line.startsWith("#")) { + continue; + } + Iterable tokens = Splitter.on(",").split(line); + String name = Iterables.get(tokens, 0); + String domain = Iterables.get(tokens, 1); + domain = domain.replaceAll(".com", ""); + EnumMap> expectedValues = kv.getValue(); + if(typesToSkip.contains(name)) { + continue; + } + TyposquattingStrategies strategy = TyposquattingStrategies.byName(name); + Assert.assertNotNull("Couldn't find " + name, strategy); + Set s = expectedValues.get(strategy); + if(s == null) { + s = new HashSet<>(); + expectedValues.put(strategy, s); + } + s.add(domain); + } + } + } + } + + @Parameterized.Parameters + public static Collection strategies() { + List ret = new ArrayList<>(); + for(TyposquattingStrategies strategy : TyposquattingStrategies.values()) { + ret.add(new Object[] { strategy }); + } + return ret; + } + + TyposquattingStrategies strategy; + public TyposquattingStrategiesTest(TyposquattingStrategies strategy) { + this.strategy = strategy; + } + + public void assertExpected(String domain, TyposquattingStrategies strategy) { + Set expectedValues = expected.get(domain).get(strategy); + Set actualValues = strategy.generateCandidates(domain); + { + Sets.SetView vals = Sets.difference(expectedValues, actualValues); + String diff = Joiner.on(",").join(vals); + Assert.assertTrue(strategy.name() + ": Found values expected but not generated: " + diff, vals.isEmpty()); + } + } + + @Test + public void test() { + for(String domain : expected.keySet()) { + assertExpected(domain, strategy); + } + } + + @Test + public void testStellar() { + for(String domain : expected.keySet()) { + Set expectedAll = TyposquattingStrategies.generateAllCandidates(domain); + Set generatedAll = (Set) StellarProcessorUtils.run("DOMAIN_TYPOSQUAT(domain)", ImmutableMap.of("domain", domain)); + Assert.assertTrue(Sets.symmetricDifference(expectedAll, generatedAll).isEmpty()); + } + } +} diff --git a/metron-platform/metron-common/src/test/resources/typosquat/amazon.csv b/metron-platform/metron-common/src/test/resources/typosquat/amazon.csv new file mode 100644 index 0000000000..ceb4e93400 --- /dev/null +++ b/metron-platform/metron-common/src/test/resources/typosquat/amazon.csv @@ -0,0 +1,259 @@ +# +# 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. +# +#fuzzer,domain-name,dns-a,dns-aaaa,dns-mx,dns-ns,geoip-country,whois-created,whois-updated,ssdeep-score +Original*,amazon.com,176.32.103.205,,amazon-smtp.amazon.com,ns1.p31.dynect.net,,,, +Addition,amazona.com,198.50.233.235,,,ns1.domainmx.com,,,, +Addition,amazonb.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonc.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazond.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Addition,amazone.com,87.238.81.156,,,,,,, +Addition,amazonf.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazong.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonh.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazoni.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonj.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonk.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonl.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonm.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonn.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazono.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonp.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonq.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonr.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazons.com,54.197.246.244,,,ns-1019.awsdns-63.net,,,, +Addition,amazont.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonu.com,,,,,,,, +Addition,amazonv.com,207.171.166.22,,,,,,, +Addition,amazonw.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazonx.com,207.171.166.22,,,ns-1.amazon.com,,,, +Addition,amazony.com,207.171.166.22,,,,,,, +Addition,amazonz.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Bitsquatting,cmazon.com,103.224.182.251,,mx92.m1bp.com,ns1.above.com,,,, +Bitsquatting,emazon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Bitsquatting,imazon.com,185.53.178.6,,mail.h-email.net,ns1.parkingcrew.net,,,, +Bitsquatting,qmazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,alazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,aoazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,aiazon.com,50.63.202.55,,mailstore1.secureserver.net,ns77.domaincontrol.com,,,, +Bitsquatting,aeazon.com,,,,,,,, +Bitsquatting,a-azon.com,50.63.202.4,,,ns07.domaincontrol.com,,,, +Bitsquatting,amczon.com,207.171.166.22,,,,,,, +Bitsquatting,amezon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amizon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amqzon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amaxon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amaron.com,72.143.24.146,,mx05-1.mycloudmailbox.com,ns61.worldnic.com,,,, +Bitsquatting,amajon.com,185.53.177.30,,,ns1.parkingspa.com,,,, +Bitsquatting,amaznn.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amazmn.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amazkn.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amazgn.com,185.53.178.7,,mail.h-email.net,ns1.parkingcrew.net,,,, +Bitsquatting,amazoo.com,209.236.72.34,,amazoo.com,ns1.westservers.net,,,, +Bitsquatting,amazol.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amazoj.com,207.171.166.22,,,ns-1.amazon.com,,,, +Bitsquatting,amazof.com,,,,ns-1.amazon.com,,,, +Homoglyph,xn--mazon-qwa.com,,,,,,,, +Homoglyph,xn--amzon-ucc.com,104.27.182.15,2400:cb00:2048:1::681b:b60f,,cass.ns.cloudflare.com,,,, +Homoglyph,xn--mazon-zjc.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--mzon-pzbb.com,,,,,,,, +Homoglyph,xn--mzon-9nab.com,,,,,,,, +Homoglyph,amaz0n.com,207.171.166.22,,,ns-1.amazon.com,,,, +Homoglyph,xn--mzon-4nab.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--amzon-1jc.com,54.163.185.105,,,ns01.domaincontrol.com,,,, +Homoglyph,xn--amzon-k11b.com,104.18.48.131,2400:cb00:2048:1::6812:3083,,kara.ns.cloudflare.com,,,, +Homoglyph,annazon.com,207.171.166.22,,,,,,, +Homoglyph,xn--mazon-i11b.com,,,,,,,, +Homoglyph,xn--mzon-koab.com,,,,,,,, +Homoglyph,xn--amzon-nra.com,,,,,,,, +Homoglyph,arrazon.com,213.186.33.2,,mx1.ovh.net,dns.ovh.net,,,, +Homoglyph,xn--amaon-x59a.com,,,,ns1gmz.name.com,,,, +Homoglyph,xn--amazn-i91b.com,184.168.221.36,,mailstore1.secureserver.net,pdns09.domaincontrol.com,,,, +Homoglyph,xn--amzon-sqa.com,198.105.244.111,2620:118:7002::1111,,a1-144.akam.net,,,, +Homoglyph,xn--amazn-uce.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--mzon-znab.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--aazon-6xe.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--amaon-vuc.com,107.180.1.108,,mailstore1.secureserver.net,pdns09.domaincontrol.com,,,, +Homoglyph,xn--mzon-poab.com,,,,,,,, +Homoglyph,xn--amzon-swa.com,,,,,,,, +Homoglyph,anazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Homoglyph,xn--mzon-fseb.com,198.105.244.228,,,,,,, +Homoglyph,xn--amzon-yqa.com,69.64.147.242,,,ns1bdg.name.com,,,, +Homoglyph,xn--aazon-919a.com,198.105.244.228,,,,,,, +Homoglyph,xn--amzon-4qa.com,198.105.244.228,,,,,,, +Homoglyph,xn--mzon-4q5ab.com,,,,,,,, +Homoglyph,xn--amzon-hra.com,,,,,,,, +Homoglyph,xn--mzon-foab.com,198.105.244.228,,,,,,, +Homoglyph,xn--mzon-p5bb.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--amazn-xob.com,50.63.202.43,,mailstore1.secureserver.net,pdns09.domaincontrol.com,,,, +Homoglyph,xn--amazn-581b.com,184.168.221.57,,mailstore1.secureserver.net,pdns09.domaincontrol.com,,,, +Homoglyph,xn--mazon-3ve.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--mazon-jwb.com,,,,,,,, +Homoglyph,xn--amaon-kib.com,,,,ns-1417.awsdns-49.org,,,, +Homoglyph,xn--amazn-okg.com,,,,,,,, +Homoglyph,xn--amazn-mye.com,,,,,,,, +Homoglyph,xn--amazn-lsf.com,,,,,,,, +Homoglyph,xn--mzon-zsab.com,198.105.244.228,,,,,,, +Homoglyph,xn--amzon-bra.com,50.63.202.58,,,ns33.domaincontrol.com,,,, +Homoglyph,xn--mzon-zmbb.com,198.105.244.228,,,,,,, +Homoglyph,amazor.com,68.178.213.61,,,ns1.namefind.com,,,, +Homoglyph,xn--mazon-1of.com,,,,,,,, +Homoglyph,amazom.com,174.129.240.167,,,ns-1.amazon.com,,,, +Homoglyph,xn--mazon-wqa.com,66.96.149.32,,mx.xn--mazon-wqa.com,ns1.dotster.com,,,, +Homoglyph,xn--amazn-3ta.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--amazn-uce.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--mazon-fra.com,,,,ns1.markmonitor.com,,,, +Homoglyph,arnazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Homoglyph,xn--amazn-mua.com,184.168.221.32,,mailstore1.secureserver.net,ns19.domaincontrol.com,,,, +Homoglyph,xn--aazon-ipc.com,,,,,,,, +Homoglyph,xn--mazon-8qa.com,184.168.221.32,,mailstore1.secureserver.net,ns05.domaincontrol.com,,,, +Homoglyph,xn--amaon-7hb.com,207.244.67.138,,,ns1.wombatdns.com,,,, +Homoglyph,xn--aazon-fl1b.com,91.215.153.210,,mailstore1.secureserver.net,ns23.domaincontrol.com,,,, +Homoglyph,xn--amazn-mye.com,,,,,,,, +Homoglyph,xn--mazon-2qa.com,103.224.212.222,,mx92.m1bp.com,ns1.above.com,,,, +Homoglyph,xn--mazon-scc.com,,,,,,,, +Homoglyph,xn--mazon-qqa.com,199.59.242.150,,mx76.m2bp.com,ns1.bodis.com,,,, +Homoglyph,xn--mazon-lra.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--amzon-lwb.com,,,,,,,, +Homoglyph,xn--amzon-5ve.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--amazn-9dc.com,184.168.221.46,,mailstore1.secureserver.net,ns37.domaincontrol.com,,,, +Homoglyph,xn--amazo-07a.com,,,,,,,, +Homoglyph,xn--mzon-43db.com,,,,ns1.markmonitor.com,,,, +Homoglyph,xn--amzon-3of.com,,,,,,,, +Hyphenation,a-mazon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Hyphenation,am-azon.com,,,,,,,, +Hyphenation,ama-zon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Hyphenation,amaz-on.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Hyphenation,amazo-n.com,,,,ns-1.amazon.com,,,, +Insertion,amsazon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Insertion,amyazon.com,207.171.166.22,,,,,,, +Insertion,amazqon.com,103.224.182.214,,mx92.m1bp.com,ns1.above.com,,,, +Insertion,amjazon.com,,,,ns-1.amazon.com,,,, +Insertion,anmazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,ama3zon.com,198.105.244.228,,,,,,, +Insertion,ajmazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amayzon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,apmazon.com,103.224.182.207,,mx92.m1bp.com,ns1.above.com,,,, +Insertion,amazxon.com,,,,,,,, +Insertion,am1azon.com,,,,,,,, +Insertion,ama2zon.com,,,,,,,, +Insertion,amwazon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Insertion,amazokn.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,ama6zon.com,,,,,,,, +Insertion,amazuon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Insertion,amnazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amazpon.com,,,,,,,, +Insertion,amaz6on.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Insertion,amazton.com,,,,ns-1.amazon.com,,,, +Insertion,amaz9on.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,am2azon.com,,,,,,,, +Insertion,amazson.com,54.235.212.68,,mail.amazson.com,ns1.pql.net,,,, +Insertion,ampazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,ama1zon.com,,,,,,,, +Insertion,amlazon.com,,,,,,,, +Insertion,amawzon.com,184.168.221.15,,mailstore1.secureserver.net,ns11.domaincontrol.com,,,, +Insertion,amaz7on.com,,,,,,,, +Insertion,amazo9n.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,almazon.com,208.91.197.128,,p.webcom.ctmail.com,ns45.worldnic.com,,,, +Insertion,amazlon.com,,,,,,,, +Insertion,amaszon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amatzon.com,,,,ns-1.amazon.com,,,, +Insertion,amazopn.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amahzon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amazgon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Insertion,amaz0on.com,207.171.166.22,,,,,,, +Insertion,amazoin.com,207.171.166.22,,,,,,, +Insertion,amazaon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amaezon.com,207.171.166.22,,,,,,, +Insertion,amkazon.com,207.171.166.22,,,,,,, +Insertion,amqazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amaxzon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amauzon.com,,,,,,,, +Insertion,amazzon.com,,,,ns-1.amazon.com,,,, +Insertion,akmazon.com,,,,ns-1.amazon.com,,,, +Insertion,amazhon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amazion.com,,,,ns-1.amazon.com,,,, +Insertion,amaazon.com,,,,ns-1.amazon.com,,,, +Insertion,amazoln.com,207.171.166.22,,,,,,, +Insertion,amagzon.com,185.53.178.7,,mail.h-email.net,ns1.parkingcrew.net,,,, +Insertion,amazeon.com,208.73.210.202,,,ns1.dsredirection.com,,,, +Insertion,amaz3on.com,198.105.244.228,,,,,,, +Insertion,amzazon.com,,,,,,,, +Insertion,amazo0n.com,207.171.166.22,,,ns-1.amazon.com,,,, +Insertion,amaqzon.com,207.171.166.22,,,,,,, +Insertion,amaz2on.com,,,,,,,, +Insertion,ama7zon.com,,,,,,,, +Insertion,amazkon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Omission,amaon.com,207.171.166.22,,,,,,, +Omission,mazon.com,184.168.221.23,,mazon-com.mail.protection.outlook.com,ns05.domaincontrol.com,,,, +Omission,amzon.com,207.171.166.22,,,,,,, +Omission,aazon.com,144.76.0.242,,,ns1.ndsplitter.com,,,, +Omission,amazo.com,144.76.0.242,,,ns1.ndsplitter.com,,,, +Omission,amazn.com,207.171.166.22,,,pdns1.ultradns.net,,,, +Repetition,aamazon.com,,,,,,,, +Repetition,amazoon.com,,,,,,,, +Repetition,ammazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Replacement,amazln.com,207.171.166.22,,,,,,, +Replacement,amwzon.com,,,,pdns1.ultradns.net,,,, +Replacement,ajazon.com,,,,,,,, +Replacement,am2zon.com,198.105.244.228,,,,,,, +Replacement,amaton.com,208.91.197.26,,,,,,, +Replacement,amzzon.com,,,,,,,, +Replacement,ama3on.com,184.168.221.43,,mailstore1.secureserver.net,ns03.domaincontrol.com,,,, +Replacement,amaaon.com,72.52.4.122,,localhost,ns1.sedoparking.com,,,, +Replacement,ama2on.com,207.171.166.22,,,ns-1.amazon.com,,,, +Replacement,ama7on.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Replacement,amahon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Replacement,ymazon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Replacement,amagon.com,208.91.197.39,,,sk.s5.ans1.ns121.ztomy.com,,,, +Replacement,wmazon.com,,,,ns-1.amazon.com,,,, +Replacement,amazin.com,,,,,,,, +Replacement,amaeon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Replacement,apazon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Replacement,amazpn.com,,,,ns-1.amazon.com,,,, +Replacement,am1zon.com,216.239.32.21,2001:4860:4802:32::15,,ns-cloud-b1.googledomains.com,,,, +Replacement,amaz9n.com,,,,ns-1.amazon.com,,,, +Replacement,amazoh.com,,,,,,,, +Replacement,ama6on.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Replacement,amyzon.com,72.52.10.14,,,ns1.markmonitor.com,,,, +Replacement,amszon.com,,,,pdns1.ultradns.net,,,, +Replacement,amazob.com,207.171.166.22,,,,,,, +Replacement,1mazon.com,172.217.8.211,2607:f8b0:4009:811::2013,,,,,, +Replacement,amason.com,212.47.223.137,,smx1.web-hosting.com,dns1.namecheaphosting.com,,,, +Replacement,amauon.com,207.171.166.22,,,,,,, +Replacement,smazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Replacement,zmazon.com,,,,,,,, +Replacement,amaqon.com,,,,,,,, +Replacement,2mazon.com,198.105.244.228,,,,,,, +Replacement,akazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Subdomain,a.mazon.com,,,,,,,, +Subdomain,am.azon.com,199.16.189.254,,,,,,, +Subdomain,ama.zon.com,184.168.221.104,,,ns1.afternic.com,,,, +Subdomain,amaz.on.com,208.78.94.160,,,,,,, +Subdomain,amazo.n.com,,,,,,,, +Transposition,maazon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Transposition,aamzon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Transposition,amzaon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Transposition,amaozn.com,207.171.166.22,,,,,,, +Transposition,amazno.com,,,,ns-1.amazon.com,,,, +Vowel-swap,omazon.com,208.91.196.152,,,sk.s7.ans1.ns147.klczy.com,,,, +Vowel-swap,amuzon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Vowel-swap,amazan.com,54.255.202.167,,,ns1.meganameservers.eu,,,, +Vowel-swap,amazen.com,199.59.242.150,,mx76.m2bp.com,ns1.bodis.com,,,, +Vowel-swap,amozon.com,207.171.166.22,,,ns-1.amazon.com,,,, +Vowel-swap,amazun.com,216.21.239.197,,mail2.siteamerica.com,dns143.b.register.com,,,, +Vowel-swap,umazon.com,52.71.185.125,,,ns1.namebrightdns.com,,,, +Various,amazoncom.com,208.73.210.202,,,ns1.dsredirection.com,,,, diff --git a/metron-platform/metron-common/src/test/resources/typosquat/github.csv b/metron-platform/metron-common/src/test/resources/typosquat/github.csv new file mode 100644 index 0000000000..1965bf2fac --- /dev/null +++ b/metron-platform/metron-common/src/test/resources/typosquat/github.csv @@ -0,0 +1,227 @@ +# +# 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. +# +#fuzzer,domain-name,dns-a,dns-aaaa,dns-mx,dns-ns,geoip-country,whois-created,whois-updated,ssdeep-score +Original*,github.com,192.30.253.112,,ALT1.ASPMX.L.GOOGLE.com,ns-1283.awsdns-32.org,,,, +Addition,githuba.com,184.168.221.50,,mailstore1.secureserver.net,ns37.domaincontrol.com,,,, +Addition,githubb.com,103.16.130.124,,mail.ext.io,ns1.afraid.org,,,, +Addition,githubc.com,103.224.212.222,,mx92.m1bp.com,ns1.above.com,,,, +Addition,githubd.com,198.105.244.228,,,,,,, +Addition,githube.com,81.171.22.6,,,ns1.weaponizedcow.com,,,, +Addition,githubf.com,198.105.244.228,,,,,,, +Addition,githubg.com,198.105.244.228,,,,,,, +Addition,githubh.com,198.105.244.228,,,,,,, +Addition,githubi.com,184.168.221.50,,mailstore1.secureserver.net,ns37.domaincontrol.com,,,, +Addition,githubj.com,198.105.244.228,,,,,,, +Addition,githubk.com,198.105.244.228,,,,,,, +Addition,githubl.com,198.105.244.228,,,,,,, +Addition,githubm.com,198.105.244.228,,,,,,, +Addition,githubn.com,198.105.244.228,,,,,,, +Addition,githubo.com,119.28.71.213,,,f1g1ns1.dnspod.net,,,, +Addition,githubp.com,198.105.244.228,,,,,,, +Addition,githubq.com,54.172.109.248,,eforward1.registrar-servers.com,dns1.registrar-servers.com,,,, +Addition,githubr.com,74.208.236.31,2607:f1c0:100f:f000::252,mx00.1and1.com,ns1087.ui-dns.biz,,,, +Addition,githubs.com,162.255.119.247,,eforward1.registrar-servers.com,dns1.registrar-servers.com,,,, +Addition,githubt.com,67.227.226.240,,,ns1.parklogic.com,,,, +Addition,githubu.com,106.187.91.218,,,ns1cnb.name.com,,,, +Addition,githubv.com,,,,a.dnspod.com,,,, +Addition,githubw.com,198.105.244.228,,,,,,, +Addition,githubx.com,,,,,,,, +Addition,githuby.com,198.105.244.228,,,,,,, +Addition,githubz.com,198.105.244.228,,,,,,, +Bitsquatting,fithub.com,4.35.164.141,,alt1.aspmx.l.google.com,ns1.monikerdns.net,,,, +Bitsquatting,eithub.com,204.11.56.48,,,ns1626.ztomy.com,,,, +Bitsquatting,cithub.com,,,,,,,, +Bitsquatting,oithub.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,withub.com,23.234.4.120,,,ns1.eedns.com,,,, +Bitsquatting,ghthub.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,gkthub.com,104.18.62.97,2400:cb00:2048:1::6812:3e61,mx.yandex.ru,sue.ns.cloudflare.com,,,, +Bitsquatting,gmthub.com,49.236.200.154,,bkpmail.localdns.com,ns14.localdns.com,,,, +Bitsquatting,gathub.com,216.250.120.46,2607:f1c0:1000:70f6:8ab4:44d2:262a:e822,mx00.1and1.com,ns1028.ui-dns.biz,,,, +Bitsquatting,gythub.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,giuhub.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,givhub.com,185.53.178.7,,mail.h-email.net,ns1.parkingcrew.net,,,, +Bitsquatting,giphub.com,47.90.201.75,,smtp.giphub.com,dns7.hichina.com,,,, +Bitsquatting,gidhub.com,67.55.92.184,,mx7.gidhub.com,ns1.liverealdeals.com,,,, +Bitsquatting,gi4hub.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,gitiub.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,gitjub.com,91.134.139.14,,,ns65.domaincontrol.com,,,, +Bitsquatting,gitlub.com,166.78.103.6,,,,,,, +Bitsquatting,gitxub.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,githtb.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,githwb.com,108.59.81.6,,,,,,, +Bitsquatting,githqb.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,githeb.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,gith5b.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,githuc.com,172.246.29.53,,,juming.dnsdun.com,,,, +Bitsquatting,githuf.com,185.53.177.31,,,ns1.protectdelegation.ca,,,, +Bitsquatting,githuj.com,104.31.90.172,2400:cb00:2048:1::681f:5aac,,coco.ns.cloudflare.com,,,, +Bitsquatting,githur.com,104.27.140.182,2400:cb00:2048:1::681b:8cb6,dc-0831986e3235.githur.com,coco.ns.cloudflare.com,,,, +Homoglyph,xn--githb-oxb.com,198.105.244.228,,,,,,, +Homoglyph,xn--ithub-v1a.com,,,,,,,, +Homoglyph,xn--gitub-fye.com,198.105.244.228,,,,,,, +Homoglyph,xn--gitub-1gg.com,198.105.244.228,,,,,,, +Homoglyph,xn--ithub-72b.com,198.105.244.228,,,,,,, +Homoglyph,xn--gthub-zsa.com,,,,ns-cloud-c1.googledomains.com,,,, +Homoglyph,xn--gitub-0kf.com,198.105.244.228,,,,,,, +Homoglyph,xn--githb-bjg.com,198.105.244.228,,,,,,, +Homoglyph,xn--githu-fwe.com,198.105.244.228,,,,,,, +Homoglyph,g1thub.com,198.105.244.228,,,,,,, +Homoglyph,gitlhub.com,198.105.244.228,,,,,,, +Homoglyph,xn--githu-hwc.com,198.105.244.228,,,,,,, +Homoglyph,githuib.com,141.22.27.142,,,ns1.domaindiscount24.net,,,, +Homoglyph,xn--gitub-ify.com,198.105.244.228,,,,,,, +Homoglyph,xn--gihub-8ye.com,198.105.244.228,,,,,,, +Homoglyph,gitihub.com,173.239.5.6,,mx7.gitihub.com,ns1.expiereddnsmanager.com,,,, +Homoglyph,xn--githu-10e.com,198.105.244.228,,,,,,, +Homoglyph,xn--gthub-h9x.com,198.105.244.228,,,,,,, +Homoglyph,qithub.com,184.168.221.34,,,ns13.domaincontrol.com,,,, +Homoglyph,xn--githb-vde.com,198.105.244.228,,,,,,, +Homoglyph,xn--ithub-zyf.com,198.105.244.228,,,,,,, +Homoglyph,glthub.com,52.71.185.125,,,ns1.namebrightdns.com,,,, +Homoglyph,xn--gthub-n4a.com,,,ec2-52-42-4-3.us-west-2.compute.amazonaws.com,dns1.registrar-servers.com,,,, +Homoglyph,xn--gthub-wwb.com,198.105.244.228,,,,,,, +Homoglyph,xn--ithub-qmc.com,50.63.202.41,,mailstore1.secureserver.net,ns25.domaincontrol.com,,,, +Homoglyph,xn--gthub-y3a.com,198.105.244.228,,,,,,, +Homoglyph,xn--gthub-cta.com,162.255.119.248,,eforward1.registrar-servers.com,dns1.registrar-servers.com,,,, +Homoglyph,xn--gihub-8db.com,198.105.244.228,,,,,,, +Homoglyph,xn--gihub-nde.com,198.105.244.228,,,,,,, +Homoglyph,xn--githb-bjg.com,198.105.244.228,,,,,,, +Homoglyph,xn--ithub-71a.com,198.105.244.228,,,,,,, +Homoglyph,xn--ithub-vjg.com,198.105.244.228,,,,,,, +Homoglyph,xn--gthub-4nc.com,198.105.244.228,,,,,,, +Homoglyph,githulb.com,198.105.244.228,,,,,,, +Homoglyph,githud.com,198.105.244.228,,,,,,, +Homoglyph,xn--githb-x49a.com,69.64.147.242,,,ns1cny.name.com,,,, +Homoglyph,xn--ithub-j1a.com,198.105.244.228,,,,,,, +Homoglyph,xn--githu-hkc.com,198.105.244.228,,,,,,, +Homoglyph,xn--ithub-wmc.com,69.64.147.10,,,dns1.name-services.com,,,, +Homoglyph,xn--gthub-qbe.com,198.105.244.228,,,,,,, +Homoglyph,xn--gthub-k41s.com,198.105.244.228,,,,,,, +Homoglyph,xn--githb-cce.com,198.105.244.228,,,,,,, +Homoglyph,xn--githb-0fb.com,198.105.244.228,,,,,,, +Homoglyph,xn--github-g1d.com,198.105.244.228,,,,,,, +Homoglyph,xn--githb-zze.com,,,,,,,, +Hyphenation,g-ithub.com,198.105.244.228,,,,,,, +Hyphenation,gi-thub.com,198.105.244.228,,,,,,, +Hyphenation,git-hub.com,192.30.253.167,,,ns1.p16.dynect.net,,,, +Hyphenation,gith-ub.com,198.105.244.228,,,,,,, +Hyphenation,githu-b.com,198.105.244.228,,,,,,, +Insertion,girthub.com,209.99.40.222,,,dns10.parkpage.foundationapi.com,,,, +Insertion,githiub.com,67.227.226.240,,mx156.hostedmxserver.com,ns1.parklogic.com,,,, +Insertion,g8ithub.com,198.105.244.228,,,,,,, +Insertion,githu8b.com,198.105.244.228,,,,,,, +Insertion,giythub.com,198.105.244.228,,,,,,, +Insertion,gitbhub.com,67.55.92.182,,mx7.gitbhub.com,ns3.renewyourexpiereddomain.com,,,, +Insertion,gith8ub.com,198.105.244.228,,,,,,, +Insertion,githuyb.com,198.105.244.228,,,,,,, +Insertion,giothub.com,198.105.244.228,,,,,,, +Insertion,githyub.com,198.105.244.228,,,,,,, +Insertion,gi6thub.com,198.105.244.228,,,,,,, +Insertion,gitzhub.com,207.244.67.214,,,ns1.dnsnuts.com,,,, +Insertion,gityhub.com,,,,,,,, +Insertion,gi5thub.com,198.105.244.228,,,,,,, +Insertion,gituhub.com,69.162.80.57,,,ns1.hastydns.com,,,, +Insertion,goithub.com,,,,,,,, +Insertion,gitnhub.com,198.105.244.228,,,,,,, +Insertion,githgub.com,69.64.147.47,,,dns1.name-services.com,,,, +Insertion,githu7b.com,198.105.244.228,,,,,,, +Insertion,githnub.com,198.105.244.228,,,,,,, +Insertion,git6hub.com,198.105.244.228,,,,,,, +Insertion,githhub.com,173.239.22.42,,,ns1.mnsdnsmart.com,,,, +Insertion,guithub.com,78.41.204.28,,,ns1.torresdns.com,,,, +Insertion,githjub.com,198.105.244.228,,,,,,, +Insertion,gkithub.com,198.105.244.228,,,,,,, +Insertion,gigthub.com,198.105.244.228,,,,,,, +Insertion,githuzb.com,198.105.244.228,,,,,,, +Insertion,gi9thub.com,198.105.244.228,,,,,,, +Insertion,githuub.com,104.27.184.65,2400:cb00:2048:1::681b:b841,,april.ns.cloudflare.com,,,, +Insertion,githzub.com,198.105.244.228,,,,,,, +Insertion,gitjhub.com,198.105.244.228,,,,,,, +Insertion,gikthub.com,198.105.244.228,,,,,,, +Insertion,githujb.com,198.105.244.228,,,,,,, +Insertion,gitghub.com,185.151.28.157,2a07:7800::157,mx.stackmail.com,ns1.eco-dns.co.uk,,,, +Insertion,githbub.com,103.224.212.222,,mx92.m1bp.com,ns1.above.com,,,, +Insertion,gitrhub.com,141.8.224.93,,,ns7.rookdns.com,,,, +Insertion,gjithub.com,198.105.244.228,,,,,,, +Insertion,gizthub.com,198.105.244.228,,,,,,, +Insertion,githuhb.com,198.105.244.228,,,,,,, +Insertion,gi8thub.com,198.105.244.228,,,,,,, +Insertion,giuthub.com,95.211.219.67,,,ns1.hastydns.com,,,, +Insertion,gitfhub.com,198.105.244.228,,,,,,, +Insertion,git5hub.com,198.105.244.228,,,,,,, +Insertion,g9ithub.com,198.105.244.228,,,,,,, +Insertion,gifthub.com,176.74.176.187,,,ns1.uniregistrymarket.link,,,, +Insertion,gith7ub.com,198.105.244.228,,,,,,, +Insertion,gijthub.com,198.105.244.228,,,,,,, +Omission,gihub.com,208.73.210.202,,,ns1.dsredirection.com,,,, +Omission,githu.com,69.172.201.153,,,ns1.uniregistrymarket.link,,,, +Omission,ithub.com,,,,,,,, +Omission,gitub.com,68.178.213.61,,,ns1.namefind.com,,,, +Omission,gthub.com,72.52.179.174,,mx156.hostedmxserver.com,ns1.parklogic.com,,,, +Omission,githb.com,109.201.135.44,,,ns1.kirklanddc.com,,,, +Repetition,ggithub.com,52.69.166.231,,,,,,, +Repetition,giithub.com,199.59.242.150,,mx76.m2bp.com,ns1.bodis.com,,,, +Repetition,gitthub.com,54.71.255.210,,gitthub.com,ns3.ifund.com,,,, +Replacement,gitgub.com,,,,,,,, +Replacement,githyb.com,185.53.179.7,,mail.h-email.net,ns1.parkingcrew.net,,,, +Replacement,yithub.com,121.42.226.133,,,dns10.hichina.com,,,, +Replacement,tithub.com,176.74.176.187,,,ns1.uniregistrymarket.link,,,, +Replacement,girhub.com,173.239.22.42,,,ns1.mnsdnsmart.com,,,, +Replacement,gighub.com,,,,,,,, +Replacement,zithub.com,,,,,,,, +Replacement,gith8b.com,198.105.244.228,,,,,,, +Replacement,gityub.com,50.63.202.50,,mailstore1.secureserver.net,ns01.domaincontrol.com,,,, +Replacement,guthub.com,192.30.253.167,,,ns1.p16.dynect.net,,,, +Replacement,hithub.com,50.63.202.32,,mailstore1.secureserver.net,ns23.domaincontrol.com,,,, +Replacement,gith7b.com,107.161.23.204,,,ns1.dnsowl.com,,,, +Replacement,githjb.com,34.233.88.36,,,ns09.domaincontrol.com,,,, +Replacement,vithub.com,78.46.90.242,,mail.vithub.com,ns1.first-ns.de,,,, +Replacement,g8thub.com,107.161.23.204,,,ns1.dnsowl.com,,,, +Replacement,gifhub.com,184.168.221.23,,mailstore1.secureserver.net,ns45.domaincontrol.com,,,, +Replacement,gitnub.com,,,,ns1.dnsimple.com,,,, +Replacement,gjthub.com,98.124.245.24,,mail.b-io.co,ns1.fabulous.com,,,, +Replacement,githzb.com,198.105.244.228,,,,,,, +Replacement,githuv.com,103.224.182.239,,mx92.m1bp.com,ns1.above.com,,,, +Replacement,giyhub.com,103.224.182.239,,mx92.m1bp.com,ns1.above.com,,,, +Replacement,gothub.com,50.63.202.25,,mailstore1.secureserver.net,ns05.domaincontrol.com,,,, +Replacement,g9thub.com,198.105.244.228,,,,,,, +Replacement,gi5hub.com,107.161.23.204,,,ns1.dnsowl.com,,,, +Replacement,gizhub.com,52.216.132.18,,alt1.aspmx.l.google.com,ns-1107.awsdns-10.org,,,, +Replacement,githhb.com,198.105.244.228,,,,,,, +Replacement,githug.com,74.124.210.249,,githug.com,ns.inmotionhosting.com,,,, +Replacement,githuh.com,97.107.140.81,,,dns1.registrar-servers.com,,,, +Replacement,githun.com,185.53.179.6,,mail.h-email.net,ns1.parkingcrew.net,,,, +Replacement,bithub.com,,,,,,,, +Replacement,githib.com,,,,,,,, +Replacement,gi6hub.com,198.105.244.228,,,,,,, +Replacement,gituub.com,184.168.221.44,,mailstore1.secureserver.net,ns57.domaincontrol.com,,,, +Replacement,gitbub.com,199.59.242.150,,mx76.m2bp.com,ns1.bodis.com,,,, +Replacement,gitzub.com,198.105.244.228,,,,,,, +Subdomain,g.ithub.com,,,,,,,, +Subdomain,gi.thub.com,,,,,,,, +Subdomain,git.hub.com,,,,,,,, +Subdomain,gith.ub.com,13.228.110.155,,,,,,, +Subdomain,githu.b.com,,,,,,,, +Transposition,igthub.com,,,smtp1.phocine.net,ns1djs.name.com,,,, +Transposition,gtihub.com,199.59.242.150,,mx76.m2bp.com,ns1.bodis.com,,,, +Transposition,gihtub.com,199.59.242.150,,mx76.m2bp.com,ns1.bodis.com,,,, +Transposition,gituhb.com,103.224.182.241,,mx92.m1bp.com,ns1.above.com,,,, +Transposition,githbu.com,167.114.142.2,,,ns1.chookdns.com,,,, +Vowel-swap,githob.com,173.239.5.6,,mx7.githob.com,ns1.expiereddnsmanager.com,,,, +Vowel-swap,githab.com,72.52.4.120,,localhost,ns1.sedoparking.com,,,, +Vowel-swap,gethub.com,,,,ns.ktnet.co.kr,,,, +Various,githubcom.com,185.53.179.7,,mail.h-email.net,ns1.parkingcrew.net,,,, diff --git a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/FunctionalFunctions.java b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/FunctionalFunctions.java index d45ffcbd89..1e30daea07 100644 --- a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/FunctionalFunctions.java +++ b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/FunctionalFunctions.java @@ -41,7 +41,7 @@ public static class Map extends BaseStellarFunction { @Override public Object apply(List args) { - List input = (List) args.get(0); + Iterable input = (Iterable) args.get(0); LambdaExpression expression = (LambdaExpression)args.get(1); if(input == null || expression == null) { return input; @@ -66,7 +66,7 @@ public static class Filter extends BaseStellarFunction { @Override public Object apply(List args) { - List input = (List) args.get(0); + Iterable input = (Iterable) args.get(0); LambdaExpression expression = (LambdaExpression) args.get(1); if(input == null || expression == null) { return input; @@ -95,7 +95,7 @@ public static class Reduce extends BaseStellarFunction { @Override public Object apply(List args) { - List input = (List) args.get(0); + Iterable input = (Iterable) args.get(0); if(input == null || args.size() < 3) { return null; } @@ -105,8 +105,7 @@ public Object apply(List args) { if(expression == null || runningResult == null) { return null; } - for(int i = 0;i < input.size();++i) { - Object rhs = input.get(i); + for(Object rhs : input) { runningResult = expression.apply(listOf(runningResult, rhs)); } return runningResult; From 9c492c4540534fa72550aff330ce6c588f640965 Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 10:17:18 -0500 Subject: [PATCH 02/28] flatfile summarizer initial commit. --- .../docker/rpm-docker/SPECS/metron.spec | 1 + .../metron/common/utils/cli/CLIOptions.java | 31 +++ .../common/utils/cli/OptionHandler.java | 48 +++- .../metron/dataloads/extractor/Extractor.java | 10 +- .../extractor/ExtractorCapabilities.java | 23 ++ .../extractor/StatefulExtractor.java | 31 +++ .../TransformFilterExtractorDecorator.java | 99 ++++++-- .../nonbulk/flatfile/CommonOptions.java | 225 ++++++++++++++++++ ...torState.java => HBaseExtractorState.java} | 10 +- .../nonbulk/flatfile/LoadOptions.java | 206 ++++------------ .../flatfile/SimpleFlatFileSummarizer.java | 53 +++++ .../nonbulk/flatfile/SummarizeOptions.java | 125 ++++++++++ .../importer/AbstractLocalImporter.java | 149 ++++++++++++ .../flatfile/importer/ImportStrategy.java | 2 +- .../nonbulk/flatfile/importer/Importer.java | 4 +- .../flatfile/importer/LocalImporter.java | 161 +++++-------- .../flatfile/importer/LocalSummarizer.java | 143 +++++++++++ .../flatfile/importer/MapReduceImporter.java | 2 +- .../flatfile/importer/Summarizers.java | 46 ++++ .../nonbulk/flatfile/writer/HDFSWriter.java | 45 ++++ .../nonbulk/flatfile/writer/LocalWriter.java | 47 ++++ .../nonbulk/flatfile/writer/Writer.java | 27 +++ .../nonbulk/flatfile/writer/Writers.java | 55 +++++ .../src/main/scripts/flatfile_summarizer.sh | 51 ++++ 24 files changed, 1295 insertions(+), 299 deletions(-) create mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/utils/cli/CLIOptions.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/ExtractorCapabilities.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/StatefulExtractor.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/CommonOptions.java rename metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/{ExtractorState.java => HBaseExtractorState.java} (87%) create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizer.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SummarizeOptions.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Summarizers.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java create mode 100755 metron-platform/metron-data-management/src/main/scripts/flatfile_summarizer.sh diff --git a/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec b/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec index 82e0a23b30..6fd2f5a11a 100644 --- a/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec +++ b/metron-deployment/packaging/docker/rpm-docker/SPECS/metron.spec @@ -201,6 +201,7 @@ This package installs the Metron Parser files %{metron_home}/bin/Whois_CSV_to_JSON.py %{metron_home}/bin/geo_enrichment_load.sh %{metron_home}/bin/flatfile_loader.sh +%{metron_home}/bin/flatfile_summarizer.sh %{metron_home}/bin/prune_elasticsearch_indices.sh %{metron_home}/bin/prune_hdfs_files.sh %{metron_home}/bin/threatintel_bulk_prune.sh diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/utils/cli/CLIOptions.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/utils/cli/CLIOptions.java new file mode 100644 index 0000000000..c43b30bf86 --- /dev/null +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/utils/cli/CLIOptions.java @@ -0,0 +1,31 @@ +/** + * 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 org.apache.metron.common.utils.cli; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; + +public interface CLIOptions & CLIOptions> { + Option getOption(); + + boolean has(CommandLine cli); + + String get(CommandLine cli); + + OptionHandler getHandler(); +} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/utils/cli/OptionHandler.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/utils/cli/OptionHandler.java index 85e752018c..6dfebb88a5 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/utils/cli/OptionHandler.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/utils/cli/OptionHandler.java @@ -18,14 +18,56 @@ package org.apache.metron.common.utils.cli; import com.google.common.base.Function; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.Option; +import com.google.common.base.Joiner; +import org.apache.commons.cli.*; +import java.util.EnumMap; import java.util.Optional; -public abstract class OptionHandler> implements Function +public abstract class OptionHandler & CLIOptions> implements Function { public Optional getValue(OPT_T option, CommandLine cli) { return Optional.empty(); } + + public abstract String getShortCode(); + + public static Options getOptions(CLIOptions[] values) { + Options ret = new Options(); + for(CLIOptions o : values) { + ret.addOption(o.getOption()); + } + return ret; + } + + public static void printHelp(String name, CLIOptions[] values) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp( name, getOptions(values)); + } + + public static & CLIOptions> + EnumMap > createConfig(CommandLine cli, OPT_T[] values, Class clazz) { + EnumMap > ret = new EnumMap<>(clazz); + for(OPT_T option : values) { + ret.put(option, option.getHandler().getValue(option, cli)); + } + return ret; + } + + public static CommandLine parse(String name, CommandLineParser parser, String[] args, CLIOptions[] values, CLIOptions helpOption) { + try { + CommandLine cli = parser.parse(getOptions(values), args); + if(helpOption.has(cli)) { + printHelp(name, values); + System.exit(0); + } + return cli; + } catch (ParseException e) { + System.err.println("Unable to parse args: " + Joiner.on(' ').join(args)); + e.printStackTrace(System.err); + printHelp(name, values); + System.exit(-1); + return null; + } + } } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/Extractor.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/Extractor.java index bd490c8fb6..7fd2741ac1 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/Extractor.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/Extractor.java @@ -20,9 +20,15 @@ import org.apache.metron.enrichment.lookup.LookupKV; import java.io.IOException; +import java.util.Collections; +import java.util.EnumSet; import java.util.Map; +import java.util.Set; public interface Extractor { - Iterable extract(String line) throws IOException; - void initialize(Map config); + Iterable extract(String line) throws IOException; + void initialize(Map config); + default Set getCapabilities() { + return EnumSet.noneOf(ExtractorCapabilities.class); + } } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/ExtractorCapabilities.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/ExtractorCapabilities.java new file mode 100644 index 0000000000..91c62323d6 --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/ExtractorCapabilities.java @@ -0,0 +1,23 @@ +/** + * 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 org.apache.metron.dataloads.extractor; + +public enum ExtractorCapabilities { + STATEFUL, + MERGEABLE; +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/StatefulExtractor.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/StatefulExtractor.java new file mode 100644 index 0000000000..df2334d33d --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/StatefulExtractor.java @@ -0,0 +1,31 @@ +/** + * 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 org.apache.metron.dataloads.extractor; + +import org.apache.metron.enrichment.lookup.LookupKV; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +public interface StatefulExtractor extends Extractor { + Object initializeState(Map config); + Object mergeStates(List states); + Iterable extract(String line, AtomicReference state) throws IOException; +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/TransformFilterExtractorDecorator.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/TransformFilterExtractorDecorator.java index 790ea9f402..c47dfc61bd 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/TransformFilterExtractorDecorator.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/extractor/TransformFilterExtractorDecorator.java @@ -17,22 +17,15 @@ */ package org.apache.metron.dataloads.extractor; -import static org.apache.metron.dataloads.extractor.TransformFilterExtractorDecorator.ExtractorOptions.INDICATOR; -import static org.apache.metron.dataloads.extractor.TransformFilterExtractorDecorator.ExtractorOptions.INDICATOR_FILTER; -import static org.apache.metron.dataloads.extractor.TransformFilterExtractorDecorator.ExtractorOptions.INDICATOR_TRANSFORM; -import static org.apache.metron.dataloads.extractor.TransformFilterExtractorDecorator.ExtractorOptions.VALUE_FILTER; -import static org.apache.metron.dataloads.extractor.TransformFilterExtractorDecorator.ExtractorOptions.VALUE_TRANSFORM; -import static org.apache.metron.dataloads.extractor.TransformFilterExtractorDecorator.ExtractorOptions.ZK_QUORUM; - import com.fasterxml.jackson.core.type.TypeReference; import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.invoke.MethodHandles; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.lang.ref.Reference; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +import com.google.common.collect.ImmutableMap; import org.apache.commons.lang.StringUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.metron.common.configuration.ConfigurationsUtils; @@ -47,8 +40,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class TransformFilterExtractorDecorator extends ExtractorDecorator { +import static org.apache.metron.dataloads.extractor.TransformFilterExtractorDecorator.ExtractorOptions.*; + +public class TransformFilterExtractorDecorator extends ExtractorDecorator implements StatefulExtractor { private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + public static final String STATE_KEY = "state"; + public static final String STATES_KEY = "states"; + protected enum ExtractorOptions { VALUE_TRANSFORM("value_transform"), @@ -56,7 +54,10 @@ protected enum ExtractorOptions { INDICATOR_TRANSFORM("indicator_transform"), INDICATOR_FILTER("indicator_filter"), ZK_QUORUM("zk_quorum"), - INDICATOR("indicator"); + INDICATOR("indicator"), + STATE_INIT("state_init"), + STATE_UPDATE("state_update"), + STATE_MERGE("state_merge"); private String key; @@ -83,6 +84,9 @@ public boolean existsIn(Map config) { private StellarProcessor transformProcessor; private StellarPredicateProcessor filterProcessor; private Map globalConfig; + private Map stateUpdate; + private String stateMerge; + private Set capabilities; public TransformFilterExtractorDecorator(Extractor decoratedExtractor) { super(decoratedExtractor); @@ -91,8 +95,11 @@ public TransformFilterExtractorDecorator(Extractor decoratedExtractor) { this.indicatorTransforms = new LinkedHashMap<>(); this.valueFilter = ""; this.indicatorFilter = ""; + this.stateUpdate = new LinkedHashMap<>(); + this.stateMerge = ""; this.transformProcessor = new StellarProcessor(); this.filterProcessor = new StellarPredicateProcessor(); + this.capabilities = EnumSet.noneOf(ExtractorCapabilities.class); } @Override @@ -110,6 +117,17 @@ public void initialize(Map config) { if (INDICATOR_FILTER.existsIn(config)) { this.indicatorFilter = getFilter(config, INDICATOR_FILTER.toString()); } + if (STATE_UPDATE.existsIn(config)) { + capabilities.add(ExtractorCapabilities.STATEFUL); + this.stateUpdate = getTransforms(config, STATE_UPDATE.toString()); + } + if(STATE_INIT.existsIn(config)) { + capabilities.add(ExtractorCapabilities.STATEFUL); + } + if (STATE_MERGE.existsIn(config)) { + capabilities.add(ExtractorCapabilities.MERGEABLE); + this.stateMerge = getFilter(config, STATE_MERGE.toString()); + } String zkClientUrl = ""; if (ZK_QUORUM.existsIn(config)) { zkClientUrl = ConversionUtils.convert(config.get(ZK_QUORUM.toString()), String.class); @@ -120,6 +138,29 @@ public void initialize(Map config) { StellarFunctions.initialize(stellarContext); this.transformProcessor = new StellarProcessor(); this.filterProcessor = new StellarPredicateProcessor(); + + } + + @Override + public Object initializeState(Map config) { + if(STATE_INIT.existsIn(config)) { + MapVariableResolver resolver = new MapVariableResolver(globalConfig); + return transformProcessor.parse( config.get(STATE_INIT.toString()).toString() + , resolver + , StellarFunctions.FUNCTION_RESOLVER() + , stellarContext + ); + } + return null; + } + + @Override + public Object mergeStates(List states) { + return transformProcessor.parse( stateMerge + , new MapVariableResolver(new HashMap() {{ put(STATES_KEY, states); }}, globalConfig) + , StellarFunctions.FUNCTION_RESOLVER() + , stellarContext + ); } private String getFilter(Map config, String valueFilter) { @@ -186,11 +227,21 @@ private Context createContext(Optional zkClient) { return builder.build(); } + @Override + public Set getCapabilities() { + return capabilities; + } + @Override public Iterable extract(String line) throws IOException { + return extract(line, new AtomicReference<>(null)); + } + + @Override + public Iterable extract(String line, AtomicReference state) throws IOException { List lkvs = new ArrayList<>(); for (LookupKV lkv : super.extract(line)) { - if (updateLookupKV(lkv)) { + if (updateLookupKV(lkv, state)) { lkvs.add(lkv); } } @@ -202,23 +253,30 @@ public Iterable extract(String line) throws IOException { * @param lkv LookupKV to transform and filter * @return true if lkv is not null after transform/filter */ - private boolean updateLookupKV(LookupKV lkv) { + private boolean updateLookupKV(LookupKV lkv, AtomicReference state) { Map ret = lkv.getValue().getMetadata(); Map ind = new LinkedHashMap<>(); String indicator = lkv.getKey().getIndicator(); // add indicator as a resolvable variable. Also enable using resolved/transformed variables and values from operating on the value metadata ind.put(INDICATOR.toString(), indicator); - MapVariableResolver resolver = new MapVariableResolver(ret, ind, globalConfig); + Map stateMap = new LinkedHashMap<>(); + stateMap.put(STATE_KEY, state.get()); + MapVariableResolver resolver = new MapVariableResolver(ret, ind, globalConfig, stateMap); transform(valueTransforms, ret, resolver); transform(indicatorTransforms, ind, resolver); // update indicator Object updatedIndicator = ind.get(INDICATOR.toString()); - if (updatedIndicator != null) { + if (updatedIndicator != null || getCapabilities().contains(ExtractorCapabilities.STATEFUL)) { if (!(updatedIndicator instanceof String)) { throw new UnsupportedOperationException("Indicator transform must return String type"); } lkv.getKey().setIndicator((String) updatedIndicator); - return filter(indicatorFilter, resolver) && filter(valueFilter, resolver); + boolean update = filter(indicatorFilter, resolver) && filter(valueFilter, resolver); + if(update && !stateUpdate.isEmpty()) { + transform(stateUpdate, stateMap, resolver); + state.set(stateMap.get(STATE_KEY)); + } + return update; } else { return false; } @@ -236,6 +294,9 @@ private void transform(Map transforms, Map varia } private Boolean filter(String filterPredicate, MapVariableResolver variableResolver) { + if(StringUtils.isEmpty(filterPredicate)) { + return true; + } return filterProcessor.parse(filterPredicate, variableResolver, StellarFunctions.FUNCTION_RESOLVER(), stellarContext); } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/CommonOptions.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/CommonOptions.java new file mode 100644 index 0000000000..a55d69d646 --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/CommonOptions.java @@ -0,0 +1,225 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile; + +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.io.FileUtils; +import org.apache.metron.common.utils.cli.CLIOptions; +import org.apache.metron.common.utils.cli.OptionHandler; +import org.apache.metron.stellar.common.utils.ConversionUtils; + +import javax.annotation.Nullable; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public class CommonOptions { + public static class Help & CLIOptions> extends OptionHandler { + + @Override + public String getShortCode() { + return "h"; + } + + + @Nullable + @Override + public Option apply(@Nullable String input) { + return new Option(getShortCode(), "help", false, "Generate Help screen"); + } + } + + public static class Quiet & CLIOptions> extends OptionHandler { + + @Override + public String getShortCode() { + return "q"; + } + + @Nullable + @Override + public Option apply(@Nullable String input) { + return new Option(getShortCode(), "quiet", false, "Do not update progress"); + } + + @Override + public Optional getValue(OPT_T option, CommandLine cli) { + return Optional.of(option.has(cli)); + } + } + + public static class ImportMode & CLIOptions> extends OptionHandler { + Object[] importModes; + Object defaultMode; + Function> resolver; + public ImportMode(Object[] importModes, Object defaultMode, Function> resolver) { + this.importModes = importModes; + this.defaultMode = defaultMode; + this.resolver = resolver; + } + + @Override + public String getShortCode() { + return "m"; + } + + @Nullable + @Override + public Option apply(@Nullable String input) { + Option o = new Option(getShortCode(), "import_mode", true + , "The Import mode to use: " + Joiner.on(",").join(importModes) + + ". Default: " +defaultMode + ); + o.setArgName("MODE"); + o.setRequired(false); + return o; + } + + @Override + public Optional getValue(OPT_T option, CommandLine cli) { + String mode = option.get(cli); + return resolver.apply(mode); + } + } + + public static class ExtractorConfig & CLIOptions> extends OptionHandler { + @Nullable + @Override + public Option apply(@Nullable String s) { + Option o = new Option(s, "extractor_config", true, "JSON Document describing the extractor for this input data source"); + o.setArgName("JSON_FILE"); + o.setRequired(true); + return o; + } + + @Override + public Optional getValue(OPT_T option, CommandLine cli) { + try { + return Optional.ofNullable(FileUtils.readFileToString(new File(option.get(cli).trim()))); + } catch (IOException e) { + throw new IllegalStateException("Unable to retrieve extractor config from " + option.get(cli) + ": " + e.getMessage(), e); + } + } + + @Override + public String getShortCode() { + return "e"; + } + } + + + public static class Log4jProperties & CLIOptions> extends OptionHandler { + @Nullable + @Override + public Option apply(@Nullable String s) { + Option o = new Option(s, "log4j", true, "The log4j properties file to load"); + o.setArgName("FILE"); + o.setRequired(false); + return o; + } + + @Override + public String getShortCode() { + return "l"; + } + } + + + public static class NumThreads & CLIOptions> extends OptionHandler { + + @Nullable + @Override + public Option apply(@Nullable String s) { + Option o = new Option(s, "threads", true, "The number of threads to use when extracting data. The default is the number of cores of your machine."); + o.setArgName("NUM_THREADS"); + o.setRequired(false); + return o; + } + + @Override + public Optional getValue(OPT_T option, CommandLine cli) { + int numThreads = Runtime.getRuntime().availableProcessors(); + if(option.has(cli)) { + numThreads = ConversionUtils.convert(option.get(cli), Integer.class); + } + return Optional.of(numThreads); + } + + @Override + public String getShortCode() { + return "p"; + } + } + + public static class BatchSize & CLIOptions> extends OptionHandler { + + @Nullable + @Override + public Option apply(@Nullable String s) { + Option o = new Option(s, "batchSize", true, "The batch size to use for HBase puts"); + o.setArgName("SIZE"); + o.setRequired(false); + return o; + } + + @Override + public Optional getValue(OPT_T option, CommandLine cli) { + int batchSize = 128; + if(option.has(cli)) { + batchSize = ConversionUtils.convert(option.get(cli), Integer.class); + } + return Optional.of(batchSize); + } + + @Override + public String getShortCode() { + return "b"; + } + } + + public static class Input & CLIOptions> extends OptionHandler { + @Nullable + @Override + public Option apply(@Nullable String s) { + Option o = new Option(s, "input", true, "The CSV File to load"); + o.setArgName("FILE"); + o.setRequired(true); + return o; + } + + @Override + public Optional getValue(OPT_T option, CommandLine cli) { + List inputs = new ArrayList<>(); + for(String input : Splitter.on(",").split(Optional.ofNullable(option.get(cli)).orElse(""))) { + inputs.add(input.trim()); + } + return Optional.of(inputs); + } + + @Override + public String getShortCode() { + return "i"; + } + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/ExtractorState.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/HBaseExtractorState.java similarity index 87% rename from metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/ExtractorState.java rename to metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/HBaseExtractorState.java index 168d251da3..f0ee3ad7d6 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/ExtractorState.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/HBaseExtractorState.java @@ -25,16 +25,18 @@ import java.io.IOException; -public class ExtractorState { +public class HBaseExtractorState { private HTableInterface table; private Extractor extractor; private HbaseConverter converter; private FileSystem fs; + private String cf; - public ExtractorState(HTableInterface table, Extractor extractor, HbaseConverter converter, Configuration config) { + public HBaseExtractorState(HTableInterface table, String cf, Extractor extractor, HbaseConverter converter, Configuration config) { this.table = table; this.extractor = extractor; this.converter = converter; + this.cf = cf; try { this.fs = FileSystem.get(config); } catch (IOException e) { @@ -42,6 +44,10 @@ public ExtractorState(HTableInterface table, Extractor extractor, HbaseConverter } } + public String getCf() { + return cf; + } + public HTableInterface getTable() { return table; } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/LoadOptions.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/LoadOptions.java index 448f406817..2967c6d45b 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/LoadOptions.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/LoadOptions.java @@ -21,6 +21,7 @@ import com.google.common.base.Splitter; import org.apache.commons.cli.*; import org.apache.commons.io.FileUtils; +import org.apache.metron.common.utils.cli.CLIOptions; import org.apache.metron.stellar.common.utils.ConversionUtils; import org.apache.metron.common.utils.cli.OptionHandler; import org.apache.metron.dataloads.nonbulk.flatfile.importer.ImportStrategy; @@ -33,48 +34,14 @@ import java.util.List; import java.util.Optional; -public enum LoadOptions { - HELP("h", new OptionHandler() { - - @Nullable - @Override - public Option apply(@Nullable String s) { - return new Option(s, "help", false, "Generate Help screen"); - } - }) - ,QUIET("q", new OptionHandler() { - - @Nullable - @Override - public Option apply(@Nullable String s) { - return new Option(s, "quiet", false, "Do not update progress"); - } - - @Override - public Optional getValue(LoadOptions option, CommandLine cli) { - return Optional.of(option.has(cli)); - } - }) - , IMPORT_MODE("m", new OptionHandler() { - @Nullable - @Override - public Option apply(@Nullable String s) { - Option o = new Option(s, "import_mode", true - , "The Import mode to use: " + Joiner.on(",").join(ImportStrategy.values()) - + ". Default: " + ImportStrategy.LOCAL - ); - o.setArgName("MODE"); - o.setRequired(false); - return o; - } - - @Override - public Optional getValue(LoadOptions option, CommandLine cli) { - String mode = option.get(cli); - return Optional.of(ImportStrategy.getStrategy(mode).orElse(ImportStrategy.LOCAL)); - } - }) - ,HBASE_TABLE("t", new OptionHandler() { +public enum LoadOptions implements CLIOptions { + HELP(new CommonOptions.Help<> ()) + ,QUIET(new CommonOptions.Quiet<>()) + , IMPORT_MODE(new CommonOptions.ImportMode<>( ImportStrategy.values() + , ImportStrategy.LOCAL + , mode -> Optional.ofNullable(ImportStrategy.getStrategy(mode).orElse(ImportStrategy.LOCAL))) + ) + ,HBASE_TABLE(new OptionHandler() { @Nullable @Override public Option apply(@Nullable String s) { @@ -88,8 +55,13 @@ public Option apply(@Nullable String s) { public Optional getValue(LoadOptions option, CommandLine cli) { return Optional.ofNullable(option.get(cli).trim()); } + + @Override + public String getShortCode() { + return "t"; + } }) - ,HBASE_CF("c", new OptionHandler() { + ,HBASE_CF(new OptionHandler() { @Nullable @Override public Option apply(@Nullable String s) { @@ -103,27 +75,19 @@ public Option apply(@Nullable String s) { public Optional getValue(LoadOptions option, CommandLine cli) { return Optional.ofNullable(option.get(cli).trim()); } - }) - ,EXTRACTOR_CONFIG("e", new OptionHandler() { - @Nullable - @Override - public Option apply(@Nullable String s) { - Option o = new Option(s, "extractor_config", true, "JSON Document describing the extractor for this input data source"); - o.setArgName("JSON_FILE"); - o.setRequired(true); - return o; - } @Override - public Optional getValue(LoadOptions option, CommandLine cli) { - try { - return Optional.ofNullable(FileUtils.readFileToString(new File(option.get(cli).trim()))); - } catch (IOException e) { - throw new IllegalStateException("Unable to retrieve extractor config from " + option.get(cli) + ": " + e.getMessage(), e); - } + public String getShortCode() { + return "c"; } }) - ,ENRICHMENT_CONFIG("n", new OptionHandler() { + ,EXTRACTOR_CONFIG(new CommonOptions.ExtractorConfig<>()) + ,ENRICHMENT_CONFIG(new OptionHandler() { + @Override + public String getShortCode() { + return "n"; + } + @Nullable @Override public Option apply(@Nullable String s) { @@ -136,126 +100,46 @@ public Option apply(@Nullable String s) { return o; } }) - ,LOG4J_PROPERTIES("l", new OptionHandler() { - @Nullable - @Override - public Option apply(@Nullable String s) { - Option o = new Option(s, "log4j", true, "The log4j properties file to load"); - o.setArgName("FILE"); - o.setRequired(false); - return o; - } - }) - ,NUM_THREADS("p", new OptionHandler() { - @Nullable - @Override - public Option apply(@Nullable String s) { - Option o = new Option(s, "threads", true, "The number of threads to use when extracting data. The default is the number of cores of your machine."); - o.setArgName("NUM_THREADS"); - o.setRequired(false); - return o; - } - - @Override - public Optional getValue(LoadOptions option, CommandLine cli) { - int numThreads = Runtime.getRuntime().availableProcessors(); - if(option.has(cli)) { - numThreads = ConversionUtils.convert(option.get(cli), Integer.class); - } - return Optional.of(numThreads); - } - }) - ,BATCH_SIZE("b", new OptionHandler() { - @Nullable - @Override - public Option apply(@Nullable String s) { - Option o = new Option(s, "batchSize", true, "The batch size to use for HBase puts"); - o.setArgName("SIZE"); - o.setRequired(false); - return o; - } - - @Override - public Optional getValue(LoadOptions option, CommandLine cli) { - int batchSize = 128; - if(option.has(cli)) { - batchSize = ConversionUtils.convert(option.get(cli), Integer.class); - } - return Optional.of(batchSize); - } - }) - ,INPUT("i", new OptionHandler() { - @Nullable - @Override - public Option apply(@Nullable String s) { - Option o = new Option(s, "input", true, "The CSV File to load"); - o.setArgName("FILE"); - o.setRequired(true); - return o; - } - - @Override - public Optional getValue(LoadOptions option, CommandLine cli) { - List inputs = new ArrayList<>(); - for(String input : Splitter.on(",").split(Optional.ofNullable(option.get(cli)).orElse(""))) { - inputs.add(input.trim()); - } - return Optional.of(inputs); - } - }) + ,LOG4J_PROPERTIES(new CommonOptions.Log4jProperties<>()) + ,NUM_THREADS(new CommonOptions.NumThreads<>()) + ,BATCH_SIZE(new CommonOptions.BatchSize<>()) + ,INPUT(new CommonOptions.Input<>()) ; Option option; String shortCode; OptionHandler handler; - LoadOptions(String shortCode, OptionHandler optionHandler) { - this.shortCode = shortCode; + LoadOptions(OptionHandler optionHandler) { + this.shortCode = optionHandler.getShortCode(); this.handler = optionHandler; this.option = optionHandler.apply(shortCode); } + @Override + public OptionHandler getHandler() { + return handler; + } + + + @Override + public Option getOption() { + return option; + } + + @Override public boolean has(CommandLine cli) { return cli.hasOption(shortCode); } + @Override public String get(CommandLine cli) { return cli.getOptionValue(shortCode); } public static CommandLine parse(CommandLineParser parser, String[] args) { - try { - CommandLine cli = parser.parse(getOptions(), args); - if(HELP.has(cli)) { - printHelp(); - System.exit(0); - } - return cli; - } catch (ParseException e) { - System.err.println("Unable to parse args: " + Joiner.on(' ').join(args)); - e.printStackTrace(System.err); - printHelp(); - System.exit(-1); - return null; - } + return OptionHandler.parse("SimpleEnrichmentFlatFileLoader", parser, args, values(), HELP); } public static EnumMap > createConfig(CommandLine cli) { - EnumMap > ret = new EnumMap<>(LoadOptions.class); - for(LoadOptions option : values()) { - ret.put(option, option.handler.getValue(option, cli)); - } - return ret; - } - - public static void printHelp() { - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp( "SimpleEnrichmentFlatFileLoader", getOptions()); - } - - public static Options getOptions() { - Options ret = new Options(); - for(LoadOptions o : LoadOptions.values()) { - ret.addOption(o.option); - } - return ret; + return OptionHandler.createConfig(cli, values(), LoadOptions.class); } } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizer.java new file mode 100644 index 0000000000..1cd1abf0f6 --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizer.java @@ -0,0 +1,53 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.PosixParser; +import org.apache.commons.io.FileUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.util.GenericOptionsParser; +import org.apache.log4j.PropertyConfigurator; +import org.apache.metron.dataloads.extractor.ExtractorHandler; +import org.apache.metron.dataloads.nonbulk.flatfile.importer.Summarizers; + +import java.io.File; +import java.util.EnumMap; +import java.util.Optional; + +public class SimpleFlatFileSummarizer { + public static void main(String... argv) throws Exception { + Configuration hadoopConfig = HBaseConfiguration.create(); + String[] otherArgs = new GenericOptionsParser(hadoopConfig, argv).getRemainingArgs(); + main(hadoopConfig, otherArgs); + } + + public static void main(Configuration hadoopConfig, String[] argv) throws Exception { + CommandLine cli = SummarizeOptions.parse(new PosixParser(), argv); + EnumMap> config = SummarizeOptions.createConfig(cli); + if(SummarizeOptions.LOG4J_PROPERTIES.has(cli)) { + PropertyConfigurator.configure(SummarizeOptions.LOG4J_PROPERTIES.get(cli)); + } + ExtractorHandler handler = ExtractorHandler.load( + FileUtils.readFileToString(new File(SummarizeOptions.EXTRACTOR_CONFIG.get(cli).trim())) + ); + Summarizers strategy = (Summarizers) config.get(SummarizeOptions.IMPORT_MODE).get(); + strategy.getSummarizer().importData(config, handler, hadoopConfig); + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SummarizeOptions.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SummarizeOptions.java new file mode 100644 index 0000000000..8d9ec2cfce --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SummarizeOptions.java @@ -0,0 +1,125 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile; + +import com.google.common.base.Joiner; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.metron.common.utils.cli.CLIOptions; +import org.apache.metron.common.utils.cli.OptionHandler; +import org.apache.metron.dataloads.nonbulk.flatfile.importer.Summarizers; +import org.apache.metron.dataloads.nonbulk.flatfile.writer.Writers; + +import javax.annotation.Nullable; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Optional; + +public enum SummarizeOptions implements CLIOptions { + HELP(new CommonOptions.Help<>()) + ,QUIET(new CommonOptions.Quiet<>()) + , IMPORT_MODE(new CommonOptions.ImportMode<>(Summarizers.values(), Summarizers.LOCAL, mode -> Optional.of(Summarizers.getStrategy(mode).orElse(Summarizers.LOCAL)))) + , OUTPUT_MODE(new OptionHandler() { + @Nullable + @Override + public Option apply(@Nullable String s) { + Option o = new Option(s, "output_mode", true + , "The output mode to use: " + Joiner.on(",").join(Writers.values()) + + ". Default: " + Writers.LOCAL + ); + o.setArgName("MODE"); + o.setRequired(false); + return o; + } + + @Override + public Optional getValue(SummarizeOptions option, CommandLine cli) { + String mode = option.get(cli); + return Optional.of(Writers.getStrategy(mode).orElse(Writers.LOCAL)); + } + + @Override + public String getShortCode() { + return "om"; + } + }) + ,EXTRACTOR_CONFIG(new CommonOptions.ExtractorConfig<>()) + ,LOG4J_PROPERTIES(new CommonOptions.Log4jProperties<>()) + ,NUM_THREADS(new CommonOptions.NumThreads<>()) + ,BATCH_SIZE(new CommonOptions.BatchSize<>()) + ,INPUT(new CommonOptions.Input<>()) + ,OUTPUT(new OptionHandler() { + @Nullable + @Override + public Option apply(@Nullable String s) { + Option o = new Option(s, "output", true, "The output file to write"); + o.setArgName("FILE"); + o.setRequired(true); + return o; + } + + @Override + public Optional getValue(SummarizeOptions option, CommandLine cli) { + return Optional.ofNullable(option.get(cli)); + } + + @Override + public String getShortCode() { + return "o"; + } + }) + ; + Option option; + String shortCode; + OptionHandler handler; + SummarizeOptions(OptionHandler optionHandler) { + this.shortCode = optionHandler.getShortCode(); + this.handler = optionHandler; + this.option = optionHandler.apply(shortCode); + } + + @Override + public OptionHandler getHandler() { + return handler; + } + + public Option getOption() { + return option; + } + + public boolean has(CommandLine cli) { + return cli.hasOption(shortCode); + } + + public String get(CommandLine cli) { + return cli.getOptionValue(shortCode); + } + + public static CommandLine parse(CommandLineParser parser, String[] args) { + return OptionHandler.parse("SimpleFlatFileSummarizer", parser, args, values(), HELP); + } + + public static EnumMap > createConfig(CommandLine cli) { + return OptionHandler.createConfig(cli, values(), SummarizeOptions.class); + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java new file mode 100644 index 0000000000..67569589da --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java @@ -0,0 +1,149 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.importer; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.metron.common.utils.file.ReaderSpliterator; +import org.apache.metron.dataloads.extractor.ExtractorHandler; +import org.apache.metron.dataloads.extractor.inputformat.WholeFileFormat; +import org.apache.metron.common.utils.cli.CLIOptions; +import org.apache.metron.dataloads.nonbulk.flatfile.LoadOptions; +import org.apache.metron.dataloads.nonbulk.flatfile.location.Location; +import org.apache.metron.dataloads.nonbulk.flatfile.location.LocationStrategy; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ForkJoinPool; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public abstract class AbstractLocalImporter & CLIOptions, STATE_T> implements Importer { + + @Override + public void importData( final EnumMap> config + , final ExtractorHandler handler + , final Configuration hadoopConfig + ) throws IOException { + validateState(config, handler); + ThreadLocal state = createState(config, hadoopConfig, handler); + boolean quiet = isQuiet(config); + boolean lineByLine = !handler.getInputFormat().getClass().equals(WholeFileFormat.class); + List inputs = getInputs(config); + FileSystem fs = FileSystem.get(hadoopConfig); + if(!lineByLine) { + extractWholeFiles(inputs, fs, state, quiet); + } + else { + int batchSize = batchSize(config); + int numThreads = numThreads(config, handler); + extractLineByLine(inputs, fs, state, batchSize, numThreads, quiet); + } + } + + protected abstract List getInputs(final EnumMap> config); + protected abstract boolean isQuiet(final EnumMap> config); + protected abstract int batchSize(final EnumMap> config); + protected abstract int numThreads(final EnumMap> config, ExtractorHandler handler); + + protected abstract void validateState(final EnumMap> config + ,final ExtractorHandler handler + ); + + protected abstract ThreadLocal createState( final EnumMap> config + , final Configuration hadoopConfig + , final ExtractorHandler handler + ); + + protected abstract void extract(STATE_T state + , String line + ) throws IOException; + + public void extractLineByLine( List inputs + , FileSystem fs + , ThreadLocal state + , int batchSize + , int numThreads + , boolean quiet + ) throws IOException { + inputs.stream().map(input -> LocationStrategy.getLocation(input, fs)) + .forEach( loc -> { + final Progress progress = new Progress(); + if(!quiet) { + System.out.println("\nProcessing " + loc.toString()); + } + try (Stream stream = ReaderSpliterator.lineStream(loc.openReader(), batchSize)) { + ForkJoinPool forkJoinPool = new ForkJoinPool(numThreads); + forkJoinPool.submit(() -> + stream.parallel().forEach(input -> { + try { + extract(state.get(), input); + if (!quiet) { + progress.update(); + } + } + catch(IOException e) { + throw new IllegalStateException("Unable to continue: " + e.getMessage(), e); + } + } + ) + ).get(); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + ); + } + + public void extractWholeFiles(List inputs, FileSystem fs, ThreadLocal state, boolean quiet) throws IOException { + final Progress progress = new Progress(); + final List locations = new ArrayList<>(); + Location.fileVisitor(inputs, loc -> locations.add(loc), fs); + locations.parallelStream().forEach(loc -> { + try(BufferedReader br = loc.openReader()) { + String s = br.lines().collect(Collectors.joining()); + extract(state.get(), s); + if(!quiet) { + progress.update(); + } + } catch (IOException e) { + throw new IllegalStateException("Unable to read " + loc + ": " + e.getMessage(), e); + } + }); + } + + public static class Progress { + private int count = 0; + private String anim= "|/-\\"; + + public synchronized void update() { + int currentCount = count++; + System.out.print("\rProcessed " + currentCount + " - " + anim.charAt(currentCount % anim.length())); + } + } + + protected void assertOption(EnumMap> config, OPTIONS_T option) { + if(!config.containsKey(option)) { + throw new IllegalStateException("Expected " + option.getOption().getOpt() + " to be set"); + } + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/ImportStrategy.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/ImportStrategy.java index df88640335..7730bb8367 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/ImportStrategy.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/ImportStrategy.java @@ -20,7 +20,7 @@ import java.util.Optional; public enum ImportStrategy { - LOCAL(LocalImporter.INSTANCE), + LOCAL(new LocalImporter()), MR(MapReduceImporter.INSTANCE) ; private Importer importer; diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Importer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Importer.java index 81ede088e1..89101efab2 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Importer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Importer.java @@ -29,6 +29,6 @@ import java.util.List; import java.util.Optional; -public interface Importer { - void importData(EnumMap> config, ExtractorHandler handler , final Configuration hadoopConfig) throws IOException; +public interface Importer> { + void importData(EnumMap> config, ExtractorHandler handler , final Configuration hadoopConfig) throws IOException; } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalImporter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalImporter.java index 652a4c3284..ec37585d40 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalImporter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalImporter.java @@ -18,17 +18,12 @@ package org.apache.metron.dataloads.nonbulk.flatfile.importer; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.hbase.client.HTableInterface; import org.apache.hadoop.hbase.client.Put; -import org.apache.metron.common.utils.file.ReaderSpliterator; import org.apache.metron.dataloads.extractor.Extractor; import org.apache.metron.dataloads.extractor.ExtractorHandler; -import org.apache.metron.dataloads.extractor.inputformat.WholeFileFormat; -import org.apache.metron.dataloads.nonbulk.flatfile.ExtractorState; +import org.apache.metron.dataloads.nonbulk.flatfile.HBaseExtractorState; import org.apache.metron.dataloads.nonbulk.flatfile.LoadOptions; -import org.apache.metron.dataloads.nonbulk.flatfile.location.Location; -import org.apache.metron.dataloads.nonbulk.flatfile.location.LocationStrategy; import org.apache.metron.enrichment.converter.EnrichmentConverter; import org.apache.metron.enrichment.converter.HbaseConverter; import org.apache.metron.enrichment.lookup.LookupKV; @@ -36,119 +31,82 @@ import java.io.*; import java.util.*; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; -public enum LocalImporter implements Importer { - INSTANCE; +public class LocalImporter extends AbstractLocalImporter { public interface HTableProviderRetriever { HTableProvider retrieve(); } + HTableProviderRetriever provider; + + public LocalImporter(HTableProviderRetriever provider) { + this.provider = provider; + } + + public LocalImporter() { + this(() -> new HTableProvider()); + } + + + @Override + protected List getInputs(EnumMap> config) { + return (List) config.get(LoadOptions.INPUT).get(); + } + + @Override + protected boolean isQuiet(EnumMap> config) { + return (boolean) config.get(LoadOptions.QUIET).get(); + } @Override - public void importData( final EnumMap> config - , final ExtractorHandler handler - , final Configuration hadoopConfig - ) throws IOException { - importData(config, handler, hadoopConfig, () -> new HTableProvider()); + protected int batchSize(EnumMap> config) { + return (int) config.get(LoadOptions.BATCH_SIZE).get(); + } + @Override + protected int numThreads(EnumMap> config, ExtractorHandler handler) { + return (int) config.get(LoadOptions.NUM_THREADS).get(); } - public void importData( final EnumMap> config - , final ExtractorHandler handler - , final Configuration hadoopConfig - , final HTableProviderRetriever provider - ) throws IOException { - ThreadLocal state = new ThreadLocal() { + + @Override + protected void validateState(EnumMap> config, ExtractorHandler handler) { + assertOption(config, LoadOptions.HBASE_CF); + assertOption(config, LoadOptions.HBASE_TABLE); + } + + + + @Override + protected ThreadLocal createState(EnumMap> config + , Configuration hadoopConfig + , final ExtractorHandler handler + ) { + ThreadLocal state = new ThreadLocal() { @Override - protected ExtractorState initialValue() { + protected HBaseExtractorState initialValue() { try { + String cf = (String) config.get(LoadOptions.HBASE_CF).get(); HTableInterface table = provider.retrieve().getTable(hadoopConfig, (String) config.get(LoadOptions.HBASE_TABLE).get()); - return new ExtractorState(table, handler.getExtractor(), new EnrichmentConverter(), hadoopConfig); + return new HBaseExtractorState(table, cf, handler.getExtractor(), new EnrichmentConverter(), hadoopConfig); } catch (IOException e1) { throw new IllegalStateException("Unable to get table: " + e1); } } }; - boolean quiet = (boolean) config.get(LoadOptions.QUIET).get(); - boolean lineByLine = !handler.getInputFormat().getClass().equals(WholeFileFormat.class); - List inputs = (List) config.get(LoadOptions.INPUT).get(); - String cf = (String) config.get(LoadOptions.HBASE_CF).get(); - if(!lineByLine) { - extractWholeFiles(inputs, state, cf, quiet); - } - else { - int batchSize = (int) config.get(LoadOptions.BATCH_SIZE).get(); - int numThreads = (int) config.get(LoadOptions.NUM_THREADS).get(); - extractLineByLine(inputs, state, cf, batchSize, numThreads, quiet); - } - + return state; } - public void extractLineByLine( List inputs - , ThreadLocal state - , String cf - , int batchSize - , int numThreads - , boolean quiet - ) throws IOException { - inputs.stream().map(input -> LocationStrategy.getLocation(input, state.get().getFileSystem())) - .forEach( loc -> { - final Progress progress = new Progress(); - if(!quiet) { - System.out.println("\nProcessing " + loc.toString()); - } - try (Stream stream = ReaderSpliterator.lineStream(loc.openReader(), batchSize)) { - ForkJoinPool forkJoinPool = new ForkJoinPool(numThreads); - forkJoinPool.submit(() -> - stream.parallel().forEach(input -> { - ExtractorState es = state.get(); - try { - es.getTable().put(extract(input, es.getExtractor(), cf, es.getConverter(), progress, quiet)); - } catch (IOException e) { - throw new IllegalStateException("Unable to continue: " + e.getMessage(), e); - } - } - ) - ).get(); - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - ); - } - - public void extractWholeFiles( List inputs, ThreadLocal state, String cf, boolean quiet) throws IOException { - final Progress progress = new Progress(); - final List locations = new ArrayList<>(); - Location.fileVisitor(inputs, loc -> locations.add(loc), state.get().getFileSystem()); - locations.parallelStream().forEach(loc -> { - try(BufferedReader br = loc.openReader()) { - String s = br.lines().collect(Collectors.joining()); - state.get().getTable().put(extract( s - , state.get().getExtractor() - , cf, state.get().getConverter() - , progress - , quiet - ) - ); - } catch (IOException e) { - throw new IllegalStateException("Unable to read " + loc + ": " + e.getMessage(), e); - } - }); + @Override + protected void extract(HBaseExtractorState state, String line) throws IOException { + HBaseExtractorState es = state; + es.getTable().put(toPut(line, es.getExtractor(), state.getCf(), es.getConverter())); } - - public List extract(String line + public List toPut(String line , Extractor extractor , String cf , HbaseConverter converter - , final Progress progress - , final boolean quiet ) throws IOException { List ret = new ArrayList<>(); @@ -157,21 +115,8 @@ public List extract(String line Put put = converter.toPut(cf, kv.getKey(), kv.getValue()); ret.add(put); } - if(!quiet) { - progress.update(); - } - return ret; - } - - public static class Progress { - private int count = 0; - private String anim= "|/-\\"; - - public synchronized void update() { - int currentCount = count++; - System.out.print("\rProcessed " + currentCount + " - " + anim.charAt(currentCount % anim.length())); - } + return ret; } } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java new file mode 100644 index 0000000000..289d2c2c0f --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java @@ -0,0 +1,143 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.importer; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.metron.common.utils.SerDeUtils; +import org.apache.metron.dataloads.extractor.ExtractorCapabilities; +import org.apache.metron.dataloads.extractor.ExtractorHandler; +import org.apache.metron.dataloads.extractor.StatefulExtractor; +import org.apache.metron.dataloads.nonbulk.flatfile.SummarizeOptions; +import org.apache.metron.dataloads.nonbulk.flatfile.writer.Writers; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicReference; + +public class LocalSummarizer extends AbstractLocalImporter { + List stateList; + + public LocalSummarizer() { + stateList = Collections.synchronizedList(new ArrayList<>()); + } + + public static class SummarizationState { + AtomicReference state; + StatefulExtractor extractor; + public SummarizationState(StatefulExtractor extractor, Object initState) { + this.state = new AtomicReference<>(initState); + this.extractor = extractor; + } + + public AtomicReference getState() { + return state; + } + + public StatefulExtractor getExtractor() { + return extractor; + } + + } + + @Override + protected boolean isQuiet(EnumMap> config) { + return (boolean) config.get(SummarizeOptions.QUIET).get(); + } + + @Override + protected int batchSize(EnumMap> config) { + return (int) config.get(SummarizeOptions.BATCH_SIZE).get(); + } + + @Override + protected int numThreads(EnumMap> config, ExtractorHandler handler) { + if(handler.getExtractor().getCapabilities().contains(ExtractorCapabilities.MERGEABLE)) { + return (int) config.get(SummarizeOptions.NUM_THREADS).get(); + } + else { + //force one thread in the case it's not mergeable. + return 1; + } + } + + @Override + protected void validateState(EnumMap> config, ExtractorHandler handler) { + if(!(handler.getExtractor() instanceof StatefulExtractor)){ + throw new IllegalStateException("Extractor must be a stateful extractor and " + handler.getExtractor().getClass().getName() + " is not."); + } + assertOption(config, SummarizeOptions.OUTPUT); + if(!handler.getExtractor().getCapabilities().contains(ExtractorCapabilities.STATEFUL)) { + throw new IllegalStateException("Unable to operate on a non-stateful extractor. " + + "If you have not specified \"stateUpdate\" in your Extractor config, there is nothing to do here and nothing will be written."); + } + + } + + @Override + protected ThreadLocal createState(EnumMap> config, Configuration hadoopConfig, ExtractorHandler handler) { + final StatefulExtractor extractor = (StatefulExtractor)handler.getExtractor(); + return ThreadLocal.withInitial(() -> { + Object initState = extractor.initializeState(handler.getConfig()); + SummarizationState ret = new SummarizationState(extractor, initState); + stateList.add(ret); + return ret; + }); + } + + + @Override + protected void extract(SummarizationState state, String line) throws IOException { + state.getExtractor().extract(line, state.getState()); + } + + @Override + public void importData(EnumMap> config, ExtractorHandler handler, Configuration hadoopConfig) throws IOException { + Writers writer = (Writers) config.get(SummarizeOptions.OUTPUT_MODE).get(); + String fileName = (String)config.get(SummarizeOptions.OUTPUT).get(); + writer.validate(fileName, hadoopConfig); + super.importData(config, handler, hadoopConfig); + StatefulExtractor extractor = (StatefulExtractor) handler.getExtractor(); + Object finalState = null; + if(stateList.size() == 1) { + finalState = stateList.get(0).getState().get(); + } + else if(stateList.size() > 1) { + List states = new ArrayList<>(); + for(SummarizationState s : stateList) { + states.add(s.getState().get()); + } + finalState = extractor.mergeStates(states); + } + if(finalState != null) { + byte[] serializedState = SerDeUtils.toBytes(finalState); + writer.write(serializedState, (String)config.get(SummarizeOptions.OUTPUT).get(), hadoopConfig); + } + } + + @Override + protected List getInputs(EnumMap> config) { + return (List) config.get(SummarizeOptions.INPUT).get(); + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/MapReduceImporter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/MapReduceImporter.java index 401ace2055..1b34ed48a1 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/MapReduceImporter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/MapReduceImporter.java @@ -38,7 +38,7 @@ import org.slf4j.LoggerFactory; -public enum MapReduceImporter implements Importer{ +public enum MapReduceImporter implements Importer { INSTANCE ; diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Summarizers.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Summarizers.java new file mode 100644 index 0000000000..180aa23c89 --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Summarizers.java @@ -0,0 +1,46 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.importer; + +import java.util.Optional; + +public enum Summarizers { + LOCAL(new LocalSummarizer()); + + private Importer importer; + + Summarizers(Importer importer) { + this.importer = importer; + } + + public Importer getSummarizer() { + return importer; + } + + public static Optional getStrategy(String strategyName) { + if(strategyName == null) { + return Optional.empty(); + } + for(Summarizers strategy : values()) { + if(strategy.name().equalsIgnoreCase(strategyName.trim())) { + return Optional.of(strategy); + } + } + return Optional.empty(); + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java new file mode 100644 index 0000000000..7e93fafa68 --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java @@ -0,0 +1,45 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.writer; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FSDataOutputStream; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; + +import java.io.IOException; + +public class HDFSWriter implements Writer { + @Override + public void validate(String fileName, Configuration hadoopConfig) { + if(StringUtils.isEmpty(fileName) || fileName.trim().equals(".") || fileName.trim().equals("..") || fileName.trim().endsWith("/")) { + throw new IllegalStateException("Filename is empty or otherwise invalid."); + } + } + + @Override + public void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException { + FileSystem fs = FileSystem.get(hadoopConfig); + try(FSDataOutputStream stream = fs.create(new Path(output))) { + IOUtils.write(obj, stream); + stream.flush(); + } + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java new file mode 100644 index 0000000000..9c9e85e75d --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java @@ -0,0 +1,47 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.writer; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.hadoop.conf.Configuration; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +public class LocalWriter implements Writer { + @Override + public void validate(String fileName, Configuration hadoopConfig) { + if(StringUtils.isEmpty(fileName) || fileName.trim().equals(".") || fileName.trim().equals("..") || fileName.trim().endsWith("/")) { + throw new IllegalStateException("Filename is empty or otherwise invalid."); + } + } + + @Override + public void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException { + File outFile = new File(output); + if(!outFile.getParentFile().exists()) { + outFile.getParentFile().mkdirs(); + } + try(FileOutputStream fs = new FileOutputStream(outFile)) { + IOUtils.write(obj, fs); + fs.flush(); + } + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java new file mode 100644 index 0000000000..7c67bcf35a --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java @@ -0,0 +1,27 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.writer; + +import org.apache.hadoop.conf.Configuration; + +import java.io.IOException; + +public interface Writer { + void validate(String output, Configuration hadoopConfig); + void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException; +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java new file mode 100644 index 0000000000..f72e527117 --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java @@ -0,0 +1,55 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.writer; + +import org.apache.hadoop.conf.Configuration; + +import java.io.IOException; +import java.util.Optional; + +public enum Writers implements Writer { + LOCAL(new LocalWriter()), + HDFS(new HDFSWriter()) + ; + private Writer writer; + + Writers(Writer writer) { + this.writer = writer; + } + public static Optional getStrategy(String strategyName) { + if(strategyName == null) { + return Optional.empty(); + } + for(Writers strategy : values()) { + if(strategy.name().equalsIgnoreCase(strategyName.trim())) { + return Optional.of(strategy); + } + } + return Optional.empty(); + } + + @Override + public void validate(String output, Configuration hadoopConf) { + writer.validate(output, hadoopConf); + } + + @Override + public void write(byte[] obj, String output, Configuration hadoopConf) throws IOException { + writer.write(obj, output, hadoopConf); + } +} diff --git a/metron-platform/metron-data-management/src/main/scripts/flatfile_summarizer.sh b/metron-platform/metron-data-management/src/main/scripts/flatfile_summarizer.sh new file mode 100755 index 0000000000..018d61aae4 --- /dev/null +++ b/metron-platform/metron-data-management/src/main/scripts/flatfile_summarizer.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# 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. +# + +BIGTOP_DEFAULTS_DIR=${BIGTOP_DEFAULTS_DIR-/etc/default} +[ -n "${BIGTOP_DEFAULTS_DIR}" -a -r ${BIGTOP_DEFAULTS_DIR}/hbase ] && . ${BIGTOP_DEFAULTS_DIR}/hbase + +# Autodetect JAVA_HOME if not defined +if [ -e /usr/libexec/bigtop-detect-javahome ]; then + . /usr/libexec/bigtop-detect-javahome +elif [ -e /usr/lib/bigtop-utils/bigtop-detect-javahome ]; then + . /usr/lib/bigtop-utils/bigtop-detect-javahome +fi + +export METRON_VERSION=${project.version} +export METRON_HOME=/usr/metron/$METRON_VERSION +export CLASSNAME="org.apache.metron.dataloads.nonbulk.flatfile.SimpleFlatFileSummarizer" +export DM_JAR=${project.artifactId}-$METRON_VERSION.jar +export HBASE_HOME=${HBASE_HOME:-/usr/hdp/current/hbase-client} +export HADOOP_OPTS="$HADOOP_OPTS $METRON_JVMFLAGS" +if [ $(which hadoop) ] +then + HADOOP_CLASSPATH=${HBASE_HOME}/lib/hbase-server.jar:`${HBASE_HOME}/bin/hbase classpath` + for jar in $(echo $HADOOP_CLASSPATH | sed 's/:/ /g');do + if [ -f $jar ];then + LIBJARS="$jar,$LIBJARS" + fi + done + export HADOOP_CLASSPATH + hadoop jar $METRON_HOME/lib/$DM_JAR $CLASSNAME -libjars ${LIBJARS} "$@" +else + echo "Warning: Metron cannot find the hadoop client on this node. This means that loading via Map Reduce will NOT function." + CP=$METRON_HOME/lib/$DM_JAR:/usr/metron/${METRON_VERSION}/lib/taxii-1.1.0.1.jar:`${HBASE_HOME}/bin/hbase classpath` + java $METRON_JVMFLAGS -cp $CP $CLASSNAME "$@" +fi + From 71e63b2604ad94c51423762582e547184169d8a2 Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 10:20:48 -0500 Subject: [PATCH 03/28] Don't want to generate original domain as it's not a typosquatted domain --- .../common/typosquat/OriginalStrategy.java | 35 ------------------- .../typosquat/TyposquattingStrategies.java | 1 - .../TyposquattingStrategiesTest.java | 1 + 3 files changed, 1 insertion(+), 36 deletions(-) delete mode 100644 metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OriginalStrategy.java diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OriginalStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OriginalStrategy.java deleted file mode 100644 index d700792ef4..0000000000 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OriginalStrategy.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * 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 org.apache.metron.common.typosquat; - -import java.util.HashSet; -import java.util.Set; - -public class OriginalStrategy implements TyposquattingStrategy { - @Override - public Set generateCandidates(String domain) { - Set ret = new HashSet<>(); - ret.add(domain); - return ret; - } - - @Override - public String name() { - return "Original*"; - } -} diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java index a8fa9e42ed..45d17e5181 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java @@ -38,7 +38,6 @@ public enum TyposquattingStrategies implements TyposquattingStrategy { SUBDOMAIN(new SubdomainStrategy()), TRANSPOSITION(new TranspositionStrategy()), VOWELSWAP(new VowelSwapStrategy()), - ORIGINAL(new OriginalStrategy()) ; TyposquattingStrategy strategy; TyposquattingStrategies(TyposquattingStrategy strategy) { diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java index b3d3de22a0..91824207c1 100644 --- a/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java +++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java @@ -43,6 +43,7 @@ public class TyposquattingStrategiesTest { */ static Set typesToSkip = new HashSet() {{ add("Various"); + add("Original*"); }}; //These are the output from DNS Twist ( https://github.com/elceef/dnstwist ). We want to ensure we match their output at minimum From 42af879d5fc1623fd9b24dd24af687292d9bcc73 Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 11:20:10 -0500 Subject: [PATCH 04/28] Fixed homoglyph bug with ACE domains --- .../common/typosquat/HomoglyphStrategy.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java index 39d8bcbeca..a781f825f1 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java @@ -18,6 +18,7 @@ package org.apache.metron.common.typosquat; import com.google.common.collect.ImmutableList; +import org.apache.commons.lang3.StringUtils; import java.net.IDN; import java.util.*; @@ -55,15 +56,23 @@ public class HomoglyphStrategy implements TyposquattingStrategy{ public static f @Override public Set generateCandidates(String originalString) { Set result = new HashSet<>(); - for(int ws = 0;ws < originalString.length();ws++) { - for(int i = 0;i < originalString.length() - ws + 1;++i) { - String win = originalString.substring(i, i+ws); + String domain = originalString; + if(StringUtils.isEmpty(domain)) { + return result; + } + if(domain.startsWith("xn--")) { + //this is an ace domain. + domain = IDN.toUnicode(domain); + } + for(int ws = 0;ws < domain.length();ws++) { + for(int i = 0;i < domain.length() - ws + 1;++i) { + String win = domain.substring(i, i+ws); for(int j = 0;j < ws;j++) { char c = win.charAt(j); if( glyphs.containsKey(c)) { for( String g : glyphs.get(c)) { String winNew = win.replaceAll("" + c, g); - String d = originalString.substring(0, i) + winNew + originalString.substring(i + ws); + String d = domain.substring(0, i) + winNew + domain.substring(i + ws); String dAscii = IDN.toASCII(d, IDN.ALLOW_UNASSIGNED); result.add(d); if(!d.equals(dAscii)) { From 7ee3ab14b81b0cb3fd899cf082050b7e3fade63e Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 12:04:58 -0500 Subject: [PATCH 05/28] Persistent bug.. --- .../metron/common/typosquat/HomoglyphStrategy.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java index a781f825f1..b0f0483a87 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java @@ -60,7 +60,7 @@ public Set generateCandidates(String originalString) { if(StringUtils.isEmpty(domain)) { return result; } - if(domain.startsWith("xn--")) { + if(isAce(domain)) { //this is an ace domain. domain = IDN.toUnicode(domain); } @@ -73,10 +73,12 @@ public Set generateCandidates(String originalString) { for( String g : glyphs.get(c)) { String winNew = win.replaceAll("" + c, g); String d = domain.substring(0, i) + winNew + domain.substring(i + ws); - String dAscii = IDN.toASCII(d, IDN.ALLOW_UNASSIGNED); result.add(d); - if(!d.equals(dAscii)) { - result.add(dAscii); + if(!isAce(d)) { + String dAscii = IDN.toASCII(d, IDN.ALLOW_UNASSIGNED); + if (!d.equals(dAscii)) { + result.add(dAscii); + } } } } @@ -86,6 +88,10 @@ public Set generateCandidates(String originalString) { return result; } + public static boolean isAce(String domain) { + return domain.startsWith("xn--"); + } + @Override public String name() { return "Homoglyph"; From 15681143e86913a692777770d0a89e1c877e3d99 Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 13:50:58 -0500 Subject: [PATCH 06/28] typo --- .../dataloads/nonbulk/flatfile/importer/LocalSummarizer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java index 289d2c2c0f..c752010dc8 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java @@ -25,6 +25,7 @@ import org.apache.metron.dataloads.extractor.ExtractorHandler; import org.apache.metron.dataloads.extractor.StatefulExtractor; import org.apache.metron.dataloads.nonbulk.flatfile.SummarizeOptions; +import org.apache.metron.dataloads.nonbulk.flatfile.writer.Writer; import org.apache.metron.dataloads.nonbulk.flatfile.writer.Writers; import java.io.File; @@ -114,7 +115,7 @@ protected void extract(SummarizationState state, String line) throws IOException @Override public void importData(EnumMap> config, ExtractorHandler handler, Configuration hadoopConfig) throws IOException { - Writers writer = (Writers) config.get(SummarizeOptions.OUTPUT_MODE).get(); + Writer writer = (Writer) config.get(SummarizeOptions.OUTPUT_MODE).get(); String fileName = (String)config.get(SummarizeOptions.OUTPUT).get(); writer.validate(fileName, hadoopConfig); super.importData(config, handler, hadoopConfig); From 0d1e7b304b926bae65a2d6b4c63dec565542ad7e Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 13:51:50 -0500 Subject: [PATCH 07/28] Weirdness with international domains. --- .../common/typosquat/HomoglyphStrategy.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java index b0f0483a87..bec152f0ae 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java @@ -19,11 +19,17 @@ import com.google.common.collect.ImmutableList; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.lang.invoke.MethodHandles; import java.net.IDN; import java.util.*; -public class HomoglyphStrategy implements TyposquattingStrategy{ public static final Map> glyphs = new HashMap>() +public class HomoglyphStrategy implements TyposquattingStrategy{ + + private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + public static final Map> glyphs = new HashMap>() {{ put('a', ImmutableList.of("à", "á", "â", "ã", "ä", "å", "ɑ", "а", "ạ", "ǎ", "ă", "ȧ", "ӓ")); put('b', ImmutableList.of("d", "lb", "ib", "ʙ", "Ь", "b̔", "ɓ", "Б")); @@ -75,9 +81,14 @@ public Set generateCandidates(String originalString) { String d = domain.substring(0, i) + winNew + domain.substring(i + ws); result.add(d); if(!isAce(d)) { - String dAscii = IDN.toASCII(d, IDN.ALLOW_UNASSIGNED); - if (!d.equals(dAscii)) { - result.add(dAscii); + try { + String dAscii = IDN.toASCII(d, IDN.ALLOW_UNASSIGNED); + if (!d.equals(dAscii)) { + result.add(dAscii); + } + } + catch(IllegalArgumentException iae) { + LOG.debug("Unable to parse " + d + ": " + iae.getMessage(), iae); } } } @@ -88,8 +99,9 @@ public Set generateCandidates(String originalString) { return result; } - public static boolean isAce(String domain) { - return domain.startsWith("xn--"); + public static boolean isAce(String domainRaw) { + String domain = domainRaw.toLowerCase(); + return domain.startsWith("xn--") || domain.contains(".xn--"); } @Override From 935d4d2933e7156219722e54cec5dfce228fdbcc Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 16:17:23 -0500 Subject: [PATCH 08/28] Updating tests and docs. --- .../metron-data-management/README.md | 101 +++++- .../importer/AbstractLocalImporter.java | 15 +- .../flatfile/importer/LocalSummarizer.java | 17 +- .../nonbulk/flatfile/writer/Writer.java | 6 + ...mpleFlatFileSummarizerIntegrationTest.java | 292 ++++++++++++++++++ .../dsl/functions/NetworkFunctions.java | 9 +- 6 files changed, 424 insertions(+), 16 deletions(-) create mode 100644 metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerIntegrationTest.java diff --git a/metron-platform/metron-data-management/README.md b/metron-platform/metron-data-management/README.md index c351f48e29..bf6ea89aee 100644 --- a/metron-platform/metron-data-management/README.md +++ b/metron-platform/metron-data-management/README.md @@ -165,12 +165,15 @@ As an example, we will be providing a CSV list of top domains as an enrichment a There are 2 property maps that work with full Stellar expressions, and 2 properties that will work with Stellar predicates. -| Property | Description -|---------------------|--- -| value_transform | Transform fields defined in the "columns" mapping with Stellar transformations. New keys introduced in the transform will be added to the key metadata. -| value_filter | Allows additional filtering with Stellar predicates based on results from the value transformations. In this example, records whose domain property is empty after removing the TLD will be omitted. -| indicator_transform | Transform the indicator column independent of the value transformations. You can refer to the original indicator value by using "indicator" as the variable name, as shown in the example above. In addition, if you prefer to piggyback your transformations, you can refer to the variable "domain", which will allow your indicator transforms to inherit transformations done to this value during the value transformations. -| indicator_filter | Allows additional filtering with Stellar predicates based on results from the value transformations. In this example, records whose indicator value is empty after removing the TLD will be omitted. +| Property | Description +|----------------------|--- +| `value_transform` | Transform fields defined in the "columns" mapping with Stellar transformations. New keys introduced in the transform will be added to the key metadata. +| `value_filter` | Allows additional filtering with Stellar predicates based on results from the value transformations. In this example, records whose domain property is empty after removing the TLD will be omitted. +| `indicator_transform`| Transform the indicator column independent of the value transformations. You can refer to the original indicator value by using "indicator" as the variable name, as shown in the example above. In addition, if you prefer to piggyback your transformations, you can refer to the variable "domain", which will allow your indicator transforms to inherit transformations done to this value during the value transformations. +| `indicator_filter` | Allows additional filtering with Stellar predicates based on results from the value transformations. In this example, records whose indicator value is empty after removing the TLD will be omitted. +| `state_init` | Allows a state object to be initialized. This is a string, so a single expression is created. The output of this expression will be available as the `state` variable. This is to be used with the `flatfile_summarizer.sh` rather than the loader. +| `state_update` | Allows a state object to be updated. This is a map, so you can have temporary variables here. Note that you can reference the `state` variable from this. This is to be used with the `flatfile_summarizer.sh` rather than the loader. +| `state_merge` | Allows a list of states to be merged. This is a string, so a single expression. There is a special field called `states` available, which is a list of the states (one per thread). This is to be used with the `flatfile_summarizer.sh` rather than the loader. top-list.csv ``` @@ -337,3 +340,89 @@ The parameters for the utility are as follows: | -r | --remote_dir | No | HDFS directory to land formatted GeoIP file - defaults to /apps/metron/geo/\/ | | -t | --tmp_dir | No | Directory for landing the temporary GeoIP data - defaults to /tmp | | -z | --zk_quorum | Yes | Zookeeper Quorum URL (zk1:port,zk2:port,...) | + +### Flatfile Summarizer + +The shell script `$METRON_HOME/bin/flatfile_summarizer.sh` will read data from local disk, HDFS or URLs and generate a summary object. +The object will be serialized and written to disk, either HDFS or local disk depending on the output mode specified. + +It should be noted that this utility uses the same extractor config as the `flatfile_loader.sh`, +but as the output target is not a key value store (but rather a summary object), it is not necessary +to specify certain configs: +* `indicator`, `indicator_filter` and `indicator_transform` are not required, but will be executed if present. +As in the loader, there will be an indicator field available if you so specify it (by using `indicator` in the config). +* `type` is neither required nor used + +Indeed, some new configs are expected: +* `state_init` : Executed once to initialize the state object (the object written out). +* `state_update`: Called once per message. The fields available are the fields for the row as well as + * `indicator` - the indicator value if you've specified it in the config + * `state` - the current state. Useful for adding to the state (e.g. `BLOOM_ADD(state, val)` where `val` is the name of a field). +* `state_merge` : If you are running this multi-threaded and your objects can be merged, this is the statement that will +merge the state objects created per thread. There is a special field available to this config: + * `states` - a list of the state objects + +One special thing to note here is that there is a special configuration +parameter to the Extractor config that is only considered during this +loader: +* inputFormat : This specifies how to consider the data. The two implementations are `BY_LINE` and `WHOLE_FILE`. + +The default is `BY_LINE`, which makes sense for a list of CSVs where +each line indicates a unit of information which can be imported. +However, if you are importing a set of STIX documents, then you want +each document to be considered as input to the Extractor. + +#### Example + +Consider the possibility that you want to generate a bloom filter with all of the domains in a CSV structured similarly to +the Alexa top 1M domains, so the columns are: +* rank +* domain name + +You want to generate a bloom filter with just the domains, not considering the TLD. +You would execute the following to: +* read data from `./top-1m.csv` +* write data to `./filter.ser` +* use 5 threads + +``` +$METRON_HOME/bin/flatfile_summarizer.sh -i ./top-1m.csv -o ./filter.ser -e ./extractor.json -p 5 -b 128 +``` + +To configure this, `extractor.json` would look like: +``` +{ + "config" : { + "columns" : { + "rank" : 0, + "domain" : 1 + }, + "value_transform" : { + "domain" : "DOMAIN_REMOVE_TLD(domain)" + }, + "value_filter" : "LENGTH(domain) > 0", + "state_init" : "BLOOM_INIT()", + "state_update" : { + "state" : "BLOOM_ADD(state, domain)" + }, + "state_merge" : "BLOOM_MERGE(states)", + "separator" : "," + }, + "extractor" : "CSV" +} +``` + +The parameters for the utility are as follows: + +| Short Code | Long Code | Is Required? | Description | +|------------|---------------------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| -h | | No | Generate the help screen/set of options | +| -q | --quiet | No | Do not update progress | +| -e | --extractor_config | Yes | JSON Document describing the extractor for this input data source | +| -m | --import_mode | No | The Import mode to use: LOCAL, MR. Default: LOCAL | +| -om | --output_mode | No | The Output mode to use: LOCAL, HDFS. Default: LOCAL | +| -i | --input | Yes | The input data location on local disk. If this is a file, then that file will be loaded. If this is a directory, then the files will be loaded recursively under that directory. | +| -i | --output | Yes | The output data location. | +| -l | --log4j | No | The log4j properties file to load | +| -p | --threads | No | The number of threads to use when extracting data. The default is the number of cores. | +| -b | --batchSize | No | The batch size to use for HBase puts | diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java index 67569589da..8b11f5ea16 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java @@ -78,6 +78,10 @@ protected abstract void extract(STATE_T state , String line ) throws IOException; + protected Location resolveLocation(String input, FileSystem fs) { + return LocationStrategy.getLocation(input, fs); + } + public void extractLineByLine( List inputs , FileSystem fs , ThreadLocal state @@ -85,7 +89,7 @@ public void extractLineByLine( List inputs , int numThreads , boolean quiet ) throws IOException { - inputs.stream().map(input -> LocationStrategy.getLocation(input, fs)) + inputs.stream().map(input -> resolveLocation(input, fs)) .forEach( loc -> { final Progress progress = new Progress(); if(!quiet) { @@ -116,8 +120,7 @@ public void extractLineByLine( List inputs public void extractWholeFiles(List inputs, FileSystem fs, ThreadLocal state, boolean quiet) throws IOException { final Progress progress = new Progress(); - final List locations = new ArrayList<>(); - Location.fileVisitor(inputs, loc -> locations.add(loc), fs); + final List locations = getLocationsRecursive(inputs, fs); locations.parallelStream().forEach(loc -> { try(BufferedReader br = loc.openReader()) { String s = br.lines().collect(Collectors.joining()); @@ -131,6 +134,12 @@ public void extractWholeFiles(List inputs, FileSystem fs, ThreadLocal getLocationsRecursive(List inputs, FileSystem fs) throws IOException { + final List locations = new ArrayList<>(); + Location.fileVisitor(inputs, loc -> locations.add(loc), fs); + return locations; + } + public static class Progress { private int count = 0; private String anim= "|/-\\"; diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java index c752010dc8..28073a351d 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java @@ -17,6 +17,7 @@ */ package org.apache.metron.dataloads.nonbulk.flatfile.importer; +import com.google.common.collect.ImmutableList; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; @@ -64,12 +65,12 @@ public StatefulExtractor getExtractor() { @Override protected boolean isQuiet(EnumMap> config) { - return (boolean) config.get(SummarizeOptions.QUIET).get(); + return (boolean) config.getOrDefault(SummarizeOptions.QUIET, Optional.of(false)).get(); } @Override protected int batchSize(EnumMap> config) { - return (int) config.get(SummarizeOptions.BATCH_SIZE).get(); + return (int) config.getOrDefault(SummarizeOptions.BATCH_SIZE, Optional.of(1)).get(); } @Override @@ -131,14 +132,18 @@ else if(stateList.size() > 1) { } finalState = extractor.mergeStates(states); } - if(finalState != null) { - byte[] serializedState = SerDeUtils.toBytes(finalState); - writer.write(serializedState, (String)config.get(SummarizeOptions.OUTPUT).get(), hadoopConfig); - } + writer.write(finalState, (String)config.get(SummarizeOptions.OUTPUT).get(), hadoopConfig); } @Override protected List getInputs(EnumMap> config) { + Object o = config.get(SummarizeOptions.INPUT).get(); + if(o == null) { + return new ArrayList<>(); + } + if(o instanceof String) { + return ImmutableList.of((String)o); + } return (List) config.get(SummarizeOptions.INPUT).get(); } } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java index 7c67bcf35a..bf41bfdcbb 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java @@ -18,10 +18,16 @@ package org.apache.metron.dataloads.nonbulk.flatfile.writer; import org.apache.hadoop.conf.Configuration; +import org.apache.metron.common.utils.SerDeUtils; import java.io.IOException; public interface Writer { void validate(String output, Configuration hadoopConfig); + default void write(Object obj, String output, Configuration hadoopConfig) throws IOException { + if(obj != null) { + write(SerDeUtils.toBytes(obj), output, hadoopConfig); + } + } void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException; } diff --git a/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerIntegrationTest.java b/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerIntegrationTest.java new file mode 100644 index 0000000000..cfc9a8d431 --- /dev/null +++ b/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerIntegrationTest.java @@ -0,0 +1,292 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.adrianwalker.multilinestring.Multiline; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.PosixParser; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.util.GenericOptionsParser; +import org.apache.metron.dataloads.extractor.ExtractorHandler; +import org.apache.metron.dataloads.nonbulk.flatfile.importer.LocalSummarizer; +import org.apache.metron.dataloads.nonbulk.flatfile.location.Location; +import org.apache.metron.dataloads.nonbulk.flatfile.location.RawLocation; +import org.apache.metron.dataloads.nonbulk.flatfile.writer.Writer; +import org.apache.metron.stellar.common.utils.StellarProcessorUtils; +import org.junit.Assert; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +public class SimpleFlatFileSummarizerIntegrationTest { + /** + { + "config" : { + "columns" : { + "rank" : 0, + "domain" : 1 + }, + "value_transform" : { + "domain" : "DOMAIN_REMOVE_TLD(domain)" + }, + "value_filter" : "LENGTH(domain) > 0", + "state_init" : "MULTISET_INIT()", + "state_update" : { + "state" : "MULTISET_ADD(state, domain)" + }, + "state_merge" : "MULTISET_MERGE(states)", + "separator" : "," + }, + "extractor" : "CSV" + } + */ + @Multiline + public static String stellarExtractorConfigLineByLine; + + /** + { + "config" : { + "columns" : { + "rank" : 0, + "domain" : 1 + }, + "value_transform" : { + "domain" : "DOMAIN_REMOVE_TLD(domain)" + }, + "value_filter" : "LENGTH(domain) > 0", + "state_init" : "MULTISET_INIT()", + "state_update" : { + "state" : "MULTISET_ADD(state, domain)" + }, + "state_merge" : "MULTISET_MERGE(states)", + "separator" : "," + }, + "extractor" : "CSV", + "inputFormat" : "WHOLE_FILE" + } + */ + @Multiline + public static String stellarExtractorConfigWholeFile; + + + public static List domains = ImmutableList.of( + "google.com", + "youtube.com", + "facebook.com", + "baidu.com", + "wikipedia.org", + "yahoo.com", + "google.co.in", + "reddit.com", + "qq.com", + "amazon.com", + "taobao.com", + "tmall.com", + "twitter.com", + "live.com", + "vk.com", + "google.co.jp", + "instagram.com", + "sohu.com", + "sina.com.cn", + "jd.com" + ); + + public static String generateData() { + List tmp = new ArrayList<>(); + int i = 1; + for(String d : domains) { + tmp.add(i + "," + d); + } + return Joiner.on("\n").join(tmp); + } + + @Test + public void testArgs() throws Exception { + String[] argv = { "-e extractor.json" + , "-o out.ser" + , "-l log4j", "-i input.csv" + , "-p 2", "-b 128", "-q" + }; + + Configuration config = new Configuration(); + String[] otherArgs = new GenericOptionsParser(config, argv).getRemainingArgs(); + + CommandLine cli = SummarizeOptions.parse(new PosixParser(), otherArgs); + Assert.assertEquals("extractor.json", SummarizeOptions.EXTRACTOR_CONFIG.get(cli).trim()); + Assert.assertEquals("input.csv", SummarizeOptions.INPUT.get(cli).trim()); + Assert.assertEquals("log4j", SummarizeOptions.LOG4J_PROPERTIES.get(cli).trim()); + Assert.assertEquals("2", SummarizeOptions.NUM_THREADS.get(cli).trim()); + Assert.assertEquals("128", SummarizeOptions.BATCH_SIZE.get(cli).trim()); + } + + public static class InMemoryLocation implements RawLocation { + Map inMemoryData; + public InMemoryLocation(Map inMemoryData) + { + this.inMemoryData = inMemoryData; + } + + @Override + public Optional> list(String loc) throws IOException { + if(loc.equals(".")) { + ArrayList ret = new ArrayList<>(inMemoryData.keySet()); + return Optional.of(ret); + } + return Optional.empty(); + } + + @Override + public boolean exists(String loc) { + return loc.equals(".") ? true:inMemoryData.containsKey(loc); + } + + @Override + public boolean isDirectory(String loc) throws IOException { + return loc.equals(".")?true:false; + } + + @Override + public InputStream openInputStream(String loc) throws IOException { + return new ByteArrayInputStream(inMemoryData.get(loc).getBytes()); + } + + @Override + public boolean match(String loc) { + return exists(loc); + } + } + + public class MockSummarizer extends LocalSummarizer { + Map mockData; + public MockSummarizer(Map mockData) { + this.mockData = mockData; + } + + @Override + protected List getLocationsRecursive(List inputs, FileSystem fs) throws IOException { + Set ret = new HashSet<>(); + for(String input : inputs) { + if(input.equals(".")) { + for(String s : mockData.keySet()) { + ret.add(resolveLocation(s, fs)); + } + } + else { + ret.add(resolveLocation(input, fs)); + } + } + return new ArrayList<>(ret); + } + + @Override + protected Location resolveLocation(String input, FileSystem fs) { + return new Location(input, new InMemoryLocation(mockData)); + } + } + + public static class PeekingWriter implements Writer { + AtomicReference ref; + public PeekingWriter(AtomicReference ref) { + this.ref = ref; + } + + @Override + public void validate(String output, Configuration hadoopConfig) { + + } + @Override + public void write(Object obj, String output, Configuration hadoopConfig) throws IOException { + ref.set(obj); + } + + @Override + public void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException { + + } + } + + @Test + public void testLineByLine() throws IOException { + testLineByLine(5); + testLineByLine(1); + } + + public void testLineByLine(final int numThreads) throws IOException { + ExtractorHandler handler = ExtractorHandler.load(stellarExtractorConfigLineByLine); + LocalSummarizer summarizer = new MockSummarizer( + ImmutableMap.of("input.csv", generateData()) + ); + final AtomicReference finalObj = new AtomicReference<>(null); + EnumMap> options = new EnumMap>(SummarizeOptions.class) {{ + put(SummarizeOptions.INPUT, Optional.of("input.csv")); + put(SummarizeOptions.BATCH_SIZE, Optional.of(5)); + put(SummarizeOptions.QUIET, Optional.of(true)); + put(SummarizeOptions.OUTPUT_MODE, Optional.of(new PeekingWriter(finalObj))); + put(SummarizeOptions.OUTPUT, Optional.of("out")); + put(SummarizeOptions.NUM_THREADS, Optional.of(numThreads)); + }}; + summarizer.importData(options, handler, new Configuration()); + String expr = "MAP_GET(DOMAIN_REMOVE_TLD(domain), s) > 0"; + for(String domain : domains) { + Boolean b = (Boolean)StellarProcessorUtils.run(expr, ImmutableMap.of("s", finalObj.get(), "domain", domain)); + Assert.assertTrue("Can't find " + domain, b); + } + } + + @Test + public void testWholeFile() throws Exception { + testWholeFile(5); + testWholeFile(1); + } + + public void testWholeFile(final int numThreads) throws IOException { + ExtractorHandler handler = ExtractorHandler.load(stellarExtractorConfigWholeFile); + LocalSummarizer summarizer = new MockSummarizer( + new HashMap() {{ + for(String domain : domains) { + put(domain, "1," + domain); + } + }} + ); + final AtomicReference finalObj = new AtomicReference<>(null); + EnumMap> options = new EnumMap>(SummarizeOptions.class) {{ + put(SummarizeOptions.INPUT, Optional.of(".")); + put(SummarizeOptions.BATCH_SIZE, Optional.of(5)); + put(SummarizeOptions.QUIET, Optional.of(true)); + put(SummarizeOptions.OUTPUT_MODE, Optional.of(new PeekingWriter(finalObj))); + put(SummarizeOptions.OUTPUT, Optional.of("out")); + put(SummarizeOptions.NUM_THREADS, Optional.of(numThreads)); + }}; + summarizer.importData(options, handler, new Configuration()); + String expr = "MAP_GET(DOMAIN_REMOVE_TLD(domain), s) > 0"; + for(String domain : domains) { + Boolean b = (Boolean)StellarProcessorUtils.run(expr, ImmutableMap.of("s", finalObj.get(), "domain", domain)); + Assert.assertTrue("Can't find " + domain, b); + } + } + +} diff --git a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/NetworkFunctions.java b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/NetworkFunctions.java index ab8ced162c..1d2655dd74 100644 --- a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/NetworkFunctions.java +++ b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/NetworkFunctions.java @@ -18,6 +18,7 @@ package org.apache.metron.stellar.dsl.functions; +import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import com.google.common.net.InternetDomainName; @@ -229,7 +230,13 @@ public Object apply(List objects) { private static String extractTld(InternetDomainName idn, String dn) { if(idn != null && idn.hasPublicSuffix()) { - return idn.publicSuffix().toString(); + String ret = idn.publicSuffix().toString(); + if(ret.startsWith("InternetDomainName")) { + return Joiner.on(".").join(idn.publicSuffix().parts()); + } + else { + return ret; + } } else if(dn != null) { StringBuffer tld = new StringBuffer(""); From afe91c341608468e2637db4a02f9428ebe19353a Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 16:18:20 -0500 Subject: [PATCH 09/28] more docs. --- metron-platform/metron-data-management/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/metron-platform/metron-data-management/README.md b/metron-platform/metron-data-management/README.md index bf6ea89aee..5660626706 100644 --- a/metron-platform/metron-data-management/README.md +++ b/metron-platform/metron-data-management/README.md @@ -412,6 +412,8 @@ To configure this, `extractor.json` would look like: } ``` +#### Parameters + The parameters for the utility are as follows: | Short Code | Long Code | Is Required? | Description | From d955e26cf4e7776642e83b23deb305fd5a238cc2 Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 16:46:30 -0500 Subject: [PATCH 10/28] Renamed test. --- ...erIntegrationTest.java => SimpleFlatFileSummarizerTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/{SimpleFlatFileSummarizerIntegrationTest.java => SimpleFlatFileSummarizerTest.java} (99%) diff --git a/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerIntegrationTest.java b/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java similarity index 99% rename from metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerIntegrationTest.java rename to metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java index cfc9a8d431..edf790b8f5 100644 --- a/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerIntegrationTest.java +++ b/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java @@ -41,7 +41,7 @@ import java.util.*; import java.util.concurrent.atomic.AtomicReference; -public class SimpleFlatFileSummarizerIntegrationTest { +public class SimpleFlatFileSummarizerTest { /** { "config" : { From 5328931504bdd069e827ba55cc6015ce9b3031f8 Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 18:23:32 -0500 Subject: [PATCH 11/28] METRON-1379: Add an OBJECT_GET stellar function --- .../metron/enrichment/stellar/ObjectGet.java | 152 ++++++++++++++++++ .../enrichment/stellar/ObjectGetTest.java | 91 +++++++++++ metron-stellar/stellar-common/README.md | 7 + 3 files changed, 250 insertions(+) create mode 100644 metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/stellar/ObjectGet.java create mode 100644 metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/stellar/ObjectGetTest.java diff --git a/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/stellar/ObjectGet.java b/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/stellar/ObjectGet.java new file mode 100644 index 0000000000..0a2ad7be25 --- /dev/null +++ b/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/stellar/ObjectGet.java @@ -0,0 +1,152 @@ +/** + * 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 org.apache.metron.enrichment.stellar; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.metron.common.utils.SerDeUtils; +import org.apache.metron.stellar.common.utils.ConversionUtils; +import org.apache.metron.stellar.dsl.Context; +import org.apache.metron.stellar.dsl.ParseException; +import org.apache.metron.stellar.dsl.Stellar; +import org.apache.metron.stellar.dsl.StellarFunction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.invoke.MethodHandles; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +@Stellar(namespace="OBJECT" + ,name="GET" + ,description="Retrieve and deserialize a serialized object from HDFS" + , params = { + "path - The path in HDFS to the serialized object" + } + , returns="The deserialized object." +) +public class ObjectGet implements StellarFunction { + private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + public static final String OBJECT_CACHE_SIZE_KEY = "object.cache.size"; + public static final String OBJECT_CACHE_EXPIRATION_KEY = "object.cache.expiration.minutes"; + public static final int OBJECT_CACHE_SIZE_DEFAULT = 1000; + public static final long OBJECT_CACHE_EXPIRATION_MIN_DEFAULT = TimeUnit.HOURS.toMinutes(24); + protected static LoadingCache cache; + private static ReadWriteLock lock = new ReentrantReadWriteLock(); + + public static class Loader extends CacheLoader { + FileSystem fs; + public Loader(Configuration hadoopConfig) throws IOException { + this.fs = FileSystem.get(hadoopConfig); + } + @Override + public Object load(String s) throws Exception { + if(StringUtils.isEmpty(s)) { + return null; + } + Path p = new Path(s); + if(fs.exists(p)) { + try(InputStream is = new BufferedInputStream(fs.open(p))) { + byte[] serialized = IOUtils.toByteArray(is); + if(serialized.length > 0) { + Object ret = SerDeUtils.fromBytes(serialized, Object.class); + return ret; + } + } + } + return null; + } + } + + @Override + public Object apply(List args, Context context) throws ParseException { + if(!isInitialized()) { + return null; + } + if(args.size() < 1) { + return null; + } + Object o = args.get(0); + if(o == null) { + return null; + } + if(o instanceof String) { + try { + return cache.get((String)o); + } catch (ExecutionException e) { + throw new IllegalStateException("Unable to retrieve " + o + " because " + e.getMessage(), e); + } + } + else { + throw new IllegalStateException("Unable to retrieve " + o + " as it is not a path"); + } + } + + @Override + public void initialize(Context context) { + try { + lock.writeLock().lock(); + Map config = getConfig(context); + long size = ConversionUtils.convert(config.getOrDefault(OBJECT_CACHE_SIZE_KEY, OBJECT_CACHE_SIZE_DEFAULT), Long.class); + long expiryMin = ConversionUtils.convert(config.getOrDefault(OBJECT_CACHE_EXPIRATION_KEY, OBJECT_CACHE_EXPIRATION_MIN_DEFAULT), Long.class); + cache = setupCache(size, expiryMin); + } catch (IOException e) { + throw new IllegalStateException("Unable to initialize: " + e.getMessage(), e); + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public boolean isInitialized() { + try { + lock.readLock().lock(); + return cache != null; + } + finally { + lock.readLock().unlock(); + } + } + + protected LoadingCache setupCache(long size, long expiryMin) throws IOException { + return CacheBuilder.newBuilder() + .maximumSize(size) + .expireAfterAccess(expiryMin, TimeUnit.MINUTES) + .build(new Loader(new Configuration())); + } + + protected Map getConfig(Context context) { + return (Map) context.getCapability(Context.Capabilities.GLOBAL_CONFIG, false).orElse(new HashMap<>()); + } +} diff --git a/metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/stellar/ObjectGetTest.java b/metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/stellar/ObjectGetTest.java new file mode 100644 index 0000000000..4a34f86e04 --- /dev/null +++ b/metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/stellar/ObjectGetTest.java @@ -0,0 +1,91 @@ +/** + * 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 org.apache.metron.enrichment.stellar; + +import com.google.common.collect.ImmutableMap; +import org.apache.commons.io.IOUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.metron.common.utils.SerDeUtils; +import org.apache.metron.stellar.common.utils.StellarProcessorUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ObjectGetTest { + FileSystem fs; + List data; + + @Before + public void setup() throws IOException { + fs = FileSystem.get(new Configuration()); + data = new ArrayList<>(); + { + data.add("apache"); + data.add("metron"); + data.add("is"); + data.add("great"); + } + + } + + @Test + public void test() throws Exception { + String filename = "target/ogt/test.ser"; + Assert.assertTrue(ObjectGet.cache == null || !ObjectGet.cache.asMap().containsKey(filename)); + assertDataIsReadCorrectly(filename); + } + + public void assertDataIsReadCorrectly(String filename) throws IOException { + try(BufferedOutputStream bos = new BufferedOutputStream(fs.create(new Path(filename), true))) { + IOUtils.write(SerDeUtils.toBytes(data), bos); + bos.flush(); + } + List readData = (List) StellarProcessorUtils.run("OBJECT_GET(loc)", ImmutableMap.of("loc", filename)); + Assert.assertEquals(readData, data); + Assert.assertTrue(ObjectGet.cache.asMap().containsKey(filename)); + } + + @Test + public void testMultithreaded() throws Exception { + String filename = "target/ogt/testmulti.ser"; + Assert.assertTrue(ObjectGet.cache == null || !ObjectGet.cache.asMap().containsKey(filename)); + Thread[] ts = new Thread[10]; + for(int i = 0;i < ts.length;++i) { + ts[i] = new Thread(() -> { + try { + assertDataIsReadCorrectly(filename); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + }); + ts[i].start(); + } + for(Thread t : ts) { + t.join(); + } + } +} diff --git a/metron-stellar/stellar-common/README.md b/metron-stellar/stellar-common/README.md index 09bd4d60dc..febf104a04 100644 --- a/metron-stellar/stellar-common/README.md +++ b/metron-stellar/stellar-common/README.md @@ -205,6 +205,7 @@ Where: | [ `MULTISET_MERGE`](#multiset_merge) | | [ `MULTISET_REMOVE`](#multiset_remove) | | [ `MULTISET_TO_SET`](#multiset_to_set) | +| [ `OBJECT_GET`](#object_get) | | [ `PREPEND_IF_MISSING`](#prepend_if_missing) | | [ `PROFILE_GET`](#profile_get) | | [ `PROFILE_FIXED`](#profile_fixed) | @@ -789,6 +790,12 @@ Where: * multiset - The multiset to convert. * Returns: The set of objects in the multiset ignoring multiplicity +### `OBJECT_GET` + * Description: Retrieve and deserialize a serialized object from HDFS + * Input: + * path - The path in HDFS to the serialized object + * Returns: The deserialized object. + ### `PREPEND_IF_MISSING` * Description: Prepends the prefix to the start of the string if the string does not already start with any of the prefixes. * Input: From 1c20be8ddcf2afad8a0772645b611ddd52c2cdf4 Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 21 Dec 2017 20:45:26 -0500 Subject: [PATCH 12/28] Ensuring original domain doesn't make it into a typosquatted domain --- .../metron/common/typosquat/TyposquattingStrategies.java | 4 +++- .../metron/common/typosquat/TyposquattingStrategiesTest.java | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java index 45d17e5181..b7fd1e7fc5 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java @@ -46,7 +46,9 @@ public enum TyposquattingStrategies implements TyposquattingStrategy { @Override public Set generateCandidates(String originalString) { - return strategy.generateCandidates(originalString); + Set candidates = strategy.generateCandidates(originalString); + candidates.remove(originalString); + return candidates; } public static Set generateAllCandidates(String originalString) { diff --git a/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java b/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java index 91824207c1..d7f99f0b79 100644 --- a/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java +++ b/metron-platform/metron-common/src/test/java/org/apache/metron/common/typosquat/TyposquattingStrategiesTest.java @@ -100,6 +100,7 @@ public TyposquattingStrategiesTest(TyposquattingStrategies strategy) { public void assertExpected(String domain, TyposquattingStrategies strategy) { Set expectedValues = expected.get(domain).get(strategy); Set actualValues = strategy.generateCandidates(domain); + Assert.assertFalse(actualValues.contains(domain)); { Sets.SetView vals = Sets.difference(expectedValues, actualValues); String diff = Joiner.on(",").join(vals); From 3c028304aaf8844c2dc83a7114c06d0670d896ee Mon Sep 17 00:00:00 2001 From: cstella Date: Fri, 22 Dec 2017 07:19:50 -0500 Subject: [PATCH 13/28] adding base document --- use-cases/typosquat_detection/README.md | 0 use-cases/typosquat_detection/drill_down.png | Bin 0 -> 246210 bytes use-cases/typosquat_detection/squid_search.png | Bin 0 -> 161855 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 use-cases/typosquat_detection/README.md create mode 100644 use-cases/typosquat_detection/drill_down.png create mode 100644 use-cases/typosquat_detection/squid_search.png diff --git a/use-cases/typosquat_detection/README.md b/use-cases/typosquat_detection/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/use-cases/typosquat_detection/drill_down.png b/use-cases/typosquat_detection/drill_down.png new file mode 100644 index 0000000000000000000000000000000000000000..d389eca51726d8217d880fd8c0549f4dfc04910c GIT binary patch literal 246210 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

XAMR+q%4zQ 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

GGte9BoaHJ}GFQ zBGOnDc(EJ!M4Ri-rd?yC%l-7;OA9hDTM)=Cb)su&1Z<6M?I`TQb)|=yEk3?m`T7X> z>{|n%Y17dI3OGKeh0(0-pAUgHoM8sKy#CI&!KauRb6$ z(;L-=JrZG;OxzVOrn1&uGFNfZ65LPRs%~It8|NiEn-|Ol9u7Wp@736bLZ^IRY0k}f zVq{n)lus^{$~NSz^!NsB)a$tnjF}&MwA6gHFCa8brm)y9gT|;zu|M>_9%WNDoTl)v;jK4QVHe4zpp2~Nzq0bE#L&0 zARmZvLS(G2&u+w$dkbEW2{U*qk&Zf#w7u%a6NIS+~ zxu4cs1k%Nr!}3XVO!1$tz{A*kqvb)UPu^ezp1FiUr$*9Ku$zK^e8av>anVqa#Nm!; z?`L4D7J=o=$_zg0B)m(@g`ea3=IvbhkLK>tsWmKX?Y_L}Ez`RS#usP%1bb=A9*`vi z-R)w6si7&}7B`}Sr`}7%UJ*_5DrF&ElJ;rlv%33so;aXm9 zZE`j9wS*V^VKya6S^h4{mzmY2^1ek#v&Y0P>os1pEzS5Guzz{(jAt=pjNv(v)xl%O zg*DCD@T54Dl4;+Jax_MJ9PAS9VEjpA~50Y5)idx#P&`+K`lRVM} zMu45Vw{Q80>s@xPU_M~jyl#8xq+C{S!BRqpWvgtij%zvg8vwWKV1aTKcTf9h8Gr06S?Ny=RJSJr!yk&eBf#KX$t{g#dC$QdQ38N>Ih zEZ<@&eY^!VoZRf`Y)@-HmRFOaupwa4-?_Y0yyZO`rK5MR2_>ZyRh(KrmE+m@E2L}V z7H|L+wCBSk|5&Zjm zjV{v;mhGQEB5DI4;*ks>{P~67h895f4biG6~NV}icTCL`|F?o z^KJai*Npw)L&Kx>$N%R0{{!Iv<@bDHfZhbZ?G+l-zvxYTKjpbpGbX+B<*lLl19CGP zuzz`g@P`0%IH8jUF6fq!{Z7M)Hopn@PV@tvLpSMlAPFCuh}7@;%~So)niBQge+{H7 zX(c6H%}q@OFb=5@(!4@mi;e;?wJoZR6kOMBg`~ojlPxf5d7`yWCY0+lod$x|T6AJ> z^Z8$=Pe=aZ;*|dE4*#Mac@7wB>??!RZUm4{ZFTj~!#*bVi;IiGlr2r6Eb>O|E>@k7 z#A7JQI;i{OLZJJwqYWVHw%=I25?B)>tuZIqN%)z-i~m#!^MRdpEGU_HcasspigsAS z|I`@t$4_GRvGVR4ekp1L_s669YHMd#@j;t<6cFE>xO>{#k$`ij0*WIm#e>%-xU@3| z1>c^ifB!UnIDVj+BM^H#dVJh8q0F|XA~Dlp^!rCTC*WDxYSVVN;$%*?g2!9J5KDM} z>*#a-U7p4CAbh?QV{?0FXCl3(CzK$+a_l#6jxGZsrC@7weI2jSw~Ekrz%Glz0W^Nr z+3xAHjpqWc^;h_v9N8mp{{iywE_mw@N?qS_)3gv=otI%;Q?bH(3I53P4k!=108pER z^#@MC)$(u33q+2KE%;N)XGkD79zY1?-p0##e;&iH=;ex&R#(XiiMVm~@dQo;e7OuW zZEcYRKE34U9U{SeEwLfAHlg*Ak|C$IGpG&s>v5h=m=gwb>FL;~XI?l+trqH(xlM!C z+8#+IY4QaY#+$24mpaTWKRr9byq>+sQ;Q1D>|_U@2RmpsBdhv0X+I_#9i-@;259Wp zB(4x1vg9bo;S=klH{@WBwH7*0u?(K@XLcPz7no;V6p*DVg24r7*OqXw(voDzgf>^c z-Gs_AI0qF$PeQU1;kC&`3k$79$k1sX;u5$$d*Q%4?ZStjRnK>3=-nXx48fnm#i;7b zR2zIH)+QOA#hkDJW*?;RjRb^H7UrNoVjx0Nc=i>|$hTmH%ZGOQN+ih8F>7Gn-vt&9 z;{ig}KRlel8?XzJc!?aQ;rzhy@zGqrI3H*mnb@di5_DUk@zMnb>aLV{fNL$GVKNOH zXDhoWIjI-uIa<&s+IE@!aa|`^D)@7gvVxS}W$&c0j>>5I$L`!XWSqAjHdi@u3alC( zgq#*;Tbnmv^4RMoY0%+3#A9(PN=gIByBl@U-~};YuPt;ymi02AfLs5e)p0EA7z9`_ z7WxvAG@%kx|t1IeeWj1CPU9EDwSn)w1TU~ zrv2tIomz$FD*sdb{d)|1-M3wBwRm0M)iU=my;_3Hy4lBm8fO6_Sbrxb(u5%nC7v1? zDII*$jL6npz}^w1Tu!s$`_Yc#^sUgN#7;Ooo7>^iVkUh<7L9%godH`aDk{QTY=|=X z9Vr34Nf`og5e?o;`2DQxbUW=1g{;nHsS$OMsvZtB3B66$fEHc{v7hDB^;Yw>^AYql zPdSZ^o<<70c5p1V<(jE>2K~fT+D>=zcZdMc#Ro&FN3(m33uS7q&&M;ovO-t^Q~sCl z?rh=29PxzbCN60_Cc*wV(IYUos7Sy$d=^NVn1m0(UPh=_V;IjYq#S}tlStM5nJ%40 zYfY)K(0-<83WOse)_&$|E60ph1H1>&!z}FVb`T?_oG#Qjtn322#AR z!p2oMF?(L}S>$tKfHj(a$fzndF=rB$KIcFMn z&X(MW6KI?_n2`qU`r$Lz3aVVq5BQaKJPhc208U+g*zBeygUYr!q>_YuKsJ`QePO!0 z6QioyX$c^O{ykUy}Xr(9H_N*mfcbQ^^{-02UTy?HlK!dXGsht zxv|NY{2r%jgvAP`O5H$=V8yq@m!tg!9Ht{?GXJ1vnxd|iBG5@kjtL=}p+`i!2^#FarwJ6?Z$Z3nZ=^!kbDM%uu;n`@(bChA$_{8t=L; zV)%@|)5F2cx!hrvzM2tM#5{=@sY%rS=z^#5p5-2@0`YtkK9Im)H3)vffzi>zP=N>f zMFs4k{K5!4jc@VAAJzVn7XNRl@_)YOc>$Hk(h5R4+6BdD6W~$co5#wQ3(yALhN3u| zHxW(WsMD5nU$Hqo(`1I1QibJ7o6gN!2T@ z!EaHLCMFWznf+5R9Mcj+O8Z-@aRF(uAKD=@47{C<=4pi#WQ9_bW~reK`qXA50op~+1aJxaJcKnEbX_O=gU>VCJ!z)Y5BPBpTX{0;oDMopVAaBa> z&6j^i#lwGsg7^g}YQI=sZQOZP>q&%^Po-cP8@i*oEV>)j#`QW(V}-CQ;cF1!78IUK z>I<9_ldJ2dHZ9p(@m>EP(oTeNe@VM2$l!1|vTsM!xZYUp z-r+?c4@;gN!aQnFg6rVU!u+oz+e4J5_n#N(e}5O)>CjU8;%7j+vk3LaTlC~4?D-cz zFX{={4C||tRopu}!2Y;I57#!yo^} zjnI34NK|;=1w{XDU^)x~1#28eQbqOO;vFdlG{mLsu`k_!zmva@y`B=JU#qJlx6tG; z0Q|6LhD6CvM?Ux+1ZUr!F)Cju#sDK5>B|Ur*+BR19ru@^+YZpP$pydwp$CGjb?=Sb z&5i{9>6_5lRk00)a$j=BQ3-~R5K%KxT<3PQ7@4d+kZsZ-48z^VS`G?AAyiyDfN7F*k!fB%60`XZ(YqBNIG zlj@laT3}9sy8ydM$XJ$7UXUROCb}S7esk$=FO6x3+;}me$Z;N5 zrjj+EH^^I)gb?`B@f(Owcw9p3sT6h2Z^9tT7~DzT^U-$LL%O4~ z#HS@lft#Q2@3|u;s%YkZWGtp7jEZ#Q7Yknp4x_fXxc6aZ@J{|96LqcqDHfoFLC9u} zp028rCFMlKlH9=GMKo@!h7_QSaa2`Q?1!khuN5p8`M^Zzi5u{|Y{6E@TWN(wJ)Fz% zMfhcXACae1s+{96)_XcRop6UXO7X)OD2^SV#JLkv_a|tdbXxQx zXp60@V00d2KW2`cAMuA>rMdqwQXWwayWqa}(G`OcRXR&+Kg^KySMc z8Jb#mJ(_2Fg?}>pE~Z}EoirYvwH%;e(e^ z-ORUcu^!sZ@`S3=)d;(z9rtR41YZDotP$NQ#aCa&RPbzz6X|6Fm^sA{QkX=vi{i7S zloYnuvn^1Wobv`^##MGz8l5cpR$x==bioTma%LAA=}7b=r{U21U0{|%9eJayvVz8LgbrAB^W z*GwbltB71UZ%wI>Qy0IY?f%h=jPNF; zXMzSJtz>uwLvfN**MoQc4$|d)$r6<06oJjj!A$_1R2j~E>K5x6s8K%Kq=z!^DEto= zdJu1zqMX&~r9WQkOmju4z>J0Tii%?Ph-aitMG%yIEeq`xaYM|hBv>)|lYEv716h=z6`8?E@&oAuuvbF!GGs}OzFR)9sIGU}4D}KiV0o$P z*%hiM8t;=WH0ek=b=U!={XHnXUMGl|=k!xTSbETP-{|>&QsjTWaq+V;Kk5)!?_;sP ztk-&1rS+0m6kqp0e;Sx0qsNNDHDvjkws54}ijUtPmajTuX8aWwH7kPS)GsnZ4<q=j8g~`-G1)%?x2^YW z*K;8QM*NA!4*dt`hUJF|APdg{|lqUuPPdr z3e}hJNdj-NROWXm_Nc>wV*VWyn=Y*Z`NoDG%C!_+ScMa*b&e{0%tYj|j8fPYO7)GB z4)=>;cuQbfT|_-*-jxs&iH|o?uZFgM&vU)FQXj8JeWmpu9llT2QD z9UUC>-+z*TR?AK$G#UP98fYiaykwwAe#T;D=rqJhinB@fu9m`LvAAo&iWXH0W|H&?&SU}2EqR7K04EB;g8!zz>V1G_@(gLQigs!0*+$}T>l@zw7a=MS zyP})+a}`Xpv}9yt0%e^ct-Nr$?xXib=nfH!6TXrE-9q?(Uj93%@*T;@-Xh8Z*4rk< zSbgbcq9J{`{srj}O4pnZNMW2~0fOZE_1PMb7`}UfK|LAUK)IAc1~3gK!4Hv{$|72Q zJeXdDlCchkVega{VEF64bX#^m?J4k~dob0>m*Ux^_W2S&lP$HCeb0)$cT=^y?#+p*$r?gIB$)uK z2rKQ4WD*&mcUb340T5pQ$kwIIZ8O5lh?+BdPdQ3g<6c8W>d=v9^j>G615H|Q|vmcB_}45^YJ`NpED`ZJIP}jbn?uT-2T|CS(`_$f|6h?kiH2sm2%2A zA^;Dja?RrdEAA)j^U>Rrhz%7VGo?{$y_#Je5$AXeO(Bk2cP;J>4A|y~c-IgD+{b@F zp&(Pje87g{L6q0ZJh)h}NcW{#dC1!bIpn@Ok)Xueuc+#=d&eWhewb-~Ok24V-H>%h zwPOwxvqc$UL3zy92D{ICN9P=Phdo{LV892`PzkY>J0q=J0j3?jKo{!O`G`MqPND!j z2G&ukwAJA3s0HQ5W+qAq<~)6SibZtcAY<--d>7?{;C&|HUKV(6UI^rgBq7B6sHh~9 zTFBRyW~eSSMq`zlR<>uKid@AU%eDtpbs2J*wE+BVyjkKH%_h>{fi$;P2<9oceRCU` z*;W&&k<{a1*GyU#P?_QBMO5raS11;R3@g+6KE7UakC%ks;juDOU|{9-J>pL%osa9#AwX>?GdgDwQEw6wI^UU&Axc;Sw;34B1s zyLi6b?l7X)_zhNRPoKqklugvP9f+xrO~ypyiICN-UyBK&w3F@ydC4J~?~g1p%6;!4 zTCUE%ah1*2itA&Fi{GVCGPZ#<9Ern7r@Em*k*>Dk5ZU+sU?TUS#q6`Wf$(pt1z)!d6W0VDt|m?xdTY}KFzIFmEh#9wbrt=7^MQGk*(mu9&Q383QKnRvrIpmhq(Tcabo8ANfvvHwO z9gJt!A!VnPmI=n^*uD$H8Y?$5V;ZwwXrNxVKYVsjVBbmQsyofa%6e?gkG#s?=WEDj zLgo)mU}b$z#>INYm!@IaB#K}aMZH9~JxAx(3C-{0n1P=sw-)8Da!eebmRr0lbs7IA zRLtRF%h9)?IY=wraqQ8FiW@c>yo$l)gTbafVaZs0lPeQ5^KD11t5Mcb8e2;GIH~|7 zfY+58;dXWs>yof+1maf$NHjF?@-o-s5HA1$XLf}|93%B&YY@&X@hCLt*-42tSPbegK)W0HtQ5xV)g9?LuLihJ}j99#}jWTSclVktZ${!zupO|Po6J9M??g&)Jp`Y?6PLiau07{H;V0PiFJ2IC{=z5#rwE3>07c9f9+@s0-HK;ElWbkg@<@u7U+ zLq3pY?A%rBEFIW$nW8pB`5W7;{0D< zeas2?P?)Er>c9BRzY^B}xg$ickaqCB=g{71$M>Q9FM<~%BjYrTW3;TsvLm#v>W>Os z=SeAz55nU~js42Mv)|@feEvJ|hxqKqm0JNCq$7unE*z15YSYS0Xe|M+)plrT2wFH5 zsT#TXAH%HzrV+Vn2+&>~X%zM69sJ|slIJG*Mb}a>zRubG0nod(51J6Pkv+u9$~yls z<6U8)G#c>W4&JQj?j8L~!U?wUH)&@VTTl0?r6&A^K`;U5V|O;sx!i zdp%320XJ>U5BRu4+!Pgr#TFs{yo;0VSI)|hnnKbgyo<`hw^ZTk_-n~C;1KL*gECWB z(lv!_4VfM*MQ$~=@>a*Keas2vhrlb#9L&s_X~O1<06eY`01JHxd6qq}U;>uRv_KGG z4{49o)%-*MEe9U?4~qH_l-Kz+TaQl40g(;CNXiJc^Wc$N2<)(8sN9Qzpil&@)wS53f3Ssg&1Af|Y9>X*aNJe(RK>!Dl zxfZhIciXR{o+89U#3}%0m%7gfmzhUnrUCePiuDnqh;~^~Au@1x}K#z~Cr(b5? zeQhkE8xh&}l|LOQUiB5dPM*X5Or3N8j_yV@<`yYBNFzh{I(n}X(>VC!ECuHP=Pp$7 z`X*F(g-i!iLI zlP+yu2ne1g$%)=0Lqa607ohHSDc1Mh8Oim9hAtGewOBLdUE?4>LeTD>L1-4a6-r84;a!@Edz~a&G3}ncc_KBK$jYcf643{FCS8oybP6(e{D82q8%pNE^n(3C>B`2 zcHEi=QPRdwEXvie12B76`WpY2lG+3L<30 zH@Q$`765H?bs%u6l{b>L$FiqnjL$?GC?d~iWYu`Nx{`*@FDBT?!oE^HkbOr#>;@d+ z8-4iU<{&JKC~mHvlF1eVkGI>?P`Vu@I_Mx#8q*j1${J+2Cll~@t2$tZx$;~h%LGb? z8QvO`wbg;0TrptaI-NWfAhZ+$h_6;dOsIbqj)zASTf;N@STqgJ>gr~}@`4>bgI%87 zBq*ieprAPZvx}FKN2x^49*amW|H+un3cBuB z;Lbw%AE0-1WAv|%kx+Lie&)a|e9dY9`BH!Y%+uTJrp1_6JhXxEqDHON3j(2MfYG>* zPmf6IUhqrLR{+P(lWD{;0A@trX{*>rN_mUpdk&dOWAw|?od!h^3jb*OMJ_@&(Sjpj zL-OYvTH^^GZ^IB==He7MRSYuiGQt$SInzdR5?C5&ZDgeHL82~gf`2T7hiD^2cAlD- z?{^gafM?8N4S@6L8giTh-~74oM2+u>D@fDpSl(DU!kn@IFF%L)`1tz!r3#E`)~gk> zD^K=l_T2y;_e%~1SXA(+$J6ZrB2p<}Nw^uqNv6h?#W};8E%r~b`_C8dNkY|D>YR_@ zMG;sn&4c-hZ@>*df56+B@PXuSo1eH6iiUb&+WC7~~i zJ<@hL&HwQHn4^a20DLpT>#oMTENCpdoq?-+2+51vp+3dekZ%z*)ReGa%#$8GJVW|Z z1~O|x_vMP6Ne#r=V}|H}sx}6m0zdX>p}cFNgo+i8ErOkAsAkEdOgQf%XOcZawulgE z*_S^b*SUJyik(0jZ(&uNOrj^Uxe%z7%f*8cP_oNbmZ_H1pl9oxGw9@K4r%ijy@c=; zFZEDWJo(2=?0IK zE*xGL%sTI)OR^rr!E0m{NPy`rLSst?C(HHSq1n0&VR!A0USB3SGTehR-!0oq3ptMu zWzNNE+~I1rFSf^T){{MYEP93_C-j=*&$5AtGPyyBnU2>^|Hjrxev$;}s8PDWKL0HH zKy`Tg(=oY~3Fr{_rD;XKL>O70nZ5&8FM*M&8FXb4-tn~A@}JokF>QA~axETA_Tp(N zi(f{h2pp%AC_7!r!|l-fj7b>I`JFIxD? zf+C5hwub)*(*?wR2v=OAwX=PL6hSdD2<*BrW%zKXn;U2}(vT{>7_+?cFG><7V>rCX zT%AKt?dA4neBi=m3l`J( zqcWeBS>`^;o=O@QSiG@()&2Um)_Y06GeQ#4XT}tsM+)4oz0G(TSdv5Up3{<*(4S>e zy)Jr0{>ZDB#!h8)o5J5VCv%tXnq|(c3sttIH3WLJ#&LcIp|;#kpi3W!k`v~6m5OqvoE zOdwnSESFCA2}Lz3zI%^e=`$0|Z!V50Ml_iOsx5o)IGm~-}JC$1Qs z7n6n3<__Z1?7lT0Etw*I?sPN^=Q{fg_?mP$h&%`Gqys~i10eQN^0fMd0O2(zpm=gX zk3He_rJ@>gDta|%5FuPlql+Sg29*H&b12~A;ct|XPyX~}KpQFOa#GNcpZs>eGLQMs zSMxU){UPJ1ZqNxY)DsQzzCp&r9GPy3)N7I=%z*M?pMVA!+#DHA%Jcg$2+2YtpuW8eJSwTxbv65a=|l)Lj4u_2 z!b;1+1r_TwB{hxrO;uIrm^3y3ljDUrXQv0R4E|>MF9-Dw!>HgJ*(aocEXUBy> zy&iKwYpH3buY^!MasTQFUMQ8-|#WEBKlo7uEkf>zxt0#uO4mzk70wnimI1X5o$kL84!E%^&h z-+JP7bsJG#G=j;3s){4zK|eP|OAA-}UpC6{bt|8810-b(lt8qJxJO+tMCDrL4CfhE z>qXmMU9;fT`0YKu6BQnB2DY8gz2i>iHfL%X2AhpP`nayXBVfXjfzjj#AZ3ZGeshr)@NRT|^cwXE3Bbf;l_xmDQeA|Zv&$PtH&vPg{v7jTwyfVeH(guEa_8T-TJ%`O*+ivo242lF&9`)nsO4}`9MMfi_5b26k5tJ^1NDHC_6r>2!Arz4& zy(lFh2!d3x&^t))0#XBnDk!0YM0)Qv1PJAO^1d^3=A4=Lc>a7pzU%t_F*=6qy`O!T zb+5JVUfv5mA%s%JQ`gB~@C)&A7l!Vn4SaS0K-#%b)oA=N@MiuvPd24Rp)%%`k^(K zY0E({_V+3BlG&m9&o_-2RLQsnOMWY;m<*ci*oM$Rodeavh`Vh0Q+`9!0l}F9=pXoA z2|+Gs0%F|VOe*>b){NBjRe<)V1OD0744d?25Ikx(+j*Kjj-tg~tkk#&_a?Lf*->C8 z)NGGuWw$R=`f*6h2Z3oOvSRMcok4bm^j@0@h@_UF4lF2K4om%s7%(i7oinH`y76t^eNhWI1H|X1@`>Gk=JMP}V?JFg7w1WxLl+E5g*e*!J z#!x_CKEpJFi@bDx>ekOG#Nnb=aDBfpMpB)03P7TR*{zb4t6*Nm&M<5#*LvogG~ov( z16*5a1;#`QzXfy(z3M7bk7GBPs%9efg4`!-E^HH5oCSNV12grz?ts*l7BqQeSm|h% zsWv)^LW0OG@ta;{i*5Bvd1@l?zR7#xx>1vkRAX3K0vIXp>a9rcCB3oht6K+d`+)XY zI}~7ksx=uYRBOf?y#K=Na1M67mzu9e*|7jax@~^t>Nxsb6XV!;?iLN+(d*%+=RtKH zp*l4bxVa%FzB)ylPpWurzUQBVoLaRe!}uQWh97eecYF?<>jcp^NqQ>=VZp4|PptP|ly?jyPp;vW zb#R?ZROSNCz`%JKO<~{rTs;gH_|>U zC{Bj(+KLTe+EuDxr{w5zK;7iJa;Ji0EYZcU7VL)`wX70dyecDS;5or!ELe^qZwLow z70zT-MTx54<>(DQ@K-OFcy3J&`CYJ(XJ!o!wctp}w}4?)wMgM65(DyG!DdjZWIMlr zp+vlz3JQUWH`000J-WEF9AJ5HPpamTiZJpG(h?77Gb5Z7E&G6>LYr9nWi2; z0wkR?4P{w{5ncfj$im0y^wE7?!cDB#B5QP8Wwzm|ZGWd)ljb1hxqQu}AEE`&)!#^j z`(-TxBGBA!^BGkm_DA2^EJ6nS=nMJ<8IY|95@UPHP_K5rit`XBs7ziWkFWuXlxjFY-DToEI_K~4 zl8OQA@STb*2x%fAy`?m+qmXib|D8avP4-$r_3CwWasM2IK$U!etvkf>uLK@?xQBLs z*{rgpv`P2!)r*FELxN}gZO(cX!(e{bbXr`ORS0%f3mN>uLPKDme5b)XvHb5IaYjw_F)~elk;Wa^zcj&v%63MIc$j@WJJDz9YbHV6d z(BThM70XiWZQ`MD_?B{D#rljpNeWx=t5opH@Z~z0dK7TdRW*6BU^Q~4 z^m_9P8u+eBDOjzn205lW2zqzM#N^_wj4hKsdic8(eGp2BwOpV<&_09QQvf8)-0)?5 zMsH@@nkD1uraZwAQqst+U3x3*z8>U+nu&8xO@66qZ^pystf$cBH=-q!X?n%yTy9*~ z>cHk38rRlvE-n&0R^yZ|*(8H&L1kV#39uk+rd1Q8zo;4T&#&gYHAw4a% zb*?MJn^jl(O0D{HO!fdj!|)kBTelbkz5{SZ5{X6AX1pd=edP?{5etXP#?KJhY8Y5@ zMt`Rs0A-oL{;w+D_r`v`BfKgIy=esku^M#1< zj3@>!NDKWD4cfrdfu)!F#tqecbkx*x>y8@41{#>Ev1HaRfR=|Uu!_m({Rn%hLgOo? zq;;RoQ!e=>^b2>0LW_e=3+0`65ZbQU#Sh+oDv;QT3wQW^PnW*8WX%qK3y-EflYP*D zD$B6Qd#362tXyC_soR6$Bo|pj`FsZ$l<37@f?r6jb+hchbZXJ;7!auD9!IWOs&tCkOHhwZ)c2zuG0z^6?#;+m1VTl8k( zG~>g!Xbab$QSs!f#Srqxc#gp4N>g`*PAJ=>RWsQ{zZi&<5Sn_B3D1pZbx|Ek>`tHb z8ozyyftM^LgBabLaSuHz&QI>qVO8nxe1beJro@y)i$_2+#W1Ab#LjcXJ0v}VB*Hi6lz!V{qBC^|?Z9mco3zj zPrcmQ_ZFl#Ofc>M*}U~qwqi}IZvXK{A`HTEW1nedwrYIsYfO11N|ncFE?(- ztWJ`mrQDC3U7zaC)kt}^Jn9Bs__?5nR}fjjpdpa(I|Q|t?{@L{ibEl9T%fGuPDj!M zTMx#sg)w$)Nf#rIZkNB&lI0Pa)aG4UE&GU~(hc6}9fiDVc7P;Jr=>J+YS#W>dG8Kl z`7Ny7j%9hgGGR*Fp|;t)APVwIa8u9gyYt}OYJpEy++YpLb5Fqy6X?=^f|El-PKK;C zdO!f3G(_Cf+u;?`N1sMlf{-rJ@G`8tHF=cGzZwNGyfExO`G!kdpUyWk-h&KxK`EDR zpUSvMyLF2z(W5wTz_`5`=(+=JEyT(q$Ah)MzO zXHhDbV!~5fZ|Berm@Cs13L04LN&q7Ta3hZ+-*g zEo&_K-h#tBTy@i{DE_Us;S0J}mly#%9MUcUv$$tjCiTh^CJ(u!WZqc*?|Sur>p3rz zNZB5+ez ziwBufr@ z&rDtf?<=wr`7>%ys3M%v->Nx?w%H_urs*2I))bjv1ieIk)%5z%Q+>w!yoqOj+JOR} zCyBoA>xOmNdl$7$OG;D5!VRVNsDw@r^qT|0*a4S811(AF1)f&R3`}P4=`gw7b6jM1 zq|lE;3Yvvu(V`(r+PQsJ=A`hmxR%D+-J8a%_6&HN#z9tp}vGV&0@l_*k z=i;xNem5yKK{Fuy-5_7)L9tpW3{p<@_D%P^)w4$f2)hvlLuD!fG9NxTwjHwu`d<^5 zOf9(0R6KN?9nxg&1#=$WeNPFMndF$0_O&Q0zdUcIB>ZA2|4XDg_PmA%10PRDLZ~GN zqcM-K6Y2H1O2oW;d_eRAA?eTjb!`@L@eCgn-HH& zyh=mY+xQ6Kg~U03pKgUE;9t#nCMvV+n;=dZBU7vre$_N3*Hh83N>U*vsgGTRj4Ticaili*_2&IG{3JARo+w@U*`9kRU@IragOL7=Z#vQ~P94^;@Jpg73rBwz; zw+o}pzX^Enb$H^E-BbjHGQMA-l9vGE7({uvm!OErXp*CuKph){eBdT1RRye2fco44 zWwO-c>CJ;zGajyhK73~TJrgUXrDiqyc4k+GXOlpr(4!&X5`w{+EE>sLE4hG}2oQj( z`7^D-ga~&l13fuTsRO9Zg7Ie)oRN4^XemGs82gjXY-#`cJSorx3Um;9Sy|o$P-$`a ztKKR7Xs;qd(Nd);f8J_(x3=DtSZ|zWjYrPsZk$p-{T$y|=0J%j z@(A^D$JFzOS=1+Bi5S&;?-7>|m9GLo@vdiyv<8lq6ETK6+i>4kbnYNWIW)S&or!#yJo zTuRZZ1y4(>K-weo4b1P;(;S|T1H-FGpK9Rsl4&spn8ekW_X-AXb1~7fUkw;oQD|3=6u{X1$ z_X}!kYbmUoH>%=#iZ$anN}G=Kt^1ekz`R$@rTvt^3>vy~m6Akm@T^C(f_8io16v3* zJ5}GM|8cWhFs8<_Rxn8KgQrL24BnZ!WlFM1!QJo37BpB{sh(1E@lHKsz*#1q%+1=p9vhau+-~fotK3~3KTct33-$Fou zm+;M8TAknIgXpk|ssKr(UxO|1xO9wrvE?t|nc~UJBKe|-K_|pTatjgx4Kx5Gk!OZA zJuN@Ee4jcb6nE2V>37fk5C&`BVmTBaAs9CBrzQq!sQ7b5*k=~vF=EWEU&rQJFSmnz z+>#;3_?lBAQh{45o`wH=_f~HNf~t(M^Et(1a((A+x#l~7V*ca!3=4_;mFUK(VNW-e z6iw)I*x-x0vjJS%93xf`E+~Y`-mPHOkQ4Qpk}4 ze_cHU8kk%Z=6)6;ryU|H*XCzWlEOj85eXg2q4O2m4i%loywu#6^%m2DW&}wmfki*| zCii%U>3=&FhRwN!6E<_Qe?W*C4P#X+ z^>No}!F_j;kG?|U7rzG9g4J3)s+D%?%zm}>l128KK2J^I=>#A>)nMY;7kgy55e7xs z>y$jX4?URJe?kT$NmPSagWY~k&GKm15T+I+8Yf#6=+rE7_p%#nka-t?nrQoJ21N;u ziDyqZD7&cyz9sm(SIlykhOc9Y=rPk$J5M36tV!v|rH^xz>d@IkBP{T*DU)QjtDvtC zctQ7g&?&SCb~s+yf@?WM*Q(pW64`_tY4P~@FncykCJ?iH(zC7ngGa}RAT&oH*v-cNFyRUKL@Ze`|4k|Ny|JMWKNXV-7pykuLEQX#KH zPnb}tjTh(?o(r)Ksyj6=F~~{irYAccve*ok22a0J46+WwNeWk7W#kLFCQ|8@I!!2Z zm(I?uUg8Q9`G9Dpm}$Yf{wj2+8gZX(Qs66%5t!YZAV-prNYSG7?aH13d|`JJCTr{o z?NljyHd0jv;V3#N8#Ls(OXkr#2DZkAeu`P|MdhkDO*O{8OkP&6Rihtl z2JA($FIFRE(!DTWdK%9uWWLRoSy_$t*aHHvL{Zgt;9I9Q{&eu7X6|Bek3mw*0|E5S zZA-9}rC4vT3g{DVsA}^wrPx7u`!9YBCTxOv5dY%}`ZdsJZim`=rirQOpCYy0{Ys8s z1UYVO;o=j7uN&zrZa?<6Snn6FrB^cs9F~f0qG(0v?D_hu zmCsf+yU<~7lH}`~;&!GC-2mFtKF5M#^|GQRv6E~q%F;sQADS@wT-^yZXEWxeI2#V{ z`e*~ZV&6&QD={B2j3oWbgX(P4w08#dfoRSMgAY`6-SloQAGc zQXh5%*W2q5fZiWC4mRfA?iBrVviKjfGbn+x8+I><3zVUD=M-^P#uBKTnSH|nGi5ub zw`ct64Y^Uv;o{PU`x{B5#lTEgi?}`@kdp%h-!O+b=szvx_p&DZKc*#AP zW&0M(Z(-tatA=uS0b?Irxc9-7BU%0Wggby@_o6hcue4UwtyRt?-k7E)Z0vX4rTnN) zHQO;IWt=>Ae1uQvw8@(qEk__222~y)i#Qq!I~l z{_t*DE0>Bl?OeZCF&|sq3px#KPy1ea=V}4V042^5E}yzHb!@Vm&J}MF{EG_p?qeg+ zu*voAJ?iT@CJ{<)rB;#b2AM`y{>iWae0w6;PFAQ4bz-e!RWOxuf(%|e(Xr=_=#sz0 za4o>b(maHedTFut0*&c)(VYo$PZC-+29eiAcSOdaOO`BYi$w_Li$S=|t>Fg zFYaxB7I=}#1L1wyu1|(~mvFPO$=lA-L7|HWP}jVxGHRHL&Q%fmTf;{~F-|PKWR6E? z6Z@^@Ign3FSqoyg_Y^#epQYE{xS<)6aj$I_2okw{W1yYW(q`KYiDYwcB5K6U_3QeL z3~LV=9fF)%MOqvx&gA%KQ~Y@CgsD}c$`>GOowzu|P+Heb2(S+7F0|l47Ap5*^=xLu zUN{KYuiR+YH7u(8*AU_~hUIWx-e8r!yb{cbgPlS|u=Zh$BfP6@B=5>P?|Si$2GGxa z()7r|wwfopgxt8VH&ht0b)PU<`L(j)_I`tt&$uz}hs>c{-H-suIs%s)*_DX`GvK(w@$Z#)o8F|-d57_H{{US3#T zm9rGPKt55NTTqn~EgR82vZ;EhAr3NTA7Yio2D42&w7l8&ZqNWZHeZ}WaKTsp5WkJb zp&k0CZuZQ6QYF8%?y*3IsO=N?DGQFm{)i=r2TtRKS7}e7 zCdNFMSqf*GJa`FmXL2rjv;S^E?$mM^?@>Yur1fZlSxc zTrZyt zb?F&kUY?l=ZUaQvHzD#dYMapmRZo6)4rykry~>VbJ`4zn?@r5!9XGA+j z%4k3L?^?hB3dKFD5Ii8FF4%6}sV*3%%os1*4h57FltY>3FDnNbALA=B_6<}+g5oK6 zYk2g-0X5^|WGzGGcdjlR(A0|lCa7`Os9*Vfl$QoUWJsEFL}>bST>6UIuP^P-!PseS zK#Dn$bb|61rS*R+ytgC4C5*l+W&ZUg{E3Gez5ETFto5_&>;ExZ{{1gx?9MVkmiX>3 z{r{Kr|LRkE{&arv4=;fK?>w>k=+T@u_y0?vQZWLn?G{3WI~9PZjuLTkQaJ7Bm1rT; z9>7w$ILdWB^pLn`JQD!ZtaMR@K=8r8IKu#lxZF|C@vmK*y!!S)DdF;^a_RTqmK+7* zB<@0b|F1FSk+bn&jA6Mk*(}#)4Y?y{!9oYuYgA#VqQh_);X17Oe7!5uKOdO`HMK+yZ+Le_{El8`UL^S|NZ z|9Ue&ow#!iK9mYpu5o}h;nfiN1eXDw<~BoKE3jfP01wgKrrB#x!6ZuG@jl}{Q|#h~ zMF-IU2>99PDv2=S=4Z zLmgw}j#;69^A@Jy+O(M++SoYAU3vS+~G!lCJ zgeJrO$$l$$2-;=DWstU4wY;p1(<_?2L^p@9GE#lZz+I+q@NHZa{;Oda*oL6;`v6vTiWVJY5hBw`54mJ z`xO~Bm0tg4${BYiwfgPLV!!tG;|w*pA_=HK0f(MB@4bJo}1(HdBJ=>Vb6OUV8ldqhKaolrQlZ>hAyj zg8sL_af-_xI7-o-IbLt1>;+Vcflq9J@oE4*odnJqY{@~4O@7_`i`oOZzu)Z5|3>I5O%U9v+pvXx$lKLocvOp_`^x1{^@q?{T*Z zJD}QLz_4~uf6&a7{`X)Z(?O!l_~S-`#IGMlC^-PmMfkLfl821JyGo=ShOX(GD#A~v z2^vfRKr;etDvbf}QX(L8#y1tG7I^_))8UCQ99H|C&+$8}gzyye=8pEfMWZkl&1mmKdprn5X zsd*`%;p3Su51iinU;SFZB@Q5N5q}T>c)@)XuaMi_@-w0vuOsT&#pu#}i&ueDisj01 z*_(xnxidiBqC|Y%>5163Cx+W(gciPSRjToYbGjUeB4g7cgg#wK3nb=%?!^)1-;c5` zm6+*5&nNFr{1ogW?=Q{-#bY1fl|%Co0aQq;E9kejczV>jf9fHyQfYd-DvuD6hA*-+ z^~afkV&Dx6i5V$sb6newIWwkeczC!67}o`hLM@iA1r8{U*#2=GalggiC_#l<|FX*P zF{GVeVb#953LdzK{7ew;)P~iGXRLiv8UMbG*KV7oYx(^8mi`%Z1(k@c*n4WrTfh9> ze+f*dj15oy;x_#?Pu2@U1*t@pl+#E4>ek+ zWrc_W4kmj%QNQ~M6jSGV6NmE~*y}}ZfsZ6I#kT?ZHUs2SipY!~=l>y>_!zT~LyQ}z z?+u^(+uvF!v!ab^ZkY4}8**YR8kgIYPir9y{xIZxi^wgo?&>CZ<*!=VtN-nv67Q}% zogme~KYwrPwnn4wGKl}fXhAl*y&MqQrj3iT`c$^xJVJe=Kg_6)=wfypP>ht^?zo6&9yOgFTd_NFIFZKlWS+6b&~q*H`_)_C;T&eW3>pdZTTU4Vps>$oY!da1U1;-ju&_k z+vUW@m#$3uZx_PgOcMIK0qA4J>up%xKjlTS^VPY##g0i&OqF}yWXoTG_+4HOh%EcA z8*wyOIQI5xcn3Duxwz-COMJ zWtFsfKNtS+{;g3rbMbWyOaZ$urc`G1V^Y0Vdfjus5VmV0?rC*@3keg;dxq`VcDq~fImTkkKr)L&2+`J!9+AR^fJ9EstRJ9*BVgCB&{1NbKuXUM`yd2H@`S({+#>eLZ!*$~# zWoeen$`Xd|yoby5D(POK*Fs~WX3OLi&u0dF7GzKiU-J|{T>d&zd`H}RldD%JQt_fk zuc(7;te}Hq?9UBdt|QH~)JDs>)s~yXvj*?lZJCCiV!`&pKxa0%uSwx>zJ(K@?EU6%;C=(p=`L2>V zhAI`#_W%?fb%t`jl`-|3`*|wx<3+LMH&WRH$vS65?G(ARIxX1SXbqy{BgY(_s=PLq z`y!8fo5I5~A7YNKO0Dm{R_+z$ubL^?{?x24?iz;Bd#Hfe4>*2j`}Aw{tA&ZRW7d2L z8kgr@Qcgd!lZU?|vF#BJoB5(PKND;%U?M@NgrSI3Y)b~xF)(6_6{f}iX2dy_yI-(>~%zy#`|MgmBnfd=bd?5-xL^&3eELV%DyKn|2 zuY0ci^5!e7Xu6Aw$5^Cog{@bmE2cbQhOlop+!OkI#<=LcCH8Z8=G+%1<&}=e%u95g zyDtX6D)x>%XI41go)Wp76rN7+MYuQoW8+fp4ku5~!L@_M#V4%_CYOCGO|wmDK2KT7 zf5|K`J?y}FM6`TU;o*N1QE@)g=CTbV1*fbrQK7-`TmDkv62rA;z!PBsj5QUBa;KQH2G$t(M=< zpUWmVwO{y&C#E^V(L~REawhSWh7CFDZDgzTWz#SzSIlwTz%t>*lVY38Y0qm*7c#b! z>KtcUU6kwC@+*uUx>uPVX3Qn=M}D`fOXZ+yp?S-a@lZu7L6qtEMQ`t(Q}Zp}K)Z;o$7_8-nI zI|)&K-Q5G);^bKcV<;IgOvkKWy!LD|bvyjn-YEx1p451WMd28CbnbgX19>Dd>ufqE zy%HFS@~YmNQbV=-i;O8LeC7|N8r~>f^}j6gMHe67vM}qGxmZ}KCcqo-I5XHYraxjh zP`Wx;r-Z$@0I!rEtF^pBQT}{wwCZFl$~xvR;1-2nJ=n0GFx#1+$K(#Glm+0Y#vJ&R zV!^Z%;95{eumnYQxWp{@m~W);gW+7lb3-VESgQt)3QpcSrV2UE z{Bl#kzJ<{|J zg6j0)PacfqmeMeo%D-I+J_kekOzf%{t00;${`D;V>*yG@kyDXfa^vvt5AsENUdLGF z))mZtwT(+!J?ad-W@2Eu7Q6i_K(zm7=>S^YE!T9RjZjuTue~!m8us-HjNhg=gX?PG z@=8znc!o3n;a0m9UYZcRy`JmP=eY5*Mu_6S5tkY4PZEcf``u~s&n*?DAMUCq&L-BM zMTVSEi3)T5%<8Foxj*J5bqYk*m^6WRggjnyZ{xVO*&45hU(+o}1H>_USV)efv21JL z&}En(r$E(ws`E;oI$v=9?s*xi+!lx*}v3iRI6;||3}2Fe+wN~bcdt&E8%Q^Wf*$8dfR$4F zZabDX z?t^u-(Y1LkiI%V}*ZwV{QmFVu(2_~Sm)8#OavPRmcBi*LdGBh*O6|NalfU(e#q)T= z@k-$^K_eyyeXZ4`#SmFZdKuo^|PMM)HlSuFsk}`D$I^x zvww8=p>oWR&4%i+Zb5ClbiwbK(8=FkSIbCGKFm!sI_H`u8Q=Sj+jyu*U?N@9#?W)4 znO)Es1U+^Q(V_fj2%D4e=cW%Dxq&H)5?JdkAblb03Zz9umU|g2oDqOS!flW%hU37O zK{;G>sVm2S2z8I%eU6nQ8 zR$+B2#k0#2J;4q|LR)}0>g^PJaKBn*Rpv~7*XBRF59 z(`?r=R69;x8d+)V3nqQK_^`UA&pt16)Kep7b@7>Vk|foD1xs%0_ob|Y4wz|Uc?gr7 z8vsy)lRV>e*DkFnq67%z4<=sxX9el5cP2yGGJsNe8;zE|i4ZRs1G*m6&7xDqGtP_v zAELC!l-QN%>mnr4z)p7A)wvd!G#L=J4zTl};G;%NSYbHmT)Rr9@(1Nyj|}Am-M+8V zYGMPx{wNq}s&n)}LK>H?Ld)jw=~gP?%khU6l_qTbMacF&?<6qgX>xXPn*Da|iwC%< zpp__o16|S^>`#39iQIfYb_-bA-30J|$w30U8UZTV1C~T6s*uQ*2Do=h6PD2d-HthT zLV=JN|GpdpFyx|+C~6J%qK2CuALbFLhr*-Vc3_I+PdjG{Mo4mxrEmmbP_+>|DBG(%I;HKY(3t4Ig3*%q!U6 zw&Kv`@o6=qj*Zaur^H++aJ(rX5t{Y7nJCoM2F7nS?Au$tNk^p>t)1dadE3B{tXgnN z+8roLd(YkasjBZ$$%fw=I~*CK#U2vHG0>*m)u=7U^C%#)p>KWCKDZh-*ygn->X!+m zl!*mZi#ay}o88e$rAZ#eF}@A|;#-M-8d0;rgAq>;u%k6m+iQ1CI$SpI1!E&!$taWG zFm=F0Dl;?DJ*QVB+JovK)o^ESNNp&}oRwe*D4q-8>p5>6gyG^T;jJEk79`Psc`3K> z0O`=d_k|{yXe8{+$QfeZ4=h`PJ+6*L%`L5Y;j4){Q)E8gxJ?*#WN0d}-!%UO7|K4m zYg6#}ONYBWz|YsjbpOr)qB!XTmo+{pss4eua^9x^Kh(5`sE`=BS-3K_B97KLBSB(7 z9m%iKVSTU@=uK7ke2Ux>D}n1Z2|#%A+Eh7s#UeagZ*n3Rybm#!`*tkK)}ky5D~h%X z2;Isorpvr8e&vZnI&}rimk_psY$MM25zC|2T2a!3o8x9GQtP z?XAfkjrk>6u`SC9PA+67@ylnW+LCC{pyCU)AU6ab>X%XFu!YFj2OHg`Avs6-eRu7L zuK$jZ!C21Y+@OdyNQ_)E&sgHo%yE7P1V*#SCE0ZRY6G=Ml{EEnN3Jb!XW)AD=6e=_ zuzn>(s_p(=2q&dOQx#CQa(Zzy0a@cG9lQ9n^S;)=nU8@ON0z!nn9#Cl2<|ge2a2644Ks#99-wH_y| z)&J5w{9a$5elMevQWWiLB!m44O%)fmmKhXOFE7y=RaRD{S6R^Loet|7_^v3%iukXZ?TI6vWx$J;8i3`(*Yxb+T-dx>kk7ti=~(5&KaNm}@3tGB0fL?KxE zxw@{#?I%YL179yMm}Bsh&L7=oeh^j*c#b|585dD>eEG8?5~N|RLDSgK!0q3>q)FQn zd`!EQ<{+%NK0?p|u{q?am z(nv_?G$+iJXLS2E*-B+2d|NLPS@veaVR=p+Z2XBpssXxMENFSP|zweq`1sl6X>R z@^T$)LejyzB<$MhTmnwRF3-*dwu8Z94&~!2jvoJIfW<)y6!T1>|!&A=)GXma~ z6^2=Hu29u!@lY!24o2kL?tO-ZAS6+=e}ke$T1+^IW$;GBeX_J-XeVJ0<8A0U8*Wv1 z`#cBp1xb#3bSe3eR~zx5)}jygzS-j5dB%U7_oV***n3y`Qb3+Ev+;5$_Yv~A+jK!Y>DIi0c$d)dpkzkyvmz!*1#%DWwLC@G?%c>iOCgev zFA28+IkCs=ajWn?<Vs zweXSF^LBIDNAHvJ&958W{RbcX(Hr^P5s=~LfV0mAAMUaz78g zIH-m^ZHij)6Sks7<(b3E!)23wWoSO>3V_Ym@}3bY##Rc$?XIMrsZ@`QsveLXBRh_@ zpjVQqu8&vnP6ZgSxbn#L;LRFI!NQJV3-`E@mLhb%h!6OXC1tURb*C?7f)l)N8!ooc)7s}*56gPCq6EmIr~uLks+As zH(}z#WS&ZzR-h_dPb(UeDZ$|(vVy$u{mBCX{feU2b?8Jtgzp0U;H!$)Bk93;SnqCu zc5$j0sqxjY2H|UP>pbx~uraf_tn+55e(wPchCxC4;d*Xni>*Y;?hJckc8EBgH_N(2 z_VLcxksjl_kfV*|RNJFf3lXXo)Xzbh#ohiwugB%D7KG}y64q!|SQ%Qj;_K)aY0=N1 zMvYUz^z&Nc;Ir^E9C)ZgIu+Bbn;jzqz!y7i39f8q{Sh_(t4xTjEH+Uo{BS<0*ECZ{@%xAhvqJb`_*!P`@YQt274;xX zb`@sit(CFof-VW$QyS;unD@Q*GXs>7w(|z976{lLY`-@@Mf2mO=B(3DGGPkMo?ZAK z7zINy$w8e$t!y$65zIkMZ~Z2LSRTYi9c~IT5N^aO`@LpwqjA}MpdIj*9gMY$uOev?DDK5pd#PLEE$wJuFZsI2aU$!p2C-!C~cdn>geBVT3)dil? zPL3%7T*XLrQ_&03Cie=t!Pc&YP5m_KjEp89Ryw@5pV^PXNMR0tAvD_^@dB-k#c!E$ zPhbTqBsOjnj2+zJLWg{qEYBv%ogcuLz6$V*wnlW_lg3#3&3P~mpxtkPIBnqXJomRD z+LM@g92v6K#L@fO`Yl|neZGZ6j#U$8 zW3e5{)Ly(Db$#LD5aWCEK~P5s#XSW-Bs;GN72?3@;OT?^RgBA42gJA!H^Pk>PKF#) zvfo2Pl)gv82@+I;MxT)j-&Ypwq^)T0eA4BlWa!t0X+-u{pJzB15ivKZ(`Vo<7z{mr z(b8YVeEWQw`GyBO@DgxBsYscl%}A@Os?S^J2dk|tmStWfTP^S&$qycb`8D8C_*#?2 z2k2)+tH_(1y3cV<;^>3}Ds~jnoTg4aE6%HL(R_K%`j`yR9uRinf5$&xDZTXm^o_`N zz0g*7Wueg2o#{^;#3zD}>ZAY-(OBrfnd_Z*ib_#{<&`b7krj#PK@n_}q|*CKJAJL5 z*r&A~In}U%FT-9Lr#Y4A(%6M>&~j*~K?aHvp%I(w#wv%#rQ%0-9;)=h2goUK8po=J zNpaJIi>j;YwdK$0cZ1BS@fUsiS9vFgXWidKOy#zI%QQ=09ST@s=+D(O{vfe9y-V8m z!e%EnuMD}JKOhvR15aW|3F+?O{;96C)JAzYHTp!nGkUfxvnob(6X0KbnWtARJq9U5 zz(mc*0sjx-;lBdKzkaGure^&>NzWvvoO5_|s<)4OV&&aNCq-j)YaTOdrODaqtO~ z-Ibcxf3pT6@3a8@$ids$}BnX|5VW2xnqXgDrYm=%}Em4jxD}Ke?MX79;jqZD5Cw8TM zz@Lyk4mK!~W5goBJ z4rBKuPEWafRWQbndBY5@Wt>0}Y1v?jeY?yAu&^;u;?%L*zPZCO#MoOe*>-l3yuEwPlArWoo2uCHoWCtU~U9DYOh;UmKvDY zEU~}sQ9z#hFFC8q|B$oxGW=&b>jY!Q8~rk?$G82N|IG`6J&D41pB^??isgJs?cz*N zxA(om;)gK3+d?v_ALCb?M8&yUP zzBdBw;Ul~N z=#6e1#n6pmBp_wdA689;NwlxiW4-{=r|2PQTX{1vPq4s}&lx*#mip?4CD8L@uMq{a z@qMO@FM!+MDev>oen}_^p*kshR&5hsoF`zoHwg=CZsS+aP+D+|CQglrFh0{B=h({= zG9qsq0#$^DRr(UvsMnVAIlig$s9qp!=-Q0|3#_qQy-|QO@qz8C?EQYD3x|cYiNN3$ z&L0#}7`t)_JNSoo)f{M7^&iIGyylPxSe!TVXj_+TAGGS)gi)O*IORVstOGXC_xdfz zP)MX>{)aOR>2`oJrBfav^T?%C8t#$9&-2`3{2}gW%87UCh|@DVYHw?9P|`4$Fylha zu3u~-hsuJ8cDHg9sjW49hG&x=XZHLoF;lGkzB$uT?WY^F_;!K1GV=CSc^q%trRgSkZ)WG34&*XKzevwPCvtqtwGl*aJk zFV*2Y;h*LI#FPF=MSo_qKRU7?sFeu~7d#HIt5l#Rff3gGzJUvPAe7Z3CCT#cPL*q( zmnF8izM`JlDuDrLg}XqdrL6QD-2^3x1S#84qTq=JUrCD#6Z|_V_udAno;Z2a3qsbU zVa4>ylJwfrV4*;!4Tq#XAS=+rNkCuJr`P*pYm=3^P3hEmcBOJMh^Ggr&2_h9wl2<(#jPGBFNj=S>=v&# z0OlXG=yY@!bylzPy?M^ix5*5UyPrkm}Eb?m|VwnT8 zDHNn$4G-wkF^OLL3r+5__CS_lv&Uq#*aUva&odRQNuk_M+Jf(GXTl65d)LuE)|}{q zXV_jRuEedr=IsdmGutsvJ}h`^n#A|fYK5PU0e=ElS1GUY$8-M=2f_z>ol1S88|e!_ zp!#5Sg=#>lD6L&F%cr~8q)GtQHkYXjIdxAvKwytJ5iy~bmD)g6Q6`-|bx-vr>tnwM zkW*B2Y*aFDUyZ|=8CZwz%wH$#&2P5QB=zR@izAM9htjcHVOo5ppZZbu&(I2_T->GC zh965QA63$>dEVqG2nPI35vKHHZ|Kv8TcdL}IXF}#J+`dp2mqZln)>7ieQ|~Yl=04k z<|IZ!v@A$=Dh)orPDpfU6Iu!f^n0J`_H*m5%ii)sLkQEK283TZsjt;gFHSL=!OANq zUSA5bep|%c+XA-FT}5sLBY4j@R1(nisJAQyvmV1g+P%uIbCfo#7-k)BgsEzQ1y_=H z=TBjxA%4YtCyTMR)%o)rc$a)>svHkM2n}j1!T>|UDAY!%9nGMK%LS?_E`bWQTUhz* zIi@8KLfOFHEQ5*^PD4oUDu#BrN%%HPKkx9JwopsMY92}J=z^O^NA*!jy8d04ZO|=1 zfCosN$Ft08e|ty&$FqWGo#1d0LTeaWA$61kvvr5~(WlFHj0w6RmJ8IZ%L-Yk_dz?{ zI0MVT*6_*TBW-1f-vTDbr39Ap65X%s_Z$rk?-Y6 zGMxZXyO4IJ-%7$bjaa)6o@)(s-9QbS!_NYsc+Sd@a{JZM4XY6ae$oU0Ga;NEDJW%; z(OTqqM10aBuHI4hX;}fsBAej7-JAh;UoVF>xY*6Gkwsvtb~2ygByZ$Ky9gf4m|SBA zB4(ggsjz-?3VdVT5n#A5>4dpb>l61p8(dUl!4K9QbkwDL#wtgui=D966vEFMryp6&W1_>&DGvy)tWah7eULh zGt+8hy0{0hS&i3Q5XafH`vdu1v`BV)qQp`|vUrNBj2VJ-e8ThR{OEr?sNerHnUXa6 ze2{ElBT-{HOs4)uXOXT7GJG;l4Hn5KNlBXMbyI=?R1 zG}P*9bo_~H4@7O5&o}(<_R4*K*(>$=H)NkABlgP2PwTuyndQ#^!(Mqt<6rHSEdtG+ zV_V0q(z_qaZ#3FybPmQc}Jw*U$=wT9uN!prYZieuki z{4KVu%B4FKU)>@dA%Df_bA^1(={MN2V;yPq{bw6L8`%}7o?N$d{w@Tr|Ez0s#_R0Lbhq(4$5)iXF zhMj1}KP4Vo671ps+O8>f{zZ4Ydp0veAWxHV|K4`x@c&K;`Ir9cugjL+MO`*7D`Jqd zhRGZst_dT)7Ugf5~oV@+H z_jSvRqo8-l5qqZX@GS$Jl3aTrJ<52zeemD$>A!z8VECnHRWLKAJ&1zpVQ=(_usA!j z_wj(@b?7(s0wrlpJNUC(04&faw8-g&Lyo$zn9)!+T6uxxbq-~Ii+ zF9B{t@{?yBie6ve{0~0myfKKO|Ewe@CtYzJIC2iI=Koip!);aM`rhx~Z|HyXPW|IY zTKmXAz>`|?M7-^W}@3NKA));ZbfNBw?%{d%-j0jSrvY8fX%m3#vc z^nln$Nx#6Z)3(4Gf}kehNK@_TL-Lqs^7#jfrN}}4FZDv=9%=tN_j?K?xeNy9MmLKu zHtw0foMM`eZTo;2WeF@( z9leFR7sA&)MfQ7sRR{!S`EBT0eJ~MP1WUn~ZX*o*+Bqg&WVqez!vgCU80f zWWys0sI&JWu`1Q5)ScGooU~FhaMs8GV#4;8RxErXqScFSxi@W^F z2Nz)!sZV9rcT;4<0W=zi2Kyl?i=B!`7w$4B;QB$SgL zJNktwWT!ofCC=yVjDIFvOTq>21&g&q7diTV4+rvDrCT2ilZ8CdF0*z$L8eR2L8)<- zA=8VYMgzJm6US!EZ^k|1EMYZr|6&>Ap5PZmd-p1342DW3bUM2<`yl4M*JJ-Cf$k26 z{YghS^xj^8sW)PRTqg9;-OclLsCuKFsjL3jm`02TMLj!?81m<6_E|7(NDn!`fuoge z51DCyc>no+17NKTZh*|wcU)|UtwuFreME^!#QDaYM`fR_chK981}`%GnU>8m>dWWJYu&{aJdNK= zzBv_l!2QSN6t(@npQ1hxJ3OF|Mmy3AeO9j(y%Ja34G?Jj%3=1!n6gsByN|N|^xFuV zsweby3SZ5WUq$gDLJO@p1}wY$xF@_3h z`vOMauNLMv^8nHCAnD69$K8&rJxZVK5#C@D<4rla>D=g3QVKZEt(S|q3ac9ZL`s!= z__Rr(qmkG5rwXEBX$sNP2($dM=m_Ie_8`rfRd^dx{C8LV=lM^ZO~~kTsx0qunjb8G zVEwVTz`ntHf6`-QGNdka#d7HT(C4LA4H z9Wuw`ZiH$S!RUsirFPXQO*MID-5toCx^&otSYX)td1loXeeX zJFryPBBL?jyM5?PN5yb7^qYoo0{f#p%|(MYTkoM4`|6&mgPbeA^Fc z`mpdb$O~CJw<*neVQX)#x2SwW^GllXl6QC(ehccT+a#(J(v&8#75sAAx7tqyq@X455dQ`hgD%UMZPB zf@R|~Pb8j6lPjl@-+u7aA5<}IUH?epeWU)7IaC^EYd`pEK`v@;w4*q2jti+XYR;0E zP&%kny1!2|S>ix?gw?!3r__H=@>(!r?<{xfe6v`uue+*VVsDL<7U$KG^b|{m%Nv!D zHpP49gYQXAMfp1~W*OGQ|FAWN(b&eJ=jwP@N~Z`J^_@RXn(tZl>0kA+;;*4h_+OE` z@?tlaq)^LaXWM%IBz{kFee-%;$L&IOkEDN7UnEyf1g@I>Befq4amy<{*2Zz6?2;jyk102*N#3=DDGty%MjU0+FifmKwv+Kf&L67jk1h@0uc0&zm4BahQ=RgO z+ynKGUtM-KcJn-jS}-TqH$J|)KrQpn4gizqyoxk-I3fb!h6bH1Klh1Q#)W7ia(CM9|3e6ntCbX8rozq@kZ zcd8xrij5l2j9t|3D)*Cmd{jFAHW}gGC~oIaMsMWq>V-kNOoDKle>cjRO&Z^F$BaX$ zV%H-c0@7uun~YTPs#vCV5FU~HcR#arY@`UBItCM{jGl!C|LZ8L|8|I%xb>b8UPI?3 z7~P2nXjvUfQ>F2w0du^4ISt?14Vp;olT7fA^I*#JIbIWALw{4hQSgc5$yJ9{iNVy2 z3pDehP?xA*m0r|JS)qhZ2nz^&vOsmLlKi!`ug6S5?ngzA*VRVXZ zznI5dPnP3y;Tsrw|Flm}yL*vwe_-#iwEoKeUfih`ncvRUn<@@qCJ4Jty%?x@BYtdo z5(aNLzarjS%21hWjqVuQ?fw!kcPLg2MT zD#6qam7sR2QDcFb+)k_NNZ{m99oK;o%qll{Ys0x%w-; zV{{6tzJ4`7bpnHWE$Le#v9g;~$zkI2Bg7MI3WSTUqb(n#R^k{XSH}CZ3<{$gP|-~| z0roX-MlKur_6J;)7t;SQkiRtf$V~rt&+>^r86j4{ru9r|T7SQx3s~3g(xp9-Gd7M@ zU*;6RY!}}ieOTF|KUpn!Rg;LS*(N ztp=m8vnjRq=S6|jhxU*YRHb+CL08xY0GrKHAuKBS@YAQnrFXTLoeWg^nqhqF=X@I= zVBSK8m=l~qj<;{$o~i7FqH(_&M~D#Qp;~WFO3BH|xj(wTy{$H350L{aL&ZChY~m@E z5~8ViX&jj;OpoFt@Zu{~vVTUCC2laePqd!(cCy?_s&rakUl(k}pXr8Zmqup)EwjD$ zmfP6QA(3vHxp!8PU+JhS;*XE0;F|~?kF`L{oh8gOaGtS z!Bkm*NwvZV0W4_mwfflX15vlq+M@dAlx6Ovp^QY(VY_~(UmuFtHZ_c zjB=kQ;n@=^KigP!+D|kKYNNc}`E;0*E}hj{fyz=N?qEKP$LX%=dk(SZNf>%s+&&ek zbyRJEkARLMQ-c^qRAjnyJG_TYFf`0zSaUaLACNcGEa zN+gxP^nY%re%H`rD@!_ z&CT>-`!d)Sg;Y9eEsr{tX*~KyPImoVRpis_KhH()``u{7WMTkey2u?8GNR){#O9r> z$C`^lII-kcG^Ld~Z_&6qt3(9l4;b804iTk!=u8_-L#(T-a~^P@;97R6emh)~ zw|5z{oKx<-THAPKoOb0Q{q0iUP2y})%R_$uM~V``_x>PDp@7t8>kP|~oQa_|kl@*0 zG29Ud5vhdZv(Cq$aq0huX=d+!OX>BOuO2R84r|j+f-GMBG zhv7J?lUnZegt~8pE}P7swVEkRm?CxI85mA>K#BR)i>zpIw}`~f`ZoeZf!m!`e|L{qPRkxa)sR;+K!(YsEt+3vTn=gp_39<7P;o<6TD-0D$>ak zyAlfQA1R+8OGh4m`p-*x`+xWNFO*9s%7px+(|D>DRjbHfN9&hOMwk8d#+ts~5W8sQ z+uE-u$S7ZM#OJ2=#)x^$sDAPIXpAvkgogSXmg8%YQBgW`Mi0o_>Q7w=WLkP%FRtX@ zcT7)#Ommoy{Mn5Fj`PpwBDhJLe*TZw74Qpr4SHOj>vu=Tzr5XNCSkPi#Q}CR+28HB z|Ckah?X#y)C3$Wk{M+g<6G79a$wWj%E(r;BbAE&K*3DO>kr{SQ zJ=lW;f_X_CMXL6kESy%kae9)<${U{(}pzqCZ1DX73EgIB6FS zKi6S~oX!95bN(;gH=7y%5r*HLN`H-f-b1dT8gEkRhX)1F7|ipvg1`xUQIYU6-KU3{ ze*|*-9sTD|{^n2DZUw@2#I((d;GJ7!W^7v(2kxdUG+5e_v{Ihn$W&el3fS7(3ii9e zq^b_Xo2QI1kLWm*-`zW;qOShbb8W#aJ)&s31n+H^B;mIue5VnNV?h>&HB{j}m@3!Q zzDv@gWaH#^o6<6vz20D0=~ph|KBN0Er)chS4s7&RFy$UE6TEK>(%Hs9xgqGspfnC8 zu{{k+vmhIUXkB2|N}ap>37L-XOCa~KM(x>_BQ=_bYZVNflglO^qz7ioj@f_ zO(Jf02gh%F%#CWCIxYVX+8VTqf&ytT;_y1v+DPIQE=<;Ha&ppL7;76nLA>Y4-XI@# z;w9u}$vH+b2z&&NtB*PYZFTW21)ktwdGlsZ!f6Swn{l)Pj&8B-IN)0ym(uG^K79D_ z^qu{o>|)dC&C|;->ozq7-oV^TgCqd(X=dil>+?D1=FeJDS9IthuklJJ&n=R^WttNi zz+heoK6=}Cw4|VNsZHsUm{{Mv7XaTH|2%r$!3LQXYX#78PH;2*Oazfn%k)}j1|65N zLm`I`kVVSy>y6+^Q%=1RqYUJ<#m4B^7;dy7iYX)~u@{1znm{Nx!!TD8qz<+=UQjYU zKB&qzjQ9_65a0A6Gc`H+J=m|9`b_#IW(xBDgZ^z_ES_R0^u-0jpEYZ;k9y+X&BPc1El zLj%IR8aB!*_&DE{mxo*+ZRbEo>P)f)R%`<8#paOgeg7civE#Tl0;s+mq4R1xuj4!k4Pn7Q@D)=@rh38$ z@qS)&F#hbs@wGP3W%XzWFx@@vhEyW6z3R{~=$@5nKS}dqYN*mbT?C(!^2PZ}+|E*J zw7pjsP!bMliXZ*#+wozC9(vD!X7EDU_x%7 zQE-L*;0RB@hc6-Vr60eLuZPOeax=ebx9c1XHhFaDt*xJ5d#Of%%9x*vZ;cuEKvHW= z(B1rvv(h2C8$V+8E|PTUbllp5=?6A7>d;}fYooH-gv)NrQ1iy`1yz^YYNYX6oodMmH2n3$-0utnbh}}XnZa0nLNoa?2LnfLF_dSA}+hp6t zHNPKU?m&`hw&HmP*ntA=`-ZW{{t z5C=fAXC5*<1?O-#pr`jv`>3Y0qKqKs8#?FW+mIwCi{Yxk+SRsRP^LQVb%UNveoK2V zXsFGbVY#HzXwv$WevvLbeMJ8rl zz*`I?J+vh_;O)!+J$2a{9GHU;I++k&On7@_WcH*daAbv6sQqnI;eQ0?ZY*Z&v5|UL zL+*FbtlSRdrYPfSam2n`LAssOWTCDn)Em znsXGc<{II4%J54v-QL8{1p}oXeO0)MQW0BkMV&oLXVYMr^?4RkzZ`o5gHq3QBxfDM ztSbhh1+eeZq@%~Ov$&1g-5QUJ2Y+OrhDO4L z!k7`LF@w0Hr&Fzg7lK1*|LSH$$yU~}PMywN8dl8-0OVNM?|CMP@3o4ipjGA({w7Wo znU)ysg4s?i&M~PR1oO`)nB^d1C5+k7kQ40QS{6QTq?tlY!=jC(d^c97OKZ%t*)EUO zn9lWszttgv$5%&Mb-N%X)%%8wj12WY7vJyc)J$1^lxk-){mQJhACPp(%U7kV;8AVnLE|9B_E0FH7nj zB5kp|>)Y567V-~ip9s1xg$_s2%O7KUYGL8>(bBJi^SX zn<5=e)YhuH9>|4VU4vvYiaqR@lD2Rh`jIWwH7r+pF`;<)`L@QR-Oqv%T;)p|)bbf& z3Z(+m1L*{Py{3@w^(FW1msO#7nI00e{y-XF`bq{Y=ppU2dhK3E^*&BQx@Z)UHuKuz zUOfO&DJAHoh->z3$q&j^5^{1XHtP3v))<^a3k!NJ*(`#?wwGG(j-gRb7@lAN=ilKP zQ&bh3O{$%3Z`V%<+9==&VjQ=A;QBcsj~-tS3<|{^kb5i1Ep4F6=yf)s-uzCk&c~jCs$WKR>6Ior8`VsPGjlQjN$3t+Ktp zmW;B&#m8`x7R?@^HGc(+m>wvtxjo#pL*CRAufEeDGz&mL$1qRt#%&9AS9vJezvaoG zxxc??WD%8~Zrcy$^7~x-X}cAT?zqdgpff&{W*5VY+Th+P0c;1See|%tqobpD!!_hUiRi2N-tTc6GZ|<0NMt^X%hI z;1!WUyHw}^HXr=(OI%lfxwnURCihFf{FubCUC3Bw!W?&*h3N@nQ=J(r8EBtLM!OOP zDX5J20Fhb&d~|PK`I@&|BNp5L5 z{Q}m@?QhWj#S2kn`nbYc?Et0DcK#fon0h_ZJmM=#BmojL;o4tgPR+vpTX+~%Kj~q* zyR(f?ORKB!#~vX_ispU}WPFz=sgRt8?v&+6Ze=08?5nAr6@bz}qm*Ed-rXkmy-p-Vb@~gK; z$^wEY-jl%QO6T-QNhmV5-0a;xCcEcv{Ak)9+Ld&H&SCi31|1#UJ{dlWlBISq88X$i zhoQQPsbg!*Hq--DI;%TOMntgb=>f5|I)A80`L+83hej!D6!8B zPoWmvHCG4T@{&{?T~ptKN$Q1kl*Xw<;$y8pl&jAQggogdKH@o5&P8C2h>M$#S?^9j z>-cWY779*$H|gk++F47AdF1`r->ACaqEciu5Xx(*DmQLCJ|tn=pN2-yTXnSXVcc&%op-xfAW^pTSu6-LOcjjS;HQV{yqabVwYDc-Q zV@K;Fi1j%CW+`n97v}upD>9Gl^q*gL;dg7ZirBir7tfg%g!j{LfKghs>pK8S&11)N z+9jU1bR4x=$h_KLxzm~2jMF{vw~Ikqg08N)nV5kLT9VMdbbqQ5&U*>`*Y^AlNpct}Xj%b0AqY`Qs3t zenRWpTb7+|W`CpXIDd)3H$-!-ivX~{XL4{Jw~Y~Xdpq5>&3o|vSUxrxeg6~tU`c^C z7L&f(nyHspw7S0dqdR?8O2Arw`>1I{9qBMSIXVFCHOWF?i%-cyb<$iF_1n7Bf#n&` zmrKAAbvsn$aIp!BTC`Xw%W3CQC3{hAPGL+@%)#l6B}<_&w4{%D*Ym;2sPTj+x}IiY zSs2=ObQ`*~`Js5Q_j8^2E&l_b#5}Bk`z8rOP#;s1W5eJzEV(h%nx#JLw~H}_vhNmv zm7Ge0;y`rcYqTJV{}NrRdsv*`M*6LY3Rk0u(tM)}(A$~1Fa2)gjWUS{k}|nM8ft#v zdv+fLvmPW`HJxyQahpYtR^M6d-0DAk-K#pTl-Q7bR?UPWjau7eNPJqJl_RO)1tb3>jl1hqTdDHHi*ZzZ{|+<$_N%7_!Tm=M zelY5a!P&vE1||?REdS@OTvb z5+OiA=Rf$JGcOUAy}i$rlceSRUsO9S{1RqQ`0xAL|9nfNc@I!iD&Y&O4M{?X|9EtP zXiENUS(B1;|M=X0{%ilkpDrX+!F-Qjv=&eSjnJEFYEM;t?i}f6uPEWQ#EtL+kd4KU zu=Jjuo>tHwTdvox)B(M|(CYk<5JZ#Z=-B5dRc4XbOttlylX!vBB4me7@N+{jKQFL_ zg47T~Xv}1aPBn-r5jU$LZ?A+vv2V49;LXFGFd0I+pu^R{7NNX+d`%FFXTSA@=ZNoP zldU0kih~dV<+L65?Zq9}ldx)TnF^BzIw?CafuMZtm5xU1rRdwk;O;|Z0(KpBH*el# zpva>+n30aJH}zvs#sjz-14$Db{l4ev=z#Qra_>Sd3hq_!lxaw(|Gb~$00k_E5hXK4 zQkTPLGQy1%?q@Yh1)ujFIzb~o23KSSiB)X$>qIJP5xKwU&7W*637g zgE@h;50LhyS3BbXY4CVR&m=19sA%t}G5|(X%<`S7eujxUCkF>dnNLOcQMg-f-{p8z zNL%}76r~NeiWi!J8A)<{;GGTH8F>S4f*kfJL*chPs;R!@>&F)-KA-Os@^JzTIa{Xn zNoi5zNk&p-_>YdYkm}zDkBY+eyc-InGZjj`ab7Yxxa+v z^J;&l9^YoE=F_3DG!bV`eb^=QsjT7b{#y|KUvEq@9W-&dK|zeD&sDfpLtK9`UTW2! zS_5m;xhl8beyXp3_{Cj)PdseNuYe7yy<6zI3;J=JCGn72t&2+Av{ScKe2<(Gy}7wE z-Q7|Kw6b8)_iTG(C`S001ReflH0T!agGz&u_vWAK(e(n$#jcajp!_Oey#k`O|kziQJAtqK&uae3nNJ7paICzxF!IQE%>g2D>i zDa78F{t3XAjlqPEf>dxA+b;Q51?<`3koVOA%4w(p=1^GO%qcE*A8$S-w$hoQGmu`_ z^65FttAs1}Ys+52WG`GL1em#t7iw3!!1tY*j{|%*83QY%1>CsrVjixa6uF(uDCB6E zJ`@9A=>6<*zCTQkfwn4=`nb?p(srm%=i{AQVWGg|BCv!x7 z1;0CYk%ElWst?6XB5s3IH@6BD7FR1YL)IX`Mj{WKxxDOzPb%}RPQ0yNz7|H^9!3bm z;9n}y<(Z|q4Pf-7i!bOPR(xw;`>e>dV3^D8oA|cM7Pfu3OomMacIzv{#YjCRo=Hn5 zAa3maX517uU=KcGaGhO9NNDb0=RAmJ4+LGAN+lR0{D26+z*g0>=X74y#~i%xiqOZ9 z>tzo2;CLQ3fhsutSX6fUxgIzQ2Ds%D*h0P-dV_p3m^=Dai>lQ2&CL>PyFtRzsE|jK zR4UqXWRVbGVB3C)Dc|eo_Xp)h5JjERa!2KxLm#n8JF88<)Afcip(_P#OW23UG7j(! z&^;pPyN}k>x&XbMWDT-uiAx9Z1kgfc@_-xc2+_5}kY-~FYFX}!La|~av0R$F5*axe znRsggS?|;H3PGNe8({Gs;C>nhBdT)k>py)ukZm7JSW5BSm~ZuH_l~?D3iFq#mrhCg z+)=g^#87AsHwZ{5OoQDdSL(6c(naadXajjb_4|w54rXUpf7ya z@z-dTuRe#FMiqkojl%5m@+R2k!uk}|WX@re)<6N;7q0~@tb_3NYP@rMS2*fGF`l4J z5FI1v0V&<$1EB}i+7EzJD}ZtV7g2K+6*4+L-e(b#V%XkwA0$e-CIVa`v050#EMO#v z&$NUuSaQ{_hs&y?P8H)9o)SGePHL$r(^k}-D`Nx zk)(}$5BW0%X#>#`{6h>%XI&*Ci>4kWg#9vslhx-uIM!@S^#PC#kVq_Y*js7REfv0- zhV+~14|QRiJ<@D@!!KUJ_eP8;t)a($(H!R&1f?va(k|_e+ucj)3omN5T{_EWqR4kN z4Gj(L8ft)(`9d&0;2K{1fnvaww=65s-=c$$_F-EWwDsnpDLdxzW<1|F#UL)|&Ya(F zE#Q23-8_tGdkm!{`f`5ay=k)BwV&C|Np7Zu?p`R-&XSu~j?128+!1^|_Yz_T4)re` zHe_gAZl6!2Dq)*oDDX`yjcR#Mo<5C_8Xp*9udef1clO-GJ ziZ5^*Yf{ZfM%8q>Nr1)khPn?KC(8uamgy zmaj+$CX|(lm+Dd!?1Mz`;sxhFm9}XXG};j+S7C*T$NXxpn}v#woyNt>LM`wrMWBKw z^^I~OQ`|loBiq;|!j!(gK5i1!0t=GpV?U`xFa8KTXgK{PFIDV&-aY`_oo6_&oF@%H zbaFTYxHhd*Pm+HLNPGW~8@FS>a62RlM7wOjoPj1=!_vLDzXcoAvQo@K`j;iUX4zEt>@e){z3 zO++m?Et$1uO8mA<)SskYGPr*IfqJWwffhkAvg_8;g!=2>I0QIuCZapam_J-j7V1Kmk{afpol7{ey7RH1u=j z=QDU!A|{)mAoE(C!*(Ovd3%z=ky5v0zx!~6VRLL9JSPT0y{ULoI=# z7vck&fjn-4Fkozzd_peFdrR-9O&j`4Q7VTHsrjWSJuT(u05Q6!k1O9c5c{PM+>;c% z|HugpyQXFeA4cd=cfM~j)m@CcWW+4J(~SqOAy@tGA>ZOD9l|pKa2RSB(cTmDUU5iY z{Ba|VpzD@14u_chyvbRKu&jVcKPPyFgE^@TND8$UilL7;NhX&xuONzX{cWf z7WnYH)itaUYdg&AimrH4sSoK{Dx1DKghowFOw>4{bCJ7HWdsUv^XwsLwfKNPatx-U z@r*CaRWoBK4DxN%smpE)N!(eeIwkK%M^CR18!kFIRBG|@umJ~q*~R3s#9UoJzlu|` zBNs54x0{++`df^`Jq9Jj2Hm=cc9rvawe>6pbUCBd`6Iih*SfbX!cue1^z47kA7S3C4Bufmu{!U+Tk4zY*z9MrU6HL{P|pet z#1iRXYui%)Z7VI`%ksZDwug(UZdzOSiGY-Qy0|4p@&+O?b^n4$Ov4+jo1omSaye=< zR8jsp@}V6x&$u}+V+L<(-BR+UC2BlT@J*@_9Szeo>W0nArtq=W9X2km`Qql3k}ev7 z$HW>f0sfF8n!D)BmqSZti(@rAMX;9XYC3K$>XlAj-Kc!q3^k0el6>&^1{q<^nHZXR z?#uv*N6$E$^Y+HFqJ(khTcm}PULo-L6J~G5gE!A@8$rT~a;ntrThw9A!TSl(h-wXo zYrBv+FzUGwL;oX%A_3So{n0Tq(#rl{M}%|}P(~Rd2J$3vkpER2+hO3`&APqFO&SsK zYs-os13s(sHOF}pH{oB`P=JQEpmwn*!+${Qsks3AVb>h_l(a|l>yiTXX~Dje(Jy|G zg!2EdA4wB|!(PC;q3%Dq-B~EO-5AHyq;lKHiPiBMo+~cT^5%bXyS0%s4=r?rMCH}5 zP1WuOJlCc#yuAO(?an}Mcf_mvB%bxZZk7N`Yth&}E7C8>PBk86l~xn235dLN3^C}y z9xJf101o$PIEP-sVet~t}5O|NRBYB0q;3TeKeitTjOQ+K97j7ggGUqfJ^P* zP%s>;0`iIXynHCqA(Quw6ZbR+yD`>%wikmA=zL?Lzy~=RV#bgT(u5@Soh(Ju3q&EP z0m>vM%07sMFSbvwUyM~4f;fR_q$v%v8KR*TnB2b+d*2o-{#;rY%er`wwC5Usf&z?G zc6&7lcirH;usc~ic5kY`I8R+J3+_dqY1EkC_qwA@f)Bk2WICWcj8(66hR=J=DCiKq z4w67+Gcz;i;xcDFXA6N-;y!Dw`)ceqi#z$ZdGFi)E14M$EvKS+LStZ&?lkgjV_xqk zv5v(Yj}~`bcq^8x{tcpD@B9{pO!RCQhGu%49!0C%TjrT3;yUqUI~&;C`)p~+1xFZpFBH)^i8t#Q zO3wjG5`dCQ02;liqPiar#2FkRGiwQp-B04?g`vN8v$RG#OP>+DC(WDv?T2Jp1H^ap zT+77YyY^wD;YcDhZ1U{8ITw5Fb6!HMIYZ2&ZUp+0*Me4#>G)bb2s8KaV6JO60Fzkk zsM=NKk4Rk$Cp%gJHDLspFMBC zeW9&i+|B9S;*$_RE`cGC9%*W6y{NM&V%Ye~qi_Pqr)~G@dPt?@+VI}?Y$GujkS9VDOoh*VrYE`r zAQQq==hG$~`_ak(-9RBIt@0P!_>LXOwLNTyqB=jRcumYX*PjlwT=L!TvKK1C_25pXA# zx_%&A#1{rE$hTKe|!i@TCo=T@7j<)9hg-uq`FEK9e;g^ka-Ou7$7(MRrZz4}t1>l#?Qk zz?!0HfD0$aUCv3b>DpRf3_ha;nEsGTM7L_6X2tH#X4m^l9hZ}QR-yjrG2QMV;FV4L zly(!dC%1jTuRjL7^`8g2i|dVgc_EnMrJs;@=Bl_|2Wt|_j-X5Dc)}o%E986rK$5-a zF6fkBH8v`Hpx2hh7a_OwC3JiCclZ0yEZkOEonF1_qF$s_d1M60j7u*{iJPuj{<}L* zr`z1Nci33*L$@e;Z6fGxbl0<&NL8e#aqJ1Xoj;mL;54fAlem+KHk$1(ZqL+xQ=|P! zgK`|Yo!<#WGaEg>3yg^cXw_vSV}bKjsNDX5Hikq7*`_+@-n-0Y8+Fl zsANON%Ba+pJwlaVBm7l9;^yOax5kH0XDtGN^)5D`A;ihL_1bBw2>NgRxSutXGRxIq zN9gZ_wKg0Hx-A@N7&mO#@|^H+hWekV5mV|9 z`lsp*{vAZ8bkV@b0k&By0GTU2Mr!d*aiwA{)?dlqJpKHB^A-z<=eaZo)k#U89!d2+ za)RP>9MQvdeA&qCf)0;z-!(tr>|~;^?cp-giC`-@dS3nois=hg%TChlX8vp(ju2?e zUJ2&3zI~ZARrU4tyb6y`zUj7~lIkU>^&N}sZfkG1KpRZ@g+$WGYA|F%FUXye0@8DS zeAHN#50f&j3NS5|Up9Dq^MU#Yz5-C#F(_14lG%a6oa%<{v;xI?M}Mh)k#oW!#q{1+ z#1}8zis1hulqT_2oX^keYG-fIwkoF%1R0Is&wK%#U~wa(Bsxee+jg@O=a?<3y=bj zISp#=JT_L=1*b>e{m{u6#-Z(sxueC{6hhwCsPth=q+^Mtu0S8g$vP4yMth<86TCSf z($pF9qhDlMGrmQj>C+L%^cE1h_Kyy0jz@7ASY>!1^ktg<%OOsq5*jU~N4J;e4>8+2 zgr%!?^WUqCvFV83kXRnd+Q?}80O1n6*u9Gz?5d|ImEEpy# zA^*N>|0E~154y<6W>r)4B%a*9mH7C$uL7!NQqSvN>?*MAeSbs~ve;g@Z!Fnv9$!A# zj8R5*@3JDMzaanLm#5eC_fR;}&}nGiVKvqr2mN972^v$4g7m96^!?&4yb2Q&_w5#! z@r*^yJ}zj`h^N`mInAV*YOf7~ui>6*#QK1V&be=;)mz>`OwQkk+PKWgNetx9QkRj` zDah&wyLIDgd0!g!%aZ9W_MEa~ch|oj)JsYo1+%jvAJ7kC%uUxjJC>60Su&W5p;M+9 z|3gqix?TBQQT-RFdUm7g$fXdL@%{G^zkbE**40ZYxc3g5QEI8=PCv(^A|th}xUeY< zwD_NUHK8}4P@<@7d6=OjtpbI`;MqW@``l862<<*5tjeUJC4QDM{G^DvzunI-J3YPG zKOs%)m9JILrSs?CDZdhID%)P^s}|p`ILX2ZwutvxMaN0J$##1vVhtx0WOCB5%mo1e z1SqEKnwkzhZV+1tRst8a01=c2E$NY)Y8BWngIM{T@&`GQRpHl5|n1 z>^&etc#F}CsHh2EU&Pe08N0|7LVN#2rMW@bCcC%syhGiSv&7P_x8O_FIGYPEMKpqI zR*uq6rE>S)JH#{-j!s&h`O*$%8T6eBbQka-mq!S0v|e{4ieIA4mcPs8DU*ckulWW7 zbIM2&+Cd{c1liiUOO=hjiAYz;pzH9i%G;urwu#o-j|WhjI? za-nq!&{Ta<>pnCL`WD(jksGvwVq){rGHyQ!>b4my?j2N1=SzjDb`yhcXCGqVt~yog zvw~=SMe(Z`ZGpn*#}R9Z!>?bBLr$t>kbD?yr(7b%!jjr? zB3~|%YPRSRA|F9wJxzkg$yo?Lr2804@ar29pImn!yZCn0Y}fq?8RwCq{rYjT3fU^J zg?V^c$FoaSu};vrxe3ih50lw(a8(7Nt#(3S+#w^q1_by74-h_AX0IZ%I)`5jMh#xU z<^xhmva|JTcYj9cNEsWOHOa}gz}RR?t4k67pmQXk#&H?3V-<^fJaD13i(ef{dYaNe zQW+LGpN)P8j}lA4PLWC@h{Wnq&wyAUOfT0oaI&v3N1ee2QVZnwoasJ%N|Z*6#$|jd z{g$!+wp$Y6MsLZjh2d%|2-=j1o&cR!3R-1-JHyKd;x(X|h}0QTKFh0vRXK|mK{Mc|Zr(KuNG@M3SJ zi%Fpo)^JOObasZ2d_-59Pw^c*P)&%kVDI&kY-gP!TZ39yA9q#v4+#)uRY!)O%PRNY zQ*X&oZZFCfa9}WMxYn`;Q*4_cJHOiYOg#%;Ufv)@h~=LA=ybxrlYo(#Q113& z+8rdEWT$oq|3uPoJPsX`UZPiqm+k@Q|Lo{gbhtMQp$NYaOBK)7Aq1KnjrLZ-XP^td z>=t|c0oB#r48<}j4-)HX%8s|vVAT792y8XCvB%+c0ke#gt4R@CT}nVJsH(p?V$yP- z5nQ1c2iR{q=V_nvz4@@!fuR#>W+``64A`JsA1=Qq!MXhe$mC671EX`fZYJDh)U?{_ zA)#}Y&!ZeXdord<-AOoEWf%|21J<4tPJ8=nn7x`*_rEP2Y%-d!lW1X<4wMX=b_z?M zt_bt56m!S4_piQ{-1dfKIdC>Yj(WVN9gshe;hY4EvOIPS4(M~aMr+eNc z*@Bty<$QYCEy8rkSmNr2_)uzB;*b$mflzP1Q67;#$dNULu(hP0w6Tu@2-b3#)}JiU zx;m8<_mCgEn97WKSpwQsxstBBaun4Es<)kWd(ZE~U~=mDLtfJ)D@BeG0ww0xFZ?Xs zEF0I=iE9DZ`*IVH6KR{$uS5RK1?e-F$!kc|F2+|-iG!}8;&`qf`4qUQb453&qDj?} z`jWxy<+puT?cM{3&>E@=1y^$cy0u6i4IF6BYYc#IOT%Hi<9NvivYC%4Msp%QS&nw4ij>^3BVnA`NgLm~ScuF5hdlUXS}Xi}YV= z`DBER|9_wJf9bwSfAcCdrz5djlKiJM5WC7Cubb@5i2D2kw(cfG#|o}&&6^<+Cbfvb z6*SvTfUcTAyM~scmN=Sb0c7Y@50yp9zdYo>X}JfGBid8w{VIcImF$Tiwl^B8%&tx8 z=$c#qrD8=y++%RUk3kAh;PL&G$!{S53IDUt5=+uYJb6Zj5{FC_KHyP-d1LZR6z!=r zUI)qHY~ZHyClhkI5b3*M$v>wi96}oZbRka~c1dM0F3r+_d))39jms<*+o=QeG&QhFC36#Ox0o3^w3;`z+`V)?qe{9hkFC|BJ7*1e($cC|;Y>;&)7M z#ERQOKomBI{d>WkALfX1xm07>6B@QE+S=OOv7BjSU%(641aQoPOb2y?!?39JvD?aw zo>(*Bu~`qX;k;c|Y9jc6ApFV}@g?G*@4y(6ZKyeH2mOdKF#OGF702PM|I(12X%xsB zht{{%@>C~8WAwz_n8<^s2{N9xy6e?c@{iXE2Rr0L8O$JK*=Da3s@@ko;XId+1_(gt zf^mLTqe_?Y$FuBQxk46F2|zAv?RL%k`DM6$6LY= z@Y*^UwdX-Bka(-+*S0&5>lzJ#oM)}FPZ+es@LE1(6m!q4i0oTxg!s{( zd%auS(V|nh8f|?Ac)uG?H4L124zqLK->vSy1GYrL-DQ(q%Zz)I{Q$6MT=?hVt?dyg zzNMwE5-939Q8MRdmJ1jP2P19YFHN?y)T;Sfrp12&XslJ=64t~*7J>8;^+YyEY=#wF zb_Tg(9!S|;z&aoQ_66BBLJ^c`~feFNoF-vNI^j zerWWU;4+s0#%AEChF1G%FR=s&2kZGA%8JAeqbL~_Xx$*!WJ;*7|) z0;Yi`6rEGPF_j@7@wua4+#kqB$gPTv9#21}b1n;1zJhgQb4}2Npl#xhC6;ToN4{_> z`*BaAYYV}A;mdJQ7E_GyNodM&3t(6cfE1VL+MpG7!BlI}s&saJfA##i#r$V~8g3xd zbr)jxk`t~BOBGBIEck2xo<;fR-=^{Gp}(PFY70E4pqd-B5Ar~tKKv4Oz8L=vF7OrT z9(u562G$2#2&QZdDflOyEmFGu7aXO|GpGyi}x2vK68ac*d8 zDyU}nori|ova^|R43$vWDkvMtF~#}VZ}+VG3`+3auL%$x6;-Qgs#Jj*wxw!DET|O( z6n^%!+YJ>u5VP}zpO$z#gt^#+x!hg=94KQ*O~?0)Eb--?j*XRBgM?W=EXz)?G$R;& z+4tU8BJow?MXf~?Y<*iWq?O-*$_IH-tbx0z&Vu**5cuQ21Ml1fY{9HfNLnJ%<1!k} zThii$3P>k=iHps$v+~o7LmZ>2hH}}%S0|(`E*lUV5v!W^kVbU96JkF+p_x_o#xOF=^4sLNb5GU~VgU{YS>9gYpjm^k zw&Iw=4PYm|AES$HA!17a$-%&>S&~MMNT0b*UL(Us5u-J!sFHAjq9(ByHhdMR8-iLj z*G^+TKeWsK|JZxasHoCyYgn<+0#QLEgCr9{g5(?&P(evW5XnduksOPxNH&4wC{h%X zgMb7D0VSg%C`m+e&Kcgd`*fev_uSJLdwk=2f4t-V=>cU^wd>i>Ue8){%{iCsvy#A2 z{7(9LE)6@*ju*sw8yyvZKU;F#FUzK0=A?QMBE+~W;tmkOO>rynE`!zeq4jM?T>xEQ zRW`S_hL`=cr5HC*alIymKOu;SNdRDceK5xQJU`0nDnNkOK3w4XwZ!k?a{@0Xb}b_g z@lNP`^aN`YE3rwB90Dq#Joeb3j?|eeKjUlEzm4#6aAY;guzMqFf1bg+T5gM9tG%m_ zd?=e1blL^&h<`TA_RcrK1#s@bsjRikw($a+}YQF=!@ar zy^z7sOaqn5dGkGjxAmw-x$iqmic5tAm!04v!>{GhIBNp02W%1&eK=a}((#JJQor#H zPt>k{UP6GzXy%LeyBp3W7uyZVJ3s?3y1|O>J;d7j_>k2)gH^!pTYw^dV)o1XMVN;X zLF6|60{Hix@nSBm2P<{YwtTQ@%6yZM=&-%v}w>Rh4b|+`Z-^f#(Cj^r!KZxcgmNiCT#YI=Claa+E%TV0Z<# zm4M6zl3&|aDq1KIke*a>0+j>+sH|%_2Q+#YURf^9MwI1KR^Ku+i=F!t`R#fE(pRDU zwv%7+Lgj{?U4G>?nF4t5pG~BWBFN83ahLvK*_*_PY)k3N#c+(q?XD;7^3EX4384cA zNznE7qfV*dC;HZn!6FnK!3jINfCoYEptql|<*fwA2#W#fWofW?Aea6@`D=A2QzQ!L z#HL76QHvoy*^(qRaC@Mt@8{2-(Y^-`(b|NK5nTB;G1psoo-9d$gN-deg~LWKCMwE| zl2h9d0f1ha(}TfHv*shPNGR;ANiC^%bkK6jgC=PVoBE4xb$s}XxlY(8q4;F5xS-LZ zxwbzSn#<9EAKp0Dm+^vEGgsecG}#&whoaH#Y}Vpy&#k{n+JpH2i;7V$V&0VwJ1@|T6l2k`5_{(wv_-8tP7j&R|?3&*WuFJCf2}5)Zvo3s6U$X#7 zl^J-uI`>=(OZSQP+Ilge0VwUUk{e1t%P3-=`RSVq+)G7#b})57e>fjbC&YD!N@LsJ zH_vrZ*-m>vjTHyss+S35(eK?XAx zVvcyTDZSu{)`7!+I%50yhBC;cvMJA4XDbik5Kiwo&KJ@rkN5_opKj;kSy=73e{BQ$ zNN1yQ1d%;aJQc%+spO@Ib_gbVv_P74)k)QGs<#kt2$cgdfoA!Yp7Z4sS~Kf|t#=gb zUAwk7_3|2}s3iNLPyQ7~g5>GD=s94tIi;iq64mx8-4p`$y@8eLBGOjB0ZwM1>9T)y zD2X@)a_EMGuO01c0*GYRX28p9C1%E~#Rx`W$QWMlxmbSH_@BO&);SShrUDx=>o39H zc%`7`_6&BS3U~#t?|8C2%#-#9A1#S%Yj^JK(Nt#oKnSdcX_8`w6WJ?-kbxR8mIG|{ z&0ARcx4*;{`LJ7OssY=T_zK(F^E~we0gZ2JK37wUDk>_hV$wkCNBhiAn^sGvY~nW9 zatR{HQrkltH;U?|qZk?`qr6+5hdM25wFOwgvQS{C5%-G+d;*z@MlS4}v)i6}0(leh z7GQAWbX3cVlS-e%iMf^N-W$BwQ_4}*`0J{`5mxG;YAX1Zz50(#D|rWD0D8~HQ~V;i z1uj}T7-(#Y|NA-ryKev2_5uI(4ySz1J!5e4bs~P7Z=W5<+TZe9w7&sw#6EG?x#a6D zNguvQ_`*>XgX9{33T%pLt!lmr{f#7=3T#2SOep*JdV8FyF9-raXt&XwVRq|QG#o0Q z7f2>{h7cp16ZXIy<_CvUgrex=ttwFJ2MR74LNZ3+mxG?^(NlfIK@Lu?;ZXzNUQy(sECEELl9a>uxKGr~$1&=ETrU51g1tku6MWvZQ%r>!zhdg8_h*3b zBF()?F8vA%4g(Dfg5{|ZC?LK{M@v4*9$&S9ibCEu@25u)I#Oo2UObNU5x<^y@)gto@i@e}6|TBC#;l+QOaIab2QY`>M?1!;yLPsVwY z)v2%QgTWeJIIa!0_^{(DYwTYU3Ir5JP}CI<<|0*nCinox0DF{rTMVB&tCv!W7@HGY z4Z3J+zPClJag2DjJvh#t<3SjMyF2_};GVQRKCP(a<>ghdZN-1q~%SID7%leLJEM|?8%8zHZfGp#)?~UPOgWnx z4dIwn23)<3@3hJl($F?^N*;9ZM^B$RG-$ds{&X$z<;_=Ihm>ABu!M7P_#<~$VzHUe z4PBKxuvRa0T%&$$_054}&%t}KT&%W7Yd_(^pf~MXQlT<_ll=dA^yHtWz51FFm&dgM+_8?m@>funS*<1E{mMxhi&6`;bPkr+=bMw894pT30Hm){TlO*U>xbiZH zI-W}awd>TEL8q)PwUh68dk>v#(QVopo=l9-6|dTH+IH%iot<8li1GG3*tGd+qC$J- zq4e?T%GLg?8pDce$8j~7^7qO$rU#4yehlYfM;xG_+*kq}&Dm0#BJbv%veT=q!U*)F z*^u{cQrT#cjOk1|)e0D}5+x4sM^f_uFgkO#2K0B&5wUEV38)Yq(U0 zADsRQaIKz05Gr$~VzHGU=2x*(Ukrq7FCF4TC#S#_;RosGXf~lUURHjrN$?{OX`_HR z`N&|g4IJkdqfJRe9RQi;X1wXdsn2uFk9nAPD%{QBwe$JaL=guwW1`m=n(NkaOYfGe z0N)u0NI)5xM0Ux1?f6r3zS8VRKw^E-u-?gyQ%l@v3b zAL4J3RT9Y^&DgZ88Z!n|(`y`$?XafW<`BBwsO!&)U&;&aT0S~2nHXab5E@Hpz%#6x z81ckuRp*CjK4Pe*p~_aW2%f1+Ti*pnhv-cwbA(!X555&(PvE`7(bXdE_Rbt1e<(Mu z?DHzefQ!oxebeZ@HVf=fd1)7B@mrqJ#hr@wj1GZ92}xF6Ddw6DdDn+mjXYN-XPvME zDI1BCUNC*Zii=xPN`P*%|1M*y0I@qSmyDXEOA*?$o)@OnNqfLR7wd@4pPUqXj806x zMu^5-BIIHBl9LW**W&EZWNbWlkpabr+qo$0pWbhQ@d-mQHUpV+ZcbC8?E;XzPHt!VTaj=8(>Xk7$YEI~({c`taaOTzj1x(fB)E zH|4yb$xy>%4x#nMp8%GWSTCPhFLkHxilFIyPA!#_A|Afp9)Z1W{y|*Fl5F&Q+3T+3 z4FI%PpCPHQOg5(QJqn8 za@rR?I!_e`oMNa2cVqN;ghTF}x6!S_hgkw*rBzq%6 zt8-tOtN$sC{ijKMzD8%HlLOhc`SFXF>Nx!55Nm#%OtKk(fNtZ0qVeKx7Y=0@yVXDk zNJu=q{YXQH6m1GSfojo)9nlo2q)x%DEB$RBA2vsNsWLxcfXePelg2{q97R)OKFOId zAL>z4x?{3treK=)K`JWfl!fNOGW0QCzv@Zd-UZVPlLkF&qT~-TvD=m?4SjK93$<9~`6p;_D z!eqeN>ysafRn|Fm3aw1TMmp4Ig|*Dv!dkm->?Tf4j&C(R9FSn--u`er9kVZupbz5i zM~H^6B@#4qU6>^O`>LX4T%}!}MbHO4`~DR6Y!F=R8J;_udu-YLg!lcVQ5B_8SDu_1 zRxt0*%Gb27rB+rQcQ7ifO7f(kf^a_Z z!x+V_SVOAKWAwr*CEe?bBRsY%cSkT!BKrEVc8)G zrt@+^!1kZ?5~ka846WfC6#C1heYYSz9*1^E&WP-}z~R$rvDBMA>B~QL8cFF>o>y6< zyV!;f47|l{tj~7mvmUBm>&;ub#gG3$CK)SxL+$B{Y20n;SWGI%>a*N+-Fowa z-kHf9LUgaw7xba3#a6KdCp+ZQ)R0SCsuw=L=cOeJp&F%IfQY45IDD+h!Hy*IZ7Lk* z=L6sVkZ8mBmxD^7>6-t7lX7l4$?3X}G1wJ$EeF+NPv>YI0JFNEaY=clG{BtDy#N(CQjg+I-2F z_V$RY01^_3X>FD4|cK^t*NotV-iHV4% zC7s6fr5D!|bo9M4ay@?Zjr;UIX+-dBcz`XCBT5|Jf_H`55Xa*#&oR+nI+ELm?lK@Qk?ku|l0taWk%)Z+&GH?FN zgmq*9_uo0a^YKY4NV)#BsmtlY<+86u$KJdHP*Pwum8U|?WBke@)R7T^S4Pf5mCL}VrA zW4)HctPIG|te55PhOQq!s#D==cQg|G5_k{Qpw}+3l3p5P{|4b1Z>5Rywg`wrXBB;< zB`k_oRL;HUKrYX6S>EJ2Z*J?zCvw}+wE41b;Mq1A(dW#9#ZOD%5M8cGg;`rz#aPdi zbz6ufH|KABmodyy~+hMLSi1y=9gjAy5 zJQf+=NxG2G1F&o0^c`4^71FyO-mjD@x2pa5jQUSU^?jdxk>xlZ4MBGCP9a&P^^h-oAj?3_p?F-CErCUJw)= z!l|a&cd`+P2k_Anx@|1jYezj&IT9I% zQ#X`64&BcslTRGtlfpCD>C(^!Z+9*BKCvG3#AF6fnCTuq#;%?3d5W2qJy{^mI;&qb z=w;Ss$JgaR1}vITfN$n@=ms{sRVsX_f01TX(qWeS+iSGMqz{88l#Ylk&DU#Q z)Z-0n#UGJN+Ax<@Yw;7yuei0%J74vBF=R-`ZKk!D^yE#bZ1iOxP24fXh2bqsO^eKY z&yIYaSYDDR&FFL}Hm1Oqi=A1mx*^O}A3Ca;Q`VVptdw+<>buytDUWX(=Tm=`1rZSWb3+~?7}%-gQd{;5W8q1z`T`kX z*viP?-v0X4-#*<}_Iv%0V(z_)!~c?Ae$##i%=FpTa6$J!0?+i}=qk zV#8_3^fJsgQC;i5eEh%d-GBS_D&%$P_jCWo7xERPgoC7Bs4esFTwFRN-fFd7djUlM z{Ql>XrRfesDLxc8`uXo%oEofk=AiYSImEw~C^-!3wBq>|hl#&)acr>GpXZAALRS8H zb0ECd!!7-`HX`EmcP{P(52>cr8mOuM?Y{l>uNEe7OKm(C%P zvv4T74M4Z(+(8gA(3|}Z8u)r4S;?{Yi2x)1^;i1s*)0W?6k@*a5N!pB`#8AmWy+LI zm-HaW+ecuIT9+h=IGh2=E1w<|1!iKl=x_u~0YP*&v2*@5a5gLfJQ)YhU`4iNKp9Zv zVi3%c-BtdOpE(Q?8ROwz>2qk4D3fw<1^(hkNZc0J(MdMFrTMXR%seA}pq7bU2a*Ms z%|MkzC1{07{(wGwB~L&yA^Fb9Vy`cu!i0kMt=7HgXcMyLU_r?89O1K^(f;|~fRR~3 zV}D&_V^Qf|4lv(dK<}h0lwuRS-{OG+pmOpthqJ`on*$=Glp60-4|Gm&ON*Ke1fX8*aFj84pZy#IhbX4kideP{Wac{p2!f0J2+yi`NVxR%v`i4)8LkB z^R?hK1F#KgLmG_&%2HKRLYZj7OmJuoD@_QbR7TRm{C3#?J0 zx-b@k0+lBF^`>oQWR@Q^9M~f2;z5(C*-|Fz%l-QnN!B9Ny-=Vf!l1P0uCd^}3mq9p z5E#)v5cS^i>0DUM1ypj?x>MgNSJHw!{it4REo*od} zs1knbR!Fw_`F?kEk#F>DH03l{DV9x8FAj?$5&&|Y5HG+Qe>)ANXVKcsFJ0&v>m;2kUA6#qosqmEWxT)gPK$DBzTk^s&j3#55tV6 z>Sz~%!$bzLf1RM8E>duMDee|n-B@D2TmslpEDtsIM#{-Kmc~yl@xAxv7iu>8U$YNQv<%V-%>z=^}sh$sQ)C0QV1kb_FDhqmr&V2c>bS9!` zGWIkBH| ztJ^tlW*(?lsRi0@y4Oafs*H|ypgmd=#Dw}cUjDus2bdrS+t)6UzGqxjAyy#_{oVy_ zvPJucrWDy=$$#b~=WA+3(fWK-YL1fPh2BOx@KUib#obwD-uKTiQbi8I(4{2&k5ByT z1F48pT4e&B?8b;V+bWU3H@Fk^*0hnYV6^TdFq-hMIB}{6P|aZD+3H(Vt#A*hcEN6!yVy~;xz7Cen>?oHE458k?b6`Hzvpe2_N7EY zKjInm)1nwvBSTD?20Ugfi=cmGm3i4u2fDT`Mp@cNAKL&=ZT2o@3AbK3GIfo;5B@K= zU6>}b$hV0T{(`%fBw0xuKqkJ~A7t}~7l3to2X~EWKrL{?`x=c_RR3{e`$`^%HB!hs znzd&#_4%+$ONhc(h_}z~RBx|rS)BNsI-$wW?utD4v~fs)x5hi>4}lK0C54;dR(!-& z1E5M~h665fUBiu25ZrIs`<%M;=1X397w3Nn0b93GiGUX9e_-x4ri%5zCW>Jsa}UA( z>tQA?y>)BWT{L#jEz+)Hh~(oCHQWY(dG!elffpuWl}7hb*>)>G2$`eoECJe$s>VLn z&lGPt!c*9(_VfDb9+O-%{05UT`sH!AkzD@vP7o7yLjmV$iVCy^ayTF(_}r8TEP>IM z>!%C2#T957WY>>P)PdW>M+ASFZ}x`U?l#^8?a$|6#`CjXhZB26jz6lti0${7GyqMI zNjfbBjeliHfANzQ>JFe46Wd_C@DXH14#PP>Hap#4xWp=x{d%@aObXxX?Kuw!z(w;lB>E^6aew{1{FaCDlb3?3tauWF zu}E^=K|dYnC0qf&6{X>YhaEAb)D*?3soJ+QHokzO`6IM`P1Kj0g_q7g*AVo(2~O7b zEsviJd*Oq?Oh;0SmgCi{g;=~PxC$XM-pTd^>r?G3z=D2$Olm8y)=TL3%ujljsFw#^ zULxFWg%#BPVikWs)*!b!={}YszTfXc$qtqFt2=s<<1pNPVE3%8KVLtjS#D9L>A4%0 zg+<1kxtFEzR!*JN&(c{fIZxlX-xkZD7|9bA@tlmwMC3!i6))pR+s9{>BF?rg9d`eC ze`-9eln7?_W!Iid<$pc7kV#u9id|p4{1f%7$owW=BHsjPjr4xD&h@yEq%T%>;2)cX zrx}i7`)Kcd6`p%Xi$B6QwJ4;*_ggEMuI`cZ{iz3M7!BnB-3a48Zi7GG=1>3n7Ylno z9I~7g2ky$_f8*jtkc(SC^rq?8>nPt8RyZ5RdKGgo{f&z&gNrlT**~}N>jjSC7(AME zqN^V{evgO0@NvFITySy!dyD?}76Jb8|KL;f=Dm^Ewtm%K(f=IaVnCpZ1nR=$JEep7 z9f2YRx~p^k`r=hH`oOxEb*U9J0%+3SHGeTJLbb@1B8JOY>saoG$o;g9| z!Y9Gq#GE|pFyy{^YHlI9bh!i*z1J5cp35g5^nVD2HE6V}A4}3%6R1t9DsoeXl&ih9ij{i<0 z`#Ak-AdySA)X*tUb8xyViojDDc<9d#yyz?2_x~qNYye0%mY;E|Zfx&bHzGH+Wy6PJ z3A3~{AI%-Y>eytTR6kgwQ(3$>EXM%f?gd9@C|iLGnu65A1vdk`vh@|+m>TXf zy7D`m-+Y$qVPCbdw&2v;vryi&9i~q{lj5x`sX*VA;9$3t_oGa;mV4xrUX%RLkyRVd z888D((gzs@7aNYix#|3?pI)f5N!XRI6Vy?z+aHv@)HFt315!|qoy~gd2@lr+b|@tG z53l~*BSSmKLyyvgth!b>z|8{X2nw4>e>u(%CE(IQd(aO9WvqFugopDComg9f*fYoy zH48tVN;wymdTR=#zM~V8oIRJp&{q2!7*f(FLc=z;fz#hG-Wuw`^={~1`MHsjutgZT zG;hN5QML*N8o6S3q!CxE5KN!+Jc78MA@hGfNv!s&FMAAy3EA(05c+I=&|T8E>F}72 z7?LeY!C;4+Es(1I=-mZ34NGvxSdSH1M*xe_T44~pe2@h73qI!XwoWDGhWwEJdF?!= zo;txqq%?vdlrj9a{S_4=Ik{7x7;M?&&O=Fb(@v`2Z8X6iSHa2TZ2F$qI%>EV8eoCe z!-i33A?@;t3xd0XkFzhvGYKLkv;vI}$#AGME1rmGI| z@dCkiN{$d;VD!O-3HF9(pROUW#@4;w6@)`jvgu!s@IYXQWzbo9A6f*di?yGg?p2Il@I!6glPT1Gm&7ONWMUzVNmW9P$%eP( z72MBG>-*B|w{~pfQ#J-?@(rfTvip8QfBfYN`4Y2*{DTZt6E7HE+8P-I_~N%B7Md=t zgIJdMcWVd?^Ojw|OYGgItC<&>iWQ~j+ouX{k|X_n)T5wxg_{$24A z4o|aR_X{^rqwqLK%C5Iq+%Z)4mnCVSl@k8l!jS#P#N4v-y4LA231t6JVBj ztS)y_?#3J=L$`wTqs{B2Y?9u+j5BPTO?j#UV~hqo3Vu#uv{Ce%km&z3G)$AclST2p za2|{+J8y@!DYw*@3wi4Q!78h={S&JU>Ozm+v*ww5g>V~o>14kN1sH~Mm8_fDQO43$E^fna4IV0>U9YNo((QE~`lWwv;zc`!$>or2GdD}du^a6>zMkdf9N88CZ zEit%M1O6H*vV%kPn7~wG%Ed5;3(wHza&|*+Ofh6k zDToFHz05Gd@%NE(OySJiOdpFQC>r1?=IDba$?{KJwWMuC-2e zt|$ixyS{2n(04E&cyOPI`YjFZAg!NzzBu## zIQcLh8lao$V4Qzow@XpZXhyj=f$7XK9NVd~qzz=!#${J&2RWi5O=y&8o7C;~OXdxO z%Ft1~qXh&M+e8>L{@T-ix|~iQ#BUsYoR0u6jiDwJbic99sthV-XNvD`qnyCD9 z)ta;8pLHZ9Gx>7Q+~gE!q{bu#Z`M|h@=TxLu>ys)~@DSK`5orKBY49+ruYmRig{RzmikJu9WI z*L|X8KKiLq9yMR$kYv5b%mE{=5g9pw8NxgHj;ymp1)Z-hpieOKL^+1m?`&+U>vNAX zIcg59DSg&bX4R&mXvJOEs7^9r`B`6@|J-7`yJ{BeyXLvN^FAD!ng`Cq`Qux4AaU>7 z5l4J=0x^lq|^DMkZ9rF8_$8PAmMb8Tz%S zjV#pKsW(wq5tS~ifN{-|GDve<`uy5!%GKcDyBXk~>vn|fqlm25CVrf*&?HY-j$XDi z7&;k+rFH=Qq?BPBOsYiq-Y-+7Z>uU_ zcd6Ysy;_@-Q#jS5H!E+V9uxYIMp5jeHvZ9RYD?6|?zZD$WD^`0tx)xi>p%T>)|6@Z zP1L_~%Nm<{>lY??d7i{=XzZ5ZyxVw(OF5lr9n6z#zN1RD0yc5~ABb(_a(^baIh~Dq z7W$p+cVgRJ@}`q3avYUnbjYw`k+r(*bI&l(uhOL?LboIXF+9`0Q*a|MtI#1omn2eP zvgZ?CKa`O;NwGaqt?B{)Go2V|!PYu!lCqUY0h@D#C)O1OREjEP4n^q6v9Y-ojQ?9y+4 z^@7$;5zs3(xT?Sb8gg|lbBR1pO zyr|B})1`e#s>KmDq0Fl#dl_?(gKiUjsQ4ms`HJJ$5=4uK6{mw-3g5p*V({;RAhLePvMqhGL93{2Z5!M00k*Np6bg-sF7FvAagn#b;*PKpFv^ zHF2Xt70Sp`i-1?O_q@=~VKAjki}vs+D4#GF$&U}6j0}5oOcFeoz zP`!cfogih;)WNEas;X*9U%*E-nrg1cTsX}wq7#1kGLLKkg3@CA3fYpSH;IZAZoS^t zP1y5vJJ&Ab<3lJz?0c7lao_Hw`uqt}|z$qZfg3pIMGk?ejLRm%sYv|Wmq$00Lbr$?z;*jBBZ z6_c=R;?C6BKL`b9kY-2di3MD1KF#>K#hY3vd=|JZC8?r1s4?7UC!m-(f+CyWs3yR3 zH&sVdBt6m9pv?ZX>b=_t#(hqb3QFY<{jSG}hjbCJ7mQh&qF(jdD zbZGbURf*-dK;y&W7=(anyQKI%dpjiieYK+^6qzmF`6pvIeDgNg_4)?8fdG>#N_p%X zgG+Bm$_3IMqM1uL3-I99aAK=b2xGryNAhQK948C<67Cj=B}7Q&yE$l?&&g_apihyZ z)5x4tfdq3?!-CCr>?dQZ*1$jLaWK4aTchsO$caU~l=6Dj*?ww;AqN>l;#UxRhD8jU z{h5r?>MKL!&xMI_LakxT@}>mb{JQldkinH?!fAFn2=X4-Dts)8OeO2++8W`0v60US z&H#YWp9>APYBmSYKZg6sNk(}`InUc#EDQaJF;Bb#E-|i0_3e`w-F`kgI?8me6ufAT z_VhuIV4C^+<43=^T>IIbIuGfiyFdRY>fG^8+>c{2oHf#zqapGXDFF66Qa>3Y(w2J| zB27f`vT>!J&elCtNWAn+n8WW%m=)!?k-d= z6GB?EuP62N$%pC%Nb_!1dtq5PDSGfvJh%L$yP!{%wMn+Q_AMvxZdHf?pAmc7JPSjI|8fA>RSTYbi52iQRFpu`Js)mQ2U#eCs zXPruSr$$|8YM&@e-Uy>;Sci_?H0#~k2DX`qZ|3E#nEyEp`?mfD^!NIb24?RPB6xxF z2ADLg?tbVQ3k5^0MvV;gU9#3O&i9>E&*Uh$YOZ7aSVC*l3hOWUE&Z7~r+C1gWPj=f zG(QLo=>;t*Z<}~w#D0`sIHz&Mi-FtS{(O9RqnT=7sP*961$WGAmP;22i_9EsI^#~C zw``d?^up75t~PR?E?=#9JL4{!lx=pe?a?7G6S*P!1j11Jj5}Mko<9}?^ib>Nya9S1 zSAOTtC7rEu2tdVQcihLH9tAXIn+dkVw$BvXAE?P+etTbNVK+*N{A!1Mq$QBZ&7LI?^9EY17XM=vB3vjUT4X9+un*P=h;?4};`o~VNV7hDKZ*ymlw%31!;4Ch}a@e?j ziZ9svGyhpkw_gU@7c0f9-y4|!eEm;!vj6s)%{jmTkJ!el?=1%T*S@9&`k?jmAHT29 zzh3_zeo8)q@XH3TIW+E>s{iX6rCDJW!Z5vmFd%;APm5CEZV6UcUf-K0@vqLA#VJ^Y zN5MV+!x#9k_XnucfVWVv{`koxRH2KgXzVDhNZfpFd-7;>EuRef$U!;c}hLFMXBY8|!q$uzhOdMxOq{ zv;M~&@s%fFrL%GTg@u#eCGNdjd&CmtB;!D8xCUf~E07t^3=p}(hPCkc_x6KeWg_sg z(xGq?>SGiGSF~st$VG1}CLRIA2c%K2SLrT*u*ex!p3xy->L`fWpI5A>MMySQJLOic z=!jxB9KRNi2#jh27GJ(O^ZFBrR}q#0(mwwLgKnZhLa+Vl)lLh9zfUl9;uBzf@oQn* zbG65i1_F|k9v_{>+mUEC$MCM{0foS&wl=5XL>z#vFF?sUDq^p{BQ^(zV+Pp$Ru8Vz z+R%$R--gN78dW9GJ$Q}?gPJB`V29FBKkCDYy^bqY|Au%fB?17BRxx4P#V(_6Cju zX(q!w(d~tibclo3Fo%I9wL9YE2IfjP+e-D*E=5CL2>m79xxnavkHTRxf2Vfm|Lw%gqy7KpIp8 zS5eQ=#(l0sVV%zUPq(d{J-0>*leTYPqYfSL0o~y6_m3dkvUed+1yjxU`-_AV^Rz)c zDdaC1&{ul!Wau@*Y(&aB4SBy_TB0scd@QmZg!k8yiUVH^sQVT@>nKIl?g;^PS43P1E% zFV4lDpYPEfpv5}7yK|Qw9H|pP5YFX{3B!RDe>!)Bn%&@da&LaUqjK`gPz^>Llf@k5 zzCYR7Q3UtZ41*^}+|h?V8@Q~Zrn7wr&~th^zz#VYy>jW4mjU|9_Nw=;%knm7!w;d% zm&tOtCyj<-I)$?WGAvOw>2|Hp47^10FP#drW|}&&$p{RSB4`899}mWge?mk}iJl7| zbhATA$&I+88gA`oNNtZV`7>@MZ?yc3SG9TMP%y<(oy|{RggMIkKt7Va=4yV#cIc{$ z_o_<}Zz`FfNk69+&7J&Q&v0yZtbNV}k`f@z>&}Prmet#O4$-+08EvR$PmO0JaVcvp z#tw5LkFq*{XCN449VrpiEipoqg7P6 zu-hx!>*COA{Hv|@$3MJj0C0m-8fWZ)G`gS!@BX|Lvu|IDFD_4g;E~iyVUj{tSpHaB zcXmm%Le^+d`z7-sa&bd(0=kx*+^_SxF3p*$Nr}3wLp)~Uv|*Eiga@yF2WxRlKs?6l zs0?mf5_>9WS4GI1a^vsJ3qvEQC5^;C@_@Pw!o|BPwfVJ;b|*X%d&8L5@6uKYVBL~i zlzH^Vm_8N^C6?$s*;=rdvcxi`*zvT3Sy=<_R^5ddAeFUY*8@!{P2xe@)rqRY705|* zA_e;oQ?D~jltw%wtBXmy;@e9ZQZ1cjq5zu*v84#)JV6+zOW?{d0ywe2&d;+_nFJOt zeNI{#)x(@0KG3HMY|JW7Z8n=rsxJ>$3k>Y;tbT%#J)8H9c*4sPJyc^=DZ;I%ZnJ%g zPHXGpp36|KU5*$=|FMw&%0&L#Pe=aIp}RJJ$fJfhOEbH%vjBZ=3M$P*NjQSqs_uFf zRJ8FXG*dnz{JzIFWUk4_C@c}v24G}9;TY-#j&&#F)>q|H9|zJki_f@NnAkBD%S7!< zP;&w~uI{4W9@%IpFzfJLq!)M16E%Z6)pC7dxa@~AhLq)JG4Q`U^_t7#$z@3D86fbJ z#3T{DP!W0XUGXb*Toq?w2@Fyyx;t2NwCgUQ5=#K){Jcxl8P=Fj#G$esC}~5RTO+(wRg1b!02+M+4qRM= z`IRfQ4nKunRN2vY7OmL~dx|e6n9+Nwr*6-)nmJ{9vsB{0m#!1E#{E)h5Jxwa2n+j{P8A`)vtlq*W zL+nR_;-J09Pi+g$V-buT?&WRF`;=g1>`**P3C)@pugzay4orB52P`FZe4D~%09KAK zcNw%{OJ^2n$LVH=Vvr$2ADB7yyM);HW$RapYHg$h>+rWyML;)HNKmUy_adq*^*C7Y z4N*0R-6deoNBUQKw@tv?!43R2bxuAuAZJQ>Od5Fy=YC5)xtb8Y__VV`*n8VnsZb;Y=rOnx?uo0$8Ma5{9b7+wLHNVS<-|qe+?n(&|0mSM&_D{TN;zJmN>?eIZxV& zF6wv))8&A-I2QR~jv6&EYsM3pt$OON2V2R;C&}+iB~d0l2#2nUAMuSM7_KX^8Zse< z!l5s9q_R*C5=Y%;#mJiISDYo06*wt-I6ltphs?uZ8?v46^mdZr=HaMpv@xmX1L=dg zFb7JzMJmVN#3Hmoe5joDIhj#jGcBU24jFb* zW%A*LZ0%e?fEeOyo~?DMT1<$|T$EU!w)KuX@LWL5ef`KlTlGd(HQp;}Z92%5X)H1lNLP%Uot*Fd)7r1xTwpUr5=i*w_66ZJFC01GLm&$e#mx}5# z^Svr{U!zmfr4RN|g$47FsihJhd;5Gw5bs2GHF>@{O?L!bW}s%Ljk?x+p@l zRNgxlUs8f={5x~X0`b((@@NLx@rE5}WnQjrv~7p$HHtj+;r1j$?a(Xjp(fh)j~&Rw znE~)SCB7idxJyoP*H!sp*qlZYlELa2KQ3$7GVvDgVhps^6~dxz@*Qsk(3i^Nhe?S| z^uf%*nfGXuhJ399C`39RI|s0{%u!)IH4S+VJ5pTw;o_G}Hb7LxSJ{a+zz!ZZc%Q;8 zn}|sa=HZaZOM-E2otbN13q2of4-Kk$39)igCZLO)zpR0zfmm!(f%@qHuh(d5wtOLfpH8k_3VHMjk3`40n^8ZAv(PpE0ChAckAcFWJbysaxVm~DaLnusvXNf6lJ zdsV=jWIrx0OR?OgzOq_O;D0UoWqpHrJkL4BBLxA5>kP~)Upc8epIEa1Hz9=GKcHf* z|J`~bFkNEPiPy739zwfQo07LxkrYo-BS_r!WmmE;f4R*w!;6*lstq>3U>R(oJWbZ=2tyEQ?WpF+TXmUd|$<{G2nD|9v?R}GfHNo4tH3aW%x zzX*MWM>F6O!n1j%bZTFHL2$r@Mk^h=+gfb_sLbH26;yUnun zrngB&H$^x;1W zL02)cgy5QurYiX%q-P>?)~?GtNgjk9DV3DyHWI`B^xf(N7_l~K>~y!;=Wm&jwVzU< zZ2D9Xp~;9gy_q%8vfvUiRC>p2bZ2{Dx03j}DqGm>_Ne5lNcm3@9&fKzi!N*0Y7MtM z%ANJk8Il^?N687yX!ZvJdK$4@cDT6|;fA`;9GT+F z1)MGFERmEdLn!6I^oEy&n{xM9W=10Zs43AE0!>crdzXn01;!TNTy5INZlpWG>CBlr zb!n>BOL}IWHCbfetQ_fkCTg`kUwJRa4LEjR2XpHWPa=tY+bz0G8hgv?9ij(GFkKpRL46Ma*vMzd6mi z+275#SF#PjFH8Hm6CHGC&tOQ6P>DjfyB{Ll{PS!yqfAVQXTlQrp<$X->#JH5Gm8o> zI#St5>esbr9uW&-P{9r^g7V(8)|5qKvu>`Egzh(etkg~OaIYF7=5f?3pOSWph-Foa z*=r1zjE+j}%tw$n2}E^np`nF=2p~u_7U@)Xjz*~4DRavz$MgmoAh1r&9(mi2CfGvp)0Ks&mh-fQ3XsM4#o-sLTU@c5&!h;iBwVdwGE5bx9y! z^Bbs4vhIXMNwIG6K;H}BCSA=$|JLafjzp6yTcq7#af{gT%o~?+kVv%prXrFIV3WFx zU2hL+a}5ZG3C#5e*^d>Fa83gSbDC7}hq&kHcHNolq>>LuwHsn%Zz-ney>Eolc3UsuJ} z03}kta%PH9CIHFtU_uq=p*LfS%UtYJq&x0Fs>9bp>;7it%!C{UZ^X&&*ZB%<``LCj zVm08}1YH+pWMHF@99C+8gQpv{cGP=Z(V#H`0V|GpKS2u#96sl?>aOknI9O9095%Y= z?na#nmA{AAq#dfaC3*W9EjW)oy>)5m^^N=2Omw3XLI<7}G zljm?+V(jsUA(U^kUEBDEo+;isEf8wK@m$e+%? zn?2Aqg)Q{xcv;=EsqkHS0KX%WWWIN6;eNLCR?11Ag=J}eexhhHa{K2{s zjA}c7qu|suV$4H?Cc9M3i1#D2IG3A7;-C@}xHG&%{i;K7h0G_}>PTcrDq=4JMe_N6 zLHgWpUz@n2cMey&zf=peS2w&eg9hFGoe) zsZ4Z+%$)tH+(Sob7Yhs+Rn3y!|KXBCVk#iYJ(#bIoltiRy0PNW48s)FK1B}Gq*+n! z*JL+|)Yy_-|Dde7Jx-_iaUph?YJECYjmG3@liGqLyEEA-F_^V@G9%*!Mt-Q*PO`?# z^m6DXsnJ(H^VXl=&v$Lw?ylH&ZcQ58-K|>AwjFjmPOu3T&&{DqXk1QsA>#%rVFH$b zqM0$BMkjhB%C~I8q1c{#B4Qr93qbp%ly%$l|5ktgTZvk$>mxOxj=d-Kjhvlj>kZ@D z*ZzU9xi3iliBJJEiM+_% zyFPs1JHX4bPWME6Y%e%(3vjokNh_n)nhP#X0iF4oci;|WrWXSJa5D<&ZI{Xz?bu2f5xO^kj&k!HPk**xOEk(FPqF`$*DG}t38d2UTNTL76YW$p|+i=HhYyQ z2Tov^o;RoxzaCebgN|AL{B&`Cz(@PeLVm+ZMed3@S(bo?7opl|6-59-F3f1FP|F zU~5FEOq6<%FZ{G{L)z_(>j{lrm^+i1<9u!6PfmJo&C@>}_KXl;xGZwptHt&wC?!R2 z+m`s+#R}Z^+8SaUb+F$>mmT-avfUCSZ$3{q1k3xhVYA$ukam|*ZnyO<&_ecn1Y~`J zbs?l?m3_hW*YJ72%!q7q%$L}Bw-dWx(o0aCo8w+tM^ zE>079YCjXSJHHi*Q{QWSm|dC@i>Bt$Ppd!v2+Uiiy+L7Y6?HrGbPsigZfZeCsTNqs z7nKc`m|;b{D`{4ZV0w7jx9hcUdvR~}q35=P1|G-{q(>jedaczmj?6kQMPS7N9fQ24 zQ6sN$dO3G}r*6I?XE*VZca2iOLv-~Qq42ZX>$$rdxkpw%Rc~z%m9L#o@lNB>4uw)= zX9-N`zi>*?ZLa0)!fu}?oiLVKbOV^%Dk?a1s9T{p5B_i$KZ2Q=3}Vx$K|1rDTlG;U z$KMQ#)`+Y)tMahTEuK1+R00P)x9(eqf9bS! zU0N*L1P7c7O6ygtMyFl+lYgi}{w?DC@vC$-k@!;k#dTdyTk}6GaMa4`zUcaxHsc)Y z7^l{UTnnXog&0$8S5)Rhq}J3$?mxVNYKct<^U^&W83gq3RvB--!7ok>CxE7J$=csxA z>9lD7wL|Gxd;EaL?_(|VHMCuZx->NfB%wc8d~i=8v`&)S2rRo*^&N#`xrFW18eaUGlIAs;sKCx#A>E1=fzI}|o z1j%Xd@R!3{(ed=Yp4!jSN)J-WH|MV%{)8=+_(gDd*v%6VTCIY%`BCyQlcEjgFy`0m z3FWgtN1@>nqTb4;Z4LJRbuF4pp-#Bk-u(?%<*GUp+Np` z&I}FCjB9`Eo-L#N|Gbhn-5%I3o{7jU=so}W4fr%dgjBQGe(c_Vo_EVnWnKusgwM?KtVu*;81ku8P8SUHX~p%9l^_x10KZ?G^_sEdBP1sZ0OO9`}J3RvRr2 zVU2IOPk;U|O!vy((8(lz%PNjYdLzw&VRi+_K&D0pDO9&t5qLnbGMpYtly15OPL`29 zNIMFos0_nrBXFtcdXS;`y_u~DMEGKXZaUx9!7MS4Y+bS282eTMLYdg!-#h+*+fx7x z9a#{VTZNMH-4L&!#Inz9!LkG^L^^Nw++Ic^cC8^-58sZ5jPDwshA1&{8HT0VPd0AIR_lXVv9f?S9;440yN-owLp+w8WRoEi6UmE3BT#h7*=T0`4SNj`QJ>Cak!}m^iT5cMSx`k11&*so>C~u_S#%1MZuV8`J4aXj{$1Cn5iKC~*$vt> zKMBWW*Rac^ax%cJc&jD+-P?%S?5J(tTQ^3{bx@*KtQKA=wt<4&N|tYN!W1?Kq#1|I zwsj%`Jr4NChMOPvmtKUHOblpTT!LYD=NmX;&mB$-Z7ew;K@TCwrQAMO>qr*%p<3EW zi=&;@d&ODXs>_&D|GW|Z>QLr$l!bFU*WD=r);H0 zIfO&Jcf_-py-+(xyaErcwGFt6+4r7BRUqv7DHrR3@be}pw?u@OBZ{tnINh)@`<)gD zF$hUZy7xXfSGk>LY+7#yQxk99QdheHS=_HXu5EJViwk@sjvF1g|A10|ci9>3p8nc2;aRvOTCVi74k zj}72cR%&{QHSjCW+|L3UZ>X6mA~fUy)69pXS?S27P!1CUR1t>v>KMK>6!`GZ5v5KT`GN5B4IG&;mo*529+ez|jgr7B z(Z4@V>)-TvSJs8(tLjbmhQ!}efE9!fi~@E3-n7}ha|WPW>L*jYHd{CP^unP_2yuHA za;YH3u(uuOsp5@GulK6If>O4N$Yf(fgQFdKNs6UNBOW4i+;n`*9TSU`B)z({E z`>07FWxjnIm!bNv|61}l=fxS>E@*X_o3-#gxjb;wSLSLd=xK_%?_f-4{YYU^=B==2 z;1#3TLi2+No@IcrLaTK1&}6KFBYL=WC|BTM>gWmA`H`agHy8=&5&bWbE@uA={642q z4UAIfO#KnUPHAifFWsy2kE|~HtIL5%qThondqM{b#s!sb7#P8<&vz7D;=#uIUVGY4 zDGlv?WIgP9^K*Ci1NQ2csPwVwhc`OaqCP*GTo`^hInzVUn?GEpb+^2uYK2i|Psacu z(YCjMFp9vq=iA-TblZ#$w~vR7K!}Rxl+?3Cx~-IFR6a8W#eSgR4ZM*e@G%?0W7Ug3x-_ zSKCX~u#FF@JSwEI%g7i2m{<@*dBR@Gk9~ht4i|JY?tzw0=fheptm6x-y@7AEb3{G- zK61{-upvq_6k>SLlRY1f9;|+SL!MjF{UmehtvFebiCTrpk7RRh-YCY9h?6&d+}ugx zLWGXCtE4|tF=|p+(l0R|>Qfn5%3)8`s(PWW@0htUIPI3H*pTBWn&*iyiL9m$1m+^* zYvz7b8zW#Bf7~+(q_P!5hbGgN^HYOCCG)Xkh7Q~tA4NA_?6MYryx+)O-19u+%(*bo zAWC`7K0Q87CsiNyz zm-6HZKHP1`NGJZ$2cs{RV$m8*vCz^?m(ZHMaHx9v{;QAA&YJoUh6bn70(|5i?0)d$ zi+ex$Yx)ni*v+p15aWsmLNVn=+kXcb98DGucL|7!QHO3a9`qf-s`_B2f5?O4Ls)klUVLR;xJIZs1}d30=Ofm#Q3^%w5nQUkPA! zNnAE}A7+S_$FhlGmXkUiY$>k-Nl$c7+r$p8VIx%t8N%79@SI<=V-?TSmVu5$u}&?{ zVehJ)Eho?8Dh$xogD&UX7!zeuf+KEJ9Y{6^iTBNHIUW?!Zk>`JmqH4p7?F8`ytL@= znjK<`tecJElmC8+vuQTgl05Q#okLMy{z??bHFOJT9<&xZOe0ky_QqP70~oZ^;L5Cl zDywiZmTc`=;@+MaZr%l9$Ic$xu8b#A12!Q^~{#lR(B z@2T zP}Q|AQUjJz1HQRzz8Jw_D)+(7R~7nI!Rgte$3lsSS6x@Qc&^B|JJc4sSqQA+w7X-a zw>)y~H>XQK+HsR-_WbJ+MNY4=|L*xpZgTbVK38{oIsIr~uP!;YZRQesBTGrO5T}%^UiDJ)*>N}N*qkfdRfc&oDBsAN0PIn5oHye8E?6kxv- z?C(??s7XiBGzOFF37PNQ`w?V%y7pFs*-v%1bgX1j!^1vnpT5U8A3S~G06u;L!(BWp z!rCTy!Yur2_wbJ^>MgSW;$T_}GQNeHS){@128m;`m9538>|`;&5jc^5#JoA--lEt@uHa=O!*QhJkKvE5bwW+T2ZA0sEcp^?Wq>BqK>;A$=x z{X`8-3Pw`zv^)%!b}AkRIjmGcFUiN(3bD?$&N{NkyG@fHW$o&^NKdHj6?D|XVPHM#l3@dzy!P=-`sATEBn=kuBHebzZqS<3-HOZH8 z0mH>Yw4lkwv8$cZUCBZ(^OBd2u_xy&6vQ-&@+NZ-bdRUsGB|P8WhBN=isiff2y2xN zLB|%$nr8hX7#p0u+R<`Sm*1}XJf~lxSWwDbvHW6(>3HGmVffpJ_HjO}gxXK8>5*PX zvaAnT1$@kYrd8>{28(LrX4b3Ky->YjY>gLXqvx!Gf!YeS|#f7W0; z>y?FF@HV}WCLv509N21=&)5A}uJ3m`>9N1(o$%Lfq1X^A)bkV4OUEGZxxuOc_mYn0 z4o0EOf>FZrd&yk6-b4kSR(XD02x!B0_TVOgyoYn_EC$?yiY zdn~^7RD^%5LjA9`dgz~H5etn2Z`hhKZ-nkV%7HztI@seI+qD#ET3IYj4DHU3Taoe3 zVUrSAj{x!r;bNk@$aDj%fty*%{0&g4Cu#b*D@|s-+bJ_tpb=pUUEx$1f~VVFePppg z{OCTM0Iq7~)vsz+5mArA-N0Ysp|I+*uEHwRq(3B4yGFC*k0wo_t{N>04AMzwFt_3 z3kq6E+E<86h5gC7r3f$|6N6QQVLmlp;-6MAqQzOd5bGPrjNLmNkN~y0A}!^g*b7wH z<4_qX`9qnN-rDD|HP?uBpgVY4IGAQ+pw-V zBCaTSCw7-!2{-z7;Ae+bWEB0_MwIIq*$Q%MLWl6Fyu{R!0$1>f6lkN&lU-=l)a#E3 z4=-Um@a`AEfe3wXtQkS`ihelQFNKg1c-BNKr_LutE2yOu{?bV4P z7wYpP;iMb+&7da5>W>2*}Ry@KRztM2Gd3!o)pHMI?9OGr8nop23aE-G-d(st~z&^_+^tqCnQMqHMY6E zZM&QYT{>YrogPEy@e3;fM>snA*nB*ocel%hW#v}h^u&|>wu(uLNwo>aN z!dsn{cce@TJHDVC%y-x?REPF;Tab2pM+T=ZB_S(!Ek@SczvZrOia^~9f|Xfks(J8> zcefVz@HBhU$FgDPYGzNwuE|>{MY3L|=t=5jQZziyE6^q~8!D5nG#esDORD%z&A2_;bfr;ndUT1TXGcy9 z3?vRJD9Ir_S4HNV++)L5YF*E$kcGEXeA*@?Om9JatLJz*QepU02T0js5!LAi%-E!V zY{xGb;>UFJ71{G;aj7bIl0bF%h8M0;(0Ozk@yfl@L`1oiiu9-Ao2`%Y(CRkHJRG2OkYcoD5W#=e6>p4?v=)q>n|CMu@rV}l+pPCdvXFiO6Zp8;mXd{h< zmMne8aJm}ABf_2>n=ob2_46^NkZs?*J*xxUo7(sd6+)7)g~JrgbMa%MkCmkY1Ta1T_+&~-(QNH%0k)w4#KIY_ z$8~85xbr3bdi_dOUbe83QC;xyDO6aa?0C``SW`;j&9#~8M3hr*j%^L)R;j-WumR2- zl$Z_?Fp1UBK5%VrnUtgXT{6}X!y`Z~l+CXHdBRbxN*XJ;E;;O;;8?dYbmEg-y6_x! zm1ES6)FBU`-gsRuK`pFFw#UW!m1#G%UFWz1zR8OQoiP6%YJg*6E3#lQ@|QuesCt!& zuwRsn{U9JTVaCOMg{`AlI{HdRciLobC1>x7AHsmJ0ue3(HABc$n7sqW4mu>#PlP&hA3H2w$@%J-vy7q`^+izaOGM&sPV59&JEy!`w;pEt8-( z#g#pKYDySVkp9Qq{L2me{R@cvJRm@=Ip+PhpZw$MaU{Zn{r|83C)k6L^}k;nv6$(| zH`~9Sr~YvQCN#W{X~toZ1WDm8h&vRog4=f)z1b69rp?C6_yZ<$Qs?U)@b~SOJM|vs z1f)P^8sC4c8zB90wY>2%J>aIL%dXGAOYC*-PDUCFv#qEUZ~o=8(ds);6{}8H6~5p4 zI2q&7AP*y*tS6nTC+AX81zElJU|NBn#`SUdYyV>;T^}aDsg{$UtR9%0K;1z*pf`#c3o*OGvU|f#JC_q_=3aT}QH-f8L zP3Z^RY>MuF!}S3mK->E^vur|_ed+p`Bgp$3PErKSDw!ST%7^kagjElx9Y$dpyZ1a; z{r6}4D<7LU?d^Mi5!B&aQAQpsW`XT(S-x?|n7Vbq+f$If1<4?6;be|pHrV&}>28Nq z>|_@tD2YY(lLQ$EWtVz~+(6SPwM3nC)g9VF?-ElWeTWZ*E>YWN%g(BdB-2P5`1|A_ z7tWl@28MV2U=4L1%cU5>C@PZ30aoT8#y%ZyICL?9aEQv1A4kA@ z+2^G9?LhFh_Cw{W)M*C^>1ZfyEDtPb1RQW7OOPA^n_8ga6QMSeU@B$<>X%fVYY{j^ z;>bxSDi=yD0s|uKjD%Cy{^?24>d&@5odnePlXDjHW54x6`pEt%xgPy0wU8Y zU>XVVY_C13ya;wzZ+)-?N(_r$w4vAXG$e3E2B9R+{4xOSrIf~#1OBTtkRo-#A~+A> z^_~k%Cx?L|dq`}Ej)6F0<=rdgNw;Z)f86~3YgX6hw(V z%UvRgm>&)QdZwS_Q3L8r!w6h zTt<8h2;H|;v+cCXF@3C%Qz8;r-la$X`<3ESQ(+Yr_D)z+yXYlAmve?$=9lJmjkiLk zsykABqf{`TCm?PlNJ2MwKszUJ+^8TLRi4Ol@$O z_7`pHu|fZ8mUKf!i5yC`89jWe07YeEvd)>0VAUhHY6T32a=fzAsc=T$iEwO`A@t`P zS$3-3Ni9->BefuZgoi{7X+l-1V7Qx_K+5F=2E zFPTUYRFf1m9aKKyl;bd1JLb)BD4`E5W1FN* zf)?G*r>uGcc7db^hWSU^Nojf^kNr(x`XP=|C@JW|rwT@0y?yR!8Q#a;tSB}^TmE=; zx@svJb@U!-ZdT=7R=s6--E7crCrw3?=kbce$iTj~xdO1+8HLP0H1=?^wYp-AjqB5M ztL(D=F(UY1qqr0OTq&Gc*0@@2&-+r%;9lQt-r^$7YdT?*Ad{MnTepPP7OG`@gjQ+A zb1OXBg)ff)Ng$OPpP>|GUoaYH(>Exj*Fz!>2O zB&G@t-lXF2RBDDsrvR=dBehclmxOJpJ;B#3i4~+vaFB1J0rxeIT>|rY68O5Bf?h#m zhDbSQZ0y>twwp(n11IOCMPoyjvciM-_%L;IaUXSY)w5lR%jm*%ESTjLdUG|^? zuA+<9u%4m%izPY06|6|mW5SM1A(@agU0oj+q=q_vv-9HT2{2-qY?I2nuK1}r=xR?= z@e*3PM{d)j7w}zZb3Y)wwX==pd(y1wc&v<58wx0i4tRP6v`Z{9a*%*a#dfRU(#$ay zf^_6X(zxaw0pZ~ua4pGRS~AkOG!@Kyaxt7+Ky|A%@)NO*0yKxzmjSYrjbOLfT{?Z3 zI%mqQK++&nw;st%RY@in)z#HhGtAkP;om?S)0-}uQ?tfXQX~Z};rfzDO_tUlvy5S1DP#ht){l$!*Y@AmGr1N#KSH@krx2hE3}6H8~7NpL4e@p#zz?V6W6u z;7RlLkM9g!s@(_)3lfl@eRDW0zO~MHr~sANrMC!^rQ-VxNLn^Z@hkb7+-RrR!9(N@ zYF}vGd6Fr*JaCs4+AiYe$NSrd_;MnK$oi#{(~}?a^-lmiN;-4eC4v%T*7=4LBbm9V zwN|(Eay_r9SP(+*LdR>LzILzvFkRjO^sqeVtUXB^f|xx=i=1lsg0N^K+n+Jo2`E2} za}-UnW7T+=vm)91otxU6A==tZr^eP2{df}K)&)MYb58N8_}QKYai?8RC4c@1W0BT| z_~d>mL^Xy+NKS`s>$xl(la}SLP@bk1lM|DYT`CP>pQ~e^f9Td}j@T>Z6GB;FDBFhz z*E8xw5^Gz0(elYUnQ^+n#|a!W0+N8eFtLL?fQ=s8_iW5*sT32u3eO zi2DXC-6O_t!ynK?TM&wF`pSjTm3=6H8?JCyZbCbXkTB-#t&Y}|o` zj}y2Zn}I!TuEUnDV3Q3QsFo5iKE~c_(_a{MJ7NoJa>;IH_2_86o@_~51R2#99!3Uo z>N(ah%kh6G2tImJ8YY-s`L02dfh)|RAHq1QNhxYHRM=6=$DuQ7rFGTF*nLy!1^+ih z-}CWhF@A@11EcY`DuCC72Y#3Fy0~`?bV5Hrv*6}~fi@_PG|^M3(CeR@or-G6So?qo z+80bgJD`1prj(lE$|oyO+D?_-QClmcHy4=>9IpaJNzbd;}t(3er4-Ikqex=r7 z)Z5zGUv+jmmHX_tt=6!v!t)skmb-#FIi0+@h`iCKwT)C?`h96d{`rJgy-*fVHUOF! z74f(XxdBQW%K~)CEgI(p%44#?hy?ahf#a^r_v*QrX5V9(p<4WC+@jgBDu~gv;=>(O z1h)mHy+b%Ke*G#O!X{~p0y>8eROjgbIt+xDcs=g|#Ar)BdJD+*mF}uzO^BY1Ya|JR z;r<`%ZXvDe3(k?kC;?y)W^VE*NjPQonFRQ}f%zRh{Anu=*ja!Q z9J8z_Zwe^(G;Jp_u0az;BFsLFF}1J;kq`(3e-1ewo84+GtKK{oAUBoZP`XGWLUw1L z4egJMXBLLlFuZZPI%F-XhrCGw4DZTcT^@MMun=U81chVpb*Z;C$r{LHz||t(8WqW` zQ~NhuE(kb(*IwK5xH3XBAUnzp5sG+MJHV39Nn-sfyaM^C3 zj7d|R6a{cvRER_SXG%iCKy@b#q+k4G4G%TtW#`K41q@OxAey{J+ zaR2R}0q{Sph>c$v0^B9~t-hRhcA9KSX8noXDx)aqJd!ECJp62U)t?hxZ1^a<(!ar0ahBSIH|%b zq?L<=G*p)Co!XqCa_6BQn}(a=nbs(w1NqiHy@CIHufKfDv|f50S8-wXlG&~d&d0rmR4qx3o0&@W--*0$XGj9k>8#!T^0ZH_FRl+XDdyfQC8!zyP#jImwd=&Lh ze+6oc9!ITl*|e*omkb7`Qc#Tk!rmYaii4D%!VL$w^pGA)|9186HG`9Ya2(=D=Uof~ zoOE64Wu)JhPc~xh4Z^c=2#L!`$+T2nAMJ;}yHMx9Smg+Q9~4sfzF|p}AMbi@tbJFM zv+d=t9cLCs!4m#~M@jSs}X1(BQ2_A=HsQlAzf zp7c&LsGT0#df({iO?8yTY=oLNM&xO}Z%4IKzxF%MkG%MTogWnz{_ksa^IzWJHV4eO zyZvcmbrCGE>4xC8uk6}iKZ@2vVVTBBAtSvvU`eNX4#<4Vl1A-fyt^>^ddjz&jjJxBMa25kTlFP?ZJOuNK%`q&G2;;=Oz3uZ8;ihv=Xk zYcT~u*P1#IbTt}}@~v<+i*s%`xufEXt@+wE0#uXk#kzQJbamsjcUno*RhEl?|1*F4 zm*!M@%AJMr`hd0kqyB3e_^%!15k)%BeUl|J;y?ajJB*!n)NXG2Lz%(J{?!uHF?o~t z<7#-m0Uky%GKpUHF{z9iv?$#TM}@}ZruZ%PNc=Etgn69n8wPg9AD&fx!|8(aQq2G4 zaMZ?@X#r zPUQuGnXbQm<%DCZk-~HZg5CJVKTRI{fE}APkUwR7G**iEFtOS)*6u57Q2UpfRXtcL1eT>wy zui>b5KTTWcsDDzofXdt9;q4&SvcXv}X0ym62D3&(M)rz&_&whBX(6y0!=1g2S`pZH zVC`FZtvoc5hgOR~V3v}4x>@wZVl|=z$hsQ zMrY9LK9}Nek?2$Ao0h`Axb7aCU8441dv9AwN5BWv_v<%trxm@-GO?9@SE<9p|kikQB4NVgU2>iY@$#)-(la8>nvXMbK)iL^{E1+H$T&F+MTBnIcKby?z|qg-}2PU!)xL2-H*d}lCnUrljv zCKV!V=^^`mLu?^R%mnd`ETXUpM*;CwRC)sHIu{9ku-LoJkYx@r=Y4vdZHcFJj>;oj zc(vlfJGDe03~AHB0MUEU@J!|QGHm>ncWLfXWxecv0ol>C@6IkpA?a9 zU!(~UKonz2y;AI1;3l6ix-g|)iC)i-d>gz`h>69j(iK)P3@I^o>k#%ytiroQi*y9@ z>-fcW>CX)!C-H6K&!2@R`gnqoolv;WdPPi}u2mjHB+iJMoEsipMbQpVFNl9lkN>`Y zӨ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%0A(n%W@ltr8&EC_zw9+}b@#=1VdO<^1FMHV3 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 Date: Fri, 22 Dec 2017 07:23:04 -0500 Subject: [PATCH 14/28] Adding a ToString writer. --- .../flatfile/writer/ToStringWriter.java | 40 +++++++++++++++++++ .../nonbulk/flatfile/writer/Writers.java | 3 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ToStringWriter.java diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ToStringWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ToStringWriter.java new file mode 100644 index 0000000000..097162693d --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ToStringWriter.java @@ -0,0 +1,40 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.writer; + +import org.apache.hadoop.conf.Configuration; +import org.apache.metron.common.utils.SerDeUtils; + +import java.io.IOException; + +public class ToStringWriter implements Writer{ + @Override + public void validate(String output, Configuration hadoopConfig) { + + } + + @Override + public void write(Object obj, String output, Configuration hadoopConfig) throws IOException { + System.out.println(obj); + } + + @Override + public void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException { + System.out.println(SerDeUtils.fromBytes(obj, Object.class)); + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java index f72e527117..e407d52171 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java @@ -24,7 +24,8 @@ public enum Writers implements Writer { LOCAL(new LocalWriter()), - HDFS(new HDFSWriter()) + HDFS(new HDFSWriter()), + TO_STRING(new ToStringWriter()) ; private Writer writer; From 34cdb55f6c43049151c5b5242a73a09119de31ef Mon Sep 17 00:00:00 2001 From: cstella Date: Fri, 22 Dec 2017 10:10:15 -0500 Subject: [PATCH 15/28] Renamed to console writer --- .../flatfile/writer/{ToStringWriter.java => ConsoleWriter.java} | 2 +- .../metron/dataloads/nonbulk/flatfile/writer/Writers.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/{ToStringWriter.java => ConsoleWriter.java} (96%) diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ToStringWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ConsoleWriter.java similarity index 96% rename from metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ToStringWriter.java rename to metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ConsoleWriter.java index 097162693d..aaf2c8ed9f 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ToStringWriter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ConsoleWriter.java @@ -22,7 +22,7 @@ import java.io.IOException; -public class ToStringWriter implements Writer{ +public class ConsoleWriter implements Writer{ @Override public void validate(String output, Configuration hadoopConfig) { diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java index e407d52171..acd03febfe 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java @@ -25,7 +25,7 @@ public enum Writers implements Writer { LOCAL(new LocalWriter()), HDFS(new HDFSWriter()), - TO_STRING(new ToStringWriter()) + CONSOLE(new ConsoleWriter()) ; private Writer writer; From b3e4408ab98d69866774bae452e9cc47efc4fbdd Mon Sep 17 00:00:00 2001 From: cstella Date: Fri, 22 Dec 2017 10:14:43 -0500 Subject: [PATCH 16/28] newline issue. --- .../nonbulk/flatfile/importer/AbstractLocalImporter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java index 8b11f5ea16..dc56c0a885 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java @@ -58,6 +58,7 @@ public void importData( final EnumMap> config int numThreads = numThreads(config, handler); extractLineByLine(inputs, fs, state, batchSize, numThreads, quiet); } + System.out.println(); } protected abstract List getInputs(final EnumMap> config); From e7d416e61a3a79b63bccf0edf6e301fce9b0a4f7 Mon Sep 17 00:00:00 2001 From: cstella Date: Fri, 22 Dec 2017 12:41:25 -0500 Subject: [PATCH 17/28] Added readme to accompany typosquat use-case --- use-cases/typosquat_detection/README.md | 431 ++++++++++++++++++++++++ 1 file changed, 431 insertions(+) diff --git a/use-cases/typosquat_detection/README.md b/use-cases/typosquat_detection/README.md index e69de29bb2..1c46a3c3c7 100644 --- a/use-cases/typosquat_detection/README.md +++ b/use-cases/typosquat_detection/README.md @@ -0,0 +1,431 @@ +# Problem Statement + +[Typosquatting](https://en.wikipedia.org/wiki/Typosquatting) is a form of cybersquatting which relies on +likely typos to trick unsuspecting users to visit possibly malicious URLs. In the best case, this is a +mischievous joke as in the following RickRoll: [http://www.latlmes.com/breaking/apache-metron-named-best-software-by-asf-1](http://www.latlmes.com/breaking/apache-metron-named-best-software-by-asf-1). +In the worst case, however, it can be overtly malicious as Bitcoin users found out in [2016](https://nakedsecurity.sophos.com/2014/03/24/bitcoin-user-loses-10k-to-typosquatters/) +when thousands of dollars of Bitcoin was stolen as part of a phishing attack which used typosquatting. + +It is therefore of use for us to detect so called typosquatting attacks as they appear over the network. We +have had for some time, through the flatfile loader and open source typosquatting generation tools such +as [DNS Twist](https://github.com/elceef/dnstwist), the ability to generated potential typosquatted domains, +import them into HBase and look them up via `ENRICHMENT_EXISTS`. + +There are some challenges with this approach, though entirely viable: +* Even for modest numbers of domains, the number of records can grow quite large. The Top Alexa 10k domains has on the order of 3 million potential typosquatted domains. +* It still requires a network hop if out of cache. + +# The Tools Metron Provides + +## Bloom Filters + +It would be nice to have a local solution for these types of problems that may tradeoff accuracy for better +locality and space. Those who have been following the general theme of Metron's analytics philosophy will see +that we are likely in the domain where a probabalistic sketching data structure is in order. In this case, we +are asking simple existence queries, so a [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter) fits +well here. + +In Metron, we have the ability to create, add and merge bloom filters via: +* `BLOOM_INIT( size, fpp)` - Creates a bloom filter to handle `size` number of elements with `fpp` probability of false positives (`0 < fpp < 1`). +* `BLOOM_ADD( filter, object)` - Add an item to an existing bloom filter. +* `BLOOM_MERGE( filters )` - Merge a `filters`, a list of Bloom Filters. + +## Typosquatting Domain Generation + +Now that we have a suitable data structure, we need a way to generate potential typosquatted domains for a +given domain. Following the good work of [DNS Twist](https://github.com/elceef/dnstwist), we have ported +their set of typosquatting strategies to Metron: +* Bitsquatting - See [here](http://dinaburg.org/bitsquatting.html) +* Homoglyphs - Substituting characters for ascii or unicode analogues which are visually similar (e.g. `latlmes.com` for `latimes.com` as above) +* Subdomain - Making part of the domain a subdomain (e.g. `am.azon.com`) +* Hyphenation +* Insertion +* Addition +* Omission +* Repetition +* Replacement +* Transposition +* Vowel swapping + +The Stellar function in Metron is `DOMAIN_TYPOSQUAT( domain )`. It is recommended to remove the TLD from the +domain. You can see it in action here with our rick roll example above: +``` +[Stellar]>>> 'latlmes' in DOMAIN_TYPOSQUAT( 'latimes') +true +``` + +## Generating Summaries + +We need a way to generate the summary sketches from flat data for this to work. This is similar to, but +somewhat different from, loading flat data into HBase. Instead of each row in the file being loaded +generating a record in HBase, what we want is for each record to contribute to the summary sketch and at the +end to write out the summary sketch. + +For this purpose, we have a new utility `$METRON_HOME/bin/flatfile_summarizer.sh` to accompany +`$METRON_HOME/bin/flatfile_loader.sh`. The same extractor config is used, but we have 3 new configuration +options: +* `state_init` - Allows a state object to be initialized. This is a string, so a single expression is created. The output of this expression will be available as the `state` variable. +* `state_update` - Allows a state object to be updated. This is a map, so you can have temporary variables here. Note that you can reference the `state` variable from this. +* `state_merge` - Allows a list of states to be merged. This is a string, so a single expression. There is a special field called `states` available, which is a list of the states (one per thread). If this is not in existence, the number of threads is bound to one. + +Just as with `flatfile_loader.sh`, you can specify the number of threads (via `-p`) and batch size +(via `-b`), but now you have the opportunity to specify the output destination (via `-o`) and the output +mode (via `-om`). +The current output modes are: +* `LOCAL` - The default, to local disk. +* `CONSOLE` - Write the object summarized out to std out. This is useful to get summary statistics about the data imported. For instance, you could determine how many typosquatted domains there are for the Alexa 10k. +* `HDFS` + +## Reading Summaries In-Stream + +These summaries are immutable data and are stored in HDFS. We want to read them in and cache them for later, +so a new stellar function called `OBJECT_GET( hdfs_path )` will allow you to read the data from HDFS and +deserialize the data into an object which can be used. Subsequent calls for the next 24 hours (by default, +defaults of the cache can be changed in the global config) will be read from the static cache. + +For instance, if you have used the `flatfile_summarizer.sh` utility described above to write out an object to +`/apps/metron/objects/alexa_10k_filter.ser`, you can read and deserialize this object and use the bloom filter +to determine if the domain `goggle` is a typosquatted domain: +``` +BLOOM_EXISTS( OBJECT_GET('/apps/metron/objects/alexa_10k_filter.ser'), 'goggle') +``` + +# Example + +In the following demo, we will: +* Generate summary data from the top 10k Alexa domains in a Bloom Filter +* Use this to detect potential typosquatting instances in proxy data + +## Preliminaries + +We assume that the following environment variables are set: +* `METRON_HOME` - the home directory for metron +* `ZOOKEEPER` - The zookeeper quorum (comma separated with port specified: e.g. `node1:2181` for full-dev) +* `BROKERLIST` - The Kafka broker list (comma separated with port specified: e.g. `node1:6667` for full-dev) +* `ES_HOST` - The elasticsearch master (and port) e.g. `node1:9200` for full-dev. + +Also, this does not assume that you are using a kerberized cluster. If you are, then the parser start command will adjust slightly to include the security protocol. + +Before editing configurations, be sure to pull the configs from zookeeper locally via +``` +$METRON_HOME/bin/zk_load_configs.sh --mode PULL -z $ZOOKEEPER -o $METRON_HOME/config/zookeeper/ -f +``` + +If you are doing this on full-dev, I'd recommend stopping existing parsers and the profiler to free up +resources. You can do this in Ambari. + +## Install Squid Proxy + +Before starting, we're going to need to install and start squid by executing the following commands: +* `yum install -y squid` +* `service squid start` + +## Retrieve Alexa Data + +From the Metron access node in `~`, retrieve the +[Alexa top domains](https://en.wikipedia.org/wiki/Alexa_Internet) data via: +``` +cd ~ +wget http://s3.amazonaws.com/alexa-static/top-1m.csv.zip +unzip top-1m.csv.zip +head -n 10000 top-1m.csv > top-10k.csv +``` + +You should now have a file `~/top-10k.csv` which contains the top 10,000 domains as per +[Alexa](https://en.wikipedia.org/wiki/Alexa_Internet). + +## Summarize + +### Configure the Bloom Filter + +In order to configure the bloom filter, we need to know two things: +1. Roughly how many elements are going into the bloom filter (an upper bound will do) +2. What kind of false positive probability do we want? + +Both of these are going to inform how large the bloom filter is going to be. We can decide 2, but 1 is +going to require some computation. Let's use the `CONSOLE` output mode of the `flatfile_summarizer.sh` +to count the number of typosquatted domains across the entire document. + +Create a file `~/extractor_count.json` with the following content: +``` +{ + "config" : { + "columns" : { + "rank" : 0, + "domain" : 1 + }, + "value_transform" : { + "domain" : "DOMAIN_REMOVE_TLD(domain)" + }, + "value_filter" : "LENGTH(domain) > 0", + "state_init" : "0L", + "state_update" : { + "state" : "state + LENGTH( DOMAIN_TYPOSQUAT( domain ))" + }, + "state_merge" : "REDUCE(states, (s, x) -> s + x, 0)", + "separator" : "," + }, + "extractor" : "CSV" +} +``` + +In this extractor config we are using the CSV extractor with the following config properties: +* `columns` - Indicates the schema of the CSV. There are 2 columns, `rank` at the first position and `domain` at the second position. +* `separator` - Use a comma to separate the columns. +* `value_transform` - For each row, transform each `domain` column by removing the TLD. +* `value_filter` - Only consider non-empty domains +* `state_init` - Initialize the state, a long integer, to 0. +* `state_update` - For each row in the CSV, update the state, which is the running partial sum, with the number of typosquatted domains for the domain +* `state_merge` - For each thread, we have a partial sum, we want to merge the partial sums into the total. + +We can run this via: +``` +$METRON_HOME/bin/flatfile_summarizer.sh -i ~/top-10k.csv -o dummy -e ~/extractor_count.json -p 5 -om CONSOLE +``` + +The output should be something like: +``` +17/12/22 17:05:19 WARN extractor.TransformFilterExtractorDecorator: Unable to setup zookeeper client - zk_quorum url not provided. **This will limit some Stellar functionality** + +Processing /root/top-10k.csv +17/12/22 17:05:20 WARN resolver.BaseFunctionResolver: Using System classloader +Processed 9999 - \ +3496552 +``` +So, we the total number of possible elements in the bloom filter summary, `3,496,552`. + +### Generate the Bloom Filter + +Now we can generate the bloom filter on HDFS. As before, we will adapt our previous extractor config to +generate the bloom filter rather than the sum of the typosquatted domains. + +Create a file `~/extractor_filter.json` with the following contents: +``` +{ + "config" : { + "columns" : { + "rank" : 0, + "domain" : 1 + }, + "value_transform" : { + "domain" : "DOMAIN_REMOVE_TLD(domain)" + }, + "value_filter" : "LENGTH(domain) > 0", + "state_init" : "BLOOM_INIT(3496552, 0.001)", + "state_update" : { + "state" : "REDUCE( DOMAIN_TYPOSQUAT( domain ), (s, x) -> BLOOM_ADD(s, x), state)" + }, + "state_merge" : "BLOOM_MERGE(states)", + "separator" : "," + }, + "extractor" : "CSV" +} +``` + +Most of the configs are the same, but there are three that are different: +* `state_init` - We have changed our state to be a bloom filter, initialized with + * `3496552` - the size calculated in the previous step + * `0.001` - The false positive probability (`0.1%`) +* `state_update` - Update the bloom filter (the `state` variable) with each typosquatted domain +* `state_merge` - Merge the bloom filters generated per thread into a final, single bloom filter to be written. + +Now we can generate the bloom filter in HDFS at `/tmp/reference/alexa10k_filter.ser` via +``` +$METRON_HOME/bin/flatfile_summarizer.sh -i ~/top-10k.csv -o /tmp/reference/alexa10k_filter.ser -e ~/extractor_filter.json -p 5 -om HDFS +``` + +You can try out the object to ensure it functions as expected via the Stellar REPL (`$METRON_HOME/bin/stellar -z $ZOOKEEPER`): +``` +[Stellar]>>> BLOOM_EXISTS(OBJECT_GET('/tmp/reference/alexa10k_filter.ser'), 'gogle') +true +[Stellar]>>> BLOOM_EXISTS(OBJECT_GET('/tmp/reference/alexa10k_filter.ser'), 'google') +false +[Stellar]>>> BLOOM_EXISTS(OBJECT_GET('/tmp/reference/alexa10k_filter.ser'), 'github') +false +[Stellar]>>> BLOOM_EXISTS(OBJECT_GET('/tmp/reference/alexa10k_filter.ser'), 'gituub') +true +``` +Notice the lag on the first call is more substantial than the subsequent calls as they are pulled from the cache. + +## Parser + +Start the squid parser via: +* Create the squid topic: `/usr/hdp/current/kafka-broker/bin/kafka-topics.sh --zookeeper $ZOOKEEPER --create --topic squid --partitions 1 --replication-factor 1` +* Start the squid parser: `$METRON_HOME/bin/start_parser_topology.sh -z $ZOOKEEPER -s squid` + +## Set up Enrichment, Threat Intel and Threat Triage + +Now that we have squid parser running, we should create an enrichment to add a field `is_potential_typosquat` +which determines if the domain is potentially a typosquatted domain. Furthermore, we should set an alert if +it's so and triage those messages. + +We can do this by creating `$METRON_HOME/config/zookeeper/enrichments/squid.json` with the following content: +``` +{ + "enrichment": { + "fieldMap": { + "stellar" : { + "config" : [ + "domain_without_tld := DOMAIN_REMOVE_TLD(domain_without_subdomains)", + "is_potential_typosquat := BLOOM_EXISTS(OBJECT_GET('/tmp/reference/alexa10k_filter.ser'), domain_without_tld)", + "domain_without_tld := null" + ] + } + } + ,"fieldToTypeMap": { } + }, + "threatIntel": { + "fieldMap": { + "stellar" : { + "config" : [ + "is_alert := (exists(is_alert) && is_alert) || is_potential_typosquat" + ] + } + + }, + "fieldToTypeMap": { }, + "triageConfig" : { + "riskLevelRules" : [ + { + "name" : "Alexa 10k Typosquat Bloom", + "comment" : "Inspect a bloom filter with potentially typosquatted domains from the top Alexa 10k", + "rule" : "is_potential_typosquat != null && is_potential_typosquat", + "score" : 10, + "reason" : "FORMAT('%s is a potential typosquatted domain from the top 10k domains from alexa', domain_without_subdomains)" + } + ], + "aggregator" : "MAX" + } + } +} + +``` + +As you can see, following the pattern of enrichments the following are done: +* A new field `is_potential_typosquat` is created which indicates whether the domain sans TLD and subdomains is a typosquatted domain according to our bloom filter of the top 10k Alexa domains +* `is_alert` is updated based on the `is_potential_typosquat` field +* A new threat triage rule is added to give the analyst sufficient context if this alert triggers and a score of 10. + +Push the configs via `$METRON_HOME/bin/zk_load_configs.sh -m PUSH -i $METRON_HOME/config/zookeeper -z $ZOOKEEPER` + +## Generate Sample Data + +We can now use `squidclient` to visit a regular domain and typosquatted domain and send the data to kafka: +``` +squidclient http://www.github.com +squidclient http://gituub.com/apache/metron +cat /var/log/squid/access.log | /usr/hdp/current/kafka-broker/bin/kafka-console-producer.sh --broker-list $BROKERLIST --topic squid +``` + +## Investigate via the Alerts UI + +We should now have data in our elasticsearch indices, so let's investigate via the alerts UI. Before we do, +we have to adjust the mappings for the indices we just created to add the `alert` nested property. You can +do that via the following: +``` +curl -XPUT "http://$ES_HOST/squid*/_mapping/squid_doc" -d '{ + "properties" : { + "action" : { + "type" : "string" + }, + "adapter:stellaradapter:begin:ts" : { + "type" : "string" + }, + "adapter:stellaradapter:end:ts" : { + "type" : "string" + }, + "bytes" : { + "type" : "long" + }, + "code" : { + "type" : "long" + }, + "domain_without_subdomains" : { + "type" : "string" + }, + "elapsed" : { + "type" : "long" + }, + "enrichmentjoinbolt:joiner:ts" : { + "type" : "string" + }, + "enrichmentsplitterbolt:splitter:begin:ts" : { + "type" : "string" + }, + "enrichmentsplitterbolt:splitter:end:ts" : { + "type" : "string" + }, + "full_hostname" : { + "type" : "string" + }, + "guid" : { + "type" : "string" + }, + "ip_dst_addr" : { + "type" : "string" + }, + "ip_src_addr" : { + "type" : "string" + }, + "is_alert" : { + "type" : "string" + }, + "is_potential_typosquat" : { + "type" : "boolean" + }, + "method" : { + "type" : "string" + }, + "original_string" : { + "type" : "string" + }, + "source:type" : { + "type" : "string" + }, + "threat:triage:rules:0:comment" : { + "type" : "string" + }, + "threat:triage:rules:0:name" : { + "type" : "string" + }, + "threat:triage:rules:0:reason" : { + "type" : "string" + }, + "threat:triage:rules:0:score" : { + "type" : "long" + }, + "threat:triage:score" : { + "type" : "double" + }, + "threatinteljoinbolt:joiner:ts" : { + "type" : "string" + }, + "threatintelsplitterbolt:splitter:begin:ts" : { + "type" : "string" + }, + "threatintelsplitterbolt:splitter:end:ts" : { + "type" : "string" + }, + "timestamp" : { + "type" : "long" + }, + "url" : { + "type" : "string" + }, + "alert" : { + "type" : "nested" + } + } +}' +``` + +Now we can visit the Alerts UI (find the link from Ambari if not on full-dev. If on full-dev, go +[here](http://node1:4201/alerts-list). + +From there you should see the following data from squid with one as an alert and the other not + +![Alerts](squid_search.png) + +Now, if you drill down into the alert, you can see our fields and the reasons specified + +![Drill Down](drill_down.png) From a272da183fcd5031a8a55f00dd9143a2069881f1 Mon Sep 17 00:00:00 2001 From: cstella Date: Fri, 22 Dec 2017 12:47:59 -0500 Subject: [PATCH 18/28] Updating OBJECT_GET documentation to be better. --- .../org/apache/metron/enrichment/stellar/ObjectGet.java | 6 +++++- metron-stellar/stellar-common/README.md | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/stellar/ObjectGet.java b/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/stellar/ObjectGet.java index 0a2ad7be25..ebb94da684 100644 --- a/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/stellar/ObjectGet.java +++ b/metron-platform/metron-enrichment/src/main/java/org/apache/metron/enrichment/stellar/ObjectGet.java @@ -50,7 +50,11 @@ @Stellar(namespace="OBJECT" ,name="GET" - ,description="Retrieve and deserialize a serialized object from HDFS" + ,description="Retrieve and deserialize a serialized object from HDFS. " + + "The cache can be specified via two properties in the global config: " + + "\"" + ObjectGet.OBJECT_CACHE_SIZE_KEY + "\" (default " + ObjectGet.OBJECT_CACHE_SIZE_DEFAULT + ")," + + "\"" + ObjectGet.OBJECT_CACHE_EXPIRATION_KEY+ "\" (default 1440). Note, if these are changed in global config, " + + "topology restart is required." , params = { "path - The path in HDFS to the serialized object" } diff --git a/metron-stellar/stellar-common/README.md b/metron-stellar/stellar-common/README.md index febf104a04..ffb42d39a6 100644 --- a/metron-stellar/stellar-common/README.md +++ b/metron-stellar/stellar-common/README.md @@ -791,7 +791,9 @@ Where: * Returns: The set of objects in the multiset ignoring multiplicity ### `OBJECT_GET` - * Description: Retrieve and deserialize a serialized object from HDFS + * Description: Retrieve and deserialize a serialized object from HDFS. The cache can be specified via two properties + in the global config: "object.cache.size" (default 1000), "object.cache.expiration.minutes" (default 1440). Note, if + these are changed in global config, topology restart is required. * Input: * path - The path in HDFS to the serialized object * Returns: The deserialized object. From 767e4976a723451c92ff7bbceffafd5c38086c19 Mon Sep 17 00:00:00 2001 From: cstella Date: Sat, 23 Dec 2017 10:32:07 -0500 Subject: [PATCH 19/28] Allowing empty outputs --- .../dataloads/nonbulk/flatfile/SummarizeOptions.java | 2 +- .../flatfile/importer/AbstractLocalImporter.java | 4 +++- .../nonbulk/flatfile/importer/LocalSummarizer.java | 4 ++-- .../nonbulk/flatfile/writer/ConsoleWriter.java | 7 ++++--- .../nonbulk/flatfile/writer/HDFSWriter.java | 11 ++++++++--- .../nonbulk/flatfile/writer/LocalWriter.java | 12 +++++++++--- .../dataloads/nonbulk/flatfile/writer/Writer.java | 7 ++++--- 7 files changed, 31 insertions(+), 16 deletions(-) diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SummarizeOptions.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SummarizeOptions.java index 8d9ec2cfce..4e644ba64b 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SummarizeOptions.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/SummarizeOptions.java @@ -74,7 +74,7 @@ public String getShortCode() { public Option apply(@Nullable String s) { Option o = new Option(s, "output", true, "The output file to write"); o.setArgName("FILE"); - o.setRequired(true); + o.setRequired(false); return o; } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java index dc56c0a885..b86f7086e4 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java @@ -58,7 +58,9 @@ public void importData( final EnumMap> config int numThreads = numThreads(config, handler); extractLineByLine(inputs, fs, state, batchSize, numThreads, quiet); } - System.out.println(); + if(!quiet) { + System.out.println(); + } } protected abstract List getInputs(final EnumMap> config); diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java index 28073a351d..229ef4eae0 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java @@ -117,7 +117,7 @@ protected void extract(SummarizationState state, String line) throws IOException @Override public void importData(EnumMap> config, ExtractorHandler handler, Configuration hadoopConfig) throws IOException { Writer writer = (Writer) config.get(SummarizeOptions.OUTPUT_MODE).get(); - String fileName = (String)config.get(SummarizeOptions.OUTPUT).get(); + Optional fileName = Optional.ofNullable((String)config.get(SummarizeOptions.OUTPUT).orElse(null)); writer.validate(fileName, hadoopConfig); super.importData(config, handler, hadoopConfig); StatefulExtractor extractor = (StatefulExtractor) handler.getExtractor(); @@ -132,7 +132,7 @@ else if(stateList.size() > 1) { } finalState = extractor.mergeStates(states); } - writer.write(finalState, (String)config.get(SummarizeOptions.OUTPUT).get(), hadoopConfig); + writer.write(finalState, fileName, hadoopConfig); } @Override diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ConsoleWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ConsoleWriter.java index aaf2c8ed9f..22f4aa1e52 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ConsoleWriter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/ConsoleWriter.java @@ -21,20 +21,21 @@ import org.apache.metron.common.utils.SerDeUtils; import java.io.IOException; +import java.util.Optional; public class ConsoleWriter implements Writer{ @Override - public void validate(String output, Configuration hadoopConfig) { + public void validate(Optional output, Configuration hadoopConfig) { } @Override - public void write(Object obj, String output, Configuration hadoopConfig) throws IOException { + public void write(Object obj, Optional output, Configuration hadoopConfig) throws IOException { System.out.println(obj); } @Override - public void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException { + public void write(byte[] obj, Optional output, Configuration hadoopConfig) throws IOException { System.out.println(SerDeUtils.fromBytes(obj, Object.class)); } } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java index 7e93fafa68..5109d5b10d 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java @@ -25,19 +25,24 @@ import org.apache.hadoop.fs.Path; import java.io.IOException; +import java.util.Optional; public class HDFSWriter implements Writer { @Override - public void validate(String fileName, Configuration hadoopConfig) { + public void validate(Optional fileNameOptional, Configuration hadoopConfig) { + if(!fileNameOptional.isPresent()) { + throw new IllegalStateException("Filename is not present."); + } + String fileName = fileNameOptional.get(); if(StringUtils.isEmpty(fileName) || fileName.trim().equals(".") || fileName.trim().equals("..") || fileName.trim().endsWith("/")) { throw new IllegalStateException("Filename is empty or otherwise invalid."); } } @Override - public void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException { + public void write(byte[] obj, Optional output, Configuration hadoopConfig) throws IOException { FileSystem fs = FileSystem.get(hadoopConfig); - try(FSDataOutputStream stream = fs.create(new Path(output))) { + try(FSDataOutputStream stream = fs.create(new Path(output.get()))) { IOUtils.write(obj, stream); stream.flush(); } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java index 9c9e85e75d..5d757fedb9 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java @@ -24,18 +24,24 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.util.Optional; public class LocalWriter implements Writer { + @Override - public void validate(String fileName, Configuration hadoopConfig) { + public void validate(Optional fileNameOptional, Configuration hadoopConfig) { + if(!fileNameOptional.isPresent()) { + throw new IllegalStateException("Filename is not present."); + } + String fileName = fileNameOptional.get(); if(StringUtils.isEmpty(fileName) || fileName.trim().equals(".") || fileName.trim().equals("..") || fileName.trim().endsWith("/")) { throw new IllegalStateException("Filename is empty or otherwise invalid."); } } @Override - public void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException { - File outFile = new File(output); + public void write(byte[] obj, Optional output, Configuration hadoopConfig) throws IOException { + File outFile = new File(output.get()); if(!outFile.getParentFile().exists()) { outFile.getParentFile().mkdirs(); } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java index bf41bfdcbb..e41fb3578f 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java @@ -21,13 +21,14 @@ import org.apache.metron.common.utils.SerDeUtils; import java.io.IOException; +import java.util.Optional; public interface Writer { - void validate(String output, Configuration hadoopConfig); - default void write(Object obj, String output, Configuration hadoopConfig) throws IOException { + void validate(Optional output, Configuration hadoopConfig); + default void write(Object obj, Optional output, Configuration hadoopConfig) throws IOException { if(obj != null) { write(SerDeUtils.toBytes(obj), output, hadoopConfig); } } - void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException; + void write(byte[] obj, Optional output, Configuration hadoopConfig) throws IOException; } From b4e40a4e47ddc6ff871ef0e95b433fb4315f8e34 Mon Sep 17 00:00:00 2001 From: cstella Date: Sat, 23 Dec 2017 11:07:10 -0500 Subject: [PATCH 20/28] Missed a compilation error. --- .../metron/dataloads/nonbulk/flatfile/writer/Writers.java | 4 ++-- .../nonbulk/flatfile/SimpleFlatFileSummarizerTest.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java index acd03febfe..8c673c61f1 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java @@ -45,12 +45,12 @@ public static Optional getStrategy(String strategyName) { } @Override - public void validate(String output, Configuration hadoopConf) { + public void validate(Optional output, Configuration hadoopConf) { writer.validate(output, hadoopConf); } @Override - public void write(byte[] obj, String output, Configuration hadoopConf) throws IOException { + public void write(byte[] obj, Optional output, Configuration hadoopConf) throws IOException { writer.write(obj, output, hadoopConf); } } diff --git a/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java b/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java index edf790b8f5..63beb53d95 100644 --- a/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java +++ b/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java @@ -215,16 +215,16 @@ public PeekingWriter(AtomicReference ref) { } @Override - public void validate(String output, Configuration hadoopConfig) { + public void validate(Optional output, Configuration hadoopConfig) { } @Override - public void write(Object obj, String output, Configuration hadoopConfig) throws IOException { + public void write(Object obj, Optional output, Configuration hadoopConfig) throws IOException { ref.set(obj); } @Override - public void write(byte[] obj, String output, Configuration hadoopConfig) throws IOException { + public void write(byte[] obj, Optional output, Configuration hadoopConfig) throws IOException { } } From fe7496fe27e81d0584eaa9b65efac13f93eadc13 Mon Sep 17 00:00:00 2001 From: cstella Date: Sat, 23 Dec 2017 12:18:23 -0500 Subject: [PATCH 21/28] Updating readme to remove dependency on -o --- use-cases/typosquat_detection/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/use-cases/typosquat_detection/README.md b/use-cases/typosquat_detection/README.md index 1c46a3c3c7..1221747712 100644 --- a/use-cases/typosquat_detection/README.md +++ b/use-cases/typosquat_detection/README.md @@ -180,7 +180,7 @@ In this extractor config we are using the CSV extractor with the following confi We can run this via: ``` -$METRON_HOME/bin/flatfile_summarizer.sh -i ~/top-10k.csv -o dummy -e ~/extractor_count.json -p 5 -om CONSOLE +$METRON_HOME/bin/flatfile_summarizer.sh -i ~/top-10k.csv -e ~/extractor_count.json -p 5 -om CONSOLE ``` The output should be something like: From 870e05fd857060b777b0c85c656200587f8011e6 Mon Sep 17 00:00:00 2001 From: cstella Date: Thu, 4 Jan 2018 09:53:27 -0500 Subject: [PATCH 22/28] forgot header. --- use-cases/typosquat_detection/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/use-cases/typosquat_detection/README.md b/use-cases/typosquat_detection/README.md index 1221747712..c9ebb51468 100644 --- a/use-cases/typosquat_detection/README.md +++ b/use-cases/typosquat_detection/README.md @@ -1,3 +1,20 @@ + # Problem Statement [Typosquatting](https://en.wikipedia.org/wiki/Typosquatting) is a form of cybersquatting which relies on From d2fb81ada4406434ea8af156966b1a9143881bcc Mon Sep 17 00:00:00 2001 From: cstella Date: Fri, 5 Jan 2018 14:15:35 -0500 Subject: [PATCH 23/28] Some weird bug fell in here. --- .../dsl/functions/FunctionalFunctions.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/FunctionalFunctions.java b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/FunctionalFunctions.java index 1e30daea07..3c5545261c 100644 --- a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/FunctionalFunctions.java +++ b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/FunctionalFunctions.java @@ -18,6 +18,7 @@ package org.apache.metron.stellar.dsl.functions; +import com.google.common.collect.Lists; import org.apache.metron.stellar.dsl.BaseStellarFunction; import org.apache.metron.stellar.dsl.Stellar; import org.apache.metron.stellar.common.LambdaExpression; @@ -41,7 +42,7 @@ public static class Map extends BaseStellarFunction { @Override public Object apply(List args) { - Iterable input = (Iterable) args.get(0); + Iterable input = getIterable(args.get(0)); LambdaExpression expression = (LambdaExpression)args.get(1); if(input == null || expression == null) { return input; @@ -66,7 +67,7 @@ public static class Filter extends BaseStellarFunction { @Override public Object apply(List args) { - Iterable input = (Iterable) args.get(0); + Iterable input = getIterable(args.get(0)); LambdaExpression expression = (LambdaExpression) args.get(1); if(input == null || expression == null) { return input; @@ -95,7 +96,7 @@ public static class Reduce extends BaseStellarFunction { @Override public Object apply(List args) { - Iterable input = (Iterable) args.get(0); + Iterable input = getIterable(args.get(0)); if(input == null || args.size() < 3) { return null; } @@ -112,6 +113,21 @@ public Object apply(List args) { } } + private static Iterable getIterable(Object o) { + if(o == null) { + return null; + } + if(o instanceof String) { + return Lists.charactersOf((String)o); + } + else if(o instanceof Iterable) { + return (Iterable)o; + } + else { + throw new IllegalArgumentException(o.getClass() + " is not an iterable, and therefore cannot be used."); + } + } + @Stellar(name="ZIP_LONGEST" , description="Zips lists into a single list where the ith element is an list " + "containing the ith items from the constituent lists. " + From 60e46ea3c134e7fe9d1442076a2882f22a61ad82 Mon Sep 17 00:00:00 2001 From: cstella Date: Fri, 5 Jan 2018 15:01:10 -0500 Subject: [PATCH 24/28] Better comments. --- .../org/apache/metron/common/typosquat/AdditionStrategy.java | 3 +++ .../apache/metron/common/typosquat/BitsquattingStrategy.java | 3 +++ .../org/apache/metron/common/typosquat/HomoglyphStrategy.java | 4 ++++ .../apache/metron/common/typosquat/HyphenationStrategy.java | 3 +++ .../org/apache/metron/common/typosquat/InsertionStrategy.java | 3 +++ .../java/org/apache/metron/common/typosquat/Keyboards.java | 4 ++++ .../org/apache/metron/common/typosquat/OmissionStrategy.java | 3 +++ .../apache/metron/common/typosquat/RepetitionStrategy.java | 3 +++ .../org/apache/metron/common/typosquat/SubdomainStrategy.java | 3 +++ .../metron/common/typosquat/TyposquattingStrategies.java | 3 +++ .../org/apache/metron/common/typosquat/VowelSwapStrategy.java | 3 +++ 11 files changed, 35 insertions(+) diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/AdditionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/AdditionStrategy.java index 423f976e34..871052d0c1 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/AdditionStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/AdditionStrategy.java @@ -20,6 +20,9 @@ import java.util.HashSet; import java.util.Set; +/** + * A typo strategy based on adding characters between ascii 97 and 123. + */ public class AdditionStrategy implements TyposquattingStrategy { @Override public Set generateCandidates(String domain) { diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/BitsquattingStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/BitsquattingStrategy.java index 004c2cacc1..32d4184b57 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/BitsquattingStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/BitsquattingStrategy.java @@ -20,6 +20,9 @@ import java.util.HashSet; import java.util.Set; +/** + * See http://dinaburg.org/bitsquatting.html for more + */ public class BitsquattingStrategy implements TyposquattingStrategy { public static int[] MASK = new int[] { 1, 2, 4, 8, 16, 32, 64, 128}; @Override diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java index bec152f0ae..19479de189 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HomoglyphStrategy.java @@ -26,6 +26,10 @@ import java.net.IDN; import java.util.*; +/** + * Substituting characters for ascii or unicode analogues which are visually similar (e.g. latlmes.com for latimes.com) + * + */ public class HomoglyphStrategy implements TyposquattingStrategy{ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HyphenationStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HyphenationStrategy.java index 08a2583919..ca6ce8f024 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HyphenationStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/HyphenationStrategy.java @@ -20,6 +20,9 @@ import java.util.HashSet; import java.util.Set; +/** + * Typos based on random hyphenation (e.g. am-azon.com vs amazon.com) + */ public class HyphenationStrategy implements TyposquattingStrategy { @Override public Set generateCandidates(String originalString) { diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/InsertionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/InsertionStrategy.java index d6a644d057..b601a35992 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/InsertionStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/InsertionStrategy.java @@ -20,6 +20,9 @@ import java.util.HashSet; import java.util.Set; +/** + * Typo strategy based on random insertion of common typos based on keyboard layout proximity. + */ public class InsertionStrategy implements TyposquattingStrategy { @Override public Set generateCandidates(String domain) { diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/Keyboards.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/Keyboards.java index 3cc70a787f..6fbd5ecfdf 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/Keyboards.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/Keyboards.java @@ -20,6 +20,10 @@ import java.util.HashMap; import java.util.Map; +/** + * This provides a mapping of nearby keys for a variety of keyboard layouts. This is useful in determining likely + * typos. + */ public enum Keyboards { QWERTY(new HashMap() {{ diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OmissionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OmissionStrategy.java index be3a49a812..c49dbb074c 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OmissionStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/OmissionStrategy.java @@ -20,6 +20,9 @@ import java.util.HashSet; import java.util.Set; +/** + * A typo strategy based on omitting characters. + */ public class OmissionStrategy implements TyposquattingStrategy { @Override diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/RepetitionStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/RepetitionStrategy.java index 81de290260..fa1b0aa115 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/RepetitionStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/RepetitionStrategy.java @@ -20,6 +20,9 @@ import java.util.HashSet; import java.util.Set; +/** + * Typo strategy around repeating existing characters. + */ public class RepetitionStrategy implements TyposquattingStrategy { @Override public Set generateCandidates(String domain) { diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/SubdomainStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/SubdomainStrategy.java index be342c2f4f..2dc06e4eec 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/SubdomainStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/SubdomainStrategy.java @@ -20,6 +20,9 @@ import java.util.HashSet; import java.util.Set; +/** + * A typo strategy around random subdomains (e.g. am.azon.com vs amazon.com) + */ public class SubdomainStrategy implements TyposquattingStrategy{ @Override diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java index b7fd1e7fc5..a9f9a417fd 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/TyposquattingStrategies.java @@ -26,6 +26,9 @@ import java.util.List; import java.util.Set; +/** + * This is a set of strategies for generating likely typos from domains. + */ public enum TyposquattingStrategies implements TyposquattingStrategy { ADDITION(new AdditionStrategy()), BITSQUATTING(new BitsquattingStrategy()), diff --git a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/VowelSwapStrategy.java b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/VowelSwapStrategy.java index 538acf9bec..0a3388d115 100644 --- a/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/VowelSwapStrategy.java +++ b/metron-platform/metron-common/src/main/java/org/apache/metron/common/typosquat/VowelSwapStrategy.java @@ -20,6 +20,9 @@ import java.util.HashSet; import java.util.Set; +/** + * A typo strategy around swapping vowels (e.g. omazon.com vs amazon.com) + */ public class VowelSwapStrategy implements TyposquattingStrategy { private static Set VOWELS = new HashSet() {{ add('a'); From fe8be62a8b324e4afa8205c1f313b37a172171b0 Mon Sep 17 00:00:00 2001 From: cstella Date: Mon, 8 Jan 2018 14:54:58 -0500 Subject: [PATCH 25/28] Reacting to Justin's comments. --- .../metron-data-management/README.md | 2 +- .../importer/AbstractLocalImporter.java | 3 +- .../nonbulk/flatfile/importer/Importer.java | 3 +- .../flatfile/importer/LocalSummarizer.java | 3 +- .../nonbulk/flatfile/writer/HDFSWriter.java | 6 ++-- .../flatfile/writer/InvalidWriterOutput.java | 28 +++++++++++++++++++ .../nonbulk/flatfile/writer/LocalWriter.java | 6 ++-- .../nonbulk/flatfile/writer/Writer.java | 2 +- .../nonbulk/flatfile/writer/Writers.java | 2 +- .../SimpleFlatFileSummarizerTest.java | 7 +++-- 10 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/InvalidWriterOutput.java diff --git a/metron-platform/metron-data-management/README.md b/metron-platform/metron-data-management/README.md index e9c20fc702..88e901cc24 100644 --- a/metron-platform/metron-data-management/README.md +++ b/metron-platform/metron-data-management/README.md @@ -441,7 +441,7 @@ The parameters for the utility are as follows: | -m | --import_mode | No | The Import mode to use: LOCAL, MR. Default: LOCAL | | -om | --output_mode | No | The Output mode to use: LOCAL, HDFS. Default: LOCAL | | -i | --input | Yes | The input data location on local disk. If this is a file, then that file will be loaded. If this is a directory, then the files will be loaded recursively under that directory. | -| -i | --output | Yes | The output data location. | +| -o | --output | Yes | The output data location. | | -l | --log4j | No | The log4j properties file to load | | -p | --threads | No | The number of threads to use when extracting data. The default is the number of cores. | | -b | --batchSize | No | The batch size to use for HBase puts | diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java index b86f7086e4..1709931da9 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/AbstractLocalImporter.java @@ -26,6 +26,7 @@ import org.apache.metron.dataloads.nonbulk.flatfile.LoadOptions; import org.apache.metron.dataloads.nonbulk.flatfile.location.Location; import org.apache.metron.dataloads.nonbulk.flatfile.location.LocationStrategy; +import org.apache.metron.dataloads.nonbulk.flatfile.writer.InvalidWriterOutput; import java.io.BufferedReader; import java.io.IOException; @@ -43,7 +44,7 @@ public abstract class AbstractLocalImporter & public void importData( final EnumMap> config , final ExtractorHandler handler , final Configuration hadoopConfig - ) throws IOException { + ) throws IOException, InvalidWriterOutput { validateState(config, handler); ThreadLocal state = createState(config, hadoopConfig, handler); boolean quiet = isQuiet(config); diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Importer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Importer.java index 89101efab2..0c7faf686f 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Importer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/Importer.java @@ -22,6 +22,7 @@ import org.apache.hadoop.fs.FileSystem; import org.apache.metron.dataloads.extractor.ExtractorHandler; import org.apache.metron.dataloads.nonbulk.flatfile.LoadOptions; +import org.apache.metron.dataloads.nonbulk.flatfile.writer.InvalidWriterOutput; import org.apache.metron.enrichment.converter.EnrichmentConverter; import java.io.IOException; @@ -30,5 +31,5 @@ import java.util.Optional; public interface Importer> { - void importData(EnumMap> config, ExtractorHandler handler , final Configuration hadoopConfig) throws IOException; + void importData(EnumMap> config, ExtractorHandler handler , final Configuration hadoopConfig) throws IOException, InvalidWriterOutput; } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java index 229ef4eae0..7042e86087 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/importer/LocalSummarizer.java @@ -26,6 +26,7 @@ import org.apache.metron.dataloads.extractor.ExtractorHandler; import org.apache.metron.dataloads.extractor.StatefulExtractor; import org.apache.metron.dataloads.nonbulk.flatfile.SummarizeOptions; +import org.apache.metron.dataloads.nonbulk.flatfile.writer.InvalidWriterOutput; import org.apache.metron.dataloads.nonbulk.flatfile.writer.Writer; import org.apache.metron.dataloads.nonbulk.flatfile.writer.Writers; @@ -115,7 +116,7 @@ protected void extract(SummarizationState state, String line) throws IOException } @Override - public void importData(EnumMap> config, ExtractorHandler handler, Configuration hadoopConfig) throws IOException { + public void importData(EnumMap> config, ExtractorHandler handler, Configuration hadoopConfig) throws IOException, InvalidWriterOutput { Writer writer = (Writer) config.get(SummarizeOptions.OUTPUT_MODE).get(); Optional fileName = Optional.ofNullable((String)config.get(SummarizeOptions.OUTPUT).orElse(null)); writer.validate(fileName, hadoopConfig); diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java index 5109d5b10d..1c0c7264cb 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/HDFSWriter.java @@ -29,13 +29,13 @@ public class HDFSWriter implements Writer { @Override - public void validate(Optional fileNameOptional, Configuration hadoopConfig) { + public void validate(Optional fileNameOptional, Configuration hadoopConfig) throws InvalidWriterOutput { if(!fileNameOptional.isPresent()) { - throw new IllegalStateException("Filename is not present."); + throw new InvalidWriterOutput("Filename is not present."); } String fileName = fileNameOptional.get(); if(StringUtils.isEmpty(fileName) || fileName.trim().equals(".") || fileName.trim().equals("..") || fileName.trim().endsWith("/")) { - throw new IllegalStateException("Filename is empty or otherwise invalid."); + throw new InvalidWriterOutput("Filename is empty or otherwise invalid."); } } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/InvalidWriterOutput.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/InvalidWriterOutput.java new file mode 100644 index 0000000000..7c237c8870 --- /dev/null +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/InvalidWriterOutput.java @@ -0,0 +1,28 @@ +/** + * 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 org.apache.metron.dataloads.nonbulk.flatfile.writer; + +public class InvalidWriterOutput extends Exception { + public InvalidWriterOutput(String message) { + super(message); + } + + public InvalidWriterOutput(String message, Throwable t) { + super(message, t); + } +} diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java index 5d757fedb9..d8bda81353 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/LocalWriter.java @@ -29,13 +29,13 @@ public class LocalWriter implements Writer { @Override - public void validate(Optional fileNameOptional, Configuration hadoopConfig) { + public void validate(Optional fileNameOptional, Configuration hadoopConfig) throws InvalidWriterOutput { if(!fileNameOptional.isPresent()) { - throw new IllegalStateException("Filename is not present."); + throw new InvalidWriterOutput("Filename is not present."); } String fileName = fileNameOptional.get(); if(StringUtils.isEmpty(fileName) || fileName.trim().equals(".") || fileName.trim().equals("..") || fileName.trim().endsWith("/")) { - throw new IllegalStateException("Filename is empty or otherwise invalid."); + throw new InvalidWriterOutput("Filename is empty or otherwise invalid."); } } diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java index e41fb3578f..ba13ba1334 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writer.java @@ -24,7 +24,7 @@ import java.util.Optional; public interface Writer { - void validate(Optional output, Configuration hadoopConfig); + void validate(Optional output, Configuration hadoopConfig) throws InvalidWriterOutput; default void write(Object obj, Optional output, Configuration hadoopConfig) throws IOException { if(obj != null) { write(SerDeUtils.toBytes(obj), output, hadoopConfig); diff --git a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java index 8c673c61f1..785ad214f0 100644 --- a/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java +++ b/metron-platform/metron-data-management/src/main/java/org/apache/metron/dataloads/nonbulk/flatfile/writer/Writers.java @@ -45,7 +45,7 @@ public static Optional getStrategy(String strategyName) { } @Override - public void validate(Optional output, Configuration hadoopConf) { + public void validate(Optional output, Configuration hadoopConf) throws InvalidWriterOutput { writer.validate(output, hadoopConf); } diff --git a/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java b/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java index 63beb53d95..17e3206dbb 100644 --- a/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java +++ b/metron-platform/metron-data-management/src/test/java/org/apache/metron/dataloads/nonbulk/flatfile/SimpleFlatFileSummarizerTest.java @@ -30,6 +30,7 @@ import org.apache.metron.dataloads.nonbulk.flatfile.importer.LocalSummarizer; import org.apache.metron.dataloads.nonbulk.flatfile.location.Location; import org.apache.metron.dataloads.nonbulk.flatfile.location.RawLocation; +import org.apache.metron.dataloads.nonbulk.flatfile.writer.InvalidWriterOutput; import org.apache.metron.dataloads.nonbulk.flatfile.writer.Writer; import org.apache.metron.stellar.common.utils.StellarProcessorUtils; import org.junit.Assert; @@ -230,12 +231,12 @@ public void write(byte[] obj, Optional output, Configuration hadoopConfi } @Test - public void testLineByLine() throws IOException { + public void testLineByLine() throws IOException, InvalidWriterOutput { testLineByLine(5); testLineByLine(1); } - public void testLineByLine(final int numThreads) throws IOException { + public void testLineByLine(final int numThreads) throws IOException, InvalidWriterOutput { ExtractorHandler handler = ExtractorHandler.load(stellarExtractorConfigLineByLine); LocalSummarizer summarizer = new MockSummarizer( ImmutableMap.of("input.csv", generateData()) @@ -263,7 +264,7 @@ public void testWholeFile() throws Exception { testWholeFile(1); } - public void testWholeFile(final int numThreads) throws IOException { + public void testWholeFile(final int numThreads) throws IOException, InvalidWriterOutput { ExtractorHandler handler = ExtractorHandler.load(stellarExtractorConfigWholeFile); LocalSummarizer summarizer = new MockSummarizer( new HashMap() {{ From 343e005897a613dcfa9ecb48ead178e063bf36c4 Mon Sep 17 00:00:00 2001 From: cstella Date: Mon, 8 Jan 2018 15:05:00 -0500 Subject: [PATCH 26/28] Removing flush. --- .../java/org/apache/metron/enrichment/stellar/ObjectGetTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/stellar/ObjectGetTest.java b/metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/stellar/ObjectGetTest.java index 4a34f86e04..400dfb8ec8 100644 --- a/metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/stellar/ObjectGetTest.java +++ b/metron-platform/metron-enrichment/src/test/java/org/apache/metron/enrichment/stellar/ObjectGetTest.java @@ -62,7 +62,6 @@ public void test() throws Exception { public void assertDataIsReadCorrectly(String filename) throws IOException { try(BufferedOutputStream bos = new BufferedOutputStream(fs.create(new Path(filename), true))) { IOUtils.write(SerDeUtils.toBytes(data), bos); - bos.flush(); } List readData = (List) StellarProcessorUtils.run("OBJECT_GET(loc)", ImmutableMap.of("loc", filename)); Assert.assertEquals(readData, data); From 2a65360781dac4f11967168ca41409769a1578d6 Mon Sep 17 00:00:00 2001 From: cstella Date: Mon, 8 Jan 2018 17:10:08 -0500 Subject: [PATCH 27/28] Updated mapping to match ES5 semantics. --- use-cases/typosquat_detection/README.md | 48 ++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/use-cases/typosquat_detection/README.md b/use-cases/typosquat_detection/README.md index c9ebb51468..144071ca64 100644 --- a/use-cases/typosquat_detection/README.md +++ b/use-cases/typosquat_detection/README.md @@ -343,13 +343,13 @@ do that via the following: curl -XPUT "http://$ES_HOST/squid*/_mapping/squid_doc" -d '{ "properties" : { "action" : { - "type" : "string" + "type" : "text","fielddata" : true }, "adapter:stellaradapter:begin:ts" : { - "type" : "string" + "type" : "text","fielddata" : true }, "adapter:stellaradapter:end:ts" : { - "type" : "string" + "type" : "text","fielddata" : true }, "bytes" : { "type" : "long" @@ -358,76 +358,76 @@ curl -XPUT "http://$ES_HOST/squid*/_mapping/squid_doc" -d '{ "type" : "long" }, "domain_without_subdomains" : { - "type" : "string" + "type" : "text","fielddata" : true }, "elapsed" : { "type" : "long" }, "enrichmentjoinbolt:joiner:ts" : { - "type" : "string" + "type" : "text","fielddata" : true }, "enrichmentsplitterbolt:splitter:begin:ts" : { - "type" : "string" + "type" : "text","fielddata" : true }, "enrichmentsplitterbolt:splitter:end:ts" : { - "type" : "string" + "type" : "text","fielddata" : true }, "full_hostname" : { - "type" : "string" + "type" : "text","fielddata" : true }, "guid" : { - "type" : "string" + "type" : "text","fielddata" : true }, "ip_dst_addr" : { - "type" : "string" + "type" : "text","fielddata" : true }, "ip_src_addr" : { - "type" : "string" + "type" : "text","fielddata" : true }, "is_alert" : { - "type" : "string" + "type" : "text","fielddata" : true }, "is_potential_typosquat" : { "type" : "boolean" }, "method" : { - "type" : "string" + "type" : "text","fielddata" : true }, - "original_string" : { - "type" : "string" + "original_text" : { + "type" : "text","fielddata" : true }, "source:type" : { - "type" : "string" + "type" : "text","fielddata" : true }, "threat:triage:rules:0:comment" : { - "type" : "string" + "type" : "text","fielddata" : true }, "threat:triage:rules:0:name" : { - "type" : "string" + "type" : "text","fielddata" : true }, "threat:triage:rules:0:reason" : { - "type" : "string" + "type" : "text","fielddata" : true }, "threat:triage:rules:0:score" : { "type" : "long" }, "threat:triage:score" : { - "type" : "double" + "type" : "float" }, "threatinteljoinbolt:joiner:ts" : { - "type" : "string" + "type" : "text","fielddata" : true }, "threatintelsplitterbolt:splitter:begin:ts" : { - "type" : "string" + "type" : "text","fielddata" : true }, "threatintelsplitterbolt:splitter:end:ts" : { - "type" : "string" + "type" : "text","fielddata" : true }, "timestamp" : { "type" : "long" }, "url" : { - "type" : "string" + "type" : "text","fielddata" : true }, "alert" : { "type" : "nested" From d88c3eb3032f3b965149f638b960e505efcee9b4 Mon Sep 17 00:00:00 2001 From: cstella Date: Tue, 9 Jan 2018 13:56:20 -0500 Subject: [PATCH 28/28] Fixed instructions for ES 5 --- use-cases/typosquat_detection/README.md | 204 ++++++++++++------------ 1 file changed, 103 insertions(+), 101 deletions(-) diff --git a/use-cases/typosquat_detection/README.md b/use-cases/typosquat_detection/README.md index 144071ca64..4e4de71c6a 100644 --- a/use-cases/typosquat_detection/README.md +++ b/use-cases/typosquat_detection/README.md @@ -325,6 +325,107 @@ As you can see, following the pattern of enrichments the following are done: Push the configs via `$METRON_HOME/bin/zk_load_configs.sh -m PUSH -i $METRON_HOME/config/zookeeper -z $ZOOKEEPER` +## Setup Indices + +We have to adjust the mappings for the indices we just created to add +the `alert` nested property and ensure each of our properties gets the +right type. One does not want to rely entirely on elasticsearch to +guess the right types. We will do that by specifying a template: +``` +curl -XPOST "http://$ES_HOST/_template/squid_index" -d '{ + "template": "squid_index*", + "mappings": { + "squid_doc": { + "dynamic_templates": [ + { + "timestamps": { + "match": "*:ts", + "match_mapping_type": "*", + "mapping": { + "type": "date", + "format": "epoch_millis" + } + } + }, + { + "threat_triage_score": { + "mapping": { + "type": "float" + }, + "match": "threat:triage:*score", + "match_mapping_type": "*" + } + }, + { + "threat_triage_reason": { + "mapping": { + "type": "text", + "fielddata": "true" + }, + "match": "threat:triage:rules:*:reason", + "match_mapping_type": "*" + } + } + ], + "properties" : { + "action" : { + "type" : "text","fielddata" : true + }, + "bytes" : { + "type" : "long" + }, + "code" : { + "type" : "long" + }, + "domain_without_subdomains" : { + "type" : "text","fielddata" : true + }, + "elapsed" : { + "type" : "long" + }, + "full_hostname" : { + "type" : "text","fielddata" : true + }, + "guid" : { + "type" : "keyword" + }, + "ip_dst_addr" : { + "type" : "ip" + }, + "ip_src_addr" : { + "type" : "ip" + }, + "is_alert" : { + "type" : "text","fielddata" : true + }, + "is_potential_typosquat" : { + "type" : "boolean" + }, + "method" : { + "type" : "text","fielddata" : true + }, + "original_text" : { + "type" : "text","fielddata" : true + }, + "source:type" : { + "type" : "keyword" + }, + "timestamp" : { + "type" : "date", + "format": "epoch_millis" + }, + "url" : { + "type" : "text","fielddata" : true + }, + "alert" : { + "type" : "nested" + } + } + } + } +}' +``` + ## Generate Sample Data We can now use `squidclient` to visit a regular domain and typosquatted domain and send the data to kafka: @@ -336,107 +437,8 @@ cat /var/log/squid/access.log | /usr/hdp/current/kafka-broker/bin/kafka-console- ## Investigate via the Alerts UI -We should now have data in our elasticsearch indices, so let's investigate via the alerts UI. Before we do, -we have to adjust the mappings for the indices we just created to add the `alert` nested property. You can -do that via the following: -``` -curl -XPUT "http://$ES_HOST/squid*/_mapping/squid_doc" -d '{ - "properties" : { - "action" : { - "type" : "text","fielddata" : true - }, - "adapter:stellaradapter:begin:ts" : { - "type" : "text","fielddata" : true - }, - "adapter:stellaradapter:end:ts" : { - "type" : "text","fielddata" : true - }, - "bytes" : { - "type" : "long" - }, - "code" : { - "type" : "long" - }, - "domain_without_subdomains" : { - "type" : "text","fielddata" : true - }, - "elapsed" : { - "type" : "long" - }, - "enrichmentjoinbolt:joiner:ts" : { - "type" : "text","fielddata" : true - }, - "enrichmentsplitterbolt:splitter:begin:ts" : { - "type" : "text","fielddata" : true - }, - "enrichmentsplitterbolt:splitter:end:ts" : { - "type" : "text","fielddata" : true - }, - "full_hostname" : { - "type" : "text","fielddata" : true - }, - "guid" : { - "type" : "text","fielddata" : true - }, - "ip_dst_addr" : { - "type" : "text","fielddata" : true - }, - "ip_src_addr" : { - "type" : "text","fielddata" : true - }, - "is_alert" : { - "type" : "text","fielddata" : true - }, - "is_potential_typosquat" : { - "type" : "boolean" - }, - "method" : { - "type" : "text","fielddata" : true - }, - "original_text" : { - "type" : "text","fielddata" : true - }, - "source:type" : { - "type" : "text","fielddata" : true - }, - "threat:triage:rules:0:comment" : { - "type" : "text","fielddata" : true - }, - "threat:triage:rules:0:name" : { - "type" : "text","fielddata" : true - }, - "threat:triage:rules:0:reason" : { - "type" : "text","fielddata" : true - }, - "threat:triage:rules:0:score" : { - "type" : "long" - }, - "threat:triage:score" : { - "type" : "float" - }, - "threatinteljoinbolt:joiner:ts" : { - "type" : "text","fielddata" : true - }, - "threatintelsplitterbolt:splitter:begin:ts" : { - "type" : "text","fielddata" : true - }, - "threatintelsplitterbolt:splitter:end:ts" : { - "type" : "text","fielddata" : true - }, - "timestamp" : { - "type" : "long" - }, - "url" : { - "type" : "text","fielddata" : true - }, - "alert" : { - "type" : "nested" - } - } -}' -``` - -Now we can visit the Alerts UI (find the link from Ambari if not on full-dev. If on full-dev, go +We should now have data in our elasticsearch indices, so let's investigate via the alerts UI. +We can visit the Alerts UI (find the link from Ambari if not on full-dev. If on full-dev, go [here](http://node1:4201/alerts-list). From there you should see the following data from squid with one as an alert and the other not