Adding time constraints into the scripts.
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / Main.java
index 12c3a2ae626e6b5b4a26751d758d69dd424b2a04..f1056b0ef56931aaf1236d46ea734e4274c7ac7f 100644 (file)
@@ -305,11 +305,14 @@ public class Main {
 //        final String onSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-onSignature-device-side.sig";
 //        final String offSignatureFile = path + "/experimental_result/standalone/dlink-plug/signatures/dlink-plug-offSignature-device-side.sig";
         // TP-Link plug
-//        final String triggerTimesFile = path + "/experimental_result/standalone/tplink-plug/timestamps/tplink-plug-nov-8-2018.timestamps";
+        final String triggerTimesFile = path + "/experimental_result/standalone/tplink-plug/timestamps/tplink-plug-nov-8-2018.timestamps";
 ////        final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-phone-side.sig";
 ////        final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-phone-side.sig";
 //        final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-device-side-outbound.sig";
 //        final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-device-side-outbound.sig";
+        final String onSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-onSignature-device-side.sig";
+        final String offSignatureFile = path + "/experimental_result/standalone/tplink-plug/signatures/tplink-plug-offSignature-device-side.sig";
+
         // D-Link siren
 //        final String triggerTimesFile = path + "/experimental_result/standalone/dlink-siren/timestamps/dlink-siren-nov-9-2018.timestamps";
 //        final String onSignatureFile = path + "/experimental_result/standalone/dlink-siren/signatures/dlink-siren-onSignature-phone-side.sig";
@@ -349,9 +352,9 @@ public class Main {
 //        final String onSignatureFile = path + "/experimental_result/standalone/wemo-plug/signatures/wemo-plug-onSignature-phone-side.sig";
 //        final String offSignatureFile = path + "/experimental_result/standalone/wemo-plug/signatures/wemo-plug-offSignature-phone-side.sig";
         // WeMo Insight plug
-        final String triggerTimesFile = path + "/experimental_result/standalone/wemo-insight-plug/timestamps/wemo-insight-plug-nov-21-2018.timestamps";
-        final String onSignatureFile = path + "/experimental_result/standalone/wemo-insight-plug/signatures/wemo-insight-plug-onSignature-phone-side.sig";
-        final String offSignatureFile = path + "/experimental_result/standalone/wemo-insight-plug/signatures/wemo-insight-plug-offSignature-phone-side.sig";
+//        final String triggerTimesFile = path + "/experimental_result/standalone/wemo-insight-plug/timestamps/wemo-insight-plug-nov-21-2018.timestamps";
+//        final String onSignatureFile = path + "/experimental_result/standalone/wemo-insight-plug/signatures/wemo-insight-plug-onSignature-phone-side.sig";
+//        final String offSignatureFile = path + "/experimental_result/standalone/wemo-insight-plug/signatures/wemo-insight-plug-offSignature-phone-side.sig";
 
 
         TriggerTimesFileReader ttfr = new TriggerTimesFileReader();
@@ -539,230 +542,230 @@ public class Main {
 //        final Map<UserAction, List<Conversation>> userActionToConversations = trafficLabeler.getLabeledReassembledTcpTraffic();
 //        final Map<UserAction, Map<String, List<Conversation>>> userActionsToConvsByHostname = trafficLabeler.getLabeledReassembledTcpTraffic(dnsMap);
 //        System.out.println("Reassembled TCP conversations occurring shortly after each user event");
-
-
-
-        /*
-         * NOTE: no need to generate these more complex on/off maps that also contain mappings from hostname and
-         * sequence identifiers as we do not care about hostnames and sequences during clustering.
-         * We can simply use the UserAction->List<Conversation> map to generate ON/OFF groupings of conversations.
-         */
-
-//        // Contains all ON events: hostname -> sequence identifier -> list of conversations with that sequence
-//        Map<String, Map<String, List<Conversation>>> ons = new HashMap<>();
-//        // Contains all OFF events: hostname -> sequence identifier -> list of conversations with that sequence
-//        Map<String, Map<String, List<Conversation>>> offs = new HashMap<>();
-//        userActionsToConvsByHostname.forEach((ua, hostnameToConvs) -> {
-//            Map<String, Map<String, List<Conversation>>> outer = ua.getType() == Type.TOGGLE_ON ? ons : offs;
-//            hostnameToConvs.forEach((host, convs) -> {
-//                Map<String, List<Conversation>> seqsToConvs = TcpConversationUtils.
-//                        groupConversationsByPacketSequence(convs, verbose);
-//                outer.merge(host, seqsToConvs, (oldMap, newMap) -> {
-//                    newMap.forEach((sequence, cs) -> oldMap.merge(sequence, cs, (list1, list2) -> {
-//                        list1.addAll(list2);
-//                        return list1;
-//                    }));
-//                    return oldMap;
-//                });
-//            });
-//        });
 //
-//        System.out.println("==== ON ====");
-//        // Print out all the pairs into a file for ON events
-//        File fileOnEvents = new File(onPairsPath);
-//        PrintWriter pwOn = null;
-//        try {
-//            pwOn = new PrintWriter(fileOnEvents);
-//        } catch(Exception ex) {
-//            ex.printStackTrace();
-//        }
-//        for(Map.Entry<String, Map<String, List<Conversation>>> entry : ons.entrySet()) {
-//            Map<String, List<Conversation>> seqsToConvs = entry.getValue();
-//            for(Map.Entry<String, List<Conversation>> entryConv : seqsToConvs.entrySet()) {
-//                List<Conversation> listConv = entryConv.getValue();
-//                // Just get the first Conversation because all Conversations in this group
-//                // should have the same pairs of Application Data.
-//                for(Conversation conv : listConv) {
-//                    // Process only if it is a TLS packet
-//                    if (conv.isTls()) {
-//                        List<PcapPacketPair> tlsAppDataList = TcpConversationUtils.extractTlsAppDataPacketPairs(conv);
-//                        for(PcapPacketPair pair: tlsAppDataList) {
-//                            System.out.println(PrintUtils.toCsv(pair, dnsMap));
-//                            pwOn.println(PrintUtils.toCsv(pair, dnsMap));
-//                        }
-//                    } else { // Non-TLS conversations
-//                        List<PcapPacketPair> packetList = TcpConversationUtils.extractPacketPairs(conv);
-//                        for(PcapPacketPair pair: packetList) {
-//                            System.out.println(PrintUtils.toCsv(pair, dnsMap));
-//                            pwOn.println(PrintUtils.toCsv(pair, dnsMap));
-//                        }
-//                    }
-//                }
-//            }
-//        }
-//        pwOn.close();
 //
-//        System.out.println("==== OFF ====");
-//        // Print out all the pairs into a file for ON events
-//        File fileOffEvents = new File(offPairsPath);
-//        PrintWriter pwOff = null;
-//        try {
-//            pwOff = new PrintWriter(fileOffEvents);
-//        } catch(Exception ex) {
-//            ex.printStackTrace();
-//        }
-//        for(Map.Entry<String, Map<String, List<Conversation>>> entry : offs.entrySet()) {
-//            Map<String, List<Conversation>> seqsToConvs = entry.getValue();
-//            for(Map.Entry<String, List<Conversation>> entryConv : seqsToConvs.entrySet()) {
-//                List<Conversation> listConv = entryConv.getValue();
-//                // Just get the first Conversation because all Conversations in this group
-//                // should have the same pairs of Application Data.
-//                for(Conversation conv : listConv) {
-//                    // Process only if it is a TLS packet
-//                    if (conv.isTls()) {
-//                        List<PcapPacketPair> tlsAppDataList = TcpConversationUtils.extractTlsAppDataPacketPairs(conv);
-//                        for(PcapPacketPair pair: tlsAppDataList) {
-//                            System.out.println(PrintUtils.toCsv(pair, dnsMap));
-//                            pwOff.println(PrintUtils.toCsv(pair, dnsMap));
-//                        }
-//                    } else { // Non-TLS conversations
-//                        List<PcapPacketPair> packetList = TcpConversationUtils.extractPacketPairs(conv);
-//                        for (PcapPacketPair pair : packetList) {
-//                            System.out.println(PrintUtils.toCsv(pair, dnsMap));
-//                            pwOff.println(PrintUtils.toCsv(pair, dnsMap));
-//                        }
-//                    }
-//                }
-//            }
-//        }
-//        pwOff.close();
-
-
-        // ================================================ CLUSTERING ================================================
-        // Note: no need to use the more convoluted on/off maps; can simply use the UserAction->List<Conversation> map
-        // when don't care about hostnames and sequences (see comment earlier).
-//        List<Conversation> onConversations = userActionToConversations.entrySet().stream().
-//                filter(e -> e.getKey().getType() == Type.TOGGLE_ON). // drop all OFF events from stream
-//                map(e -> e.getValue()). // no longer interested in the UserActions
-//                flatMap(List::stream). // flatten List<List<T>> to a List<T>
-//                collect(Collectors.toList());
-//        List<Conversation> offConversations = userActionToConversations.entrySet().stream().
-//                filter(e -> e.getKey().getType() == Type.TOGGLE_OFF).
-//                map(e -> e.getValue()).
-//                flatMap(List::stream).
-//                collect(Collectors.toList());
-//        //Collections.sort(onConversations, (c1, c2) -> c1.getPackets().)
 //
-//        List<PcapPacketPair> onPairs = onConversations.stream().
-//                map(c -> c.isTls() ? TcpConversationUtils.extractTlsAppDataPacketPairs(c) :
-//                        TcpConversationUtils.extractPacketPairs(c)).
-//                flatMap(List::stream). // flatten List<List<>> to List<>
-//                collect(Collectors.toList());
-//        List<PcapPacketPair> offPairs = offConversations.stream().
-//                map(c -> c.isTls() ? TcpConversationUtils.extractTlsAppDataPacketPairs(c) :
-//                        TcpConversationUtils.extractPacketPairs(c)).
-//                flatMap(List::stream). // flatten List<List<>> to List<>
-//                collect(Collectors.toList());
-//        // Note: need to update the DnsMap of all PcapPacketPairs if we want to use the IP/hostname-sensitive distance.
-//        Stream.concat(Stream.of(onPairs), Stream.of(offPairs)).flatMap(List::stream).forEach(p -> p.setDnsMap(dnsMap));
-//        // Perform clustering on conversation logged as part of all ON events.
-////        DBSCANClusterer<PcapPacketPair> onClusterer = new DBSCANClusterer<>(10.0, 45);
-//        DBSCANClusterer<PcapPacketPair> onClusterer = new DBSCANClusterer<>(2, 2);
-//        //DBSCANClusterer<PcapPacketPair> onClusterer = new DBSCANClusterer<>(10.0, 10);
-//        List<Cluster<PcapPacketPair>> onClusters = onClusterer.cluster(onPairs);
-//        // Perform clustering on conversation logged as part of all OFF events.
-////        DBSCANClusterer<PcapPacketPair> offClusterer = new DBSCANClusterer<>(10.0, 45);
-//        DBSCANClusterer<PcapPacketPair> offClusterer = new DBSCANClusterer<>(2, 2);
-//        //DBSCANClusterer<PcapPacketPair> offClusterer = new DBSCANClusterer<>(10.0, 10);
-//        List<Cluster<PcapPacketPair>> offClusters = offClusterer.cluster(offPairs);
-//        // Sort the conversations as reference
-//        List<Conversation> sortedAllConversation = TcpConversationUtils.sortConversationList(allConversations);
-//        // Output clusters
-//        System.out.println("========================================");
-//        System.out.println("       Clustering results for ON        ");
-//        System.out.println("       Number of clusters: " + onClusters.size());
-//        int count = 0;
-//        List<List<List<PcapPacket>>> ppListOfListReadOn = new ArrayList<>();
-//        List<List<List<PcapPacket>>> ppListOfListListOn = new ArrayList<>();
-//        for (Cluster<PcapPacketPair> c : onClusters) {
-//            System.out.println(String.format("<<< Cluster #%02d (%03d points) >>>", ++count, c.getPoints().size()));
-//            System.out.print(PrintUtils.toSummaryString(c));
-//            if(c.getPoints().size() > 45 && c.getPoints().size() < 55) {
-//            //if(c.getPoints().size() > 25) {
-//                // Print to file
-//                List<List<PcapPacket>> ppListOfList = PcapPacketUtils.clusterToListOfPcapPackets(c);
-//                ppListOfListListOn.add(ppListOfList);
-//            }
-//        }
-//        // TODO: Merging test
-//        ppListOfListListOn = PcapPacketUtils.mergeSignatures(ppListOfListListOn, sortedAllConversation);
-//        // TODO: Need to remove sequence 550 567 for Blossom phone side since it is not a good signature (overlap)!
-////        PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 1);
-//        // TODO: Need to remove sequence 69 296 for Blossom device side since it is not a good signature (overlap)!
-////        PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 2);
-//        // TODO: Need to remove sequence number 2 for ST plug since it is not a good signature!
-//        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 2);
-//        // TODO: Need to remove sequence number 0 for Arlo Camera since it is not a good signature!
-//        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 0);
-//        // TODO: Need to remove sequence number 0 for TP-Link plug since it is not a good signature!
-//        // TODO: This sequence actually belongs to the local communication between the plug and the phone
-//        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 0);
-//        ppListOfListListOn = PcapPacketUtils.sortSignatures(ppListOfListListOn);
-//        PcapPacketUtils.printSignatures(ppListOfListListOn);
-//        //count = 0;
-//        /*for (List<List<PcapPacket>> ll : ppListOfListListOn) {
-//            PrintUtils.serializeClustersIntoFile("./onSignature" + ++count + ".sig", ll);
-//            ppListOfListReadOn.add(PrintUtils.deserializeClustersFromFile("./onSignature" + count + ".sig"));
-//        }*/
-//        PrintUtils.serializeSignatureIntoFile("./onSignature.sig", ppListOfListListOn);
-//        ppListOfListReadOn = PrintUtils.deserializeSignatureFromFile("./onSignature.sig");
+//        /*
+//         * NOTE: no need to generate these more complex on/off maps that also contain mappings from hostname and
+//         * sequence identifiers as we do not care about hostnames and sequences during clustering.
+//         * We can simply use the UserAction->List<Conversation> map to generate ON/OFF groupings of conversations.
+//         */
 //
-//        System.out.println("========================================");
-//        System.out.println("       Clustering results for OFF       ");
-//        System.out.println("       Number of clusters: " + offClusters.size());
-//        count = 0;
-//        List<List<List<PcapPacket>>> ppListOfListReadOff = new ArrayList<>();
-//        List<List<List<PcapPacket>>> ppListOfListListOff = new ArrayList<>();
-//        for (Cluster<PcapPacketPair> c : offClusters) {
-//            System.out.println(String.format("<<< Cluster #%03d (%06d points) >>>", ++count, c.getPoints().size()));
-//            System.out.print(PrintUtils.toSummaryString(c));
-//            if(c.getPoints().size() > 45 && c.getPoints().size() < 55) {
-//            //if(c.getPoints().size() > 25) {
-//                // Print to file
-//                List<List<PcapPacket>> ppListOfList = PcapPacketUtils.clusterToListOfPcapPackets(c);
-//                ppListOfListListOff.add(ppListOfList);
-//            }
-//        }
-//        // TODO: Merging test
-//        ppListOfListListOff = PcapPacketUtils.mergeSignatures(ppListOfListListOff, sortedAllConversation);
-//        // TODO: Need to remove sequence 69 296 for Blossom device side since it is not a good signature (overlap)!
-////        PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 3);
-//        // TODO: Need to remove sequence number 1 for Nest Thermostat since it is not a good signature!
-//        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 1);
-//        // TODO: Need to remove sequence number 0 for Arlo Camera since it is not a good signature!
-////        PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 1);
-//        // TODO: Need to remove sequence number 2 for ST plug since it is not a good signature!
-//        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 2);
-//        // TODO: Need to remove sequence number 0 for TP-Link plug since it is not a good signature!
-//        // TODO: This sequence actually belongs to the local communication between the plug and the phone
-//        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 0);
-//        ppListOfListListOff = PcapPacketUtils.sortSignatures(ppListOfListListOff);
-//        PcapPacketUtils.printSignatures(ppListOfListListOff);
-//        //count = 0;
-//        /*for (List<List<PcapPacket>> ll : ppListOfListListOff) {
-//            PrintUtils.serializeClustersIntoFile("./offSignature" + ++count + ".sig", ll);
-//            ppListOfListReadOff.add(PrintUtils.deserializeClustersFromFile("./offSignature" + count + ".sig"));
-//        }*/
-//        PrintUtils.serializeSignatureIntoFile("./offSignature.sig", ppListOfListListOff);
-//        ppListOfListReadOff = PrintUtils.deserializeSignatureFromFile("./offSignature.sig");
-//        System.out.println("========================================");
-        // ============================================================================================================
-
-        // TODO: This part is just for DBSCAN sensitivity experiment
-        // TODO: This part is just for DBSCAN sensitivity experiment
-        // TODO: This part is just for DBSCAN sensitivity experiment
-        // TODO: This part is just for DBSCAN sensitivity experiment
-        // TODO: This part is just for DBSCAN sensitivity experiment
+////        // Contains all ON events: hostname -> sequence identifier -> list of conversations with that sequence
+////        Map<String, Map<String, List<Conversation>>> ons = new HashMap<>();
+////        // Contains all OFF events: hostname -> sequence identifier -> list of conversations with that sequence
+////        Map<String, Map<String, List<Conversation>>> offs = new HashMap<>();
+////        userActionsToConvsByHostname.forEach((ua, hostnameToConvs) -> {
+////            Map<String, Map<String, List<Conversation>>> outer = ua.getType() == Type.TOGGLE_ON ? ons : offs;
+////            hostnameToConvs.forEach((host, convs) -> {
+////                Map<String, List<Conversation>> seqsToConvs = TcpConversationUtils.
+////                        groupConversationsByPacketSequence(convs, verbose);
+////                outer.merge(host, seqsToConvs, (oldMap, newMap) -> {
+////                    newMap.forEach((sequence, cs) -> oldMap.merge(sequence, cs, (list1, list2) -> {
+////                        list1.addAll(list2);
+////                        return list1;
+////                    }));
+////                    return oldMap;
+////                });
+////            });
+////        });
+////
+////        System.out.println("==== ON ====");
+////        // Print out all the pairs into a file for ON events
+////        File fileOnEvents = new File(onPairsPath);
+////        PrintWriter pwOn = null;
+////        try {
+////            pwOn = new PrintWriter(fileOnEvents);
+////        } catch(Exception ex) {
+////            ex.printStackTrace();
+////        }
+////        for(Map.Entry<String, Map<String, List<Conversation>>> entry : ons.entrySet()) {
+////            Map<String, List<Conversation>> seqsToConvs = entry.getValue();
+////            for(Map.Entry<String, List<Conversation>> entryConv : seqsToConvs.entrySet()) {
+////                List<Conversation> listConv = entryConv.getValue();
+////                // Just get the first Conversation because all Conversations in this group
+////                // should have the same pairs of Application Data.
+////                for(Conversation conv : listConv) {
+////                    // Process only if it is a TLS packet
+////                    if (conv.isTls()) {
+////                        List<PcapPacketPair> tlsAppDataList = TcpConversationUtils.extractTlsAppDataPacketPairs(conv);
+////                        for(PcapPacketPair pair: tlsAppDataList) {
+////                            System.out.println(PrintUtils.toCsv(pair, dnsMap));
+////                            pwOn.println(PrintUtils.toCsv(pair, dnsMap));
+////                        }
+////                    } else { // Non-TLS conversations
+////                        List<PcapPacketPair> packetList = TcpConversationUtils.extractPacketPairs(conv);
+////                        for(PcapPacketPair pair: packetList) {
+////                            System.out.println(PrintUtils.toCsv(pair, dnsMap));
+////                            pwOn.println(PrintUtils.toCsv(pair, dnsMap));
+////                        }
+////                    }
+////                }
+////            }
+////        }
+////        pwOn.close();
+////
+////        System.out.println("==== OFF ====");
+////        // Print out all the pairs into a file for ON events
+////        File fileOffEvents = new File(offPairsPath);
+////        PrintWriter pwOff = null;
+////        try {
+////            pwOff = new PrintWriter(fileOffEvents);
+////        } catch(Exception ex) {
+////            ex.printStackTrace();
+////        }
+////        for(Map.Entry<String, Map<String, List<Conversation>>> entry : offs.entrySet()) {
+////            Map<String, List<Conversation>> seqsToConvs = entry.getValue();
+////            for(Map.Entry<String, List<Conversation>> entryConv : seqsToConvs.entrySet()) {
+////                List<Conversation> listConv = entryConv.getValue();
+////                // Just get the first Conversation because all Conversations in this group
+////                // should have the same pairs of Application Data.
+////                for(Conversation conv : listConv) {
+////                    // Process only if it is a TLS packet
+////                    if (conv.isTls()) {
+////                        List<PcapPacketPair> tlsAppDataList = TcpConversationUtils.extractTlsAppDataPacketPairs(conv);
+////                        for(PcapPacketPair pair: tlsAppDataList) {
+////                            System.out.println(PrintUtils.toCsv(pair, dnsMap));
+////                            pwOff.println(PrintUtils.toCsv(pair, dnsMap));
+////                        }
+////                    } else { // Non-TLS conversations
+////                        List<PcapPacketPair> packetList = TcpConversationUtils.extractPacketPairs(conv);
+////                        for (PcapPacketPair pair : packetList) {
+////                            System.out.println(PrintUtils.toCsv(pair, dnsMap));
+////                            pwOff.println(PrintUtils.toCsv(pair, dnsMap));
+////                        }
+////                    }
+////                }
+////            }
+////        }
+////        pwOff.close();
+//
+//
+//        // ================================================ CLUSTERING ================================================
+//        // Note: no need to use the more convoluted on/off maps; can simply use the UserAction->List<Conversation> map
+//        // when don't care about hostnames and sequences (see comment earlier).
+////        List<Conversation> onConversations = userActionToConversations.entrySet().stream().
+////                filter(e -> e.getKey().getType() == Type.TOGGLE_ON). // drop all OFF events from stream
+////                map(e -> e.getValue()). // no longer interested in the UserActions
+////                flatMap(List::stream). // flatten List<List<T>> to a List<T>
+////                collect(Collectors.toList());
+////        List<Conversation> offConversations = userActionToConversations.entrySet().stream().
+////                filter(e -> e.getKey().getType() == Type.TOGGLE_OFF).
+////                map(e -> e.getValue()).
+////                flatMap(List::stream).
+////                collect(Collectors.toList());
+////        //Collections.sort(onConversations, (c1, c2) -> c1.getPackets().)
+////
+////        List<PcapPacketPair> onPairs = onConversations.stream().
+////                map(c -> c.isTls() ? TcpConversationUtils.extractTlsAppDataPacketPairs(c) :
+////                        TcpConversationUtils.extractPacketPairs(c)).
+////                flatMap(List::stream). // flatten List<List<>> to List<>
+////                collect(Collectors.toList());
+////        List<PcapPacketPair> offPairs = offConversations.stream().
+////                map(c -> c.isTls() ? TcpConversationUtils.extractTlsAppDataPacketPairs(c) :
+////                        TcpConversationUtils.extractPacketPairs(c)).
+////                flatMap(List::stream). // flatten List<List<>> to List<>
+////                collect(Collectors.toList());
+////        // Note: need to update the DnsMap of all PcapPacketPairs if we want to use the IP/hostname-sensitive distance.
+////        Stream.concat(Stream.of(onPairs), Stream.of(offPairs)).flatMap(List::stream).forEach(p -> p.setDnsMap(dnsMap));
+////        // Perform clustering on conversation logged as part of all ON events.
+//////        DBSCANClusterer<PcapPacketPair> onClusterer = new DBSCANClusterer<>(10.0, 45);
+////        DBSCANClusterer<PcapPacketPair> onClusterer = new DBSCANClusterer<>(2, 2);
+////        //DBSCANClusterer<PcapPacketPair> onClusterer = new DBSCANClusterer<>(10.0, 10);
+////        List<Cluster<PcapPacketPair>> onClusters = onClusterer.cluster(onPairs);
+////        // Perform clustering on conversation logged as part of all OFF events.
+//////        DBSCANClusterer<PcapPacketPair> offClusterer = new DBSCANClusterer<>(10.0, 45);
+////        DBSCANClusterer<PcapPacketPair> offClusterer = new DBSCANClusterer<>(2, 2);
+////        //DBSCANClusterer<PcapPacketPair> offClusterer = new DBSCANClusterer<>(10.0, 10);
+////        List<Cluster<PcapPacketPair>> offClusters = offClusterer.cluster(offPairs);
+////        // Sort the conversations as reference
+////        List<Conversation> sortedAllConversation = TcpConversationUtils.sortConversationList(allConversations);
+////        // Output clusters
+////        System.out.println("========================================");
+////        System.out.println("       Clustering results for ON        ");
+////        System.out.println("       Number of clusters: " + onClusters.size());
+////        int count = 0;
+////        List<List<List<PcapPacket>>> ppListOfListReadOn = new ArrayList<>();
+////        List<List<List<PcapPacket>>> ppListOfListListOn = new ArrayList<>();
+////        for (Cluster<PcapPacketPair> c : onClusters) {
+////            System.out.println(String.format("<<< Cluster #%02d (%03d points) >>>", ++count, c.getPoints().size()));
+////            System.out.print(PrintUtils.toSummaryString(c));
+////            if(c.getPoints().size() > 45 && c.getPoints().size() < 55) {
+////            //if(c.getPoints().size() > 25) {
+////                // Print to file
+////                List<List<PcapPacket>> ppListOfList = PcapPacketUtils.clusterToListOfPcapPackets(c);
+////                ppListOfListListOn.add(ppListOfList);
+////            }
+////        }
+////        // TODO: Merging test
+////        ppListOfListListOn = PcapPacketUtils.mergeSignatures(ppListOfListListOn, sortedAllConversation);
+////        // TODO: Need to remove sequence 550 567 for Blossom phone side since it is not a good signature (overlap)!
+//////        PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 1);
+////        // TODO: Need to remove sequence 69 296 for Blossom device side since it is not a good signature (overlap)!
+//////        PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 2);
+////        // TODO: Need to remove sequence number 2 for ST plug since it is not a good signature!
+////        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 2);
+////        // TODO: Need to remove sequence number 0 for Arlo Camera since it is not a good signature!
+////        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 0);
+////        // TODO: Need to remove sequence number 0 for TP-Link plug since it is not a good signature!
+////        // TODO: This sequence actually belongs to the local communication between the plug and the phone
+////        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOn, 0);
+////        ppListOfListListOn = PcapPacketUtils.sortSignatures(ppListOfListListOn);
+////        PcapPacketUtils.printSignatures(ppListOfListListOn);
+////        //count = 0;
+////        /*for (List<List<PcapPacket>> ll : ppListOfListListOn) {
+////            PrintUtils.serializeClustersIntoFile("./onSignature" + ++count + ".sig", ll);
+////            ppListOfListReadOn.add(PrintUtils.deserializeClustersFromFile("./onSignature" + count + ".sig"));
+////        }*/
+////        PrintUtils.serializeSignatureIntoFile("./onSignature.sig", ppListOfListListOn);
+////        ppListOfListReadOn = PrintUtils.deserializeSignatureFromFile("./onSignature.sig");
+////
+////        System.out.println("========================================");
+////        System.out.println("       Clustering results for OFF       ");
+////        System.out.println("       Number of clusters: " + offClusters.size());
+////        count = 0;
+////        List<List<List<PcapPacket>>> ppListOfListReadOff = new ArrayList<>();
+////        List<List<List<PcapPacket>>> ppListOfListListOff = new ArrayList<>();
+////        for (Cluster<PcapPacketPair> c : offClusters) {
+////            System.out.println(String.format("<<< Cluster #%03d (%06d points) >>>", ++count, c.getPoints().size()));
+////            System.out.print(PrintUtils.toSummaryString(c));
+////            if(c.getPoints().size() > 45 && c.getPoints().size() < 55) {
+////            //if(c.getPoints().size() > 25) {
+////                // Print to file
+////                List<List<PcapPacket>> ppListOfList = PcapPacketUtils.clusterToListOfPcapPackets(c);
+////                ppListOfListListOff.add(ppListOfList);
+////            }
+////        }
+////        // TODO: Merging test
+////        ppListOfListListOff = PcapPacketUtils.mergeSignatures(ppListOfListListOff, sortedAllConversation);
+////        // TODO: Need to remove sequence 69 296 for Blossom device side since it is not a good signature (overlap)!
+//////        PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 3);
+////        // TODO: Need to remove sequence number 1 for Nest Thermostat since it is not a good signature!
+////        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 1);
+////        // TODO: Need to remove sequence number 0 for Arlo Camera since it is not a good signature!
+//////        PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 1);
+////        // TODO: Need to remove sequence number 2 for ST plug since it is not a good signature!
+////        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 2);
+////        // TODO: Need to remove sequence number 0 for TP-Link plug since it is not a good signature!
+////        // TODO: This sequence actually belongs to the local communication between the plug and the phone
+////        //PcapPacketUtils.removeSequenceFromSignature(ppListOfListListOff, 0);
+////        ppListOfListListOff = PcapPacketUtils.sortSignatures(ppListOfListListOff);
+////        PcapPacketUtils.printSignatures(ppListOfListListOff);
+////        //count = 0;
+////        /*for (List<List<PcapPacket>> ll : ppListOfListListOff) {
+////            PrintUtils.serializeClustersIntoFile("./offSignature" + ++count + ".sig", ll);
+////            ppListOfListReadOff.add(PrintUtils.deserializeClustersFromFile("./offSignature" + count + ".sig"));
+////        }*/
+////        PrintUtils.serializeSignatureIntoFile("./offSignature.sig", ppListOfListListOff);
+////        ppListOfListReadOff = PrintUtils.deserializeSignatureFromFile("./offSignature.sig");
+////        System.out.println("========================================");
+//        // ============================================================================================================
+//
+//        // TODO: This part is just for DBSCAN sensitivity experiment
+//        // TODO: This part is just for DBSCAN sensitivity experiment
+//        // TODO: This part is just for DBSCAN sensitivity experiment
+//        // TODO: This part is just for DBSCAN sensitivity experiment
+//        // TODO: This part is just for DBSCAN sensitivity experiment
 //        List<Conversation> onConversations = userActionToConversations.entrySet().stream().
 //                filter(e -> e.getKey().getType() == Type.TOGGLE_ON). // drop all OFF events from stream
 //                map(e -> e.getValue()). // no longer interested in the UserActions
@@ -790,7 +793,7 @@ public class Main {
 //
 //        double eps = 10; // loop from eps 1-10
 //        int minPts = 50; // loop from minPts 30-50
-//        for(int epsCount = 1; epsCount <= eps; epsCount++) {
+//        for(int epsCount = 7; epsCount <= eps; epsCount++) {
 //            for(int minPtsCount = 30; minPtsCount <= minPts; minPtsCount++) {
 //                System.out.println("Eps: " + epsCount + " --- minPts: " + minPtsCount);
 //                DBSCANClusterer<PcapPacketPair> onClusterer = new DBSCANClusterer<>(epsCount, minPtsCount);
@@ -807,7 +810,7 @@ public class Main {
 //                List<List<List<PcapPacket>>> ppListOfListListOn = new ArrayList<>();
 //                for (Cluster<PcapPacketPair> c : onClusters) {
 //                    System.out.println(String.format("<<< Cluster #%02d (%03d points) >>>", ++count, c.getPoints().size()));
-//                    System.out.print(PrintUtils.toSummaryString(c));
+////                    System.out.print(PrintUtils.toSummaryString(c));
 //                    if (c.getPoints().size() > 45 && c.getPoints().size() < 55) {
 ////                        if(c.getPoints().size() > 25) {
 //                        // Print to file