import unittest
import time
from datetime import datetime
from aminer.analysis.EntropyDetector import EntropyDetector
from aminer.input.LogAtom import LogAtom
from aminer.parsing.MatchElement import MatchElement
from aminer.parsing.ParserMatch import ParserMatch
from unit.TestBase import TestBase
from aminer.AminerConfig import DEFAULT_PERSISTENCE_PERIOD


class EntropyDetectorTest(TestBase):
    """Unittests for the EntropyDetector."""

    def test1receive_atom(self):
        """
        This test case checks the normal detection of new character sets. The charset detector is used to learn an alphabet and detect new
        characters for different identifiers. Test if log atoms are processed correctly and the detector is learning (learn_mode=True) and
        stops if learn_mode=False. Test if stop_learning_time and stop_learning_no_anomaly_timestamp are implemented properly.
        """
        t = time.time()
        expected_string = '%s Value entropy anomaly detected\n%s: "None" (%d lines)\n  %s\n\n'
        dtf = "%Y-%m-%d %H:%M:%S"

        # Prepare log atoms that represent string values. Anomalies are detected when character pair distributions deviate.
        # The following events are generated:
        #  value: aminer
        #  value: logdata-anomaly-miner
        #  value: ait-aecid
        #  value: austrian
        #  value: institute
        #  value: lfmvasacz
        log_atom1 = LogAtom(b"aminer", ParserMatch(MatchElement("/value", b"aminer", b"aminer", None)), t+1, None)
        log_atom2 = LogAtom(b"logdata-anomaly-miner", ParserMatch(MatchElement("/value", b"logdata-anomaly-miner", b"logdata-anomaly-miner", None)), t+2, None)
        log_atom3 = LogAtom(b"ait-aecid", ParserMatch(MatchElement("/value", b"ait-aecid", b"ait-aecid", None)), t+3, None)
        log_atom4 = LogAtom(b"austrian", ParserMatch(MatchElement("/value", b"austrian", b"austrian", None)), t+4, None)
        log_atom5 = LogAtom(b"institute", ParserMatch(MatchElement("/value", b"institute", b"institute", None)), t+5, None)
        log_atom6 = LogAtom(b"lfmvasacz", ParserMatch(MatchElement("/value", b"lfmvasacz", b"lfmvasacz", None)), t+6, None)

        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], prob_thresh=0.05, learn_mode=True, output_logline=False)
        total_freq = {}
        freq = {}
        # Forward log atoms to detector
        # First value should generate an anomaly, because no frequencies are known yet
        # Input: aminer
        # Expected output: Anomaly
        ed.receive_atom(log_atom1)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 1).strftime(dtf), ed.__class__.__name__, 1, "aminer"))
        self.reset_output_stream()
        self.add_data(log_atom1.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # Second value should not generate an anomaly, because it contains substring "miner" which shares charpairs with "aminer"
        # Input: logdata-anomaly-miner
        # Expected output: None
        ed.receive_atom(log_atom2)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom2.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # Third value should not generate an anomaly, since it is a normal string
        # Input: ait-aecid
        # Expected output: None
        ed.receive_atom(log_atom3)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom3.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # Fourth value should not generate an anomaly, since it is a normal string
        # Input: austrian
        # Expected output: None
        ed.receive_atom(log_atom4)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom4.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # Fifth value should not generate an anomaly, since it is a normal string
        # Input: institute
        # Expected output: None
        ed.receive_atom(log_atom5)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom5.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # Sixth value should generate an anomaly, since it is a randomly generated string
        # Input: lfmvasacz
        # Expected output: Anomaly
        ed.receive_atom(log_atom6)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 6).strftime(dtf), ed.__class__.__name__, 1, "lfmvasacz"))
        self.reset_output_stream()
        self.add_data(log_atom6.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # frequencies should change if skip_repetitions = False
        ed.receive_atom(log_atom6)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom6.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # prob_thresh 10%
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], prob_thresh=0.1, learn_mode=True, output_logline=False)
        total_freq = {}
        freq = {}
        ed.receive_atom(log_atom1)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 1).strftime(dtf), ed.__class__.__name__, 1, "aminer"))
        self.reset_output_stream()
        self.add_data(log_atom1.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom2)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom2.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom3)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom3.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom4)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 4).strftime(dtf), ed.__class__.__name__, 1, "austrian"))
        self.reset_output_stream()
        self.add_data(log_atom4.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom5)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom5.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom6)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 6).strftime(dtf), ed.__class__.__name__, 1, "lfmvasacz"))
        self.reset_output_stream()
        self.add_data(log_atom6.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # prob_thresh 50%
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], prob_thresh=0.5, learn_mode=True, output_logline=False)
        total_freq = {}
        freq = {}
        ed.receive_atom(log_atom1)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 1).strftime(dtf), ed.__class__.__name__, 1, "aminer"))
        self.reset_output_stream()
        self.add_data(log_atom1.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom2)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 2).strftime(dtf), ed.__class__.__name__, 1, "logdata-anomaly-miner"))
        self.reset_output_stream()
        self.add_data(log_atom2.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom3)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 3).strftime(dtf), ed.__class__.__name__, 1, "ait-aecid"))
        self.reset_output_stream()
        self.add_data(log_atom3.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom4)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 4).strftime(dtf), ed.__class__.__name__, 1, "austrian"))
        self.reset_output_stream()
        self.add_data(log_atom4.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom5)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 5).strftime(dtf), ed.__class__.__name__, 1, "institute"))
        self.reset_output_stream()
        self.add_data(log_atom5.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom6)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 6).strftime(dtf), ed.__class__.__name__, 1, "lfmvasacz"))
        self.reset_output_stream()
        self.add_data(log_atom6.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # default_freqs = True
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], default_freqs=True, learn_mode=True, output_logline=False)
        default_f = [True, "\n\t~`!@#$%^&*()_+-", [["\f", [["f", 2]]], [" ", [[" ", 312527], ["$", 12], ["(", 1520], [",", 6], ["0", 2], ["4", 210], ["8", 75], ["<", 58], ["D", 5449], ["H", 14898], ["L", 6849], ["P", 10276], ["T", 23773], ["X", 290], ["`", 1958], ["d", 74474], ["h", 195782], ["l", 64742], ["p", 65902], ["t", 408490], ["x", 22], ["|", 38], ["#", 6], ["'", 3062], ["+", 2], ["/", 12], ["3", 300], ["7", 134], [";", 8], ["?", 8], ["C", 9334], ["G", 5688], ["K", 2484], ["O", 4266], ["S", 13139], ["W", 9355], ["[", 408], ["_", 220], ["c", 90632], ["g", 44086], ["k", 13940], ["o", 161371], ["s", 182472], ["w", 187994], ["{", 8], ["\"", 22346], ["&", 42], ["*", 112], [".", 2358], ["2", 691], ["6", 180], [":", 14], [">", 2], ["B", 12213], ["F", 8428], ["J", 5957], ["N", 7370], ["R", 5046], ["V", 3389], ["Z", 250], ["b", 109654], ["f", 95818], ["j", 6186], ["n", 56010], ["r", 54486], ["v", 15242], ["z", 238], ["~", 2], ["%", 2], [")", 2], ["-", 550], ["1", 1613], ["5", 132], ["9", 74], ["A", 16635], ["E", 4590], ["I", 45393], ["M", 17353], ["Q", 356], ["U", 753], ["Y", 2574], ["a", 293192], ["e", 47200], ["i", 125201], ["m", 99016], ["q", 5914], ["u", 27850], ["y", 29288]]], ["$", [[" ", 2], ["3", 2], ["2", 6], ["4", 10]]], ["(", [[" ", 2], ["\"", 34], ["$", 12], ["'", 24], ["*", 8], ["1", 28], ["3", 24], ["2", 30], ["5", 2], ["A", 54], ["C", 12], ["B", 32], ["E", 12], ["D", 16], ["G", 6], ["F", 40], ["I", 120], ["H", 48], ["K", 10], ["J", 2], ["M", 48], ["L", 14], ["O", 20], ["N", 26], ["P", 26], ["S", 46], ["U", 8], ["T", 124], ["W", 38], ["V", 2], ["Y", 4], ["_", 14], ["a", 306], ["`", 2], ["c", 22], ["b", 50], ["e", 24], ["d", 18], ["g", 10], ["f", 80], ["i", 122], ["h", 102], ["k", 2], ["j", 2], ["m", 20], ["l", 20], ["o", 86], ["n", 38], ["p", 16], ["s", 106], ["r", 6], ["u", 6], ["t", 240], ["w", 212], ["v", 2], ["y", 6], ["~", 8]]], [",", [["!", 2], [" ", 200706], ["\"", 10148], ["'", 1656], [")", 4], ["*", 18], ["-", 780], [",", 10], ["1", 40], ["0", 263], ["3", 6], ["2", 42], ["5", 44], ["4", 28], ["7", 4], ["6", 20], ["9", 12], ["8", 18], [":", 4], ["A", 4], ["I", 42], ["J", 2], ["M", 2], ["T", 2], ["[", 2], ["a", 328], ["c", 8], ["b", 76], ["e", 6], ["d", 4], ["g", 10], ["f", 60], ["i", 36], ["h", 36], ["k", 6], ["m", 10], ["l", 6], ["o", 22], ["n", 8], ["q", 2], ["p", 2], ["s", 64], ["r", 8], ["t", 84], ["w", 70]]], ["0", [[" ", 512], ["%", 16], ["'", 14], [")", 20], ["-", 20], [",", 155], [".", 70], ["1", 38], ["0", 714], ["3", 17], ["2", 32], ["5", 34], ["4", 13], ["7", 30], ["6", 21], ["9", 34], ["8", 20], [";", 8], [":", 22], ["@", 20], ["I", 6], ["]", 46], ["m", 2], ["s", 6], ["t", 74], ["x", 10], ["}", 18]]], ["4", [[" ", 70], ["'", 4], [")", 2], ["-", 12], [",", 70], [".", 46], ["1", 24], ["0", 82], ["3", 24], ["2", 24], ["5", 34], ["4", 16], ["7", 28], ["6", 16], ["9", 24], ["8", 34], [";", 6], [":", 44], ["@", 8], ["T", 2], ["]", 60], ["t", 64], ["}", 18], ["|", 32]]], ["8", [[" ", 64], ["'", 6], ["-", 12], [",", 68], [".", 28], ["1", 192], ["0", 155], ["3", 132], ["2", 89], ["5", 26], ["4", 56], ["7", 26], ["6", 74], ["9", 37], ["8", 12], [";", 12], [":", 14], ["?", 2], ["@", 10], ["]", 54], ["m", 2], ["t", 56], ["}", 18], ["|", 44]]], ["<", [["A", 64], ["C", 132], ["B", 10], ["E", 18], ["D", 14], ["G", 4], ["F", 20], ["I", 14], ["H", 94], ["K", 2], ["M", 14], ["L", 8], ["O", 14], ["N", 2], ["P", 14], ["S", 14], ["R", 10], ["T", 224], ["W", 24], ["Y", 2], ["m", 2], ["s", 2]]], ["@", [[" ", 102], ["c", 8], ["e", 14], [",", 8], [".", 8], ["u", 6], ["v", 16]]], ["D", [["!", 4], [" ", 358], ["'", 72], ["*", 16], ["-", 64], [",", 14], [".", 66], [";", 2], ["?", 2], ["A", 93], ["C", 2], ["E", 240], ["D", 2], ["G", 10], ["F", 8], ["I", 220], ["M", 2], ["L", 2], ["O", 89], ["N", 14], ["P", 2], ["S", 28], ["R", 70], ["U", 24], ["V", 2], ["Y", 12], ["a", 1027], ["e", 2124], ["i", 779], ["j", 6], ["m", 148], ["o", 2366], ["n", 8], ["r", 642], ["u", 914], ["w", 4], ["y", 20]]], ["H", [[" ", 112], ["'", 14], [",", 8], [".", 210], ["1", 126], ["3", 42], ["2", 54], ["5", 12], ["4", 12], ["7", 12], ["6", 12], ["9", 12], ["8", 12], ["?", 2], ["A", 410], ["E", 722], ["F", 4], ["I", 298], ["M", 4], ["O", 260], ["N", 2], ["Q", 4], ["S", 6], ["R", 20], ["U", 26], ["T", 60], ["Y", 20], ["a", 2890], ["e", 16114], ["i", 2886], ["h", 2], ["m", 2], ["o", 2880], ["s", 4], ["u", 596], ["v", 2], ["y", 24]]], ["L", [["!", 2], [" ", 102], ["'", 40], [")", 2], ["-", 4], [",", 10], [".", 40], ["1", 6], ["2", 8], ["5", 2], ["4", 2], ["6", 2], ["8", 2], [":", 8], ["A", 120], ["C", 14], ["E", 261], ["D", 38], ["G", 14], ["F", 26], ["I", 210], ["H", 4], ["K", 46], ["J", 2], ["M", 6], ["L", 134], ["O", 98], ["N", 2], ["P", 4], ["S", 36], ["R", 6], ["U", 84], ["T", 12], ["W", 2], ["Y", 32], ["a", 2534], ["e", 1957], ["i", 1482], ["h", 70], ["l", 2], ["o", 2216], ["u", 614], ["w", 2], ["y", 30]]], ["P", [["!", 2], [" ", 30], ["-", 4], [".", 72], ["A", 198], ["E", 228], ["G", 8], ["I", 66], ["H", 24], ["K", 2], ["M", 8], ["L", 90], ["O", 110], ["P", 26], ["S", 18], ["R", 198], ["U", 54], ["T", 202], ["Y", 10], ["a", 2387], ["e", 1866], ["f", 50], ["i", 2690], ["h", 472], ["l", 486], ["o", 1094], ["s", 84], ["r", 4898], ["u", 314], ["t", 12], ["w", 2], ["y", 38]]], ["T", [["!", 20], [" ", 496], ["'", 18], ["*", 34], ["-", 20], [",", 66], [".", 132], [":", 6], ["A", 150], ["C", 14], ["B", 2], ["E", 2568], ["F", 2], ["I", 236], ["H", 1216], ["M", 20], ["L", 24], ["O", 330], ["N", 14], ["P", 14], ["S", 62], ["R", 71], ["U", 70], ["T", 106], ["W", 110], ["Y", 144], ["Z", 2], ["a", 643], ["e", 802], ["i", 1134], ["h", 41758], ["o", 3328], ["s", 100], ["r", 532], ["u", 500], ["w", 517], ["v", 8], ["y", 54], ["z", 4]]], ["X", [["A", 2], [" ", 22], ["C", 6], ["E", 2], ["'", 2], ["I", 444], ["-", 2], [",", 4], [".", 84], ["1", 2], ["P", 6], ["2", 2], ["u", 30], ["T", 78], ["V", 302], ["X", 266], [":", 6], ["e", 4]]], ["`", [[" ", 4], ["\"", 2], ["'", 2], ["2", 2], ["A", 122], ["C", 26], ["B", 74], ["E", 14], ["D", 38], ["G", 30], ["F", 28], ["I", 270], ["H", 66], ["K", 4], ["J", 30], ["M", 66], ["L", 44], ["O", 26], ["N", 52], ["P", 34], ["S", 80], ["R", 14], ["U", 6], ["T", 166], ["W", 92], ["V", 4], ["Y", 66], ["_", 2], ["a", 62], ["c", 32], ["b", 40], ["e", 40], ["d", 24], ["g", 28], ["f", 38], ["i", 24], ["h", 26], ["k", 6], ["j", 2], ["m", 40], ["l", 28], ["o", 24], ["n", 14], ["q", 2], ["p", 40], ["s", 34], ["r", 18], ["u", 10], ["t", 98], ["w", 22], ["v", 2], ["y", 8]]], ["d", [["!", 1346], [" ", 316392], ["\"", 78], ["'", 892], [")", 158], ["-", 2110], [",", 27454], [".", 15448], ["1", 6], [";", 2238], [":", 1318], ["?", 904], [">", 32], ["]", 6], ["_", 10], ["a", 15612], ["`", 12], ["c", 64], ["b", 98], ["e", 66856], ["d", 5952], ["g", 2672], ["f", 682], ["i", 36856], ["h", 178], ["k", 152], ["j", 316], ["m", 1162], ["l", 4894], ["o", 27386], ["n", 2680], ["q", 32], ["p", 44], ["s", 12352], ["r", 13004], ["u", 5376], ["t", 176], ["w", 382], ["v", 1300], ["y", 5438], ["z", 4], ["}", 6]]], ["h", [["!", 1480], [" ", 66490], ["\"", 16], ["'", 580], [")", 46], ["-", 674], [",", 7634], [".", 3060], [";", 500], [":", 124], ["?", 354], [">", 8], ["_", 8], ["a", 130321], ["`", 2], ["c", 78], ["b", 454], ["e", 366316], ["d", 180], ["g", 2], ["f", 464], ["i", 118000], ["h", 16], ["k", 98], ["m", 1012], ["l", 810], ["o", 56794], ["n", 878], ["q", 34], ["p", 20], ["s", 1392], ["r", 8693], ["u", 9628], ["t", 23686], ["w", 410], ["v", 4], ["y", 4342], ["z", 2]]], ["l", [["!", 688], [" ", 55493], ["\"", 28], ["'", 776], [")", 58], ["*", 8], ["-", 1168], [",", 9058], ["/", 2], [".", 4175], ["1", 2], ["2", 4], [";", 588], [":", 138], ["?", 512], [">", 18], ["@", 2], ["]", 2], ["_", 14], ["a", 40424], ["c", 880], ["b", 428], ["e", 90647], ["d", 35897], ["g", 498], ["f", 11866], ["i", 53960], ["h", 30], ["k", 3952], ["j", 880], ["m", 2350], ["l", 72010], ["o", 43088], ["n", 488], ["q", 6], ["p", 1936], ["s", 9240], ["r", 1482], ["u", 8878], ["t", 7890], ["w", 1710], ["v", 3288], ["y", 43772], ["x", 2], ["z", 52]]], ["p", [["!", 222], [" ", 12684], ["\"", 12], ["'", 274], [")", 8], ["*", 16], ["-", 458], [",", 2678], [".", 1598], [";", 206], [":", 32], ["?", 102], [">", 2], ["_", 2], ["a", 24384], ["c", 110], ["b", 74], ["e", 40018], ["d", 12], ["g", 26], ["f", 100], ["i", 12578], ["h", 3890], ["k", 248], ["m", 220], ["l", 19938], ["o", 24960], ["n", 82], ["p", 12676], ["s", 4980], ["r", 27372], ["u", 7468], ["t", 8624], ["w", 150], ["y", 1538], ["z", 4]]], ["t", [["!", 1698], [" ", 244288], ["\"", 74], ["'", 4144], [")", 206], ["*", 10], ["-", 2634], [",", 24442], ["/", 22], [".", 15012], ["9", 30], [";", 1952], [":", 386], ["?", 2014], [">", 34], ["@", 16], ["I", 4], ["N", 2], ["]", 6], ["_", 20], ["a", 36864], ["c", 4804], ["b", 164], ["e", 93708], ["d", 32], ["g", 50], ["f", 1186], ["i", 67393], ["h", 380618], ["k", 30], ["j", 2], ["m", 1109], ["l", 15192], ["o", 120320], ["n", 980], ["p", 168], ["s", 20376], ["r", 31046], ["u", 18070], ["t", 25046], ["w", 8348], ["v", 6], ["y", 14950], ["x", 22], ["z", 596]]], ["x", [["!", 16], [" ", 1654], ["'", 108], [")", 6], ["-", 174], [",", 480], ["/", 2], [".", 262], ["1", 10], [";", 40], [":", 6], ["?", 20], ["_", 4], ["a", 1314], ["c", 2462], ["b", 4], ["e", 1456], ["g", 2], ["f", 26], ["i", 1676], ["h", 354], ["l", 20], ["o", 82], ["q", 56], ["p", 3828], ["s", 6], ["u", 144], ["t", 3514], ["w", 4], ["y", 88], ["x", 30]]], ["|", [[" ", 30], ["C", 294]]], ["#", [["1", 6], [" ", 2]]], ["'", [["!", 22], [" ", 5218], ["\"", 130], ["'", 52], [")", 8], ["-", 136], [",", 274], [".", 194], ["9", 24], ["8", 10], [";", 12], [":", 4], ["?", 40], ["A", 506], ["C", 94], ["B", 292], ["E", 88], ["D", 124], ["G", 154], ["F", 90], ["I", 826], ["H", 360], ["K", 12], ["J", 52], ["M", 174], ["L", 102], ["O", 202], ["N", 222], ["Q", 12], ["P", 86], ["S", 328], ["R", 24], ["U", 38], ["T", 922], ["W", 482], ["V", 22], ["Y", 356], ["a", 288], ["c", 614], ["b", 42], ["e", 614], ["d", 2832], ["g", 48], ["f", 28], ["i", 98], ["h", 36], ["k", 6], ["m", 1148], ["l", 1792], ["o", 90], ["n", 44], ["q", 2], ["p", 40], ["s", 16835], ["r", 660], ["u", 62], ["t", 7172], ["w", 60], ["v", 880], ["y", 66], ["}", 2]]], ["+", [[";", 2], ["B", 2], ["-", 4]]], ["/", [[" ", 26], ["\"", 2], ["e", 20], ["I", 14], ["h", 6], ["1", 2], ["s", 2], ["2", 4], ["5", 4], ["4", 2], ["6", 2]]], ["3", [["!", 2], [" ", 76], [")", 18], ["*", 8], ["-", 6], [",", 98], ["/", 2], [".", 66], ["1", 54], ["0", 158], ["3", 44], ["2", 60], ["5", 42], ["4", 18], ["7", 38], ["6", 24], ["9", 26], ["8", 20], [";", 10], [":", 48], ["?", 2], ["@", 4], ["]", 60], ["d", 6], ["i", 4], ["h", 2], ["r", 50], ["t", 26], ["v", 2], ["}", 18], ["|", 38]]], ["7", [["!", 2], [" ", 64], ["'", 10], ["-", 8], [",", 68], ["/", 4], [".", 46], ["1", 21], ["0", 36], ["3", 12], ["2", 35], ["5", 16], ["4", 14], ["7", 32], ["6", 26], ["9", 40], ["8", 34], [";", 10], [":", 28], ["@", 18], ["]", 48], ["h", 2], ["m", 4], ["t", 34], ["}", 18], ["|", 26]]], [";", [[" ", 14368], ["\"", 42], ["'", 54], ["h", 2], ["*", 2], ["-", 146], [",", 2], ["[", 4]]], ["?", [[" ", 5000], ["\"", 7386], ["'", 680], [")", 14], ["-", 90], [",", 2], [".", 118], ["[", 2], ["?", 2], [">", 2]]], ["C", [[" ", 50], ["\"", 14], ["'", 12], ["*", 2], ["-", 4], [",", 6], ["/", 2], [".", 24], ["A", 126], ["C", 22], ["E", 112], ["D", 20], ["I", 76], ["H", 3260], ["K", 60], ["L", 26], ["O", 164], ["P", 6], ["S", 8], ["R", 38], ["U", 26], ["T", 117], ["Y", 16], ["a", 2763], ["e", 294], ["i", 277], ["h", 2428], ["l", 446], ["o", 4926], ["s", 4], ["r", 556], ["u", 212], ["y", 42], ["z", 24]]], ["G", [["!", 2], [" ", 132], ["\"", 8], ["'", 8], ["-", 56], [",", 22], [".", 10], [";", 2], [":", 2], ["?", 4], ["A", 72], ["E", 134], ["G", 10], ["F", 2], ["I", 34], ["H", 70], ["L", 16], ["O", 60], ["N", 14], ["S", 10], ["R", 64], ["U", 92], ["T", 2], ["Y", 2], ["Z", 2], ["a", 744], ["e", 958], ["d", 2], ["i", 460], ["h", 266], ["l", 212], ["o", 2628], ["n", 6], ["r", 1160], ["u", 880], ["w", 2], ["y", 2]]], ["K", [[" ", 28], ["'", 2], [",", 6], [".", 8], ["?", 2], ["A", 4], ["E", 64], ["F", 2], ["I", 44], ["H", 2], ["K", 4], ["L", 12], ["O", 2], ["N", 4], ["S", 12], ["R", 6], ["U", 2], ["W", 4], ["Y", 2], ["a", 442], ["e", 504], ["i", 860], ["h", 122], ["l", 40], ["o", 290], ["n", 96], ["r", 96], ["u", 782], ["y", 10]]], ["O", [["!", 6], [" ", 466], ["\"", 2], ["'", 106], ["-", 4], [",", 12], [".", 38], [":", 2], ["?", 2], ["A", 6], ["C", 47], ["B", 32], ["E", 13], ["D", 52], ["G", 52], ["F", 288], ["I", 18], ["H", 28], ["K", 222], ["J", 50], ["M", 160], ["L", 98], ["O", 78], ["N", 489], ["P", 30], ["S", 64], ["R", 346], ["U", 338], ["T", 104], ["W", 64], ["V", 39], ["Y", 8], ["Z", 2], ["a", 2], ["c", 234], ["b", 128], ["e", 2], ["d", 26], ["g", 14], ["f", 1458], ["i", 6], ["h", 1000], ["k", 2], ["m", 60], ["l", 240], ["o", 44], ["n", 3744], ["p", 86], ["s", 22], ["r", 798], ["u", 554], ["t", 162], ["w", 32], ["v", 74], ["y", 2], ["x", 6], ["z", 68]]], ["S", [["!", 8], [" ", 616], ["'", 12], ["*", 6], ["-", 20], [",", 40], [".", 122], [";", 2], [":", 12], ["?", 2], ["A", 56], ["C", 58], ["E", 296], ["D", 2], ["G", 4], ["F", 4], ["I", 91], ["H", 76], ["K", 8], ["M", 14], ["L", 10], ["O", 98], ["N", 2], ["Q", 4], ["P", 30], ["S", 104], ["R", 2], ["U", 42], ["T", 322], ["W", 4], ["Y", 2], ["a", 2150], ["c", 1208], ["e", 1405], ["i", 968], ["h", 5152], ["k", 34], ["m", 374], ["l", 166], ["o", 4132], ["n", 120], ["q", 44], ["p", 776], ["s", 2], ["u", 1246], ["t", 1564], ["w", 144], ["v", 8], ["y", 126], ["z", 18]]], ["W", [["!", 2], [" ", 58], [")", 2], [",", 10], [".", 28], ["A", 136], ["E", 96], ["D", 4], ["G", 2], ["I", 90], ["H", 128], ["L", 4], ["O", 76], ["N", 12], ["S", 2], ["R", 8], ["Y", 4], ["a", 1096], ["e", 4362], ["i", 2096], ["h", 10098], ["o", 1611], ["r", 58], ["u", 18]]], ["[", [["*", 2], ["1", 112], ["3", 56], ["2", 112], ["5", 30], ["4", 40], ["7", 4], ["6", 34], ["9", 4], ["8", 2], ["A", 12], ["C", 2], ["B", 6], ["E", 24], ["D", 4], ["G", 14], ["F", 2], ["I", 22], ["H", 30], ["J", 34], ["M", 28], ["L", 16], ["N", 4], ["P", 42], ["S", 6], ["R", 36], ["T", 18], ["W", 4], ["a", 2], ["b", 4], ["d", 2], ["g", 2], ["f", 14], ["m", 2], ["l", 4], ["o", 4], ["p", 6], ["s", 4], ["t", 50]]], ["_", [[" ", 100], ["'", 2], ["-", 12], [",", 38], [".", 28], [";", 4], ["A", 14], ["D", 2], ["I", 30], ["H", 4], ["M", 4], ["L", 2], ["O", 2], ["N", 2], ["T", 12], ["_", 736], ["^", 6], ["a", 14], ["c", 12], ["b", 4], ["e", 6], ["d", 6], ["f", 14], ["i", 4], ["h", 2], ["m", 8], ["l", 6], ["o", 2], ["n", 14], ["p", 4], ["s", 10], ["r", 2], ["u", 4], ["t", 10], ["w", 8], ["v", 4], ["y", 4], ["x", 4]]], ["c", [["!", 38], [" ", 2940], ["\"", 6], ["'", 62], ["-", 122], [",", 498], [".", 480], [";", 56], [":", 18], ["?", 22], ["C", 8], ["G", 8], ["F", 2], ["L", 230], ["Q", 2], ["P", 2], ["S", 2], ["a", 38996], ["c", 5012], ["e", 54872], ["d", 38], ["i", 13186], ["h", 55038], ["k", 20111], ["m", 4], ["l", 12408], ["o", 57624], ["n", 26], ["q", 496], ["p", 66], ["s", 944], ["r", 13732], ["u", 9748], ["t", 19868], ["w", 8], ["v", 6], ["y", 1692], ["z", 12]]], ["g", [["!", 572], [" ", 77496], ["\"", 32], ["'", 490], [")", 44], ["-", 1388], [",", 8820], [".", 5284], [";", 654], [":", 276], ["?", 530], [">", 4], ["a", 16556], ["c", 8], ["b", 10], ["e", 31120], ["d", 134], ["g", 3662], ["f", 14], ["i", 11514], ["h", 36708], ["m", 368], ["l", 8714], ["o", 16464], ["n", 4300], ["p", 22], ["s", 6714], ["r", 16774], ["u", 6849], ["t", 1104], ["w", 42], ["y", 516], ["z", 14], ["}", 8]]], ["k", [["!", 306], [" ", 20132], ["\"", 14], ["'", 392], [")", 32], ["-", 554], [",", 4148], [".", 2414], ["1", 2], [";", 294], [":", 60], ["?", 214], [">", 10], ["@", 10], ["a", 870], ["c", 66], ["b", 38], ["e", 34087], ["d", 24], ["g", 58], ["f", 344], ["i", 13220], ["h", 948], ["k", 244], ["j", 22], ["m", 100], ["l", 2880], ["o", 816], ["n", 11134], ["q", 2], ["p", 12], ["s", 4228], ["r", 68], ["u", 68], ["t", 20], ["w", 314], ["v", 10], ["y", 768], ["z", 2]]], ["o", [["!", 648], [" ", 114177], ["\"", 18], ["'", 1162], [")", 38], ["-", 958], [",", 5210], [".", 2232], [";", 354], [":", 58], ["?", 516], ["K", 2], ["J", 2], ["]", 4], ["_", 6], ["a", 7834], ["`", 2], ["c", 9710], ["b", 5854], ["e", 2996], ["d", 16602], ["g", 5294], ["f", 99287], ["i", 10524], ["h", 872], ["k", 14852], ["j", 986], ["m", 51326], ["l", 30027], ["o", 36626], ["n", 131194], ["q", 172], ["p", 16136], ["s", 26802], ["r", 99219], ["u", 128095], ["t", 47116], ["w", 48246], ["v", 20522], ["y", 3366], ["x", 840], ["z", 456], ["}", 2]]], ["s", [["!", 2144], [" ", 245069], ["\"", 154], ["'", 1554], [")", 266], ["*", 14], ["-", 1948], [",", 37726], [".", 19990], ["1", 4], [";", 3000], [":", 928], ["=", 2], ["?", 1424], [">", 50], ["[", 6], ["]", 38], ["_", 24], ["a", 37342], ["c", 11410], ["b", 1092], ["e", 89922], ["d", 372], ["g", 288], ["f", 1206], ["i", 41018], ["h", 48184], ["k", 7002], ["j", 20], ["m", 5638], ["l", 7892], ["o", 41490], ["n", 2836], ["q", 1070], ["p", 17022], ["s", 38918], ["r", 118], ["u", 22362], ["t", 98283], ["w", 5082], ["v", 104], ["y", 2112], ["z", 8]]], ["w", [["!", 302], [" ", 25552], ["\"", 32], ["'", 332], [")", 38], ["-", 630], [",", 4620], ["/", 2], [".", 2130], [";", 296], [":", 56], ["?", 312], [">", 6], ["_", 4], ["a", 69912], ["c", 62], ["b", 88], ["e", 43746], ["d", 980], ["g", 230], ["f", 300], ["i", 50742], ["h", 55558], ["k", 232], ["j", 2], ["m", 12], ["l", 1768], ["o", 28157], ["n", 11280], ["p", 14], ["s", 3452], ["r", 3078], ["u", 116], ["t", 106], ["w", 8], ["y", 240], ["z", 2]]], ["{", [["`", 2], ["c", 2], ["E", 2], ["G", 2], ["s", 6], ["o", 4], ["1", 224], ["3", 226], ["2", 230], ["5", 24], ["4", 34], ["7", 22], ["6", 22], ["9", 22], ["8", 24], ["t", 8]]], ["\"", [[" ", 19496], ["\"", 12], ["'", 120], [")", 34], ["*", 70], ["-", 198], [",", 42], [".", 98], ["1", 4], ["3", 2], ["2", 4], ["5", 4], ["4", 4], ["6", 2], ["8", 6], [";", 74], [":", 2], ["?", 4], ["A", 4542], ["C", 1250], ["B", 2388], ["E", 472], ["D", 1474], ["G", 1096], ["F", 924], ["I", 8984], ["H", 2746], ["K", 138], ["J", 270], ["M", 1850], ["L", 912], ["O", 1848], ["N", 2630], ["Q", 110], ["P", 880], ["S", 1906], ["R", 350], ["U", 236], ["T", 5524], ["W", 6722], ["V", 340], ["Y", 4228], ["X", 4], ["[", 14], ["Z", 6], ["]", 8], ["_", 20], ["a", 732], ["`", 158], ["c", 118], ["b", 452], ["e", 46], ["d", 138], ["g", 54], ["f", 182], ["i", 408], ["h", 256], ["k", 10], ["j", 14], ["m", 148], ["l", 118], ["o", 112], ["n", 94], ["q", 4], ["p", 130], ["s", 230], ["r", 36], ["u", 32], ["t", 1014], ["w", 398], ["v", 22], ["y", 272]]], ["&", [["h", 2], ["c", 8], [" ", 26]]], ["*", [[" ", 206], ["\"", 146], [")", 6], ["*", 636], [",", 12], [".", 4], [":", 8], [">", 2], ["A", 16], ["C", 4], ["B", 16], ["E", 20], ["D", 8], ["G", 2], ["F", 12], ["I", 6], ["H", 4], ["K", 4], ["L", 4], ["O", 6], ["N", 2], ["P", 2], ["S", 16], ["T", 92], ["W", 18], ["V", 14], ["Y", 2], ["[", 36], ["]", 54], ["n", 6]]], [".", [["!", 36], [" ", 88376], ["\"", 12990], ["'", 1624], [")", 132], ["(", 2], ["*", 27], ["-", 436], [",", 236], [".", 4176], ["0", 16], ["2", 8], ["4", 6], ["7", 2], ["6", 2], ["9", 14], [";", 20], [":", 166], ["?", 38], ["A", 46], ["C", 12], ["B", 12], ["E", 20], ["D", 4], ["G", 22], ["F", 12], ["I", 138], ["H", 38], ["K", 2], ["J", 2], ["M", 34], ["L", 10], ["O", 10], ["N", 20], ["Q", 2], ["P", 8], ["S", 38], ["R", 2], ["U", 4], ["T", 108], ["W", 42], ["V", 6], ["Y", 20], ["[", 26], ["]", 10], ["_", 8], ["a", 4], ["`", 6], ["c", 32], ["b", 2], ["e", 36], ["i", 16], ["m", 26], ["o", 2], ["s", 4], ["u", 24], ["t", 40], ["x", 10], ["z", 2]]], ["2", [[" ", 128], ["\"", 2], ["'", 6], [")", 12], ["*", 6], ["-", 20], [",", 132], ["/", 2], [".", 82], ["1", 127], ["0", 229], ["3", 90], ["2", 98], ["5", 112], ["4", 96], ["7", 78], ["6", 88], ["9", 51], ["8", 80], [";", 4], [":", 56], ["@", 14], ["]", 70], ["d", 6], ["n", 28], ["t", 20], ["}", 20], ["|", 66]]], ["6", [[" ", 60], ["-", 12], [",", 70], ["/", 2], [".", 30], ["1", 24], ["0", 76], ["3", 14], ["2", 34], ["5", 26], ["4", 19], ["7", 26], ["6", 32], ["9", 21], ["8", 22], [";", 10], [":", 32], ["?", 2], ["@", 10], ["]", 44], ["m", 4], ["t", 68], ["}", 18], ["|", 52]]], [":", [[" ", 3056], ["\"", 2], ["'", 20], [")", 2], ["(", 8], ["*", 2], ["-", 1142], [".", 260], ["1", 118], ["I", 4], ["3", 44], ["2", 90], ["5", 14], ["4", 30], ["7", 14], ["6", 16], ["9", 12], ["8", 12], ["R", 4], ["r", 4]]], [">", [[" ", 88], ["#", 2], ["\"", 4], ["$", 2], ["-", 2], [",", 2], [":", 2], ["<", 24], ["A", 2], ["@", 2], ["C", 2], ["F", 8], ["I", 10], ["M", 2], ["L", 2], ["T", 14], ["W", 4], ["_", 2], ["^", 2], ["a", 6], ["c", 8], ["f", 10], ["i", 12], ["h", 6], ["m", 8], ["o", 8], ["p", 2], ["s", 8], ["t", 8], ["w", 6], ["v", 2], ["{", 2]]], ["B", [[" ", 16], ["'", 2], [",", 4], [".", 12], ["A", 44], ["C", 38], ["B", 6], ["E", 200], ["I", 62], ["K", 702], ["M", 6], ["L", 69], ["O", 247], ["S", 8], ["R", 26], ["U", 52], ["Y", 62], ["a", 2602], ["e", 3594], ["i", 1068], ["h", 100], ["j", 2], ["l", 520], ["o", 2392], ["r", 974], ["u", 8016], ["w", 2], ["y", 828]]], ["F", [["A", 194], [" ", 300], ["E", 36], ["F", 18], ["I", 98], ["j", 2], ["l", 372], ["O", 166], [",", 2], [">", 2], ["i", 958], ["r", 5046], ["U", 14], ["o", 3334], ["a", 2482], ["e", 430], ["R", 78], [".", 10], ["u", 184], ["L", 20], ["T", 30]]], ["J", [["A", 18], ["a", 1388], ["E", 82], ["d", 2], ["'", 2], ["I", 2], ["-", 2], ["o", 2830], [".", 132], ["i", 314], ["s", 2], ["U", 30], ["O", 54], ["e", 1904], ["u", 1679]]], ["N", [["!", 6], [" ", 451], ["\"", 8], ["'", 28], ["-", 4], [",", 48], [".", 96], [";", 2], [":", 8], ["?", 2], ["A", 108], ["C", 124], ["B", 48], ["E", 247], ["D", 328], ["G", 216], ["F", 2], ["I", 92], ["H", 2], ["K", 22], ["J", 2], ["L", 4], ["O", 186], ["N", 40], ["S", 124], ["R", 13], ["U", 20], ["T", 298], ["V", 13], ["Y", 14], ["a", 3392], ["e", 2202], ["i", 1384], ["o", 4850], ["u", 72]]], ["R", [["!", 2], [" ", 2352], ["\"", 4], ["'", 20], ["*", 6], ["-", 4], [",", 78], [".", 718], [":", 2], ["?", 2], ["A", 178], ["C", 20], ["B", 12], ["E", 320], ["D", 100], ["G", 68], ["F", 4], ["I", 219], ["K", 70], ["M", 30], ["L", 42], ["O", 189], ["N", 84], ["Q", 2], ["P", 18], ["S", 90], ["R", 70], ["U", 34], ["T", 272], ["W", 16], ["V", 14], ["Y", 93], ["a", 374], ["e", 1237], ["i", 323], ["h", 52], ["o", 2304], ["u", 2014], ["t", 2], ["y", 20]]], ["V", [["A", 47], ["a", 1798], ["B", 2], ["E", 276], ["'", 2], [" ", 18], ["I", 587], ["-", 2], [",", 12], ["O", 26], ["l", 30], ["i", 510], ["r", 4], ["U", 2], ["o", 228], ["y", 26], ["e", 465], ["R", 22], [".", 162], ["u", 4], ["Y", 6]]], ["Z", [["a", 32], ["\"", 2], ["E", 16], ["d", 4], ["I", 2], ["h", 68], [",", 4], ["o", 22], ["n", 30], ["i", 26], ["u", 10], ["O", 4], ["e", 124]]], ["b", [["!", 40], [" ", 1058], ["'", 68], [")", 4], ["*", 4], ["-", 98], [",", 414], [".", 244], [";", 24], [":", 6], ["?", 36], [">", 4], ["a", 13924], ["c", 22], ["b", 1618], ["e", 60104], ["d", 78], ["g", 4], ["f", 16], ["i", 6998], ["h", 46], ["j", 990], ["m", 324], ["l", 22082], ["o", 19980], ["n", 44], ["s", 2992], ["r", 13256], ["u", 20366], ["t", 1570], ["w", 30], ["v", 88], ["y", 13906]]], ["f", [["!", 178], [" ", 90391], ["\"", 8], ["'", 72], [")", 16], ["*", 2], ["-", 876], [",", 2770], [".", 1846], [";", 240], [":", 102], ["?", 144], ["G", 2], ["I", 2], ["a", 20108], ["c", 14], ["b", 38], ["e", 23990], ["d", 2], ["g", 10], ["f", 10886], ["i", 22788], ["h", 6], ["k", 12], ["j", 16], ["m", 12], ["l", 7808], ["o", 46468], ["n", 16], ["p", 2], ["s", 464], ["r", 21052], ["u", 10540], ["t", 10202], ["w", 62], ["v", 2], ["y", 396], ["x", 2]]], ["j", [["a", 724], ["!", 2], ["e", 4002], ["'", 2], ["i", 118], ["o", 3558], [".", 4], ["u", 4654]]], ["n", [["!", 1140], [" ", 164227], ["\"", 84], ["'", 9982], [")", 108], ["*", 6], ["-", 2184], [",", 19804], [".", 11592], [";", 1670], [":", 478], ["?", 1178], [">", 50], ["J", 4], ["]", 18], ["_", 4], ["a", 17316], ["c", 30762], ["b", 372], ["e", 74881], ["d", 155134], ["g", 116276], ["f", 3720], ["i", 23814], ["h", 996], ["k", 7828], ["j", 896], ["m", 518], ["l", 7014], ["o", 57750], ["n", 7832], ["q", 950], ["p", 298], ["s", 29725], ["r", 506], ["u", 4864], ["t", 72732], ["w", 558], ["v", 3580], ["y", 9090], ["x", 498], ["z", 154], ["}", 4]]], ["r", [["!", 1102], [" ", 128583], ["\"", 78], ["'", 2438], [")", 108], ["*", 14], ["-", 2050], [",", 18518], [".", 12898], [";", 1346], [":", 332], ["?", 1112], [">", 28], ["A", 2], ["@", 14], ["_", 6], ["a", 45838], ["c", 7992], ["b", 2520], ["e", 175663], ["d", 22490], ["g", 6450], ["f", 3064], ["i", 57977], ["h", 1474], ["k", 6764], ["j", 14], ["m", 12284], ["l", 8396], ["o", 61720], ["n", 15999], ["q", 220], ["p", 3358], ["s", 36440], ["r", 17042], ["u", 12282], ["t", 29678], ["w", 1522], ["v", 4906], ["y", 24200], ["x", 6], ["z", 128]]], ["v", [["!", 34], [" ", 1478], ["'", 360], [")", 2], ["-", 58], [",", 566], [".", 316], [";", 12], [":", 4], ["?", 30], ["_", 2], ["a", 8210], ["e", 85189], ["g", 2], ["i", 17242], ["k", 2], ["m", 16], ["l", 218], ["o", 6350], ["n", 508], ["s", 216], ["r", 658], ["u", 248], ["t", 4], ["v", 22], ["y", 640]]], ["z", [["!", 8], [" ", 344], ["\"", 2], ["'", 14], [")", 4], ["-", 40], [",", 172], [".", 178], [";", 8], [":", 2], ["?", 22], ["a", 592], ["b", 6], ["e", 3788], ["d", 18], ["g", 8], ["i", 920], ["h", 122], ["k", 6], ["m", 104], ["l", 356], ["o", 1122], ["n", 2], ["s", 6], ["r", 2], ["u", 156], ["v", 14], ["y", 202], ["z", 622]]], ["~", [[")", 6]]], ["\t", [["\t", 174], [" ", 136], ["D", 2]]], ["!", [["!", 12], [" ", 7580], ["\"", 6860], ["'", 556], [")", 42], ["*", 12], ["-", 108], [",", 4], [".", 170], ["I", 2], ["v", 6], ["[", 2], ["_", 6]]], ["%", [[" ", 8]]], [")", [[" ", 830], ["-", 56], [",", 506], [".", 102], ["5", 2], ["[", 2], [":", 16], [";", 58], ["?", 2]]], ["-", [["!", 8], [" ", 5090], ["\"", 550], ["'", 68], ["(", 2], ["+", 4], ["-", 6008], [",", 22], [".", 2], ["1", 12], ["2", 16], ["5", 24], ["4", 2], ["7", 4], ["6", 6], ["8", 4], ["?", 22], ["A", 170], ["C", 118], ["B", 200], ["E", 88], ["D", 116], ["G", 118], ["F", 62], ["I", 194], ["H", 172], ["K", 16], ["J", 90], ["M", 196], ["L", 74], ["O", 38], ["N", 44], ["Q", 6], ["P", 134], ["S", 172], ["R", 44], ["T", 160], ["W", 74], ["V", 28], ["Y", 22], ["Z", 4], ["a", 1098], ["`", 16], ["c", 1092], ["b", 1366], ["e", 476], ["d", 942], ["g", 452], ["f", 1014], ["i", 408], ["h", 966], ["k", 224], ["j", 64], ["m", 808], ["l", 922], ["o", 468], ["n", 446], ["q", 40], ["p", 884], ["s", 1836], ["r", 562], ["u", 122], ["t", 1410], ["w", 812], ["v", 66], ["y", 140], ["z", 12]]], ["1", [[" ", 112], ["'", 4], [")", 16], ["*", 10], ["-", 14], [",", 112], ["/", 2], [".", 68], ["1", 246], ["0", 318], ["3", 164], ["2", 280], ["5", 224], ["4", 214], ["7", 188], ["6", 204], ["9", 126], ["8", 572], [";", 4], [":", 40], ["@", 4], ["O", 2], ["]", 48], ["s", 52], ["t", 22], ["}", 18], ["|", 88]]], ["5", [[" ", 98], ["\"", 2], ["'", 2], ["-", 4], [",", 88], [".", 46], ["1", 22], ["0", 140], ["3", 28], ["2", 32], ["5", 32], ["4", 22], ["7", 32], ["6", 16], ["9", 14], ["8", 18], [";", 10], [":", 48], ["?", 2], ["@", 14], ["]", 64], ["t", 82], ["}", 18], ["|", 44]]], ["9", [[" ", 74], ["'", 2], [")", 4], ["-", 6], [",", 40], [".", 22], ["1", 26], ["0", 43], ["3", 48], ["2", 14], ["5", 18], ["4", 15], ["7", 34], ["6", 20], ["9", 18], ["8", 10], [";", 12], [":", 38], ["@", 6], ["]", 44], ["t", 32], ["}", 18], ["|", 46]]], ["=", [["E", 2], ["=", 8], ["T", 14], [" ", 12]]], ["A", [[" ", 4464], ["\"", 2], ["'", 12], ["-", 18], [",", 4], [".", 24], ["A", 6], ["C", 108], ["B", 58], ["E", 22], ["D", 77], ["G", 50], ["F", 18], ["I", 98], ["H", 10], ["K", 18], ["M", 89], ["L", 220], ["N", 497], ["Q", 2], ["P", 2116], ["S", 220], ["R", 481], ["U", 44], ["T", 292], ["W", 18], ["V", 78], ["Y", 66], ["X", 6], ["Z", 2], ["a", 2], ["c", 208], ["b", 496], ["e", 2], ["d", 372], ["g", 352], ["f", 1144], ["i", 66], ["h", 554], ["k", 64], ["j", 4], ["m", 1358], ["l", 3042], ["o", 140], ["n", 12454], ["q", 4], ["p", 230], ["s", 2898], ["r", 1643], ["u", 754], ["t", 3060], ["w", 48], ["v", 60], ["y", 30], ["x", 2], ["z", 30]]], ["E", [["!", 20], [" ", 1253], ["\"", 2], ["'", 18], ["*", 2], ["-", 14], [",", 30], [".", 100], [":", 8], ["?", 4], ["A", 176], ["C", 152], ["B", 30], ["E", 92], ["D", 166], ["G", 32], ["F", 34], ["I", 60], ["H", 6], ["K", 8], ["M", 80], ["L", 142], ["O", 14], ["N", 490], ["Q", 6], ["P", 124], ["S", 360], ["R", 730], ["U", 18], ["T", 184], ["W", 90], ["V", 102], ["Y", 34], ["X", 64], ["a", 450], ["c", 46], ["b", 14], ["d", 90], ["g", 62], ["f", 20], ["i", 64], ["h", 58], ["k", 6], ["m", 1500], ["l", 226], ["o", 4], ["n", 1398], ["q", 20], ["p", 138], ["s", 148], ["r", 118], ["u", 358], ["t", 98], ["v", 1326], ["y", 70], ["x", 298], ["z", 2], ["}", 2]]], ["I", [["!", 34], [" ", 40514], ["\"", 4], ["'", 2748], ["-", 52], [",", 526], [".", 576], [";", 42], [":", 6], ["?", 88], ["A", 76], ["C", 182], ["B", 47], ["E", 82], ["D", 78], ["G", 140], ["F", 78], ["I", 1054], ["K", 12], ["M", 76], ["L", 150], ["O", 134], ["N", 704], ["Q", 4], ["P", 18], ["S", 277], ["R", 122], ["U", 2], ["T", 378], ["V", 298], ["X", 156], ["Z", 8], ["_", 46], ["a", 2], ["c", 146], ["b", 10], ["d", 16], ["g", 48], ["f", 1944], ["m", 196], ["l", 216], ["o", 30], ["n", 5298], ["p", 28], ["s", 930], ["r", 122], ["t", 8656], ["v", 100], ["x", 2], ["z", 2]]], ["M", [["!", 4], [" ", 68], ["\"", 2], ["'", 12], ["-", 4], [",", 12], ["/", 8], [".", 1208], [":", 2], ["A", 346], ["C", 28], ["B", 34], ["E", 243], ["D", 6], ["G", 12], ["I", 130], ["M", 24], ["L", 2], ["O", 117], ["N", 16], ["P", 50], ["S", 26], ["R", 8], ["U", 28], ["W", 6], ["Y", 24], ["a", 8688], ["c", 378], ["e", 1576], ["f", 2], ["i", 2158], ["o", 4266], ["s", 2], ["r", 2578], ["u", 518], ["y", 1492]]], ["Q", [["U", 48], ["C", 2], ["u", 494], [".", 4]]], ["U", [["!", 2], [" ", 106], ["'", 6], [",", 2], [".", 10], ["A", 16], ["C", 48], ["B", 24], ["E", 54], ["D", 44], ["G", 12], ["F", 6], ["I", 12], ["K", 2], ["M", 60], ["L", 68], ["N", 116], ["P", 26], ["S", 130], ["R", 182], ["U", 2], ["T", 156], ["V", 2], ["Z", 6], ["c", 2], ["g", 12], ["h", 34], ["k", 4], ["m", 16], ["l", 30], ["n", 859], ["p", 360], ["s", 32], ["r", 68], ["t", 50], ["v", 16]]], ["Y", [["!", 4], [" ", 260], ["\"", 2], ["'", 4], ["-", 68], [",", 10], [".", 22], [";", 2], ["A", 2], ["B", 2], ["E", 26], ["L", 4], ["O", 112], ["S", 26], ["R", 4], ["T", 2], ["a", 122], ["c", 2], ["e", 1328], ["i", 10], ["o", 3878], ["s", 10], ["u", 26], ["v", 8]]], ["]", [["!", 2], [" ", 322], ["J", 2], ["-", 2], [",", 44], [".", 14], [";", 24], [">", 2]]], ["a", [["!", 310], [" ", 65518], ["\"", 24], ["'", 716], [")", 20], ["*", 1], ["-", 724], [",", 2766], [".", 1558], ["1", 2], [";", 152], [":", 30], ["?", 144], [">", 2], ["S", 2], ["_", 6], ["a", 122], ["`", 6], ["c", 35608], ["b", 19042], ["e", 752], ["d", 56288], ["g", 18377], ["f", 7666], ["i", 47228], ["h", 1140], ["k", 13604], ["j", 480], ["m", 24754], ["l", 68865], ["o", 314], ["n", 216874], ["q", 102], ["p", 18548], ["s", 105951], ["r", 97182], ["u", 12725], ["t", 135418], ["w", 10880], ["v", 25744], ["y", 29029], ["x", 666], ["z", 1906], ["}", 2]]], ["e", [["!", 3010], [" ", 487805], ["\"", 166], ["'", 4249], [")", 336], ["*", 10], ["-", 4298], [",", 40540], [".", 24278], [";", 3704], [":", 890], ["?", 2866], [">", 78], ["B", 2], ["I", 2], ["S", 2], ["[", 6], ["]", 18], ["_", 42], ["a", 79086], ["`", 2], ["c", 27918], ["b", 1598], ["e", 45884], ["d", 142368], ["g", 8394], ["f", 13916], ["i", 18692], ["h", 2842], ["k", 1590], ["j", 380], ["m", 31126], ["l", 54118], ["o", 4898], ["n", 129345], ["q", 1706], ["p", 17078], ["s", 100714], ["r", 205409], ["u", 2658], ["t", 41944], ["w", 11422], ["v", 24561], ["y", 23800], ["x", 14052], ["z", 560], ["}", 4]]], ["i", [["!", 50], [" ", 1222], ["\"", 2], ["'", 184], [")", 4], ["*", 2], ["-", 384], [",", 450], [".", 254], [";", 14], [":", 6], ["?", 14], ["@", 2], ["G", 2], ["Y", 2], ["]", 2], ["_", 8], ["a", 10716], ["c", 45183], ["b", 6986], ["e", 33445], ["d", 40015], ["g", 26388], ["f", 17002], ["i", 24], ["h", 72], ["k", 7006], ["j", 18], ["m", 40198], ["l", 43870], ["o", 33038], ["n", 232657], ["q", 394], ["p", 5884], ["s", 107323], ["r", 32008], ["u", 1844], ["t", 102683], ["w", 38], ["v", 16166], ["y", 2], ["x", 2074], ["z", 2892]]], ["m", [["!", 462], [" ", 35852], ["\"", 24], ["'", 294], [")", 58], ["-", 610], [",", 7564], [".", 6290], ["1", 2], [";", 758], [":", 298], ["?", 470], [">", 22], ["]", 2], ["a", 45673], ["c", 96], ["b", 7420], ["e", 83120], ["d", 36], ["g", 4], ["f", 768], ["i", 24836], ["h", 10], ["k", 22], ["m", 5770], ["l", 522], ["o", 32940], ["n", 1218], ["p", 15046], ["s", 8640], ["r", 202], ["u", 10278], ["t", 200], ["w", 24], ["y", 17480]]], ["q", [["a", 2], [" ", 2], ["u", 12073], [",", 2], ["'", 2]]], ["u", [["!", 428], [" ", 17752], ["\"", 16], ["'", 1182], [")", 6], ["-", 186], [",", 1924], [".", 1140], [";", 124], [":", 18], ["?", 428], ["S", 12], ["T", 2], ["_", 2], ["a", 6632], ["c", 12934], ["b", 5730], ["e", 10797], ["d", 6988], ["g", 18286], ["f", 2056], ["i", 9148], ["h", 30], ["k", 496], ["j", 84], ["m", 8440], ["l", 37068], ["o", 708], ["n", 43221], ["q", 64], ["p", 17232], ["s", 44836], ["r", 48568], ["u", 18], ["t", 49162], ["w", 10], ["v", 428], ["y", 210], ["x", 498], ["z", 722]]], ["y", [["!", 1032], [" ", 118640], ["\"", 62], ["'", 1440], [")", 154], ["-", 2010], [",", 18388], [".", 10860], [";", 1366], [":", 466], ["?", 946], [">", 26], ["]", 2], ["_", 4], ["a", 2624], ["`", 2], ["c", 242], ["b", 640], ["e", 11272], ["d", 206], ["g", 138], ["f", 198], ["i", 4422], ["h", 84], ["k", 76], ["m", 714], ["l", 818], ["o", 28106], ["n", 212], ["p", 410], ["s", 8723], ["r", 738], ["u", 58], ["t", 3028], ["w", 464], ["v", 110], ["x", 14], ["z", 40]]], ["}", [[" ", 6], [",", 2]]]]]
        freq = {}
        total_freq = {}
        for elem in default_f[2]:
            first_char = int.from_bytes(bytes(elem[0], "utf-8"), "big")
            second_char_list = elem[1]
            freq[first_char] = {}
            total_freq[first_char] = 0
            for second_char_elem in second_char_list:
                second_char = int.from_bytes(bytes(second_char_elem[0], "utf-8"), "big")
                frequency = second_char_elem[1]
                freq[first_char][second_char] = frequency
                total_freq[first_char] += frequency
        ed.receive_atom(log_atom1)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom1.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom2)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom2.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom3)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom3.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom4)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom4.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom5)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom5.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom6)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 6).strftime(dtf), ed.__class__.__name__, 1, "lfmvasacz"))
        self.reset_output_stream()
        self.add_data(log_atom6.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # skip_repetitions = True
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], skip_repetitions=True, learn_mode=True, output_logline=False)
        total_freq = {}
        freq = {}
        ed.receive_atom(log_atom1)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 1).strftime(dtf), ed.__class__.__name__, 1, "aminer"))
        self.reset_output_stream()
        self.add_data(log_atom1.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom2)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom2.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom3)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom3.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom4)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom4.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom5)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.add_data(log_atom5.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        ed.receive_atom(log_atom6)
        self.assertEqual(self.output_stream.getvalue(), expected_string % (datetime.fromtimestamp(t + 6).strftime(dtf), ed.__class__.__name__, 1, "lfmvasacz"))
        self.reset_output_stream()
        self.add_data(log_atom6.raw_data.decode(), freq, total_freq)
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # frequencies should not change if skip_repetitions = True
        ed.receive_atom(log_atom6)
        self.assertEqual(self.output_stream.getvalue(), "")
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        # stop_learning_time
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], learn_mode=True, output_logline=False, stop_learning_time=100)
        self.assertTrue(ed.receive_atom(log_atom1))
        log_atom1.atom_time = t + 99
        self.assertTrue(ed.receive_atom(log_atom1))
        self.assertTrue(ed.learn_mode)
        log_atom1.atom_time = t + 102
        self.assertTrue(ed.receive_atom(log_atom1))
        self.assertFalse(ed.learn_mode)

        # stop_learning_no_anomaly_time
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], learn_mode=True, output_logline=False, stop_learning_no_anomaly_time=100)
        log_atom1.atom_time = t
        self.assertTrue(ed.receive_atom(log_atom1))
        log_atom1.atom_time = t + 100
        self.assertTrue(ed.receive_atom(log_atom1))
        self.assertTrue(ed.learn_mode)
        log_atom2.atom_time = t + 100
        self.assertTrue(ed.receive_atom(log_atom2))
        self.assertTrue(ed.learn_mode)
        log_atom1.atom_time = t + 200
        self.assertTrue(ed.receive_atom(log_atom3))
        self.assertTrue(ed.learn_mode)
        log_atom1.atom_time = t + 201
        self.assertTrue(ed.receive_atom(log_atom1))
        self.assertFalse(ed.learn_mode)

    def test2do_timer(self):
        """Test if the do_timer method is implemented properly."""
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"])
        t = time.time()
        ed.next_persist_time = t + 400
        self.assertEqual(ed.do_timer(t + 200), 200)
        self.assertEqual(ed.do_timer(t + 400), DEFAULT_PERSISTENCE_PERIOD)
        self.assertEqual(ed.do_timer(t + 999), 1)
        self.assertEqual(ed.do_timer(t + 1000), DEFAULT_PERSISTENCE_PERIOD)

    def test3allowlist_event(self):
        """Test if the allowlist_event method is implemented properly."""
        # This test case checks whether an exception is thrown when entering an event of another class.
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"])
        analysis = "Analysis.%s"
        self.assertRaises(Exception, ed.allowlist_event, analysis % "NewMatchPathValueDetector", self.output_stream.getvalue(), None)

        # The EntropyDetector can not handle allowlisting data and therefore an exception is expected.
        self.assertRaises(Exception, ed.allowlist_event, analysis % ed.__class__.__name__, self.output_stream.getvalue(), ["random", "Data"])

        # This test case checks in which cases an event is triggered and compares with expected results.
        self.assertEqual(ed.allowlist_event(analysis % ed.__class__.__name__, "/s1", None), "Allowlisted path %s in %s." % ("/s1", analysis % ed.__class__.__name__))
        self.assertEqual(ed.constraint_list, ["/s1"])

        ed.learn_mode = False
        self.assertEqual(ed.allowlist_event(analysis % ed.__class__.__name__, "/d1", None), "Allowlisted path %s in %s." % ("/d1", analysis % ed.__class__.__name__))
        self.assertEqual(ed.constraint_list, ["/s1", "/d1"])

    def test4blocklist_event(self):
        """Test if the blocklist_event method is implemented properly."""
        # This test case checks whether an exception is thrown when entering an event of another class.
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"])
        analysis = "Analysis.%s"
        self.assertRaises(Exception, ed.blocklist_event, analysis % "NewMatchPathValueDetector", self.output_stream.getvalue(), None)

        # The EntropyDetector can not handle allowlisting data and therefore an exception is expected.
        self.assertRaises(Exception, ed.blocklist_event, analysis % ed.__class__.__name__, self.output_stream.getvalue(), ["random", "Data"])

        # This test case checks in which cases an event is triggered and compares with expected results.
        self.assertEqual(ed.blocklist_event(analysis % ed.__class__.__name__, "/s1", None), "Blocklisted path %s in %s." % ("/s1", analysis % ed.__class__.__name__))
        self.assertEqual(ed.ignore_list, ["/s1"])

        ed.learn_mode = False
        self.assertEqual(ed.blocklist_event(analysis % ed.__class__.__name__, "/d1", None), "Blocklisted path %s in %s." % ("/d1", analysis % ed.__class__.__name__))
        self.assertEqual(ed.ignore_list, ["/s1", "/d1"])

    def test5persistence(self):
        """Test the do_persist and load_persistence_data methods."""
        t = time.time()
        ed = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], prob_thresh=0.05, learn_mode=True, output_logline=False)
        log_atom1 = LogAtom(b"aminer", ParserMatch(MatchElement("/value", b"aminer", b"aminer", None)), t + 1, None)
        log_atom2 = LogAtom(b"logdata-anomaly-miner",  ParserMatch(MatchElement("/value", b"logdata-anomaly-miner", b"logdata-anomaly-miner", None)), t + 2, None)
        log_atom3 = LogAtom(b"ait-aecid", ParserMatch(MatchElement("/value", b"ait-aecid", b"ait-aecid", None)), t + 3, None)
        log_atom4 = LogAtom(b"austrian", ParserMatch(MatchElement("/value", b"austrian", b"austrian", None)), t + 4, None)
        log_atom5 = LogAtom(b"institute", ParserMatch(MatchElement("/value", b"institute", b"institute", None)), t + 5, None)
        log_atom6 = LogAtom(b"lfmvasacz", ParserMatch(MatchElement("/value", b"lfmvasacz", b"lfmvasacz", None)), t + 6, None)

        total_freq = {}
        freq = {}
        ed.receive_atom(log_atom1)
        self.add_data(log_atom1.raw_data.decode(), freq, total_freq)
        ed.receive_atom(log_atom2)
        self.add_data(log_atom2.raw_data.decode(), freq, total_freq)
        ed.receive_atom(log_atom3)
        self.add_data(log_atom3.raw_data.decode(), freq, total_freq)
        ed.receive_atom(log_atom4)
        self.add_data(log_atom4.raw_data.decode(), freq, total_freq)
        ed.receive_atom(log_atom5)
        self.add_data(log_atom5.raw_data.decode(), freq, total_freq)
        ed.receive_atom(log_atom6)
        self.add_data(log_atom6.raw_data.decode(), freq, total_freq)
        ed.do_persist()
        with open(ed.persistence_file_name, "r") as f:
            self.assertEqual(f.read(), '[[-1, [[97, 3], [108, 2], [105, 1]]], [97, [[109, 1], [116, 1], [45, 1], [110, 2], [108, 1], [105, 1], [101, 1], [117, 1], [115, 1], [99, 1]]], [109, [[105, 2], [97, 1], [118, 1]]], [105, [[110, 3], [116, 2], [100, 1], [97, 1]]], [110, [[101, 2], [111, 1], [-1, 1], [115, 1]]], [101, [[114, 2], [99, 1], [-1, 1]]], [114, [[-1, 2], [105, 1]]], [108, [[111, 1], [121, 1], [102, 1]]], [111, [[103, 1], [109, 1]]], [103, [[100, 1]]], [100, [[97, 1], [-1, 1]]], [116, [[97, 1], [45, 1], [114, 1], [105, 1], [117, 1], [101, 1]]], [45, [[97, 2], [109, 1]]], [121, [[45, 1]]], [99, [[105, 1], [122, 1]]], [117, [[115, 1], [116, 1]]], [115, [[116, 2], [97, 1]]], [102, [[109, 1]]], [118, [[97, 1]]], [122, [[-1, 1]]]]')

        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)
        ed.total_freq = {}
        ed.freq = {}
        ed.load_persistence_data()
        self.assertEqual(ed.total_freq, total_freq)
        self.assertEqual(ed.freq, freq)

        other = EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/value"], prob_thresh=0.05, learn_mode=True, output_logline=False)
        self.assertEqual(other.total_freq, ed.total_freq)
        self.assertEqual(other.freq, ed.freq)

    def test6validate_parameters(self):
        """Test all initialization parameters for the detector. Input parameters must be validated in the class."""
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, ["default"], ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, None, ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, "", ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, b"Default", ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, True, ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, 123, ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, 123.3, ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, {"id": "Default"}, ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, (), ["/model/value"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, set(), ["/model/value"])

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], [""])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], "")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], b"Default")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], True)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], 123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], 123.3)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], {"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], set())

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=-1)
        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=1.1)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=b"Default")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh="123")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=["Default"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=[])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=0)
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=0.5)
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], prob_thresh=1)

        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs=b"True")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs="True")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs=123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs=123.22)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs=["Default"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs=[])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], default_freqs=True)

        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions=b"True")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions="True")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions=123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions=123.22)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions=["Default"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions=[])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], skip_repetitions=True)

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id="")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=None)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=b"Default")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=True)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=123.22)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=["Default"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=[])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], persistence_id="Default")

        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=b"True")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode="True")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=123.22)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=["Default"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=[])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True)

        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=None)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=b"True")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline="True")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=123.22)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=["Default"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=[])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], output_logline=True)

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=[""])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list="")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=b"Default")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=True)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=123.3)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=[])
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], ignore_list=None)

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=[""])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list="")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=b"Default")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=True)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=123.3)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=[])
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], constraint_list=None)

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=-1)
        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=0)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=b"Default")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time="123")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=["Default"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=[])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=100)
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=100.22)

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=-1)
        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=0)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=b"Default")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time="123")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=["Default"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=[])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=100)
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_no_anomaly_time=100.22)

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], learn_mode=True, stop_learning_time=100, stop_learning_no_anomaly_time=100)

        self.assertRaises(ValueError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list=["/tmp/syslog"])
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list="")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list=b"Default")
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list=True)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list=123)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list=123.22)
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list={"id": "Default"})
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list=())
        self.assertRaises(TypeError, EntropyDetector, self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list=set())
        EntropyDetector(self.aminer_config, [self.stream_printer_event_handler], ["/model/value"], log_resource_ignore_list=["file:///tmp/syslog"])

    @staticmethod
    def add_data(string, freq, total_freq):
        for i, x in enumerate(string):
            num = ord(x)
            total_freq[num] = total_freq.get(num, 0) + 1
            if i == 0:
                key = -1
            else:
                key = ord(string[i - 1])
            freq[key] = freq.get(key, {})
            freq[key][num] = freq[key].get(num, 0) + 1
        freq[ord(string[len(string) - 1])] = freq.get(ord(string[len(string) - 1]), {})
        freq[ord(string[len(string) - 1])][-1] = freq[ord(string[len(string) - 1])].get(-1, 0) + 1
        total_freq[-1] = total_freq.get(-1, 0) + 1


if __name__ == "__main__":
    unittest.main()
