From 2669e2cc60528c20797440a8a5b3998bdcd25682 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 26 Feb 2018 11:49:26 -0500 Subject: [PATCH 01/41] Initial changes. --- .../ingestmodule/Bundle.properties | 2 + .../ingestmodule/IngestModule.java | 46 ++++---- .../ingestmodule/IngestModuleFactory.java | 28 ++++- .../ingestmodule/IngestSettings.java | 71 ++++++++++++ .../ingestmodule/IngestSettingsPanel.form | 70 ++++++++++++ .../ingestmodule/IngestSettingsPanel.java | 101 ++++++++++++++++++ 6 files changed, 297 insertions(+), 21 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties create mode 100755 Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java create mode 100755 Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form create mode 100755 Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties new file mode 100755 index 0000000000..c903c40421 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties @@ -0,0 +1,2 @@ +IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings +IngestSettingsPanel.ignorePreviousNotableItemsCheckbox.text=Ignore previously seen notable items. diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 09f3c63449..b3bf0505e6 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -55,9 +55,11 @@ import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListen */ @Messages({"IngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)", "IngestModule.prevCaseComment.text=Previous Case: "}) -class IngestModule implements FileIngestModule { +final class IngestModule implements FileIngestModule { - private final static Logger LOGGER = Logger.getLogger(IngestModule.class.getName()); + static final boolean DEFAULT_IGNORE_PREVIOUS_NOTABLE_ITEMS = false; + + private final static Logger logger = Logger.getLogger(IngestModule.class.getName()); private final IngestServices services = IngestServices.getInstance(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); private static final IngestModuleReferenceCounter warningMsgRefCounter = new IngestModuleReferenceCounter(); @@ -66,6 +68,12 @@ class IngestModule implements FileIngestModule { private CorrelationDataSource eamDataSource; private Blackboard blackboard; private CorrelationAttribute.Type filesType; + + private final boolean ignorePreviousNotableItems; + + IngestModule(IngestSettings settings) { + ignorePreviousNotableItems = settings.isIgnorePreviousNotableItems(); + } @Override public ProcessResult process(AbstractFile af) { @@ -89,7 +97,7 @@ class IngestModule implements FileIngestModule { try { dbManager = EamDb.getInstance(); } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); + logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); return ProcessResult.ERROR; } @@ -113,7 +121,7 @@ class IngestModule implements FileIngestModule { postCorrelatedBadFileToBlackboard(af, caseDisplayNames); } } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS return ProcessResult.ERROR; } } @@ -131,7 +139,7 @@ class IngestModule implements FileIngestModule { eamArtifact.addInstance(cefi); dbManager.prepareBulkArtifact(eamArtifact); } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error adding artifact to bulk artifacts.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error adding artifact to bulk artifacts.", ex); // NON-NLS return ProcessResult.ERROR; } @@ -148,19 +156,19 @@ class IngestModule implements FileIngestModule { try { dbManager = EamDb.getInstance(); } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); + logger.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); return; } try { dbManager.bulkInsertArtifacts(); } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error doing bulk insert of artifacts.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error doing bulk insert of artifacts.", ex); // NON-NLS } try { Long count = dbManager.getCountArtifactInstancesByCaseDataSource(eamCase.getCaseUUID(), eamDataSource.getDeviceID()); - LOGGER.log(Level.INFO, "{0} artifacts in db for case: {1} ds:{2}", new Object[]{count, eamCase.getDisplayName(), eamDataSource.getName()}); // NON-NLS + logger.log(Level.INFO, "{0} artifacts in db for case: {1} ds:{2}", new Object[]{count, eamCase.getDisplayName(), eamDataSource.getName()}); // NON-NLS } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error counting artifacts.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error counting artifacts.", ex); // NON-NLS } // TODO: once we implement shared cache, if refCounter is 1, then submit data in bulk. @@ -193,7 +201,7 @@ class IngestModule implements FileIngestModule { // Don't allow sqlite central repo databases to be used for multi user cases if ((Case.getCurrentCase().getCaseType() == Case.CaseType.MULTI_USER_CASE) && (EamDbPlatformEnum.getSelectedPlatform() == EamDbPlatformEnum.SQLITE)) { - LOGGER.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository."); + logger.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository."); throw new IngestModuleException("Cannot run on a multi-user case with a SQLite central repository."); // NON-NLS } jobId = context.getJobId(); @@ -202,14 +210,14 @@ class IngestModule implements FileIngestModule { try { centralRepoDb = EamDb.getInstance(); } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error connecting to central repository database.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error connecting to central repository database.", ex); // NON-NLS throw new IngestModuleException("Error connecting to central repository database.", ex); // NON-NLS } try { filesType = centralRepoDb.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS throw new IngestModuleException("Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS } Case autopsyCase = Case.getCurrentCase(); @@ -223,7 +231,7 @@ class IngestModule implements FileIngestModule { try { eamCase = centralRepoDb.newCase(autopsyCase); } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error creating new case in ingest module start up.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error creating new case in ingest module start up.", ex); // NON-NLS throw new IngestModuleException("Error creating new case in ingest module start up.", ex); // NON-NLS } } @@ -231,7 +239,7 @@ class IngestModule implements FileIngestModule { try { eamDataSource = CorrelationDataSource.fromTSKDataSource(eamCase, context.getDataSource()); } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error getting data source info.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error getting data source info.", ex); // NON-NLS throw new IngestModuleException("Error getting data source info.", ex); // NON-NLS } // TODO: once we implement a shared cache, load/init it here w/ syncronized and define reference counter @@ -245,7 +253,7 @@ class IngestModule implements FileIngestModule { centralRepoDb.newDataSource(eamDataSource); } } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error adding data source to Central Repository.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error adding data source to Central Repository.", ex); // NON-NLS throw new IngestModuleException("Error adding data source to Central Repository.", ex); // NON-NLS } @@ -268,7 +276,7 @@ class IngestModule implements FileIngestModule { // index the artifact for keyword search blackboard.indexArtifact(tifArtifact); } catch (Blackboard.BlackboardException ex) { - LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS } // send inbox message @@ -277,9 +285,9 @@ class IngestModule implements FileIngestModule { // fire event to notify UI of this new artifact services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT)); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS + logger.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS } catch (IllegalStateException ex) { - LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS + logger.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java index ed3d4f0915..a0ec1f4329 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.centralrepository.optionspanel.GlobalSettingsPanel; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; /** * Factory for Central Repository ingest modules @@ -34,8 +35,13 @@ import org.sleuthkit.autopsy.centralrepository.optionspanel.GlobalSettingsPanel; "IngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation"}) public class IngestModuleFactory extends IngestModuleFactoryAdapter { - private static final String VERSION_NUMBER = "0.8.0"; + private static final String VERSION_NUMBER = "0.9.0"; + /** + * Get the name of the module. + * + * @return The module name. + */ static String getModuleName() { return Bundle.IngestModuleFactory_ingestmodule_name(); } @@ -76,5 +82,23 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter { globalOptionsPanel.load(); return globalOptionsPanel; } + + @Override + public IngestModuleIngestJobSettings getDefaultIngestJobSettings() { + return new IngestSettings(); + } + + @Override + public boolean hasIngestJobSettingsPanel() { + return true; + } + + @Override + public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { + if (!(settings instanceof IngestSettings)) { + throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings"); + } + return new IngestSettingsPanel((IngestSettings) settings); + } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java new file mode 100755 index 0000000000..e69e625b85 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java @@ -0,0 +1,71 @@ +/* + * Central Repository + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.ingestmodule; + +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; + +/** + * Ingest job settings for the Correlation Engine module. + */ +final class IngestSettings implements IngestModuleIngestJobSettings { + + private static final long serialVersionUID = 1L; + + private boolean ignorePreviousNotableItems; + + /** + * Instantiate the ingest job settings with default values. + */ + IngestSettings() { + this.ignorePreviousNotableItems = IngestModule.DEFAULT_IGNORE_PREVIOUS_NOTABLE_ITEMS; + } + + /** + * Instantiate the ingest job settings. + * + * @param ignorePreviousNotableItems Ignore previously seen notable items. + */ + IngestSettings(boolean ignorePreviousNotableItems) { + this.ignorePreviousNotableItems = ignorePreviousNotableItems; + } + + @Override + public long getVersionNumber() { + return serialVersionUID; + } + + /** + * Are previously identified notable items ignored? + * + * @return True if ignored; otherwise false. + */ + boolean isIgnorePreviousNotableItems() { + return ignorePreviousNotableItems; + } + + /** + * Consider or ignore previously identified notable items. + * + * @param ignorePreviousNotableItems Are previously identified notable items + * ignored? + */ + void setIgnorePreviousNotableItems(boolean ignorePreviousNotableItems) { + this.ignorePreviousNotableItems = ignorePreviousNotableItems; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form new file mode 100755 index 0000000000..c60abee00d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form @@ -0,0 +1,70 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java new file mode 100755 index 0000000000..77e04d1528 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java @@ -0,0 +1,101 @@ +/* + * Central Repository + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.ingestmodule; + +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; + +/** + * Ingest job settings panel for the Correlation Engine module. + */ +final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { + + /** + * Creates new form IngestModulePanel + */ + public IngestSettingsPanel(IngestSettings settings) { + initComponents(); + customizeComponents(settings); + } + + /** + * Update components with values from the ingest job settings. + * + * @param settings The ingest job settings. + */ + private void customizeComponents(IngestSettings settings) { + ignorePreviousNotableItemsCheckbox.setSelected(settings.isIgnorePreviousNotableItems()); + } + + @Override + public IngestModuleIngestJobSettings getSettings() { + return new IngestSettings(ignorePreviousNotableItemsCheckbox.isSelected()); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + ingestSettingsLabel = new javax.swing.JLabel(); + ignorePreviousNotableItemsCheckbox = new javax.swing.JCheckBox(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + ingestSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestSettingsLabel, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ingestSettingsLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(ignorePreviousNotableItemsCheckbox, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ignorePreviousNotableItemsCheckbox.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(ignorePreviousNotableItemsCheckbox)) + .addComponent(ingestSettingsLabel)) + .addContainerGap(83, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(ingestSettingsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(ignorePreviousNotableItemsCheckbox) + .addContainerGap(245, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JCheckBox ignorePreviousNotableItemsCheckbox; + private javax.swing.JLabel ingestSettingsLabel; + // End of variables declaration//GEN-END:variables + +} From bd1f6346a13f8db591295db8a8603eea3ddf6d6a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 26 Feb 2018 13:13:19 -0500 Subject: [PATCH 02/41] Added flag toggle. --- .../ingestmodule/IngestModule.java | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index b3bf0505e6..49a89555a0 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -23,10 +23,12 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.ingest.FileIngestModule; @@ -48,6 +50,7 @@ import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener; +import org.sleuthkit.datamodel.ContentTag; /** * Ingest module for inserting entries into the Central Repository database on @@ -76,7 +79,7 @@ final class IngestModule implements FileIngestModule { } @Override - public ProcessResult process(AbstractFile af) { + public ProcessResult process(AbstractFile abstractFile) { if (EamDb.isEnabled() == false) { /* * Not signaling an error for now. This is a workaround for the way @@ -86,10 +89,22 @@ final class IngestModule implements FileIngestModule { */ return ProcessResult.OK; } + + if(ignorePreviousNotableItems) { //DLG: + CorrelationAttribute attribute = EamArtifactUtil.getCorrelationAttributeFromContent(abstractFile, TskData.FileKnown.BAD, null); //DLG: + //DLG: try { + //DLG: List contentTagsList = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(abstractFile); + //DLG: ContentTag tag = contentTagsList.get(0); + //DLG: tag.getId(); + //DLG: } catch (TskCoreException ex) { + //DLG: Exceptions.printStackTrace(ex); //DLG: + //DLG: return ProcessResult.ERROR; + //DLG: } + } //DLG: blackboard = Case.getCurrentCase().getServices().getBlackboard(); - if (!EamArtifactUtil.isValidCentralRepoFile(af)) { + if (!EamArtifactUtil.isValidCentralRepoFile(abstractFile)) { return ProcessResult.OK; } @@ -107,18 +122,18 @@ final class IngestModule implements FileIngestModule { } // get the hash because we're going to correlate it - String md5 = af.getMd5Hash(); + String md5 = abstractFile.getMd5Hash(); if ((md5 == null) || (HashUtility.isNoDataMd5(md5))) { return ProcessResult.OK; } /* Search the central repo to see if this file was previously * marked as being bad. Create artifact if it was. */ - if (af.getKnown() != TskData.FileKnown.KNOWN) { + if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && !ignorePreviousNotableItems) { try { List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); if (!caseDisplayNames.isEmpty()) { - postCorrelatedBadFileToBlackboard(af, caseDisplayNames); + postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNames); } } catch (EamDbException ex) { logger.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS @@ -132,7 +147,7 @@ final class IngestModule implements FileIngestModule { CorrelationAttributeInstance cefi = new CorrelationAttributeInstance( eamCase, eamDataSource, - af.getParentPath() + af.getName(), + abstractFile.getParentPath() + abstractFile.getName(), null, TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database. ); From a569657a05e09f01a3cd795c2ba5a937d8f6dacb Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 26 Feb 2018 13:53:49 -0500 Subject: [PATCH 03/41] Fixed compile issues with panel. --- .../ingestmodule/IngestModuleFactory.java | 4 ++-- .../ingestmodule/IngestSettingsPanel.form | 7 ------- .../ingestmodule/IngestSettingsPanel.java | 8 ++------ 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java index a0ec1f4329..e9c9a5a88f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java @@ -67,8 +67,8 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter { } @Override - public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) { - return new IngestModule(); + public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { + return new IngestModule((IngestSettings) settings); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form index c60abee00d..fbcf49c00d 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form @@ -1,13 +1,6 @@
- - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java index 77e04d1528..e7b559e0e5 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java @@ -60,15 +60,13 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { ingestSettingsLabel = new javax.swing.JLabel(); ignorePreviousNotableItemsCheckbox = new javax.swing.JCheckBox(); - setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); - ingestSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(ingestSettingsLabel, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ingestSettingsLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(ignorePreviousNotableItemsCheckbox, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ignorePreviousNotableItemsCheckbox.text")); // NOI18N - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() @@ -89,8 +87,6 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { .addComponent(ignorePreviousNotableItemsCheckbox) .addContainerGap(245, Short.MAX_VALUE)) ); - - pack(); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables From a518eb721c879e9e51d1c5efa0340b3e50dcca42 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 27 Feb 2018 15:21:34 -0500 Subject: [PATCH 04/41] Cleanup. --- .../ingestmodule/IngestModule.java | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 49a89555a0..041c6b9d85 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -71,9 +71,9 @@ final class IngestModule implements FileIngestModule { private CorrelationDataSource eamDataSource; private Blackboard blackboard; private CorrelationAttribute.Type filesType; - + private final boolean ignorePreviousNotableItems; - + IngestModule(IngestSettings settings) { ignorePreviousNotableItems = settings.isIgnorePreviousNotableItems(); } @@ -89,18 +89,6 @@ final class IngestModule implements FileIngestModule { */ return ProcessResult.OK; } - - if(ignorePreviousNotableItems) { //DLG: - CorrelationAttribute attribute = EamArtifactUtil.getCorrelationAttributeFromContent(abstractFile, TskData.FileKnown.BAD, null); //DLG: - //DLG: try { - //DLG: List contentTagsList = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(abstractFile); - //DLG: ContentTag tag = contentTagsList.get(0); - //DLG: tag.getId(); - //DLG: } catch (TskCoreException ex) { - //DLG: Exceptions.printStackTrace(ex); //DLG: - //DLG: return ProcessResult.ERROR; - //DLG: } - } //DLG: blackboard = Case.getCurrentCase().getServices().getBlackboard(); @@ -127,8 +115,10 @@ final class IngestModule implements FileIngestModule { return ProcessResult.OK; } - /* Search the central repo to see if this file was previously - * marked as being bad. Create artifact if it was. */ + /* + * Search the central repo to see if this file was previously marked as + * being bad. Create artifact if it was. + */ if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && !ignorePreviousNotableItems) { try { List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); @@ -149,7 +139,7 @@ final class IngestModule implements FileIngestModule { eamDataSource, abstractFile.getParentPath() + abstractFile.getName(), null, - TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database. + TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database. ); eamArtifact.addInstance(cefi); dbManager.prepareBulkArtifact(eamArtifact); @@ -250,7 +240,7 @@ final class IngestModule implements FileIngestModule { throw new IngestModuleException("Error creating new case in ingest module start up.", ex); // NON-NLS } } - + try { eamDataSource = CorrelationDataSource.fromTSKDataSource(eamCase, context.getDataSource()); } catch (EamDbException ex) { From 7553c3418c5a41794195fa09a2b24754a7a29ae9 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 27 Feb 2018 16:16:21 -0500 Subject: [PATCH 05/41] Cleanup. --- .../autopsy/centralrepository/ingestmodule/IngestModule.java | 3 --- .../centralrepository/ingestmodule/IngestSettingsPanel.java | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 041c6b9d85..829f0b006e 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -23,12 +23,10 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.Blackboard; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.ingest.FileIngestModule; @@ -50,7 +48,6 @@ import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener; -import org.sleuthkit.datamodel.ContentTag; /** * Ingest module for inserting entries into the Central Repository database on diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java index e7b559e0e5..f7afdec94e 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java @@ -27,7 +27,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { /** - * Creates new form IngestModulePanel + * Creates new form IngestSettingsPanel */ public IngestSettingsPanel(IngestSettings settings) { initComponents(); From 32209514efd13b34421dbd4da836d718df493cc1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 5 Mar 2018 10:13:22 -0500 Subject: [PATCH 06/41] Revised. --- .../eventlisteners/CaseEventListener.java | 4 +- .../eventlisteners/IngestEventsListener.java | 60 +++++++++++++++---- .../ingestmodule/Bundle.properties | 2 +- .../ingestmodule/IngestModule.java | 22 +++++-- .../ingestmodule/IngestSettings.java | 28 ++++----- .../ingestmodule/IngestSettingsPanel.form | 12 ++-- .../ingestmodule/IngestSettingsPanel.java | 16 ++--- 7 files changed, 97 insertions(+), 47 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index b053d9df17..807cfef4bd 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.coreutils.ThreadUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -464,6 +463,7 @@ final class CaseEventListener implements PropertyChangeListener { if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) { Case curCase = (Case) event.getNewValue(); IngestEventsListener.resetCeModuleInstanceCount(); + IngestEventsListener.resetCorrelationModulesFlaggingNotableCount(); if (!EamDb.isEnabled()) { return; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 0877bc1685..2f1efd3785 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2017 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -56,7 +56,8 @@ public class IngestEventsListener { private static final Logger LOGGER = Logger.getLogger(CorrelationAttribute.class.getName()); final Collection recentlyAddedCeArtifacts = new LinkedHashSet<>(); - private static int ceModuleInstanceCount = 0; + private static int correlationModuleInstanceCount = 0; + private static int correlationModulesFlaggingNotableCount = 0; private final ExecutorService jobProcessingExecutor; private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d"; private final PropertyChangeListener pcl1 = new IngestModuleEventListener(); @@ -87,21 +88,20 @@ public class IngestEventsListener { } /** - * Enable this IngestEventsListener to add contents to the Correlation - * Engine. - * + * Increase the number of IngestEventsListeners adding contents to the + * Correlation Engine. */ public synchronized static void incrementCorrelationEngineModuleCount() { - ceModuleInstanceCount++; //Should be called once in the Correlation Engine module's startup method. + correlationModuleInstanceCount++; //Should be called once in the Correlation Engine module's startup method. } /** - * Disable this IngestEventsListener from adding contents to the Correlation - * Engine. + * Decrease the number of IngestEventsListeners adding contents to the + * Correlation Engine. */ public synchronized static void decrementCorrelationEngineModuleCount() { if (getCeModuleInstanceCount() > 0) { //prevent it ingestJobCounter from going negative - ceModuleInstanceCount--; //Should be called once in the Correlation Engine module's shutdown method. + correlationModuleInstanceCount--; //Should be called once in the Correlation Engine module's shutdown method. } } @@ -110,7 +110,7 @@ public class IngestEventsListener { * is being run during injest to 0. */ synchronized static void resetCeModuleInstanceCount() { - ceModuleInstanceCount = 0; //called when a case is opened in case for some reason counter was not reset + correlationModuleInstanceCount = 0; //called when a case is opened in case for some reason counter was not reset } /** @@ -120,7 +120,43 @@ public class IngestEventsListener { * @return boolean True for Correlation Engine enabled, False for disabled */ private synchronized static int getCeModuleInstanceCount() { - return ceModuleInstanceCount; + return correlationModuleInstanceCount; + } + + /** + * Increase the number of IngestEventsListeners adding contents to the + * Correlation Engine with notable item flagging enabled. + */ + public synchronized static void incrementCorrelationModulesFlaggingNotableCount() { + correlationModulesFlaggingNotableCount++; + } + + /** + * Decrease the number of IngestEventsListeners adding contents to the + * Correlation Engine with notable item flagging enabled. + */ + public synchronized static void decrementCorrelationModulesFlaggingNotableCount() { + if (correlationModulesFlaggingNotableCount > 0) { + correlationModulesFlaggingNotableCount--; + } + } + + /** + * Reset the counter which keeps track of if the Correlation Engine Module + * is being run during injest and flagging notable items to 0. + */ + synchronized static void resetCorrelationModulesFlaggingNotableCount() { + correlationModulesFlaggingNotableCount = 0; + } + + /** + * Wether or not the Correlation Engine Module is enabled for any of the + * currently running ingest jobs and flagging notable items. + * + * @return boolean True for Correlation Engine enabled, False for disabled + */ + private synchronized static int getCorrelationModulesFlaggingNotableCount() { + return correlationModulesFlaggingNotableCount; } @NbBundle.Messages({"IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)", @@ -219,7 +255,7 @@ public class IngestEventsListener { @Override public void run() { - if (!EamDb.isEnabled()) { + if (!EamDb.isEnabled() || getCorrelationModulesFlaggingNotableCount() == 0) { return; } final ModuleDataEvent mde = (ModuleDataEvent) event.getOldValue(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties index c903c40421..a525713f7c 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties @@ -1,2 +1,2 @@ IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings -IngestSettingsPanel.ignorePreviousNotableItemsCheckbox.text=Ignore previously seen notable items. +IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 829f0b006e..20fbf86753 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -57,7 +57,7 @@ import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListen "IngestModule.prevCaseComment.text=Previous Case: "}) final class IngestModule implements FileIngestModule { - static final boolean DEFAULT_IGNORE_PREVIOUS_NOTABLE_ITEMS = false; + static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS = true; private final static Logger logger = Logger.getLogger(IngestModule.class.getName()); private final IngestServices services = IngestServices.getInstance(); @@ -69,10 +69,14 @@ final class IngestModule implements FileIngestModule { private Blackboard blackboard; private CorrelationAttribute.Type filesType; - private final boolean ignorePreviousNotableItems; + private final boolean flagTaggedNotableItems; + /** + * //DLG: + * @param settings + */ IngestModule(IngestSettings settings) { - ignorePreviousNotableItems = settings.isIgnorePreviousNotableItems(); + flagTaggedNotableItems = settings.isFlagTaggedNotableItems(); } @Override @@ -116,7 +120,7 @@ final class IngestModule implements FileIngestModule { * Search the central repo to see if this file was previously marked as * being bad. Create artifact if it was. */ - if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && !ignorePreviousNotableItems) { + if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) { try { List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); if (!caseDisplayNames.isEmpty()) { @@ -151,6 +155,11 @@ final class IngestModule implements FileIngestModule { @Override public void shutDown() { IngestEventsListener.decrementCorrelationEngineModuleCount(); + + if (flagTaggedNotableItems) { + IngestEventsListener.decrementCorrelationModulesFlaggingNotableCount(); + } + if ((EamDb.isEnabled() == false) || (eamCase == null) || (eamDataSource == null)) { return; } @@ -185,6 +194,11 @@ final class IngestModule implements FileIngestModule { @Override public void startUp(IngestJobContext context) throws IngestModuleException { IngestEventsListener.incrementCorrelationEngineModuleCount(); + + if (flagTaggedNotableItems) { + IngestEventsListener.incrementCorrelationModulesFlaggingNotableCount(); + } + if (EamDb.isEnabled() == false) { /* * Not throwing the customary exception for now. This is a diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java index e69e625b85..32ab9e9f2d 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java @@ -27,22 +27,22 @@ final class IngestSettings implements IngestModuleIngestJobSettings { private static final long serialVersionUID = 1L; - private boolean ignorePreviousNotableItems; + private boolean flagTaggedNotableItems; /** * Instantiate the ingest job settings with default values. */ IngestSettings() { - this.ignorePreviousNotableItems = IngestModule.DEFAULT_IGNORE_PREVIOUS_NOTABLE_ITEMS; + this.flagTaggedNotableItems = IngestModule.DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS; } /** * Instantiate the ingest job settings. * - * @param ignorePreviousNotableItems Ignore previously seen notable items. + * @param flagTaggedNotableItems Flag previously tagged notable items. */ - IngestSettings(boolean ignorePreviousNotableItems) { - this.ignorePreviousNotableItems = ignorePreviousNotableItems; + IngestSettings(boolean flagTaggedNotableItems) { + this.flagTaggedNotableItems = flagTaggedNotableItems; } @Override @@ -51,21 +51,21 @@ final class IngestSettings implements IngestModuleIngestJobSettings { } /** - * Are previously identified notable items ignored? + * Are previously tagged notable items to be flagged? * - * @return True if ignored; otherwise false. + * @return True if flagging; otherwise false. */ - boolean isIgnorePreviousNotableItems() { - return ignorePreviousNotableItems; + boolean isFlagTaggedNotableItems() { + return flagTaggedNotableItems; } /** - * Consider or ignore previously identified notable items. + * Flag or ignore previously identified notable items. * - * @param ignorePreviousNotableItems Are previously identified notable items - * ignored? + * @param ignorePreviousNotableItems Are previously tagged notable items to + * be flagged? */ - void setIgnorePreviousNotableItems(boolean ignorePreviousNotableItems) { - this.ignorePreviousNotableItems = ignorePreviousNotableItems; + void setFlagTaggedNotableItems(boolean flagTaggedNotableItems) { + this.flagTaggedNotableItems = flagTaggedNotableItems; } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form index fbcf49c00d..2abe207b5a 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form @@ -1,6 +1,6 @@ - + @@ -21,11 +21,11 @@ - + - + @@ -35,7 +35,7 @@ - + @@ -52,10 +52,10 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java index f7afdec94e..46538f41c2 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java @@ -40,12 +40,12 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { * @param settings The ingest job settings. */ private void customizeComponents(IngestSettings settings) { - ignorePreviousNotableItemsCheckbox.setSelected(settings.isIgnorePreviousNotableItems()); + flagTaggedNotableItemsCheckbox.setSelected(settings.isFlagTaggedNotableItems()); } @Override public IngestModuleIngestJobSettings getSettings() { - return new IngestSettings(ignorePreviousNotableItemsCheckbox.isSelected()); + return new IngestSettings(flagTaggedNotableItemsCheckbox.isSelected()); } /** @@ -58,12 +58,12 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { private void initComponents() { ingestSettingsLabel = new javax.swing.JLabel(); - ignorePreviousNotableItemsCheckbox = new javax.swing.JCheckBox(); + flagTaggedNotableItemsCheckbox = new javax.swing.JCheckBox(); ingestSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(ingestSettingsLabel, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ingestSettingsLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(ignorePreviousNotableItemsCheckbox, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ignorePreviousNotableItemsCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(flagTaggedNotableItemsCheckbox, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -74,9 +74,9 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(ignorePreviousNotableItemsCheckbox)) + .addComponent(flagTaggedNotableItemsCheckbox)) .addComponent(ingestSettingsLabel)) - .addContainerGap(83, Short.MAX_VALUE)) + .addContainerGap(75, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -84,13 +84,13 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { .addContainerGap() .addComponent(ingestSettingsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(ignorePreviousNotableItemsCheckbox) + .addComponent(flagTaggedNotableItemsCheckbox) .addContainerGap(245, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JCheckBox ignorePreviousNotableItemsCheckbox; + private javax.swing.JCheckBox flagTaggedNotableItemsCheckbox; private javax.swing.JLabel ingestSettingsLabel; // End of variables declaration//GEN-END:variables From b9255ff9c60e676a54f0a31c1345ee0291ad424c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 6 Mar 2018 11:06:02 -0500 Subject: [PATCH 07/41] Added logic for comparing previous instances. --- .../ingestmodule/IngestModule.java | 33 ++++++++++++++++--- .../ingestmodule/IngestSettingsPanel.form | 2 +- .../ingestmodule/IngestSettingsPanel.java | 2 +- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 20fbf86753..3396eb8ff2 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -23,6 +23,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.casemodule.Case; @@ -120,14 +121,36 @@ final class IngestModule implements FileIngestModule { * Search the central repo to see if this file was previously marked as * being bad. Create artifact if it was. */ - if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) { + + if (abstractFile.getKnown() != TskData.FileKnown.KNOWN) { + CorrelationAttribute contentCorrelationAttribute = EamArtifactUtil.getCorrelationAttributeFromContent(abstractFile, TskData.FileKnown.BAD, null); try { - List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); - if (!caseDisplayNames.isEmpty()) { - postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNames); + List caseDisplayNamesList = EamDb.getInstance().getListCasesHavingArtifactInstancesKnownBad( + contentCorrelationAttribute.getCorrelationType(), contentCorrelationAttribute.getCorrelationValue()); + String currentCaseDisplayName = Case.getCurrentCase().getDisplayName(); + boolean taggedOutsideCurrentCase = false; + if (!caseDisplayNamesList.isEmpty()) { + for (String name : caseDisplayNamesList) { + if (!name.equals(currentCaseDisplayName)) { + taggedOutsideCurrentCase = true; + break; + } + } + } + + if(flagTaggedNotableItems || !taggedOutsideCurrentCase) { + try { + caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); + if (!caseDisplayNamesList.isEmpty()) { + postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList); + } + } catch (EamDbException ex) { + logger.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS + return ProcessResult.ERROR; + } } } catch (EamDbException ex) { - logger.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error searching database for content.", ex); // NON-NLS return ProcessResult.ERROR; } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form index 2abe207b5a..564031cb72 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form @@ -25,7 +25,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java index 46538f41c2..57d4f0a098 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java @@ -76,7 +76,7 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { .addGap(10, 10, 10) .addComponent(flagTaggedNotableItemsCheckbox)) .addComponent(ingestSettingsLabel)) - .addContainerGap(75, Short.MAX_VALUE)) + .addContainerGap(65, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) From 3d5ac054226f2fc926fc78044115422cf2005141 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 6 Mar 2018 17:33:14 -0500 Subject: [PATCH 08/41] Corrected logic to match story criteria. --- .../eventlisteners/IngestEventsListener.java | 12 ++++--- .../ingestmodule/IngestModule.java | 35 +++++-------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 2f1efd3785..f4e0fd9fbe 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -255,7 +255,7 @@ public class IngestEventsListener { @Override public void run() { - if (!EamDb.isEnabled() || getCorrelationModulesFlaggingNotableCount() == 0) { + if (!EamDb.isEnabled()) { return; } final ModuleDataEvent mde = (ModuleDataEvent) event.getOldValue(); @@ -276,10 +276,12 @@ public class IngestEventsListener { // query db for artifact instances having this TYPE/VALUE and knownStatus = "Bad". // if gettKnownStatus() is "Unknown" and this artifact instance was marked bad in a previous case, // create TSK_INTERESTING_ARTIFACT_HIT artifact on BB. - List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); - if (!caseDisplayNames.isEmpty()) { - postCorrelatedBadArtifactToBlackboard(bbArtifact, - caseDisplayNames); + if (getCorrelationModulesFlaggingNotableCount() > 0) { + List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); + if (!caseDisplayNames.isEmpty()) { + postCorrelatedBadArtifactToBlackboard(bbArtifact, + caseDisplayNames); + } } eamArtifacts.add(eamArtifact); } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 3396eb8ff2..d1362fce63 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -124,34 +124,17 @@ final class IngestModule implements FileIngestModule { if (abstractFile.getKnown() != TskData.FileKnown.KNOWN) { CorrelationAttribute contentCorrelationAttribute = EamArtifactUtil.getCorrelationAttributeFromContent(abstractFile, TskData.FileKnown.BAD, null); - try { - List caseDisplayNamesList = EamDb.getInstance().getListCasesHavingArtifactInstancesKnownBad( - contentCorrelationAttribute.getCorrelationType(), contentCorrelationAttribute.getCorrelationValue()); - String currentCaseDisplayName = Case.getCurrentCase().getDisplayName(); - boolean taggedOutsideCurrentCase = false; - if (!caseDisplayNamesList.isEmpty()) { - for (String name : caseDisplayNamesList) { - if (!name.equals(currentCaseDisplayName)) { - taggedOutsideCurrentCase = true; - break; - } + if (flagTaggedNotableItems) { + try { + List caseDisplayNamesList = EamDb.getInstance().getListCasesHavingArtifactInstancesKnownBad( + contentCorrelationAttribute.getCorrelationType(), contentCorrelationAttribute.getCorrelationValue()); + if (!caseDisplayNamesList.isEmpty()) { + postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList); } + } catch (EamDbException ex) { + logger.log(Level.SEVERE, "Error searching database for content.", ex); // NON-NLS + return ProcessResult.ERROR; } - - if(flagTaggedNotableItems || !taggedOutsideCurrentCase) { - try { - caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); - if (!caseDisplayNamesList.isEmpty()) { - postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList); - } - } catch (EamDbException ex) { - logger.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS - return ProcessResult.ERROR; - } - } - } catch (EamDbException ex) { - logger.log(Level.SEVERE, "Error searching database for content.", ex); // NON-NLS - return ProcessResult.ERROR; } } From 7a065600f9e98bd4bdb6b73f0f123774e2552d9a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 6 Mar 2018 17:58:42 -0500 Subject: [PATCH 09/41] Fixed a few typos. --- .../eventlisteners/IngestEventsListener.java | 5 +++-- .../centralrepository/ingestmodule/IngestModule.java | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index f4e0fd9fbe..5815e6b527 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -114,7 +114,7 @@ public class IngestEventsListener { } /** - * Wether or not the Correlation Engine Module is enabled for any of the + * Whether or not the Correlation Engine Module is enabled for any of the * currently running ingest jobs. * * @return boolean True for Correlation Engine enabled, False for disabled @@ -153,7 +153,8 @@ public class IngestEventsListener { * Wether or not the Correlation Engine Module is enabled for any of the * currently running ingest jobs and flagging notable items. * - * @return boolean True for Correlation Engine enabled, False for disabled + * @return boolean True for Correlation Engine flagging enabled, False for + * disabled */ private synchronized static int getCorrelationModulesFlaggingNotableCount() { return correlationModulesFlaggingNotableCount; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index d1362fce63..db802950c3 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -73,8 +73,9 @@ final class IngestModule implements FileIngestModule { private final boolean flagTaggedNotableItems; /** - * //DLG: - * @param settings + * Instantiate the Correlation Engine ingest module. + * + * @param settings The ingest settings for the module instance. */ IngestModule(IngestSettings settings) { flagTaggedNotableItems = settings.isFlagTaggedNotableItems(); @@ -123,9 +124,9 @@ final class IngestModule implements FileIngestModule { */ if (abstractFile.getKnown() != TskData.FileKnown.KNOWN) { - CorrelationAttribute contentCorrelationAttribute = EamArtifactUtil.getCorrelationAttributeFromContent(abstractFile, TskData.FileKnown.BAD, null); if (flagTaggedNotableItems) { try { + CorrelationAttribute contentCorrelationAttribute = EamArtifactUtil.getCorrelationAttributeFromContent(abstractFile, TskData.FileKnown.BAD, null); List caseDisplayNamesList = EamDb.getInstance().getListCasesHavingArtifactInstancesKnownBad( contentCorrelationAttribute.getCorrelationType(), contentCorrelationAttribute.getCorrelationValue()); if (!caseDisplayNamesList.isEmpty()) { From eacd201dcd5f9b5985350934ce6ead76f901a95d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 6 Mar 2018 18:00:10 -0500 Subject: [PATCH 10/41] Fixed typo. --- .../centralrepository/eventlisteners/IngestEventsListener.java | 2 +- .../autopsy/centralrepository/ingestmodule/IngestModule.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 5815e6b527..9e6d488069 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -150,7 +150,7 @@ public class IngestEventsListener { } /** - * Wether or not the Correlation Engine Module is enabled for any of the + * Whether or not the Correlation Engine Module is enabled for any of the * currently running ingest jobs and flagging notable items. * * @return boolean True for Correlation Engine flagging enabled, False for diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index db802950c3..e0e7c2d7bf 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -23,7 +23,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.casemodule.Case; From 43fcae798d1b3992a70518c2e808bbde731ad03a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 6 Mar 2018 22:25:29 -0500 Subject: [PATCH 11/41] Simplified 'process()' logic. --- .../ingestmodule/IngestModule.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index e0e7c2d7bf..865a5d7086 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -122,19 +122,15 @@ final class IngestModule implements FileIngestModule { * being bad. Create artifact if it was. */ - if (abstractFile.getKnown() != TskData.FileKnown.KNOWN) { - if (flagTaggedNotableItems) { - try { - CorrelationAttribute contentCorrelationAttribute = EamArtifactUtil.getCorrelationAttributeFromContent(abstractFile, TskData.FileKnown.BAD, null); - List caseDisplayNamesList = EamDb.getInstance().getListCasesHavingArtifactInstancesKnownBad( - contentCorrelationAttribute.getCorrelationType(), contentCorrelationAttribute.getCorrelationValue()); - if (!caseDisplayNamesList.isEmpty()) { - postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList); - } - } catch (EamDbException ex) { - logger.log(Level.SEVERE, "Error searching database for content.", ex); // NON-NLS - return ProcessResult.ERROR; + if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) { + try { + List caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); + if (!caseDisplayNamesList.isEmpty()) { + postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList); } + } catch (EamDbException ex) { + logger.log(Level.SEVERE, "Error searching database for content.", ex); // NON-NLS + return ProcessResult.ERROR; } } From 10ad0a004db2b7048f22e4394a24da1ad96fd687 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 6 Mar 2018 22:28:11 -0500 Subject: [PATCH 12/41] Fixed typo. --- .../autopsy/centralrepository/ingestmodule/IngestModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 865a5d7086..8c4bd236a2 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -129,7 +129,7 @@ final class IngestModule implements FileIngestModule { postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList); } } catch (EamDbException ex) { - logger.log(Level.SEVERE, "Error searching database for content.", ex); // NON-NLS + logger.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS return ProcessResult.ERROR; } } From 8522b322a4acddd51f1ae3419622242334f0532b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 6 Mar 2018 22:43:55 -0500 Subject: [PATCH 13/41] Removed unnecessary initializations. --- .../eventlisteners/IngestEventsListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 9e6d488069..bc404e2606 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -56,8 +56,8 @@ public class IngestEventsListener { private static final Logger LOGGER = Logger.getLogger(CorrelationAttribute.class.getName()); final Collection recentlyAddedCeArtifacts = new LinkedHashSet<>(); - private static int correlationModuleInstanceCount = 0; - private static int correlationModulesFlaggingNotableCount = 0; + private static int correlationModuleInstanceCount; + private static int correlationModulesFlaggingNotableCount; private final ExecutorService jobProcessingExecutor; private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d"; private final PropertyChangeListener pcl1 = new IngestModuleEventListener(); From 2000a48a1bb5f7d19f0b3be8761a023f4771d124 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 8 Mar 2018 11:31:36 -0500 Subject: [PATCH 14/41] Module version changed to match application version. --- .../centralrepository/ingestmodule/IngestModuleFactory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java index e9c9a5a88f..d6fe88a51d 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java @@ -25,6 +25,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.centralrepository.optionspanel.GlobalSettingsPanel; +import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; /** @@ -35,8 +36,6 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; "IngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation"}) public class IngestModuleFactory extends IngestModuleFactoryAdapter { - private static final String VERSION_NUMBER = "0.9.0"; - /** * Get the name of the module. * @@ -58,7 +57,7 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter { @Override public String getModuleVersionNumber() { - return VERSION_NUMBER; + return Version.getVersion(); } @Override From 863e3b7a1bfb3e9375de0b01b9a6f07f8ed80a8c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 9 Mar 2018 18:11:01 -0500 Subject: [PATCH 15/41] 2229: Use getOpenCase() instead of getCurrentCase() --- .../ExplorerNodeActionVisitor.java | 15 ++++- .../directorytree/ExtractUnallocAction.java | 12 ++-- .../autopsy/recentactivity/Extract.java | 12 +++- .../autopsy/thunderbirdparser/MboxParser.java | 16 ++++- .../autopsy/thunderbirdparser/PstParser.java | 14 ++++- .../ThunderbirdMboxFileIngestModule.java | 59 ++++++++++++++----- 6 files changed, 98 insertions(+), 30 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index 583c2aa157..c4def667aa 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -23,12 +23,15 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; @@ -71,8 +74,12 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Image img) { List lst = new ArrayList<>(); //TODO lst.add(new ExtractAction("Extract Image", img)); - lst.add(new ExtractUnallocAction( + try { + lst.add(new ExtractUnallocAction( NbBundle.getMessage(this.getClass(), "ExplorerNodeActionVisitor.action.extUnallocToSingleFiles"), img)); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(ExplorerNodeActionVisitor.class.getName()).log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS + } return lst; } @@ -84,8 +91,12 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Volume vol) { List lst = new ArrayList<>(); - lst.add(new ExtractUnallocAction( + try { + lst.add(new ExtractUnallocAction( NbBundle.getMessage(this.getClass(), "ExplorerNodeActionVisitor.action.extUnallocToSingleFile"), vol)); + } catch (NoCurrentCaseException ex) { + Logger.getLogger(ExplorerNodeActionVisitor.class.getName()).log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS + } return lst; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index 1960089075..e288fcb2a2 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -69,14 +69,14 @@ final class ExtractUnallocAction extends AbstractAction { private long currentImage = 0L; private final boolean isImage; - public ExtractUnallocAction(String title, Volume volume) { + public ExtractUnallocAction(String title, Volume volume) throws NoCurrentCaseException { super(title); isImage = false; OutputFileData outputFileData = new OutputFileData(volume); filesToExtract.add(outputFileData); } - public ExtractUnallocAction(String title, Image image) { + public ExtractUnallocAction(String title, Image image) throws NoCurrentCaseException { super(title); isImage = true; currentImage = image.getId(); @@ -596,14 +596,14 @@ final class ExtractUnallocAction extends AbstractAction { * * @param img Image file to be analyzed */ - OutputFileData(Image img) { + OutputFileData(Image img) throws NoCurrentCaseException { this.layoutFiles = getUnallocFiles(img); Collections.sort(layoutFiles, new SortObjId()); this.volumeId = 0; this.imageId = img.getId(); this.imageName = img.getName(); this.fileName = this.imageName + "-Unalloc-" + this.imageId + "-" + 0 + ".dat"; //NON-NLS - this.fileInstance = new File(Case.getCurrentCase().getExportDirectory() + File.separator + this.fileName); + this.fileInstance = new File(Case.getOpenCase().getExportDirectory() + File.separator + this.fileName); this.sizeInBytes = calcSizeInBytes(); } @@ -612,7 +612,7 @@ final class ExtractUnallocAction extends AbstractAction { * * @param volume Volume file to be analyzed */ - OutputFileData(Volume volume) { + OutputFileData(Volume volume) throws NoCurrentCaseException { try { this.imageName = volume.getDataSource().getName(); this.imageId = volume.getDataSource().getId(); @@ -623,7 +623,7 @@ final class ExtractUnallocAction extends AbstractAction { this.imageId = 0; } this.fileName = this.imageName + "-Unalloc-" + this.imageId + "-" + volumeId + ".dat"; //NON-NLS - this.fileInstance = new File(Case.getCurrentCase().getExportDirectory() + File.separator + this.fileName); + this.fileInstance = new File(Case.getOpenCase().getExportDirectory() + File.separator + this.fileName); this.layoutFiles = getUnallocFiles(volume); Collections.sort(layoutFiles, new SortObjId()); this.sizeInBytes = calcSizeInBytes(); diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java index 4cb6eaf8e3..403e03c9ed 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java @@ -41,17 +41,23 @@ import org.sleuthkit.datamodel.*; abstract class Extract { - protected Case currentCase = Case.getCurrentCase(); - protected SleuthkitCase tskCase = currentCase.getSleuthkitCase(); + protected Case currentCase; + protected SleuthkitCase tskCase; private final Logger logger = Logger.getLogger(this.getClass().getName()); private final ArrayList errorMessages = new ArrayList<>(); String moduleName = ""; boolean dataFound = false; - Extract() { + Extract() { } void init() throws IngestModuleException { + try { + currentCase = Case.getOpenCase(); + tskCase = currentCase.getSleuthkitCase(); + } catch (NoCurrentCaseException ex) { + throw new IngestModuleException("Exception while getting open case.", ex); + } } abstract void process(Content dataSource, IngestJobContext context); diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MboxParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MboxParser.java index 77345eb853..bebd365686 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MboxParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MboxParser.java @@ -56,6 +56,7 @@ import org.apache.james.mime4j.stream.MimeConfig; import org.apache.tika.parser.txt.CharsetDetector; import org.apache.tika.parser.txt.CharsetMatch; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.EncodedFileOutputStream; @@ -267,8 +268,18 @@ class MboxParser { * @param email * @param e */ + @NbBundle.Messages ({"MboxParser.handleAttch.noOpenCase.errMsg=Exception while getting open case."}) private void handleAttachment(EmailMessage email, Entity e, long fileID, int index) { - String outputDirPath = ThunderbirdMboxFileIngestModule.getModuleOutputPath() + File.separator; + String outputDirPath; + String relModuleOutputPath; + try { + outputDirPath = ThunderbirdMboxFileIngestModule.getModuleOutputPath() + File.separator; + relModuleOutputPath = ThunderbirdMboxFileIngestModule.getRelModuleOutputPath() + File.separator; + } catch (NoCurrentCaseException ex) { + addErrorMessage(Bundle.MboxParser_handleAttch_noOpenCase_errMsg()); + logger.log(Level.INFO, Bundle.MboxParser_handleAttch_noOpenCase_errMsg(), ex); //NON-NLS + return; + } String filename = e.getFilename(); // sanitize name. Had an attachment with a Japanese encoded path that @@ -325,8 +336,7 @@ class MboxParser { EmailMessage.Attachment attach = new EmailMessage.Attachment(); attach.setName(filename); - attach.setLocalPath(ThunderbirdMboxFileIngestModule.getRelModuleOutputPath() - + File.separator + uniqueFilename); + attach.setLocalPath(relModuleOutputPath + uniqueFilename); attach.setSize(new File(outPath).length()); attach.setEncodingType(TskData.EncodingType.XOR1); email.addAttachment(attach); diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java index 541415e82b..367e913007 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java @@ -33,6 +33,8 @@ import java.util.List; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.ingest.IngestModule; import org.sleuthkit.autopsy.ingest.IngestMonitor; import org.sleuthkit.autopsy.ingest.IngestServices; import static org.sleuthkit.autopsy.thunderbirdparser.ThunderbirdMboxFileIngestModule.getRelModuleOutputPath; @@ -206,7 +208,15 @@ class PstParser { */ private void extractAttachments(EmailMessage email, PSTMessage msg, long fileID) { int numberOfAttachments = msg.getNumberOfAttachments(); - String outputDirPath = ThunderbirdMboxFileIngestModule.getModuleOutputPath() + File.separator; + String outputDirPath; + try { + outputDirPath = ThunderbirdMboxFileIngestModule.getModuleOutputPath() + File.separator; + } catch (NoCurrentCaseException ex) { + addErrorMessage( + NbBundle.getMessage(this.getClass(), "PstParser.extractAttch.errMsg.failedToExtractToDisk", + filename)); + logger.log(Level.WARNING, "Failed to extract attachment from pst file.", ex); //NON-NLS + } for (int x = 0; x < numberOfAttachments; x++) { String filename = ""; try { @@ -237,7 +247,7 @@ class PstParser { attachment.setSize(attach.getFilesize()); attachment.setEncodingType(TskData.EncodingType.XOR1); email.addAttachment(attachment); - } catch (PSTException | IOException | NullPointerException ex) { + } catch (PSTException | IOException | NullPointerException | NoCurrentCaseException ex) { /** * Swallowing null pointer as it is caused by a problem with * getting input stream (library problem). diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java index 10dc2d31ce..9215fd3e8b 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java @@ -28,9 +28,11 @@ import java.util.Set; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.Logger; @@ -76,13 +78,22 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { @Override public void startUp(IngestJobContext context) throws IngestModuleException { this.context = context; - fileManager = Case.getCurrentCase().getServices().getFileManager(); + try { + fileManager = Case.getOpenCase().getServices().getFileManager(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); + } } @Override public ProcessResult process(AbstractFile abstractFile) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); + try { + blackboard = Case.getOpenCase().getServices().getBlackboard(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); + return ProcessResult.ERROR; + } // skip known if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) { @@ -133,8 +144,14 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { */ @Messages({"ThunderbirdMboxFileIngestModule.processPst.indexError.message=Failed to index encryption detected artifact for keyword search."}) private ProcessResult processPst(AbstractFile abstractFile) { - String fileName = getTempPath() + File.separator + abstractFile.getName() + String fileName; + try { + fileName = getTempPath() + File.separator + abstractFile.getName() + "-" + String.valueOf(abstractFile.getId()); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return ProcessResult.ERROR; + } File file = new File(fileName); long freeSpace = services.getFreeDiskSpace(); @@ -225,8 +242,14 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { emailFolder = emailFolder + mboxFileName; emailFolder = emailFolder.replaceAll(".sbd", ""); //NON-NLS - String fileName = getTempPath() + File.separator + abstractFile.getName() + String fileName; + try { + fileName = getTempPath() + File.separator + abstractFile.getName() + "-" + String.valueOf(abstractFile.getId()); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return ProcessResult.ERROR; + } File file = new File(fileName); long freeSpace = services.getFreeDiskSpace(); @@ -270,8 +293,8 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { * * @return */ - public static String getTempPath() { - String tmpDir = Case.getCurrentCase().getTempDirectory() + File.separator + public static String getTempPath() throws NoCurrentCaseException { + String tmpDir = Case.getOpenCase().getTempDirectory() + File.separator + "EmailParser"; //NON-NLS File dir = new File(tmpDir); if (dir.exists() == false) { @@ -280,8 +303,8 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { return tmpDir; } - public static String getModuleOutputPath() { - String outDir = Case.getCurrentCase().getModuleDirectory() + File.separator + public static String getModuleOutputPath() throws NoCurrentCaseException { + String outDir = Case.getOpenCase().getModuleDirectory() + File.separator + EmailParserModuleFactory.getModuleName(); File dir = new File(outDir); if (dir.exists() == false) { @@ -290,8 +313,8 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { return outDir; } - public static String getRelModuleOutputPath() { - return Case.getCurrentCase().getModuleOutputDirectoryRelativePath() + File.separator + public static String getRelModuleOutputPath() throws NoCurrentCaseException { + return Case.getOpenCase().getModuleOutputDirectoryRelativePath() + File.separator + EmailParserModuleFactory.getModuleName(); } @@ -408,11 +431,19 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { String senderAddress; senderAddressList.addAll(findEmailAddresess(from)); - AccountFileInstance senderAccountInstance = null; + AccountFileInstance senderAccountInstance = null; + + Case openCase; + try { + openCase = Case.getOpenCase(); + } catch (NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS + return null; + } if (senderAddressList.size() == 1) { senderAddress = senderAddressList.get(0); try { - senderAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, EmailParserModuleFactory.getModuleName(), abstractFile); + senderAccountInstance = openCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, EmailParserModuleFactory.getModuleName(), abstractFile); } catch(TskCoreException ex) { logger.log(Level.WARNING, "Failed to create account for email address " + senderAddress, ex); //NON-NLS @@ -431,7 +462,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { recipientAddresses.forEach((addr) -> { try { AccountFileInstance recipientAccountInstance = - Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr, + openCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr, EmailParserModuleFactory.getModuleName(), abstractFile); recipientAccountInstances.add(recipientAccountInstance); } @@ -467,7 +498,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { bbart.addAttributes(bbattributes); // Add account relationships - Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL); + openCase.getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL); try { // index the artifact for keyword search From 4cec521f8b49b4a927ee0a92fde99648bec0622a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Mon, 12 Mar 2018 16:13:17 -0400 Subject: [PATCH 16/41] 2229: Part 27: Add comments. --- .../directorytree/ExtractUnallocAction.java | 4 ++++ .../ThunderbirdMboxFileIngestModule.java | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index e288fcb2a2..c229628e26 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -595,6 +595,8 @@ final class ExtractUnallocAction extends AbstractAction { * Contingency constructor in event no VolumeSystem exists on an Image. * * @param img Image file to be analyzed + * + * @throws NoCurrentCaseException if there is no open case. */ OutputFileData(Image img) throws NoCurrentCaseException { this.layoutFiles = getUnallocFiles(img); @@ -611,6 +613,8 @@ final class ExtractUnallocAction extends AbstractAction { * Default constructor for extracting info from Volumes. * * @param volume Volume file to be analyzed + * + * @throws NoCurrentCaseException if there is no open case. */ OutputFileData(Volume volume) throws NoCurrentCaseException { try { diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java index 9215fd3e8b..9e0cf9b962 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java @@ -291,7 +291,8 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { /** * Get a path to a temporary folder. * - * @return + * @throws NoCurrentCaseException if there is no open case. + * @return the temporary folder */ public static String getTempPath() throws NoCurrentCaseException { String tmpDir = Case.getOpenCase().getTempDirectory() + File.separator @@ -303,6 +304,12 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { return tmpDir; } + /** + * Get a module output folder. + * + * @throws NoCurrentCaseException if there is no open case. + * @return the module output folder + */ public static String getModuleOutputPath() throws NoCurrentCaseException { String outDir = Case.getOpenCase().getModuleDirectory() + File.separator + EmailParserModuleFactory.getModuleName(); @@ -313,6 +320,12 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { return outDir; } + /** + * Get a relative path of a module output folder. + * + * @throws NoCurrentCaseException if there is no open case. + * @return the relative path of the module output folder + */ public static String getRelModuleOutputPath() throws NoCurrentCaseException { return Case.getOpenCase().getModuleOutputDirectoryRelativePath() + File.separator + EmailParserModuleFactory.getModuleName(); From 5087904d949f221d7e29233d8b99efae27cd96a1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Mon, 12 Mar 2018 16:24:53 -0400 Subject: [PATCH 17/41] 2229: Part 27 Remove unused imports and correct the log message. --- .../org/sleuthkit/autopsy/thunderbirdparser/PstParser.java | 6 ++---- .../thunderbirdparser/ThunderbirdMboxFileIngestModule.java | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java index 367e913007..a8889a864c 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java @@ -212,10 +212,8 @@ class PstParser { try { outputDirPath = ThunderbirdMboxFileIngestModule.getModuleOutputPath() + File.separator; } catch (NoCurrentCaseException ex) { - addErrorMessage( - NbBundle.getMessage(this.getClass(), "PstParser.extractAttch.errMsg.failedToExtractToDisk", - filename)); - logger.log(Level.WARNING, "Failed to extract attachment from pst file.", ex); //NON-NLS + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return; } for (int x = 0; x < numberOfAttachments; x++) { String filename = ""; diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java index 9e0cf9b962..bafa4e8f0c 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java @@ -28,7 +28,6 @@ import java.util.Set; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; From 6397c0e9368393f95e4f120231646fb20b12f555 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 13 Mar 2018 10:31:17 -0400 Subject: [PATCH 18/41] Fixed merge issue regarding LOGGER variable. --- .../autopsy/centralrepository/ingestmodule/IngestModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 2d4fd7c798..6acd46f175 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -96,7 +96,7 @@ final class IngestModule implements FileIngestModule { try { blackboard = Case.getOpenCase().getServices().getBlackboard(); } catch (NoCurrentCaseException ex) { - LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + logger.log(Level.SEVERE, "Exception while getting open case.", ex); return ProcessResult.ERROR; } @@ -226,7 +226,7 @@ final class IngestModule implements FileIngestModule { try { autopsyCase = Case.getOpenCase(); } catch (NoCurrentCaseException ex) { - LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); + logger.log(Level.SEVERE, "Exception while getting open case.", ex); throw new IngestModuleException("Exception while getting open case.", ex); } From 43187f2e1cd039f6b043910479cd79dd66c1376b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 13 Mar 2018 14:05:21 -0400 Subject: [PATCH 19/41] Updated IngestEventsListener to track last CE module setting. --- .../eventlisteners/CaseEventListener.java | 2 +- .../eventlisteners/IngestEventsListener.java | 47 ++++++------------- .../ingestmodule/IngestModule.java | 29 ++++++------ 3 files changed, 30 insertions(+), 48 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 0f65dd8130..da11671a08 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -42,6 +42,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.coreutils.ThreadUtils; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -480,7 +481,6 @@ final class CaseEventListener implements PropertyChangeListener { if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) { Case curCase = (Case) event.getNewValue(); IngestEventsListener.resetCeModuleInstanceCount(); - IngestEventsListener.resetCorrelationModulesFlaggingNotableCount(); if (!EamDb.isEnabled()) { return; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 10bc4f61c3..87f675daa0 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -58,7 +58,7 @@ public class IngestEventsListener { final Collection recentlyAddedCeArtifacts = new LinkedHashSet<>(); private static int correlationModuleInstanceCount; - private static int correlationModulesFlaggingNotableCount; + private static boolean flagNotableItems; private final ExecutorService jobProcessingExecutor; private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d"; private final PropertyChangeListener pcl1 = new IngestModuleEventListener(); @@ -123,42 +123,23 @@ public class IngestEventsListener { private synchronized static int getCeModuleInstanceCount() { return correlationModuleInstanceCount; } - + /** - * Increase the number of IngestEventsListeners adding contents to the - * Correlation Engine with notable item flagging enabled. + * Are notable items being flagged? + * + * @return True if flagging notable items; otherwise false. */ - public synchronized static void incrementCorrelationModulesFlaggingNotableCount() { - correlationModulesFlaggingNotableCount++; + private synchronized static boolean isFlagNotableItems() { + return flagNotableItems; } - + /** - * Decrease the number of IngestEventsListeners adding contents to the - * Correlation Engine with notable item flagging enabled. + * Configure the listener to flag notable items or not. + * + * @param value True to flag notable items; otherwise false. */ - public synchronized static void decrementCorrelationModulesFlaggingNotableCount() { - if (correlationModulesFlaggingNotableCount > 0) { - correlationModulesFlaggingNotableCount--; - } - } - - /** - * Reset the counter which keeps track of if the Correlation Engine Module - * is being run during injest and flagging notable items to 0. - */ - synchronized static void resetCorrelationModulesFlaggingNotableCount() { - correlationModulesFlaggingNotableCount = 0; - } - - /** - * Whether or not the Correlation Engine Module is enabled for any of the - * currently running ingest jobs and flagging notable items. - * - * @return boolean True for Correlation Engine flagging enabled, False for - * disabled - */ - private synchronized static int getCorrelationModulesFlaggingNotableCount() { - return correlationModulesFlaggingNotableCount; + public synchronized static void setFlagNotableItems(boolean value) { + flagNotableItems = value; } @NbBundle.Messages({"IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)", @@ -278,7 +259,7 @@ public class IngestEventsListener { // query db for artifact instances having this TYPE/VALUE and knownStatus = "Bad". // if gettKnownStatus() is "Unknown" and this artifact instance was marked bad in a previous case, // create TSK_INTERESTING_ARTIFACT_HIT artifact on BB. - if (getCorrelationModulesFlaggingNotableCount() > 0) { + if (isFlagNotableItems()) { List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); if (!caseDisplayNames.isEmpty()) { postCorrelatedBadArtifactToBlackboard(bbArtifact, diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 6acd46f175..252b996e17 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -74,7 +74,7 @@ final class IngestModule implements FileIngestModule { /** * Instantiate the Correlation Engine ingest module. - * + * * @param settings The ingest settings for the module instance. */ IngestModule(IngestSettings settings) { @@ -127,7 +127,6 @@ final class IngestModule implements FileIngestModule { * Search the central repo to see if this file was previously marked as * being bad. Create artifact if it was. */ - if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) { try { List caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); @@ -163,11 +162,7 @@ final class IngestModule implements FileIngestModule { @Override public void shutDown() { IngestEventsListener.decrementCorrelationEngineModuleCount(); - - if (flagTaggedNotableItems) { - IngestEventsListener.decrementCorrelationModulesFlaggingNotableCount(); - } - + if ((EamDb.isEnabled() == false) || (eamCase == null) || (eamDataSource == null)) { return; } @@ -202,11 +197,17 @@ final class IngestModule implements FileIngestModule { @Override public void startUp(IngestJobContext context) throws IngestModuleException { IngestEventsListener.incrementCorrelationEngineModuleCount(); - - if (flagTaggedNotableItems) { - IngestEventsListener.incrementCorrelationModulesFlaggingNotableCount(); - } - + + /* + * Tell the IngestEventsListener to flag notable items based on the + * current module's configuration. This is a work around for the lack of + * an artifacts pipeline. Note that this can be changed by another + * module instance. All modules are affected by the value. While not + * ideal, this will be good enough until a better solution can be + * posited. + */ + IngestEventsListener.setFlagNotableItems(flagTaggedNotableItems); + if (EamDb.isEnabled() == false) { /* * Not throwing the customary exception for now. This is a @@ -227,9 +228,9 @@ final class IngestModule implements FileIngestModule { autopsyCase = Case.getOpenCase(); } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Exception while getting open case.", ex); - throw new IngestModuleException("Exception while getting open case.", ex); + throw new IngestModuleException("Exception while getting open case.", ex); } - + // Don't allow sqlite central repo databases to be used for multi user cases if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) && (EamDbPlatformEnum.getSelectedPlatform() == EamDbPlatformEnum.SQLITE)) { From b01b197556c7075c7de432e74204a459fd1447dd Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 13 Mar 2018 14:36:43 -0400 Subject: [PATCH 20/41] Simplified getIngestJobSettingsPanel(). --- .../centralrepository/ingestmodule/IngestModuleFactory.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java index d6fe88a51d..26be4930e1 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java @@ -94,9 +94,6 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter { @Override public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { - if (!(settings instanceof IngestSettings)) { - throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings"); - } return new IngestSettingsPanel((IngestSettings) settings); } From 5b062aade1679a4d3475027e1ba073f963aa2a97 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Wed, 14 Mar 2018 13:31:13 -0400 Subject: [PATCH 21/41] 2229: Part 27: Update logging level to severe for NoCurrentCaseException and remove incorrect import Logger --- .../ExplorerNodeActionVisitor.java | 6 ++-- .../autopsy/thunderbirdparser/MboxParser.java | 2 +- .../autopsy/thunderbirdparser/PstParser.java | 6 +++- .../ThunderbirdMboxFileIngestModule.java | 33 ++++++++++++------- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index c4def667aa..27fb56fd68 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -24,7 +24,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.util.NbBundle; @@ -44,6 +43,7 @@ import org.sleuthkit.datamodel.LocalFile; import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.Volume; +import org.sleuthkit.autopsy.coreutils.Logger; public class ExplorerNodeActionVisitor extends ContentVisitor.Default> { @@ -78,7 +78,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default emails = parser.parse(file, abstractFile.getId()); - processEmails(emails, abstractFile); + try { + processEmails(emails, abstractFile); + } catch (NoCurrentCaseException ex) { + logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS + return ProcessResult.ERROR; + } if (file.delete() == false) { logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS @@ -336,8 +348,9 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { * * @param emails * @param abstractFile + * @throws NoCurrentCaseException if there is no open case. */ - private void processEmails(List emails, AbstractFile abstractFile) { + private void processEmails(List emails, AbstractFile abstractFile) throws NoCurrentCaseException { List derivedFiles = new ArrayList<>(); @@ -421,9 +434,10 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { * * @param email * @param abstractFile + * @throws NoCurrentCaseException if there is no open case. */ @Messages({"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."}) - private BlackboardArtifact addArtifact(EmailMessage email, AbstractFile abstractFile) { + private BlackboardArtifact addArtifact(EmailMessage email, AbstractFile abstractFile) throws NoCurrentCaseException { BlackboardArtifact bbart = null; List bbattributes = new ArrayList<>(); String to = email.getRecipients(); @@ -445,13 +459,8 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { AccountFileInstance senderAccountInstance = null; - Case openCase; - try { - openCase = Case.getOpenCase(); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Exception while getting open case.", ex); //NON-NLS - return null; - } + Case openCase = Case.getOpenCase(); + if (senderAddressList.size() == 1) { senderAddress = senderAddressList.get(0); try { From cc4ec0f66b320f86aeb4cf66d2540be691e63add Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 14 Mar 2018 14:46:16 -0400 Subject: [PATCH 22/41] Restore live triage docs and some changes to other images. --- .../images/case-properties-history-tab.PNG | Bin 29219 -> 28533 bytes docs/doxygen-user/images/live_triage_case.png | Bin 0 -> 26594 bytes .../images/live_triage_dialog.png | Bin 0 -> 17794 bytes docs/doxygen-user/images/live_triage_ds.png | Bin 0 -> 39635 bytes .../images/live_triage_script.png | Bin 0 -> 12839 bytes .../images/multi_user_case_select.png | Bin 44244 -> 15919 bytes docs/doxygen-user/live_triage.dox | 33 ++++++++++++++++++ docs/doxygen-user/main.dox | 1 + 8 files changed, 34 insertions(+) create mode 100644 docs/doxygen-user/images/live_triage_case.png create mode 100644 docs/doxygen-user/images/live_triage_dialog.png create mode 100644 docs/doxygen-user/images/live_triage_ds.png create mode 100644 docs/doxygen-user/images/live_triage_script.png create mode 100644 docs/doxygen-user/live_triage.dox diff --git a/docs/doxygen-user/images/case-properties-history-tab.PNG b/docs/doxygen-user/images/case-properties-history-tab.PNG index fc0a4da441bf5cfce71ddfab700066e8b2196994..0a5d8f25b75fbc102bb21cbe921c518f4417e6de 100644 GIT binary patch delta 8454 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 S3b;TDxB%GI&t;ucLK6TvSzk^7 literal 0 HcmV?d00001 diff --git a/docs/doxygen-user/images/live_triage_ds.png b/docs/doxygen-user/images/live_triage_ds.png new file mode 100644 index 0000000000000000000000000000000000000000..f21a50aa82317547361a10f34ee02e5b34512221 GIT binary patch literal 39635 zcmaI71yqz#*9JP2C?MS}DJ@+BA`Q~rNJ=*&IfBw%(jYC}-AZ>O-Ce=}Lv!Ep`~JJu zzwW>8ti@tZ?K$s>y`R1J^Maj^#@!|13i$WJ zNmkbt1VYDy{~>@<(}{sfR5v+ADbx)FB0OBe%lasM5QrKiCn>J+dEsaoVxXb6vgtwn5FML6S#J~+X?kYCPtfc}e<$;l3N|{Nk%b`^=p#Y}{mbcklHxkn=3=?x zI@+|$75rNqm=*{mg1-+H;^ie^M1hyK9`9D4Jlx$=J`{91o7>nNe0zb%XZI&2Ia$DB z5I>y*-UnMSV|0{*Vs06h>uUd0nL1)hgV$H5uC5Nb-=x~z+M4$Li!us4AP97=zA6M= zrGhm3ID`?)%Rj{8F?{GB7?{85N{S#J#rfBT`*9@wM^tpPum5$NAbHgE^z=(IKJtUq zZ#78p_H4ygCWm?OrXoZ9G*wD+^5@2pC@6ffLD}v&;SmvZu*NG*ZNna7LJ++6%gKhU zzj7+i0G^Drl$6w);Rs}St%JeZB;HuF*mGJ0p!fsqY>qsN4txW-5y^0^3UGBd^6jQ` zdhATk1=|;VBXb}$Zl3D6zDRxuS0^9$^ zl>F%)@ZXg6zw3=%CMDp#;@}XmN)y>F&nm^1kQT?5jv%f&j9h&YpzgfPD!xW5y(R`< z8k3mTvkSZ-?cE|xvC~!4w8*EW+Y7w#`bP#gzMDpm@kd!_b#wErUxE#gi*@hdvZu^) z*`sDBQ5sWZvm>2g>%kd35;Iz9$v4B*@CPJjWsHUtr9LdHA5&d8Ru#{$`kq`Tb!{|* zptQ6!%_MW8H;HD`^A$Vv%;2L^UA+q^PAsiVM2Nu6WoXUrn2eC>OSP=6oy2VVjo$fdbzqOad<+uKct3|yL=}qzl}wm6e<OU+`q$J5slsezd3^K}NPt zw|;+C6)!64`&ev^Mq}#FUVC$~?3D`p^^Y1p~%rMhqw<(&}M!9^1kug|E_L*DLh1C<{Ht0*&-FZ3kG>dNQ#>yn%r zv3A{+|D`3(_F$cQ=<5I-$r#CsnAt>^V~XO#xu@Li6f(zbtjuWdD-KD?+P{f&l=(>x z`U{ehVquH*@M6Ycn|pcTYfYPj)O`Jh)hbaL!i8q$calY8i{mg>Vg4T@SDTG@mn6FC2oU!zFj%!P^1-Vg%(01pjTQ?S;Cad z`Zt|QmsvvmA6|JiTn`*P4c~V0+=s%~>fLqDgK-Ar(YLbfOtP;}>26(_l4-Hp=!0&( z=`nbWJp9QD+68&W=Gyyn0yy00>(RE{y`(k}@bzZYP;P|~v?3!FdH2)qK>U>S{nfi} z#=bFQ=fJ6}EM>m?FY1a;01g8h93JtU@f+dhMm3LdOmw2M3XI|_M2?uAyYdoYwY$BR>&>wc45EiPqnS_ z0fz5W3w_?!ap+H?xiJ)I9iiA~EC^g7j2N6;X;*ElJYkbpO5N8jxr|S?TXYZT${E67 zrKKN`b*AG3E1j(n{ZYRUll05w0x_;xjVwz7Tz~SH6&>5J24wZlOW630IP2H>2c;#Z zo>m~I2@O;w{ZY5;1!l*m^BWbELmjF2`;ZRY5B8ke-3Gk-dh;!?)~5Z3uRM(2@xm5! zsLI1>J;~E$j8fksI0?o5acRx_Xq0cp7DrHVT?(p0o?36a$M%>u*LB@~vRB9+rG zRL-0}FJw2=ZFId6_D1*X4hd;8btHUcxKF!Sao5Be>)EDI%=7>Zs;T)4ehEA%QbZ&% zj-W@nF&Crh2o9c@iMFVA_0IhbRPsXStan#_7JI^#-j!_-@V? zb<{@KuF2m0tg+lRcdR-%iFNsGAuH3yBtt`8ZsXWbY z0<+&{Z7Y9Xv0Iu+zHqxyP%xNFpz?yQFY2#6Y%3Q3v9=Efx3;*Ygo%3EE6`3%J}2a) zSIL19NPdu?SHJq|K6N4EU@F;HiW;8~PZBQBynAZzR`PkGQP}EB*-3NT?M|J-N#=XW z;FZ;7A#PqiQ|2`3Lp``?=A7ILt+~hR$39);9;3AB+blCyQ|4Ibq!O)a!w(q{+sWpG zIf&QP!<3=F^%2jx5*%C*6VpmZQVKe>3Q!L(v54d1Ox#&j_*iCK{R%{vyqF%lxkO$xQ2dm|0dEG1NsrQ4% zFgEQmW24(mZ?r-_T>4L0N`?F+;U=smIjrOPv)a{#?e8TM?#Hik!QtE#GbmVXUbbCq z%IcHRQ}ME_GVZ4v?(^!#O|S-GO4#ZFvoZzP?P{9!?53?_`RpC5>e2bJvY1C!axx%+ zVjv>Kl!!giMhf;QkkS1^yu3JuT_u( z3-*jIDk6+j@R4i&KqQmJ-m=D3`N04~=F?TOt84EWPGPH>bQIaCdlO&MGd&qeslex$ zElU%*zt?3I6@5?JU@P~1eF!yrPY>&4FDu3#*T2SdkU?SgiK}f)m%{u@7fL;w-0dq= zoHQF6N!a{?F0hoe6TJe)6S^QWJ2=9`h*L~mtk)EQ&9?{nF)N2Lb?`F!I-i)8V4NZk zU$k&0xo?fy0zmjth)ik&4B_(oB^<;bEtKIp1rcCl_YWyI*0>%Z>%eCCAV}%lWGHa? zfQm+JmM){x@BaE9*n~($k&p>`kUN`xXpW3zsds&;?K(>AJf?^>z*ypa<^mow-%75U zuDPWB`VC@$U7jNJ;7`vI8se&CK%FC}Uf}CJQ{hYd2dA;-A2eHQvfF6D{3H5kbldiz ze}sz4nxuHIRk>DKf_nJa@1Xj%T^e|*FWH;rytWN*?=A*5jjtT5HY*yrprM6dVgKMR zA}0;dr?Zl4+j~IF_jp8nrD*EOk8jWRA6R~~A^V>E1<(N`!qC6j4@dO~-1*CIaIDa7 zCqnTUop6DsprnW3vAaBhCVY_%G+TJ*y_emw@c&-~;O!u6nSUsKLl$0m_aAxxKTRS3 zkoo^-)VRos1~CN%h2fuX>cDEgvD=iD5RF$oWGm0}K~j2iA@t5oj-}>Ox$2}d9*W%( zuEbK~Y4yA?MqHE-z6jLSQ~~`F@`EM21f;sf1XhGz6q3E>+NutbxjgPF;B@`X*NWTq z)fZbETg0xBhFODuoJ8OQ#V6(-Wy6aiLo{BTtyEb^)8nXG1hr_ZtymS!>WB2_Xy3V; zJsWblSTRWk;X!=>E4{YMW1992z^4<9Nqr3f2JTj>IS+L(EwHYDcX zxYM7^dJ$9)Rr9ia2Afry#S*c$ONmOK?*GMy<|odlqV*s@{l@Us16C}^jl4)!mWIYG zR*mw;n)v`45^{bZxZC>PY@&plSyPC6H+^n5w(3)r@H>tD;q)|jX3mKmZ7Yqqgm|cB z8RC;fQmT#x4Ne_Cqj#V#@PtRj32|D%zdu$C&gMMvx z*SptrHXZSd}va$QWPXL-CHCybLgET zmrtA$sxuaSqC$=ra5idzHO06Qm?TheVZUO*txFm9=W6mM=@A|Lg2Gfga`J=6L>4Vc z^7Vk4LXT4WY#cs~4L{Yoq@-zITDN2G$Gx(3S1jqp!O6IA{ccl{t{=wOBtp?oRX$5o zu~tvcXa0gtz_AI(m1)*dl%|oFSGko8p8Nwt@5*^EVNZ{Dhl5_!61>Yn8_6Bkbp$9BH)wYfaQqqZ|IRKqtdG zNTx%yRH>btTdlxy6;I;CJpnzFn)pWG+ebul)&40!9lRM&{=FU&6}6Lodi&S4B8nuZ zmW%;&EtAcwj+k}BCRL&Lf2$XRkCj~{b&j*h!N2|Q=Km=Y$Nt$@uot|jUcVCGFAmpT zW5H{Q4|E!w%}>LQp(0{yWM5%@Gn5k(69Vx-)7Rd0r;FP*-$+_PcKpCs&^Ziv37d$wOuTegB2Uz*!DQIv^2DntjvqJGi9){T7J8;1a{-q=Of} zVbFe!ur*Wsr{A8x{2ze<|LyzkW7*x;cmENFN%vo2ZT`+cv~QmjW}}tJ<5f zX|o8)vX&4vi{Sk3*lA1wH2av*41iQ~7^BQ1bWVTEO8BkPz701Tq4Q-M=HEylST=5X z?m@}5;AS~0STTqg9u*H0>AO3!lh#R4T3yB zC7=dKvdk!^ve}F3-(ozK zqg`@o8E#ZIdkD3-On^lP33O76kv?-vMegiw>2$4_b>+e^D^Gal-jtr0Wmvuuz}S-C7izaAUy7Qe^a06hdYRJ6-$^y1=h ze%I4Wl{XSeu(se+uE>N4?J5SAw-0N!ux_LDu(9NxoA{EwPKv@Og1Cf$9JV*l}CZ5l-3Ibe5J+;cF7cDsJLVdj> zI4xo)_DH)gl^dot;~nY>h+2kmk>n)oEsVYgg~%qx7dhGI@J*FdyJMGR$9WX@539-{ zSpQj~@Fq!|wygfv#@nfTUM}t1x!iOfGuBj%EY=BfKUsVg%*frqEX=^rTq%cE^EsYx zzO~l@*omvz(uDvQPDH431KRiV3%lYfVRFpi-&NNBIX_zI==1Yt92^Y@ciF`pbaRut zjN)}#EgBr3_ovkk^n~(y1pl7Uo6Ia*9%)iEva@DJ??47jQkd|vo|a0wj#&dBN?FD> zSjXdcwZMfIA^>gBY1{hhf{_(bb}v0m-)?2<_6zP3kW~MC?c~LQB&SSF@&+;fRAH(w zwbgbjMmZ4cNY;6nE28D);2YBH)>%4_0iQrA+ub z-1N=Z5=)a;6>l;}e;qN~@ZTxv*QPA0=e;+bs!=OGNG)}|!9UawSTlSdT!_r!JSbT_ z7&XD?oC)kLY1hwu0YP9@%9Sl5LUfj@rDbRlVk98!t69!ex(ZBhwci{BrIK`clb7CTJ!+9p5 z*2)&VX$G9Hphgo_Q?aG7-W+Z2e78thC!bGx=&o2~xEMP^py1spK>mYdf&6A=MHq=SToj;4Nq;>YN?o?Lg5l#y{AeX9;z>8{V+sBy98Iv?oj7wr7`PR7&6DQ`XgUtHSrmPpIW%4L4iT z`kr|tch{%YZYRj%_&VhHby8u2SK-#|9|d(?^^a~I1VG2;LfJ4T$%MExh2z2VAjC6y z8wVBz4(d}=SKFgojU7$@B~ouo!-&>zT-v@%+UC%L_ng6RCFb?Rh${MvT(tSx#1|-z zXM4>X!kGr@bjy-i05~r(^!R(XFN*Y)vgg5Yzi$nL06C^Ex#zfW)LXDzcWjW4RvNuN zH@WjxPZZoZn)LU?=C*D2PpOf67OfiVt9Oay)}YzDazDb+2B;M|9M{5`?%5Q)&?y#W zzT6X=WE1_*G`iu*J^OGRd`E+cdvp94kpHg>NHTW0Ok%W^l88eO<4|-AUin7W**xYo zr|BonDK%|HPfrcQ;D095VLV!kaO;XU>d0d`E1XhB@1QtRIya6Wlta^<(4OJ(kVDFr z${6VRCc*dNaxQ?{!0%>TfB+=XQFNt%s#y72)h}a2igLcZgl{JlX%;Z3Z_V5@bYs^t znXQXT_;6z(@caP?qqI|X16vPPnCe!tj5M2C`qu1HDZC&@v`BV<*eqO8j+sWf{lD{9 zh0p&vVC$Q7S-iKK&+2jlplB67q#Z!|fLJo!H68hjLUGZ?;{sgpc!@yu-JzWmtcQ)@w9a1fyF4Vg9H4#mbG&nSyF}1aVEn1HpQ?kHlh#A7(kEO6N>MG=g zKkY#E#pG!l2)jKtmUc9=-cd0$j2Q#IK@xyxsZ96a%M43gM1e?!dwjv)%`L$vpWGEbREEo9H0qrGt!Xm-auL zIw?4&0tVU31?o7O<#YOgf5^S6_Hrd~8g+2$xT=4Zu1$(h`qYzoNBxj3$fv@7g#gW6 zFX+ZtB+0oWr!mp7!TzmE^?)6FhH&9D&GYYy4bh>bybLze$%6TW;)6`Bnr|2mu0{yO zwE|pb@a9Ac9Ak*~JRPTx)7Sz`n1DehH|eToInr#9p;lcl8mCbdg?$5EB}^x4S{iZe zXE{YK%?_5OIvNY#iKdVh_Ll_nEeoe9d-~2Bka^_3Q1Z?^9z??dkxCYl95|%5oy&=w zn1KnCz)@=xGm_QIT{>UhiqP@<-r_omQ^_Bq*ZHaLa&F#IzL|xaoO?fO8L_oKrR6`N zC^MGyw!}od13W`QiT3LL*MurrGQBhw;Eb%9aBk+%kUI(-EML9$t_|GsMM$Lt27g%^ zmETeG!jzSAmY}wGTY_x;2(vE>;HEJM`w zv^F;6(~}Ihv8Z>k$9{<}R_yiG{0QNC8G#&XmVoaSyxRid!%g;xmO&BP8<1jR)kUC! z@c=0q?^W!xQ=^z`0`H!J<^)SegSsCGinwbu&vEImrrh}m+w^qJ>1Z^SEGzmPc?r_P zt4QUP!0{ikJ8Z@smlm^GcemfLfb7Ttp?kp9xfFmfl7Z_8wW)-2;qFyK4iDwj_;y_4K z8Z9i5oM9%zjPeQ5w%$^4BCi)?PSNtu5AK9ss;IB;Z_?UuQ_#@3Ty}@v-{MI)9*ZCC zkwy^anpWv3zaf6@f|=3>(}}vQeZPEpd^P8fCD={@twt`{&z~RO>6VT@n@vc%(L8_O(W@*C4oWR59EOG<4;6UIEfV>D-kApai!BK(x~rza zC=DIc+s=#&N7IFTuYiU^B}cjS1vu=TetvoTWx4a2Pn%#XlCFU{9bg=^UY!^a>OU(p*?TM6cOFxUrMAK^ zCpm42=3IRr9TNPOZB-+kzqIw^h`Vwr_U^Ll;SPa*X+*xGsQX&eJnHb%E1EE0^HVan zu~s&JZ>vp8rh>j%*`$Qg_R~=T8k)3^caP(SOm}m33xUSW5p8{*^5=Nt9MB zO(YPG7xQ>%tWw?VGkn^W;^64eI(R9!Y>;;S=Mq}4gZSa8uvXELm3{-iVWa9W&lHMj zB&NSYv7eZQmv4VN=SpP}Ny5)(v-IbuGuW>BdGZ`qk_QzkmP>{rRhmud&PwzN4%xyr zS^cX1jVw714$-%u$-b+pl8u7xNFRh$x_8m32Vb7W4gVL0Vfp!}Wj_5SvYK>A4grz> z3sE+Y)HJo)C{9$P6E!_p8nog zYe&WwZb1fNBdKdn0zRh|kwYtRd--mZg8nu_M`jSJa(ZfmG!FR;F*1DydRUP(Oq%&o zgoqJbu%H~92Tths-IVPeCwn2m7}32-(-~u*UH+oyQ!(gwcF~m;{=T+Ro-sRIAgBX7 z7A2ZC7>vQRau)cy;*qQ_#`N_+$OtvAF*-njm7K0O?T7 zV2KEwvL_KH2+#dt4JG?$-7Fc;OJAKg>V@acV^m428ZjZ=zea=-SW2X1FdoBV!7@#YS=$4j*%Rrk+DW8e{!bfN*$0X zG_TYKCf><**T;kQ=-|!Z1R1~859={Q2x>3P@*`zL0PxEUP<61E76kF#!J{Abd}84Y zir9;$)@;Qxwbxpe_A7~$d(ocZ7vxhF9_Lz9&L+`{7g^PxK#x+Mcz8*8#?EPKa&epf znugswNqc%*g1PX$#J~6ee%Q7K2d1AD@u^|jgGcv67?=J=6^>J7qjcw@*mLW_;7=c?k*89Dz5fxty6`?8J!e$=*z=xlZKiq=eHDE4MoM6I0al%za$9|$%s zvl)m|{&XGV{wODGYv%9JU1|`aS_sB^gF$kh@+W?6*~hSKWab)?cS+@?x>2g03mV?ecun~w7udXTACuPcvt_YuV$P0<5q5+Yqg%5-kgV$=G(zaDgpVnD$ zmnQ0W-yu@!CG(P0o5zbTa@{{>;xFuE8sC`rk5Oj{;)2GN#kaf$)tkh6&1-fvU!0lu zTd8es`n{Y3B2V=*>OtUS>xq)Y8Nrj#Ex`hznz7*DUTr8=R3<8bgCpXcw|RjA+w9&) z|Mhy*hqvQWaWV3VhQwO4llQ%$y^6RNk#`)8$dq;$enP&Gxzei}6_d?3* zU}KO^y=d1`Y2Dy=lq=)VxkQEaxlc$dYF#x295_Yn%bFetUXvQM(lQmS{l^Ng?y$08 zO)XbJgaQ@updtWZLW0`8a0C7S#FU+Ojux zgMeP7<&)*7)4j>ZVy?Oy;~|a*)Y93y8Pa~0#qU52>{7+edq5)u5#a}_dHk!M%Q=IG zuR%m%{Sf=mFRt=S7Rm0+p1&_XplW|gLn?DCkd^)AC?tlV!?^r%(y3z5v-5_mR&KR;diF~eM{fl7zS=z^qS!;&k3%aOg1|jzH^apj zARsN)N@AGgSatbgM{VM1wr+Uo`g7|t8+ zd;(Z-Zx%E9&~7Pw{7O*o$X;;0LYZubdA1sHCV3bh3|}jQY{=fw)cT^+9u_lkM0XG*}frkuN z29F}ylN&&z82cU{TJ^4t!%#fRd$Z1_5oko zLH!f%IoIr*ZmnM6=Q0NoM-MiUkq5N^H99&H+cHT~d%z^(Pq&!>hr4#sZ6-4`v0dNr zbk2O+!n{&`zPc&XQ2)ZlqTRm&v)0%w)|zdXV5@00Nh9x7R?2Kx1*_MksV{@2$FnMj zWubIrxMjQE>5Fxrk7=e>M{gp?^gb_}St4ILqfZYm}Q`q4wtOUlElhK-M#8ox8(rx2dy-$~_@KAQWFz)5M&{7uA z&C=G@Uxmd}jQ)3pxBqsjzmD8GJhWuk2t)gQ(hE`WgV_#T-$;Yj(cP8Q{+nw1Y z)>fBk`@syc5giDkfB9l>94njK8t4Oo4o_W@Y8ONe>DUyBYThadwpjRHe-Wt0DsCez z9~tDg+jMWFxgf0L+|mewp^ZULG2ehaWE5aZ)~$!1DCEGm;VHHKP&SC$t4Z z`c?NW-bXRt3&yOFNr@)W?#;2j-z}vs7}U(PeLg8zW=Ok1 zhTnKE`RzNAoB`mR0SerqPTIhL>37?QHb>)-f?w_=+G-P~l5wDiu0maF=3&7Zc`)t8 z@q3;vAYak=PP!5u%g_wXrY&U)%!GbDgbmNAe`7G>pt@$Ut1B;?eHXOAr>!il6V7rI z^%LP;R#R%?uR8K{-NJM0Cc+1=B5hTVG0s>kHq5|!!SVNYC(bY6$$MPRmqOIdGwr0DoQz%(p9(Jx0Tbjxy8Hj#rC22DB` z5!NsmE5ylL?dYMPw44>ta2J;K*M1K-mPtjcQ7SW^q_+@7-|Sbw%c;sr{E%0QsSF z?FD!_>%SVUk%Okw$+}nvh6>k8LFE67oA3<1yvF~P)pE1DzzYxn(g9w=kG?maR3N2^~(lU^2!_zLL*sRMuH!kz28N1=$-2>4I2Pf)ArW^6XAd-$rw zs+BchlbnkbUCOn?7I<4#Bsbc;*}Qm%et6B<*B=(m!VaZt^klkDe>?|?V9?B|XAVC6 znz=QH)eN}S$#i%x=_txwo_s&KgpS_1cBY#ZbH{%UXW4&TJ|}ZS0s-U;UCG9g2lw2f zH-|r)M?XkzwZEz;$oX|Q8x*u4pXkQF+H5nKB9fM03M4?LRYY2yli}; zb_$L;&k&SB!O)%9m;;^wbBtyHT?m92d{|uajY!9+OYEh|e`<8KkdBG9)zx*Mp|iby z%tE38pOM&aTqD7SJ`ev-s>+_S_e*b_7hJjavGN=Z0_kPy}P)Sf@5kyh%zm6@)*M9sG{t{N>pDmkh z&lj&Z5Z0aKdD*HfA(vd~v# z+D-%^u%B1R1pmgNpcoNcyoHryJJo%Ee%Y1z_PX_@lEI*}3 zIhvp2A2b1?_WAEM!^zFn2IA-WF#suuo5nMtF`LC^we$sMFw*A2-;wNbhp9S?Z|-7g z5q!&h$Z(dBZ-BG?wWUx)ofL6rBdQ@iUv4qJ)lk0T zTJ!B-0~D0prB9t)<_N5xhalTQ6yuE~$+_=S-ZB${pP*+0!7A%{*?KMOKZUoKCa0TW zMtHiQpT*OC@?!`|OBskFop3GHuP_qw0QaoR-@&i-E^M^JRtkT2H<0D^%|I(tBTgdKh;{Xg1_vPgAYJ{h*Y1+8?Hp$l~wA#Hn?VYmA`|n)9OsiXvUe^-nS?qmBfnNl~ ziGNA&Xfw}dPQX=R7dF%X#RtC&+=TJh=4~siFJA>84e$V#E$=aA@Y0JL0J7zZE&<=b3G!I@V(0)u^ZJs<4@>vcstDGt(zO!oM+*cDG_G?HD5^T(BS z@k`Ms8n`FD(-wF$vHkwL#_ib$z$HK2<}Q5iLBh4KuZVVb@OwUd#{9_aax2vLNVR*7 z0z-RajBEanziwgN7$o8BI3j^m$vvaz((lPKs@)5|RUZMK#>p$Q@FK-~W)}c29TZD^ z^Iggro6`^BAy_I^uS>ziX=?WlXjhF-Wc2mFIrC{~l9!cNK`zbQC9AHV6z*w>c!$bD zwtmHdWg^SH)xtm$J|c0I)Ycf%tz|n=vR(5I5iD(^b@+PP3&oEO9d5LdBUS)&%ateh z?LUC(eG8vlDns3$1biE`TpItp2za#=IskRmbh}pi0dL@x*-&?j!gdgKKe<|{&mjAS zib&kpMvhn3Vdb`Sv5%kmmltvE#yubjL!W?Y(gff#5RkfX+~t;za`K}RH`VVE-MLGL z*=sMdQsEY+4?E})f-n&NC&~u)y%yvgdp61hBs&Gf$D@_f1t#n>N47PAyqG(Vu(pmp zVa49={ylJzt@RdttNwX>5gZD{m`=u$U)KM(cV{Je{@PhWd%9g0j~o;AmKMRBg~>|A zSL(?auNd1~s--PUQ98|T8F+!}OEx=hA?TfYmuJtH6LEl5vT(xU{{$q{h?T~v{&5uB z{2yhBU1rPlgX2M83ef)Hr_#zwY(^l5`NJ4+T1gv!{g-|N9DcakaQ>I11QZ3l0PHUO z^M5pb$$ohl^E-z72TK8*$+#hVZKn_?J%mzetY%74@H{cc&)HRKN&g zClEvt}peXH)uCG(*Nqx`i22 zeJ)p2qGKUjsvG}tyn*!a1)Rg#*}3Vqef@K+L-Z>*rvQTy-wrJ6<>$4i!#a4D82gv( z?NP~;59s;JAx0xU%MA-Nzgg;UcZ7#K5jSb}0dJ@;_wCmo^h?Itg+!ju@w|dB`I)B5%SyJU>?@2(V{Fcn>Tq) zmgGOa>MAng*#PIJplURgvwZ$xlZmhM$Kh+BhOuwBqSnQqzr5+@3^HEvv>P_Wu<8f# zS_n@J1R6{Kj5H}LDNU>LL8_DE9!*hk7#H%}K78=34GsSJrSvC3i{P##qN9(7Jjv51 zJXpfff_5cpkJx#ycL$G1$BZTLGq>Rs>34HscrO%Lx^r6VT~>0Te1ev(?~p{RBmeWb zl!df?%4q4oys%^MJg3qijh;I^N=n(zBO|EVzBiY#n~Yc;V8`X^G76urn$rian;qkm zyYs`}6)SwVZG9tPU*E0k?}9!_%1R}dJ--<7AkghOnW(J$5iq6)u4;Jl&DQ!H)&1|@ zGCqIQKXtWJeTfwiV901x6z6 zm;GmzrlV7%=%*rryMuk9A#wbzXS>0DS zDCG!P*^IaHXp`sJ&hO?!CBy4`{i^daw}W51B7*A!>J^{2H(ik)R>S_`7-FaNDevHR z>|Z@hHz}#3WBONbT_p~?ey@a{QrvE|Nf@_+_q3TuQT*|o3mY}PaH$JZcZjHNbMm=2 zkFB*Cl-Ydxm_A!vy~TQn!*kBUP|}}|6Rd+?`8=*Vwa<q98&9-IRaQ*c}P-qmA%Fw1j*;jd@({8dHs*=mN&K)mjw^ixuG4krKc^9EF>f@ljpl}jcqhb&0Kr8;S=;} zySt2@CMT=a#8+HvTG^;_lptjL?J1MbddZVvX*%7Ga`O|TTz5uys7?%`qu%_*>YbI7 z6(b|fZf$3syyp&<_okKDuzMAKX4w-zz*?B>x&|*6QoX!KmRlmid4_co{v70FJve=O zw;DVJEs%T|xn%O4jHXL&HB zsRd{&kkK7kESg|qwPhLvnn3Tu#q3e0Eo8Jsc&z3fV(JE z9oc_#Rs0SH6wc)$kZ%C}q5b!P=;# zeJmi`g|2rx_~kW#zWx%vlbAK?TX}y>QSp$tX@Ef}?WUOkO$_ivY9{(;3*W5yiF6{o zG{8^(kA3|=EaU$+nm@pmCs-g1_ZE+iuYhqJw?*Gs4FYr&yCI}5`e|NdV9tP(vJeqO z{eg-~?52dGtf4QRywMP_zh6GCO?W%r&VF-d9DM<>X+R%S@kJhis)Y_P2e2ZI-C{5M z=5ZtuK^NVj=)dyzoRON*fl0n0cfxftHUii!kk2##-k%h*v)D(`SW&_5`%}5NFI9A3 z`ACP~c;VdNbh$l!`ZhxcY^QLmQeArt}g>)$eTtO^&6IGa*!9STXk};nlv$lm#N_lD5 zR`zS~s~y`PHm4{2_8<5CSBF`ni*|UeE3chg&}PFtX&J{Bw>p^agQuFUKPt=beJ<(s zJlri|C)*Ys&is!31M?-yNv@L~Kih?{LOT}C%A)VOKPu(JCGnoJ2jDkV#;Hv%04qW4 z$Q&WZ@zkfKSI*J0 z3c^`kLMM68J^$#;qDodB(!NIfse)(+IZJIeo3}9T-bQ=%QRV#`>7w9L1wOS=L885E z=Du0M@=@-aS>F<_z*N@^bRDbtW2hFNn}a+|c^w*_>BU}E>fBRUAXzKxK;~>=AP-o zUTn?C5pHO=C=;#a3^_vP2lq#;eEx?Ekn#R&_Ca>-4V_bJs>f>NF+&NIEek)bQ?O@j zqH*X&i7;CIT#?If!{T&sC#OtJ_&c*2_hrQk`#pl5F^ur4h3I zxi~LYS%YU0ox!Pl|@0j(W%`WRCl3N5ZxoV(FTD z{|D)$hry}PeJW=t=@_R`y|TU4WIpqqNK!-j=f}0)5x&C$MNKTWC+l>u_0ZLGBlnff ztw~BSTf8Q%3W z8b7|7b7pszffQTM&WD!Y>y-eX)tT$%m(A(bg>`(3JR zU<1q0@m1Bxo z>`Cp5B_`}T@{nb(6O&7c3JVULZbmYG{R~F}Mk)i3`}BFg$2D)*43S;^i*!B8x+V8f zJC2q_;8jbMA(nkG^uX2f&a>v>{`SVsrpvfz7qz5fwX#Wd!Eq{Tj&PN>T`IZZlHL!7 z*V6b|KqiSF&`gzU2uT$hr`O7r|Df&KqJUOJL zDvE7MNj_I$P0b#SCa!G{+@6KO$#~!`ns4~|_CYkUVKrty0V*^b8}J_1?!yX=lup&) zi3>C0>2$AcQJ#;VGA3ibd0;Xmh>O18zdO(m9Vg#BzpwfBlXdRR&m35xHnV(6TuwqJ zas>hK-h)*`QtiQ}&=5eyMv7J(lV>Wo)hmB~IKJ_nSLl17Ze5L%-w{4zj`G-)AZ}E~ z#yzXpZl1F8nQXP)ShJrki|Tpr>fU~Oyr@VW^^FWz%!k|JamNl|mzmbbMl3m!41|P4 zwe##kX4@1bL&d}@FV|}Wa(B@}1RTc=Tg<19y=$yWrzs5OB>R-krn;lEHu{L2*+pQ= zg1sTiY7CUuu*Z1xg2rcko>t44yE%*uXJ+w)mh}lo*PnWPyT|A`^#z7Lv8DLn z<@4U56ma|JqoaNbumn9bQkqd+xpGz4PXe(t#?k?SRxTg1 zuH%Pu9#&hzRprSsL>&TV7=Z4O?`cKW+P8$w~lZ9K1v+dHV1d(+UyRj z5W&#LvIQS2fs}^3H+{DUiOcAQ$XWK&umcWAEoy}LE0}SPUl(>*tUD;&biO?$+ZUm2 zo$iC6Wp08__VRtw620-2KO#f*wgft+r({y|R9##j=Tt&y?$4*s*KG zLL&F)78jfD1IqPi+7#x^hEflpUw&PGjpf(8^$KKtvT#G%o*E|2FqP$Dug`07o$hDB zH)1&NcA;k~>gsq_cbRD%XvH!;&%3GIypPsExZ=u_d0$tv{PTN?pc?lE*+e@+mU~}! z`6bt(ia*9fF^}nJG*BO@{QlhCOlnZU=GfuZ)U%lYR;Rz~Dl-c-`2@1B z=mop)+qK@MZr!}wEWlUWRQGtHl;}QyY2al+c|h%NdVc1fe}ur^5@U)Za>Euk7X3pm zSz4%I&$&NeaXGXFi%j?0=_T%TNUT4Y_e%EJ{&i}4HE304qmS6sU|C94o}QP|_wqc- zNh@fEQkjd@x^T#b?86LNPo6Im+RS~~UEjV8`>IGs?qNk=)sVKI<6KAJ7I&sAPgc>Wqq>H$j+H;6MY2|2?nzGJW=p;C`F zw5^U-RFM9|)Il9Rrxe)(<-Q?BsvH5jg>PvZRkRpuf3Erg-et~zY#G|`2Tn)j{|wcAl|eyqI*0>>vcK`wBP5jS(zeq%vd&WE zsAR>j&~=Y~l8eir^o#bSLf(|~Sg(1hkw#+triy2EbEf3@MQPN1KCPYQt-&tXX(Taa zeR6=oVB$V(YQ^cGAWK*5sm&e=3UZs2)I*^@ACA~vZUA;CLt>}6x*XD{qi7T*L z{^K$hr^^T)yo6ATwej8uE$sdV&MiR~zjm$3>Rsg5SFRXm8b`wc*Ri(s-}?@p@}c)Q z%P(?X&(YJjs!7_lZt@YLR{v;pwk-G!;OkzRbecUs^uJ)F_3|Z1I-Hv(cIBkuGk`gi zbK>gVFthdYbNnu}X6@w<$T&#aUTfGTF--PDrZXSq7c9==_?5_x?+P~^nNd)F@a$}l zX3Z-9^IKxZK}FMb0iuHZ3s4b_Rlw0MRAaVzU99!@XYh7Hp_uhz@G+2xbz+WuVxt6d z&X;a}En`?frTw!hs=spRKcwe>s>c4W)b2n1^zSv?-e~93LCf2d2KPegw(=CdSewWS z2PfK(NiD&Y7#Z0|`AI={Dvn?s?*|F|cwL-R*Y8qam{gZQ7-8`8ES1G`)Te7Q!4h;2 z01=4@xKf$Z$dVsL^BLd4?X|y&d`UnD~^D}m^l#F=YTThJ)lnZ-AH64 zP~0}wZ~J{DWOu?V;|;sL3`>pE@GY05v~*#@>{UtZt@A6O2igISxO1^it)L+*Dx8ed z*>tTahDPk}!X(R<)m}$}#gF^CLuha>KABiPoXy6T)}Cc&v{`4q8V=v*0_^%K3la%U17247ddNl^H1Q2sd)jNA zq-h?P^y`!z=lT*TGA=@v&|TG2E@akEE=+D3NE|%UsefhhE$vTTc4D=r>ECK4SC@Jp zRayQ^f)Ya}d6(PvKLtO2*K(1b_r3pDva{N(DD-K}io-Ux{xZ}0#0*HoBfrXXd=4iP z}`tj zOHXDlQySUo(6ebO|FAGc*{|1$cCDaI0mW;3^we{DS_#bsAN&2d$z8GoO!o!!Gc z4vd`AJ=%T+IOtuWHo1m{iO8mFfBczTC5p=}RSzJwM=z@sd@ml(_UM3(Hf+s5+pd2+ z4nHF!v#3!S+_g6U9BKEKYc@h>Hci2{I*R@ahjz4#MP@IKAT2}vI0e<4Gu$W>Cl&s8 zKVeYs^Qdik4L7%ObT+4J|4ib-t?~h|1OAED0ob9HWV&QwX?hGXFLxD2qcZ`h7J0$` zcG|02m9$Oi)vO^HI?jS-vav)apf%@4?lL~k?UJqCV%~P0aj*9Q7Sd+u*bxj#Og5I# zt>2WswieDQAu5!oXWl-mEHGVKX64z2p-_O05 z!6H=cakALo&i#+=r9UCIT!qLnf>{TuS(|ms6-xBT$o22qY=oq5?%oWJHr*_^^z}56 zLX~+UlGEgq^nUmR`b0fJ^$##|R-Urig5!x)e*F*nV<={d66(p@G@RY z6TPP?p5ckoOBhdTwT#Y@T1j;{3kmw^`4kVY?+-q`?m1TAS60rWM6i5sPcx#ahqz?t zD9Ux}LW&_#e=j`>Go8qO>$pdFi4bT`b##h6*r#%QdVY6DM7t;XcKKzL{-CeBDz#7B z_9GNS8h^Ch7lw*1y|EIBw6bHXxv!pqx`^WFn0S+Zi*`>gjsgRqWzY_rLtvxXWfX&_ z9JXwV&b%Rz4_7yJJe;W;YHBct4g8Q3AM{gE*vTb$fWf=8xm>`ph*`5KH8C;2PP!oR zPkVb?oDfu$yy~b;r7ir)M93#x(+19O?jd>zVrWc1vz;7x>ZiKP=M#usO~)q*woG#e z2gS|akLxp0PSob4rdyFBlh08);GL+SKK86Gr)T-v^j}ycx{3>nXea zb-8(eG+=PndR_6@9yY!ePhJfa@GnsI$&T0l`0+X5;_jR$IkbA{DUwKd_b{zA@KmEHwJ}|-ur_v^a@paM}X4S z;mj@a;^C)`QK5RFhu?)Dem40{#yi%&G+JCG!rKQW+m?Ge=SeS+O0F?t_KO zv)?u7`X-!QWF}YM@{P8;<)WDlDxIrV*N;a$bIJl`Czwsv(G_{yMxWo*0ZY_nP~t*V z3>4KQ1Wm#x-6CA4CR`&gZa?v3_?}hqqkekx3hU3ghMS0RS5Gq-=xo4$y!xrddqq)V zxfjAF^3%Jj)%zrRiSpT_8yZE14?b{SrB3qPh`TqxEXlcR&AXRM^Qi`yO$Z~2VF8?a zXemzZ=nrR0RsB0$Ulk*~R%2E?zoXu@B`(s4n#}c`ZAU`I0$yPeZJqGK5VfGKDzE`u zd`!ngsAI+*j!rzMJ@LG=sc#SSn%U+|R>+Cx!>LvlX1Ys@%p)ie9vx6XfzXZ`MC*u(zAP@y>6sPM zjBjDN8WB%f{B9+9fcON}&6D;Sm6P|7$oBtuW!#xd$W3Nq-I~v8<>DWgG~4lGV0uN3!RJS*;{Uk53CWBPtOld3JFdajRcZ1rs_v6iS(xf^9-ohA`#3nPVox~_Jp_xIAs@zy94vf=lW{-GY zp3AFX_DD_MDgAad_94!>i8Qaixsc5D%q3Qig|OUCjfC~^egZQFI zW_|@_w6V;gk@i(YUoUOR4!OD}+?yQE89SLsXcHHx*X}NN?McpFtQKlFLsv}c>B-Zq zuq)e+XcwG*hGP332a3WMJqJ(Rpm~T}1}B}-zWgMik!kJl6nnC^b^=Sqi*7+>ZwpfQ zt3_oPfyDZWnt#ay>~weupf2shZNFm`|Fm8sW$j{993~s5Qt0)Yt3CY*$_bZNbpcKxj&q ze(lWD($k?k%`75gqUkp?l(o*+Im>L3bZ(&0wBya7c~}=-1@uJKqOp7dMRm5!dYNe7 zdi%-Xc;diVy*FE(9O!Q(E*JXxlo;iWdjRIc{~fx5|5xa0UNIv&D6gOp#S{1dn_`Lk z8=orfKb21SFJEOW(IoV_qM^J2_CS0_GcK-_rKwx!u!QsM(a#EWQh6O4<-!V`tPyj? zG@{cw-Ja$v9Od{!J~aa^HugL>QtC9n4AEyXDA8=S(mzgXNam1hN?tKo0>##Vx+Ws= z&#Dr@tpT4m|KZDjI`(g8|8v5}{Mh%8E2WSDxJGA}x7ngNQ!S+8hap`yIyh!J&b=$al>U}AmWuLW2QufLd!L-)Ji&o31^&XF$*)r}Kva;?>m!^vOj&36@tZ;(y?z(=a{;DL?f| zZTF#b7e!3PB>~EV;p&$+BzO*whsjYo+=9EtH-GZVl83nW+u29 zM9HsmvMq$6si`L(r-^b=J-IMt`oxV8f`K)hg2!B?1KM5^z6P#N@u?*JkLxXuh=7nl zzEx#aQ|e$-GEK^AB0K?RS39?7v@YExe&KLYWEbr+{1j0l98?UO-8m&9QSs##VI5{CaUa(ui7Y3V;|33mb=?b4vOG1P+mQq~Uv(m5LlvspzSxm?n=Y4$2)! zCmQnA6VG}FNy*09X)!B(=Bqi5q3~Q%zxwZK1skh2@Zk*q-g;j1h0^t}+oV;c_C9@1 zVg*`qE%ZB45qht8>Gj#H$_Z{C0SUJBk0%PzpIPOVf_L5f>K`I%hf3+JSX{CcuSZs*31LO|u!T*<3Ahx7xW$ ziJX^wyosu8#Ow?M+4<=wYbvx*XW+`~KTYt3Pagx1qCS3ku~~W=-3Y+V**EQcrH3rq zIC@GtiJ)NC#`J1h*>Fy3=f-)fsUkaDEBo?-M6m$kQ(BTN5}e}l0%zS-o*Pp)H~Fmg zl1NT5vF+SNeFq0$G&aJJessGJ1#Vt;&Ux?bOyphe4W}bj41knt6jY6twn9T%t?@U% zOW@^As3NTQpB3a2Hyp*Fu}|^fb_2eaf`eFKsenGdJM3 zrQX8(c3^x76;JXIuT0z`*rcTxAW|hHn3@z`?hyCzD=70opo&c~V>5}ix|iAi$`aiz zKow1+VXGo$9Kz#M+SYY>&FMUu-j;j=Slqe}brVa7v6+NalAzX;@>rPra8nv8x^`&b|VTLmD*-3Ti5V zbV@89f(p!lR~we(CP5Cj@osVGdO%~_MzcTRYDBo{V0_6SI-OMC@7T+H8RM_wKi*Mx;p}aXUU&DWd2F*BJnm{t~=bH4oRbRQ~UKG)q*BtTvjLghQ z(5y)}ZW`=x|Grc&Y2}<&{S=*y(LyjDpv(ku_@2q)kXO^n#{!8Z+5O& zOVR!TYO%92{smeQ_LtsyL&-bs5v8VMHd&cJkjhn&HYgLJK|VyTW0nDu{*$en*=juN zV`nnpxSKhcd~_1XPd44v5we^ZZZusF^E=$@d0_$;JUmfb{JFN{aB$Ac8_%8CSU*6L z`nwm~0D#9V4wgB0{vSkKlPpC1h%uw1++c1|+?vztlv|~T5lS<30j=B2?q+p_2$%TN z_1fQD$W9p=Y8(D?Rh<6YYOiQJ3>_g?HnXb)JeD(UDH!kpy|J{i-oAK`K5^1N`^;+Q zGxDSanP$2pjCU*(sy-FgmsCJ=o3bsWr)3H&X48aTe@-aW<0mG0X_sY%qhO1se-P7; zy+cFl!Yl}wu%8C`jv_=}07p3)f$WwdY8vd9Q_L_0wGgwJ zWJr~2vbH;m-6)nQ-t1KmA52n%5AbRx@Kz=FUH+;e@0>uCV%8Ane2{<6U`%+i!te~` z)!xz!;LQ#_1vVL$QmM^tNwTjHa_`?pOV`xYc+JmYW(M4GwBML5HQ#^u;Sb-i;K~=fMVbT}&vXHlwaLbFn(*Fa zod3oUuZN#Z)kD+nu@Ve1e8jn1@QI3`{&5tE~p=TY`Nt=8Zx+J#>22ltv6zk#(I=A?lnygTNQeM z1R)=7Gw!-)%fR*Xt=GzEXfOC|=>|DiZ?5#+A z!fr;6(XrX#eii&wd3BhwmlzJz?sdSs1vwZUgFBZabe}IfHhk+C66`ts_jZ@y?;~MT zFR7T{S@)_%0r7Z1>CHRDE&j_%)V~iH9T?k8>1XP}Y2tge8&;8##=fLCh(-4RDCEyUiqatWnqpRu$7LVb0oJ4LfUPja zg(H*2-?Ur|4svSc^xiX4}=t0 zZ4VCW?J3WX2vGW*UZmJz){1}lUNF+;cr$r;*4m9I7=8+|-2G9nhZv4h^YStb3hlQT zZgn?D5YAB+8`|zBXx;ek&L5^U&mmY=hSKq)zNO$sBVpqdu}i!Ar5}jS+Y7UjTpYE4WqDJ0z2K` z0$rmcbUz|3eJbjxPyC8mO5-7t4e7X2&x7$2nCbVcfi@qmawmnk6Kd?X_}YuSLAdXk zhcDcB;rd+8l<4V+=j$2F7{o&gi?p;w|I7o+l|R~;+}vEoQb+OXWD4>tfq1yxjjX53 zU%*3|-N(`#^cQth218lg$1ac6*QkKOOQ;zS*VwgN3h?M#x6+T-#x^_!VgLYu_2~|x zN`1fic^nQlb}<0wECif~^)xpbuiBna>>H;xRUWrd->zSxNnVFRijpHK54_{BRSxx{ z#6GAFuCl25uA$G-{~d0_Tf=S-v8%3(0$AvQ@5!hF+G|axdtCgg>AocVbMeEj+Z5Q# z$}s@KBMsyKHIEW(6I&yy->yRZ&U6A9!-0XXI*Z7A$^V(EbdVnv{>Sd8S@Rq2&A_C8 z^d;NicEj#1XdLG+ePn7kvfz<<)jbBBzOaSZUkj{ddI3@)h1B2b-+V^OpD(Uz4o_!{>mvtEut(W>&@Tf)l95ChGRNKn9 z4GhES0ZK;`z&)c}W2K}%&-B@!pxvw&XQwh^wK&yikX}6#%n~`BcM%Ub-z?^J-^$Gr zKR>My$3Kr90ZM-SIPM**&wjz$+$!CVED9NT+t@kkL2i2YEC9re`bqKJ5SN;mB-&X+ z)eWt6Ev>1rHr}%T9Alw+WFWw%c@5p|DP?nEJg1n~_6)aj>q&PfrY5nqkF|5GoC6aT z{7mFd;IL0^=jI2?!tupwgEunv8V=z+dVB9sE*NVdbgH|g&eVE(MkfV=iQSYvEjjVz z@eBdBbw=2PSRPHdj9}?D$L|Q7C{VU=AGhH@9eynMFuQj1h z`$Y5ec|>JlyG;1LVNyjsZE`*OLZV(SrJG4EO9LY>^^JF>mps9U`drZBp(8hTmG-PH zCR_gCb?W87mU5_nFTZkz*cr}(s*u2myK{=`WLw3BYkyPR)tQ6eh2hpnCUH~Oir$|% z`0YMRfhiSwAiq9JezQl-IiIK{bf#PW8Pe5Pjw!wk-@31(?VTr~5l>~k-Cpj@55Ly; z-VWxtABElhhK;;T^gsNws!^pa0m}EG5N`>FK#;#rH2YALHf?@y^3cygj>6YPzsusj z5ppqI{IIu$B^2^sp?%{${xSw4z5>{ZWI7*q``zc9Fw`X58h(8|<%X> znhf__WWIhn69WO7bQ+cf30m|Q2IwZEy*k2?w(|( z?UiJ>WaT$u9E8~2gU30FE`;PR4K_`;tyo}3*RTc4zKlqQdprKqSh1{S}9 zBMuWQ!MNF>1-=K-R%%mwcuDbNzc90MI4BmiPJev?tZHQ3uHVv{OXWu_6l_oA+XFk; zfVu|je)u3KF}uG4?22~1EZpYT9Tx{%aONIWM?!Y=V0oUDwnS$UrYecM8l0wV`zU=_ zcRqjec8~5}@#Lum-Qix+qN9Y>Zs4B(E#1}&gIMp6vq^sur(w6wJ5y>gF1Y6%T=b88 zVWj9e0^H_(aj0sZmH*O+W!#-!ncQcCeAS((#QP6oX|cx-=%5MAt@>a}jy`9#Ms*d8 zX2a6$M1()zW%)tI7?{F>wS*)+HN7RfR-mLMb5o+ZT=hki5id%m(g#z3XKc%u;93qsDyp5%Kb)*_QQz$y?2q zJ_}lyq&@ig;%XY#W0R`ZDT>XIEW80KWyOM}q`J8pgX!v}vEp$nG)i%Dz^=LHOm)o< zTTxI-GabhM4WBZ9`yYH-Quw-1Im_PCvN9Z6)zzbA;KzIH%jfy?gt=Cg;W6Pulu|9E zwnA+p=lj7aqs>qL6&8?^+WrcVG<%7JhtWu?XVn|nuP`YMbcnU3aWV1*Ux=vzcpVks zT625n|4Jxf@7n(*f|3_RYb?|LzZfo;NKjv+^b@P2u?lQTokZt?`2!K;% z-cf~ZKE9(41+4A0&bRi>QfaNj1|20Wo}{$%x>O1(IH!P2P zo1pNrovrX-qu2W2f~j)Wya9E@X~!HF(dS$hp96nkqO)+KJ9LDuPk}s-CR-5Q(^b+xH-)Pq z=x}9kxDC^Q!6QW2&w7-q4|V#UTg>8TZKpFs-Mwwmvq@drZ>!LvFzfSev5<161axmZ zccY6Rck|2MB)NtkpnAL>+p@8zG%jtaE37FfaOparv}~Qx7xnHvz3>NnHgmhAPy2DZf&TGSDGRJB9sa+i6`6$(+f=wQ z`8NRN;`%hxv_{Uh<}PNKq!~3zPoUoN5CRDT^b7w019=A*mMxA!#B`XQ2$o;e){Lg! z#sVFxr8AAm!YrW}*0XR|Rp}jLUgDC@T({49*Y^FA3Eq3?wfeP!X(0`>KNbA^Z(j&r z5hu>*u>lpbY-X2X(cb8VEN`^-q89>_3XWDMe*@28XHPlNu;-Qjt=jfQik~cw4_Qw2 zlmuJrtpo@JsAFuw81cF26dgfdnLnZ@(PFw&SnZ|!9!021`SE6m0va1YtMiiIe$lI| z3y}mU!wJOB9`L>`=a`~-_gr3pE|~=Ak}gsu5~y&HNtR~h@f;Td61QMnl~aIMFj##R znV~T;`Y+uaWIFzpE5^AuYOgjiKqTy;vL0RAZ0%$A_V&^56?o={^a(23U-awJyiStAbz zt=H%d>Q1oV_n{EIS5YPpi%M$X*oUIG3FO8pOLhGx{F1k8E1rdJ^SwoYQ zwo{-p8u&{l)n_YU?#WFY3;{P&sPsA2LG*GpJJsD4`M~Zy zXR692wlpiB2i%kT!pc}eOPIzp`tT@VV${Aly-J-A#u8iyo8p4{BAdr z^4K}_gaWE#lXVCrfl^>%46%F4cd{$vo7zw#-WYRXd?i3Se#U}92Hge}d{GMJ9ZQV} zv&)OhmztTA#(i9AXxu7O)_ScivHwG6Y`zh!nJr$RLQE)MJybTx|4W(_5vE1#&NNyc za@j5E+OATZc3R*+^%n9Q+PKnPSg6QX z6fgZso^eBPc-l{^y0<^8pRTlfFc)l1*!oAcWE7#`_podoRo;W5hS`*lu4-2WGZJYJ zAs7xQmDetK&mM_TU~b;5fz?be2njdU1HjLjpB-7cyAvc-V*mNh=MZ25NU2cNMCaRZ zq|~5HJy#_1zm;s(_0AGBh&}sH4i@C5ZNB{oNsf0uWlN$ zUrx3Bi~IQa5=a!LG5@M2Q|T}FVj9GexjafDAowHy|C<*hB+mXwQHjO@$Xr^JMyQ>~AO8B3$4;+I?hwM0W0wz-j?P zl@03I0@*-M#-c{*ZGytJ*q^VwhlU>I9;;{s=rPg&rAPo3(;Fl7X;iaNoiVJ&h%QEp z0AIE4=exZ31TY~wSwjKb>Cf;j=hsc&x|BjCO!bq(t&w$Cld&`=q&V6!;Kl8DXSujz z72cwvH1aX?r$0>ZB-VfmxSS&pgq6)PCl)x{aB^KnKK13-co6qYj+1m$rgtvAlB_;R zU91sHY2ND9>vs@_i8AI}r}Mszzb&rPXe@p*Jj9FHi0K!BW@8QCFIN|CzG zsk-kc0!y~dgKH;4UZ;?*{#QoiJ+b<6_*BJJY3TYOaT9LJ;{igBZx5+m$G;LVxZv&gP z7!{S+Kzb`pej?FkKO{_mnba{Tj=VmzOJ3E3v3VY=h}d+9ix}nlTe^GE1uYt=SzDrd zNYBHv8XhZQXwYjvBnT|sAnRj|h<5LUH8MHl(2O;RK|ip>cen5)Gy>D-c_{rBKgc|V ze)@YSJ+IO@8a84>`zw;z(0&^Ro1t^o-j(X>vgs5a#G*kzcpY)v2;m}B$P=*AL@aTT z10raEadWhi8tqac4xBM&9-PMyyb*;b#a?}=4lM>vB?0mxS`jJTwhNAt(8Y1Ys>C`S zC#TIg2i+UtO?vW_%AmT)edeajb$le{o%)hFOu4*4bIi0!g_rmp?Ph$D|8U5P@;Pn! zef&lEia1>Cy`YvLcHw1Ff5=mOwklp7taKdkQj{v-FFx8N)1>Id=S?gl5+AQrM4-|B zFjHS0g*0{4q6#`#ab5S}Yq_KjzJ^K_QkpjR&j=$Kjc~ z3|hK@R$Mtp1KBb`Sh|d1lJm0DC`)(*-E|EUHUS&?VvuARTT<10#p55T;&}~bPBjwqmgA|& z($+D+p5)kFF5I`dKzYvoyg5%~UHS&;LRl$8hN<8|ZX=Qtm*JTAI)^+dUh0ZxRAb5X z3!jTDMRKfD=?LMud7LyKKIh7^+B=7Gh)`-&NX5$^V^_$}Z6qGM)B~+I)Z6F_*GIFb!t>HH~EA1-aDX706X<(w7m%fU_~A zfe3c`)}g8TE0~+WM{}!K1#nMv`d7&;q(I zCe~5)hxNS^KV|2!-mDHVlIUSbas=l{+I#tAKeUSjZqplMm20}4oED#)@-kv-8Byg3 z81z(aKg0}Wi zs3Wx&`zW}#TxvqwcHLcc?r_>vA$h*R*Or(oDb*$Q17z?~E}ebjBP*n*5#-XN=ZtKW z<@XgfbBv&4oqM@dZ$92onG=XN#Pq^m)^W|{Rpd9zuz8{4LfIrnTPHbormWlgw~`sp z*}1@`ZSPD!cgzqJ;;B!Rs7$s=3lqO86P*kBnIe;1-07qqaqln2MXoMZHM`|xgogp# z&p9s}o$FLeR!wNI=Z~FSy)L~loLEJB@<%9r*t<3gLD?WM!)9*3F6~}f9F+zd8|WyR z-lDS~2pla6ixQ@v!8qhOSkIVL6uG5)6h!AhLD_sk@BvS#0-vLlx|>L4Q$6c9* z%V);DUtPmwj75SeMh)>Rs5t*P~A%oqN?}=;+X!+gi5YPtVR+QZV&X$F1C>T zz{n^&XM%n!#3)|G$fI0Jee@A&m&LlA!@j^jp~1b6qSTHA=rWyY9^`M0@}bvN`6xx_ z2k2_ljSiq4j0F9$c>=h7_H}^BZ^q`EHo0)m(HQ%q#M-4B0oBTdf^ql+kNB{pkx*o+ zAw9bWtQ?0LwvC=LYuX0sXCV9$CZ+so^z?a56ROS{DCx_ns|!Oa3H=aE622s}q2%(^ zqxAOZT&uIjC?DGJ{v9PhQfY{_^U0%l5U#?uAPmE0Z9kl(z z%qb15)XK)ii%mjlqO?J=*TpKxq?}5t1faSb_ibzK$v@Y~XU$v_DdNl5aNg>Kp?|4U zEQ_5=9EbxUo*27e`jF9Hl>0&Ksd{NumA({bH!=oh=?+z5q_i+Tc%KE=?LuT(&iD$kPH z!1wiVXs}GiG~H8tJ1S^FS`$4swVF?DTuLlp9O*B=$E{8SVu_(%pO|6F!F!&0;>Ox# zgdm56Rj@-LYn(4bo+bD9-}$~#yHk`Rmmx#t)Ue%ZwBqkYXAUmQTZX1$Q1it@W?-U_ zz92_62?II}kxPylGeu$7`EU@M7MS@{3F(=XR*k%)@tiK?ZFU(LoI}F1m`i*hd3&ou zbzXnEoWZS(1q_wpB^d(5M&Gxbz!h$GDRs6S>)4L;oFP+@5@yggF(=d+PLS0^UniaR zl4@)$mmDqm>mhRch#ff$^0vX(-@JJ-m+Ea`;oYf$MM8p5K1++>X; zAPVn!!~m4rDffP~*7FV6jw%+in1((qi63#yT3BA?_cKZ{iZ7KKXfU5`q^Y|~?Cuwu zn&(OGDq~|Vb{I*lbh;mM^Yj{OqheX}YmGFHgX1wPf*u-4_8B+;VD1>{dchg7@;HI< zn>yC%!FX9r< z%y4MBODcxcn5c}UDKQ$5hW7NGylrMWI*S_G=!Aw@41Rx34-;X3-`wuHF*=^>VjIs?3OgktGXOtSK5)s? z3mR~~a92_ptMx8$w4$UNe1sv1J@GPlDr7Wm#RH?eoNO>hEBAjccB}zD|Ys$tO3_>qYTxK0^j! zQa0%VkgS{(ClK;exJLPO=WHjr#L-hSADO0djgs&)Z8AJa8OY+(wNBp|`bupQSl!S^ z^l8E73_ z<1kM3RfxTgqx?Vyx9;S{O~)-WLjYp)wg;u6P6Zd9Yi%V$=>aTp~+wFEpRIr$RN}6tB7!~l(W~^jJRK%e?SZPA=V;i z9j`>+H|0q-wTQQn-2Jf@@LC}*nb&;(Dl7!+vYEw*n)w*-w_Q2lh&yYNn}T}MvPY`` z|6cjlg;u2?bKO;C%>Ke%Q*@xj`ht(4iA00OTiS8ki0G``nL^$3{pcfjdaUE>hKRCH z5oSMC4y6A}D2clIZHz?7n_>^IX0z{1FW_$li*v1C&{qA}Q5vj^dltiQ@6<%Md^`K| zsIdHP6f%Q!HciFm3ln|bi!;pibzl;B#C5>vt>L+HSrFU<%PvW&qzxMGx4?vd7o5Bl z{8k9Gft6pTB)gioBt@)h(zE3xXE zVw>Li+@YZ@Bo^kAi=?$F(YI!(VNy4P#Oh!y)qfq(4R+{3Fx3#XksHwR%CUncyV9qN zt$6h+S{N&Tcv`qqyK%1oDH(OYEr=>dvHEvn*SlcGO*d3fYfNlVsYC~JUFPVsK_ z;I#+@AR7!HZpc&zRZ0c}Ij{URV+skbqWHR)uW;2tH*l!+SGsv;XwEE|S}J^$NX0OX z%y|1JrTlgq36L&L6hDrARNqI{M8`SmpF)UABe_bc`@A^4neOen?&=!e;|h74$9zaq z420K8qC%JhrLC-Hd+hz-Ci{1SBM$|(qFwY>K{-{mkKKM}WSwpflD9ML+>jA{LKi&m z44+>8vj>51QitZ#Eb{SyF{JTk%tbNg2x)kARn@cJr{O87zd}nht$Kr#u~m3H90WZC zA}a?Q2qzGi_*(nZDx8g-`UTSm?a6ncXWw-hbDUMa4JlnZGm<=$HhY__4_Om(Lsu4d zLyu{cChe?425{HN+DCFy;V;V+yN+jUT5NMaIVd)!!`D*P~A?0M;>$)H>2R>6WRT@tBaZOkc zzVHCM>@QGzJ4xbWqd19+F7v{iLm(Z}04N9*&qbgo5MuT>^*}>jNq^un+il}dd`Un8 zlj@srOcc{qZ30u)5VzS~(|!X6%Vos{dosDB*Zni7nUM+YU3RI5h0Argf~h~PS;5az zCow{mO=@NpRyBg&9Cl+W3>@CBIivlxUK5QU%1HGjY(ZVk4kWEYNJmyoA ztu5}a4?vnTOBxx#I$lYe55|MKPJaIovxAW!w3DddMIcUe3PqmxR)?$M zy)cU*4ceQ*B$5k>E#?%gljTie5_HM|z@^-~Y}N+QTY@;n1ON&ilz$D+I7|$&hRCen zbT(Fs=e_r}bYIEE-1u>27jv1>1aBa~zCsQ|G>uDWLU@<<0spvK48aKX9F(|?T(h=B zMRGMI@&}(B7j-ZrUca%mz%adBf!E7IBbgSjB-Xpi!-2OeU6SyVXTqc^a>6>olSs+hZasY7_F3& zIhi-nLdAm71tqBn#zPt)X z8tgzCY7`m^XC-eh<8DJ+UC0j)0bwhqJ$rQOK}L;BgvQK_Z5P{Z45J~M#2Fzv3eEu% zBt^ZM%e1DTG%3$GHyz-PZz2bCJ#FaZ^Kc>>piWA8PO7|_JbCCdonEO1{nW6;nadcR1}aNkUB#uDI8NvK11Jh*|Tqd2dfGQ6gScY)Fp zLFqD+4I~FIrUi;OR2CBbjfR=9RHze!uT9D6h;so1O7LjhyLjXYmvr9*CqH~GZTyd2 zbE5n)c^2RI(P&L#CyF#PVeI4by$RkR?NCx=<`GS!g)K$68Z!w98HC6f=KfR2AGg{pf4acw0X40k1 z0|(y7JZB13!{do?p-#ZH&>dHm{sPX`UNPDN zlgC;vn)9h}4J;#&ps5o!E-AZ;8%E^RO2tJ%S#dkT%LJ48poFZNeN^xfM_u;{%Q?GMsg>0CogCcd@`C=b06PYJBx{@-lEm{P z>Bu(%fzxBB=?Ztk6&2usO?L^4+zs;rUd=PQX+d|5Pem28Kj{BdcI8n?ZtcEvx}8eD zqh^_U8p0n0n>#lEo>)!uZ3-*5Ze%`&=zvp>=zh}R=e%39A96PV!{B;_H7+aut zT|5bT^Ja~e*H_f=s5c^YkLr!arZlY)5mk&z#n-QiN71@-rtbqkKeabFY52dbbNbtMAN&Z zqe!!f1P$FYX&G^Gp~R^b|KnuDL_+^I&lcbu|5kV$l%W)t_9Wzj zNELtyz&~cF7Bg7z7!hfo=(bQrjTw90WB7gTZfYCI^5-)_t?!?|eP3ofdsVo!+j{H0 z1LKtQ2M&At&FxR>S3*nUih0V6Zc$#fQc<*NLJGJnm0GW^d*Q?L=9xpR+pzPn0s63o zh)F$d6@~!}+QBoZ6$# zS$YN7uCL=@!fdwXJnyfHL7m%fW=}J~=|+$~%$+@?(aOA%eD^qzIt%~?!v_kb9)`2zVXw+<;>xk`?%t@zpSPoDsUhlc|r1ic+G zj0W?Ms&vUxZFiLAK5tb_sXAXo{T^34QKWw?6+8skK~J(ZBjJjdIQF0x@t%iDo8z1T z;31@ZRSxPMwpdG00BhGL_~pl$nCn94H|zI=?c2er-??{jTLuuxYWCkwYD+q3a!i$Y z_E4(L4hst-NCj0FMH{xbqXI;6fGOV1*v5kFe`$=~1u2ua*H>{*6F>d*2&WI&PvJ=B za5mtOe^ylmaz^{)NxU<=_J`a{B;TAbFNj&o_#Mp;XyS5HPU=Fk8^>6M5Uk#jc<3`@ z5o+sZ?hq6NFZU?Xi%>nd@oA|u5oBdR-U)^yny3!iBD-qez6iUKz zvgMVGr~ACZ0XIIglveEau>ZM6`rJSO2(O}}xVO2_Bn^DtvWh4@w*)y!G_V{-?8o#N zhL!EMAV`48daJr+^n&_?ciq5xiV0`%B>>u8m4{t+yOu-wZxAjUfY0lqLS-{p%-e@r zLLNe2QYdG7^fVVXoDIY~JM z>VJM1MM3qKNhGW_Iej9VV$rzKROyV3;M}sHAr%wzm>WiT_)J z0HoO0y&{0C%Y+4R30b?~+LbF;qKl!_)@Ws?)t@vei$;OHyiQ@kp$$})LdJ2RYlZPe zs%&NS14;J!NxmZaJHno(c@&(_p;oxNrkGJ(L-@!wYp zf>MQCKwjT>K*K;cdIpmx1lkoKo}dK)^E7S&N1nsDCaIg1jC5WyefQdiE>{%LGp65h z6~(y(N-;F7V1IqXAIiX71hTycEo8(_`)!wNQN07|V}2czaw>tPcXj~R`INQJDkWWA z8_qHc6A859V7NB8kmB=s2Ysu9VAq_sIBMbPTmP>gZ`Vb1z%6E3OiU=bRS{Lylrl{S zE-4UIItr#brd;{njW12bfPTS(QBYMtG45HTty{$Ia$kZ<^HDyMl+@1r!@3&KsT`}} z!BG=*cWIJEO@tQULS269iXZnWTbZ0JN68?vf_f>;6{;w@x`cFeJS^(3VAGD7Px6Go zm-n-?7gzW{8-ff&DwWflrk~J3prtd7T^t#ntAK%a8isY{N! zHO)Tgz--eb_y+$E%tBtyEqG0gvJ4yzEv8^)X{S4eq<1lGg2N(#6Q(tIC3Vsl!;F6nDhPK&lBsR?DY(E;Lb=Ilc*fJFe2BFwD}zBtslg!P&)3qCb8Fa z41;;BNe2lfqe`sP@#Yanyok9>9_;h&k$BiQCj){NF!%ymJEdF2!)IW)Og$g7)5)z^ zuCz#j&m#GJ@lKtzTIQE{3qg-6o_Vb`{fVSVp|>~irv6cvlAff}pa;;(=={nZEA>H> zt1T6cx&ElPIBN;_1rg=uE^(kc2N_AwZ0)glHvYuN7F-s_+g8+q$NTlJd`f1+7to1= zNQ_p5bzEwrN0)U!`;0NPBOIQVc9tkWGYj3 zp?a0-)CHMQ$Zg{G*C(@Ka~nfEXoszm^-J%oZ{I#^c4`qL{z4{vnG3>~UOPw|^RQTSWp=i` zi+)Zorpb|F4CB}X5T+dy{(OvS*>D)IX?Sl(git6t0u9{U-$B8&D4i0-D%ne{qjGE^i zmg096V;yhCP06H85t(ggBN}qMhZU?kXSF*%yoHN7Mz18*+euO4Kyj{t2Y7|=VC1{G zafKjG!o=Q)s*nCTq^1_5S5B~uU)z&qFTl$798eFXQ#+XT0=h7QL?VWeq4b&gb|s-f z@TuMa8B{8$c9Oxl&c$}gjyFHA7CxNrb;ok(9;NB`vmGTu2gGzGPXOanP&qsg7@s#R zl#uGY9EG*;RYzHn_Ueb8;`GVW#6|SnK$)Q~#rtja{6I(C8I!y&(FM_Qs(NeHP1ZsJ zlzqYMmkNHV0>9>^(r zi<7WcN5X``M4HMDaC!meS=(G}9xq6yvy7HzW@q!$*%J~(@Pd&V{5h6qAm&RpGb(BA zvKT4vBZB623IzI+CG#Pa)kVliGHI994J5n}D=jdw3Jc<{dT$6(OVb%kl)42s2D7E; zAp6OYS{)xit0WzC`RFPu(+)>nZd|>^1LJ~BZqWQap$sq@!vl0#dGsi21aK$_!7P>l zRh0E+Y@eEK{5z)G2~bb6gDCr2R8%oI3$Z#>5Xg{y=b@8&V3UF_xMbR499kQ3fNW}# zcNiH*z(ZIp@g$m->LApU;NdV<%>9Pxi(KYSNYp{Xw4|uH!q5f&Db4@GDL+C0 zgm*0I!}W0JFY87-V_>`r4=2fzn2p75SCqZ*NT0_WAXaCsuw^3RSGc$bOQXKp&iJOM zTiUXvQ9X8sC@LOnqpB%okw@cf)*JviP${0ALv-q{<@;y8MrtuqpkSPo1 VP!p%L^wuIUr(E1Y$m5s){BK6w1_%TQ?(XgmArRbM0}SpEg1d#_Zkgc09fG?C@9)UDcaP9LoUlux*s4ZV_UDwK%L&1%(_TtYSdWXjW+Q% zPGq7?`j0;eKFFy3ATWv?HHq9|C+nE(dO4L(2&4x4MTqRWV`JHQbo3f>-8>RINCJ{j z0Y@=1xuFj^I12N9dZe`25vgusv*tRxWxNTaLJC+6C#s^`?Ji!6rFq;U(|$w>$U#^% zg2Bw*6B1(8_PTDt=skER6s`mWkh`<~<}0a_o3@G3xx8qhI7dLRD0Fn&_yMoga2f0! z)w=_TU`~RoN7pb`dg!Gv;l@9Q(g889#hfYq!hj4ae97yiSk zT8x-^Gl!r1Ami-mSm%<)f{@j~4*`hoFr`!Yqk_ftJk~2Za|6lFIQ7DoWTuzINzJx? ztkX;7ez8oXN(=CWWHuT~A#amt^rW(GZz!m(+RsKv#uo!PX7Ra_-T;|LAzU%uDIFr@u zvYzq>eRZ1T=SLWz?%8{v4`0h6|7y>N0psVf*HTN$wek8Ow+&w?9OL|DwIgg_Ov^UI z9L>lWY79c@a$lN*_8I;0H^0aGZ*$5QfwuQT+Vy`o@fR5t#z7uy(Ce8MXB()r{)Jb5 zRkqJ}-f40%*(Rvhdvk~@vklKL13G&P4sV8*-owGL4!zo%F;Lz^EXDKZeu}m&OZviuXWT8&t2kBDQm1B)SFX(+{cPNN`k{)Mb^2`VkR;)*>xPppGgWK$R+HanAA+Fet{QJ}~e!gq$k~|`8V%sAnbYD(4-XaBF zq2%yf?O99M@V$lu?`t(evgxwcjLMI=nT$B1m+wq@%j;?51Apf<)LgFp#N5E2a9%5^ zqDr&{ZdlPrM~;-5TMxtKdM7^mFq*gQuK(?Sh&2+Z)&0O*=9T|Ug;(?8shy8!s`O`) zXq)1nr{nTxBB%G?5BILAKg6?SGZc9PAZ~J%gMt9+=NNOui$*t_% z$R+F%GDe5)o0!bfSZC*@! zVFD|Rx0lhO(4CvV#Su%XKYkr&^x3CGSgk8YzWdbP=Ccr4owB>gnh}|~ll5vOCuCV_%p2y*xX{>KVhrNAE2s?1(E1^ zBLJUzI-5Qka?_X5w+oo`yb-z{caQFU272${D{Q^W&jcUqIG$iZtx}SoVW>k-6+3wE5nY#Aq9{ZfuIeN71VtXJ&dzX)l)JTeC)+t+S~$4%37Q&R$LCq~|(j%A`3 z&x@{WdM~SgRq1fp34nwCNO-5+*?qewO4ivG)%AY5$MF$z$IQ!j^?|`uo^jMtg$}JQ z1|byfn*vw7OTg61%w>MWo1cmp7k?2d#)BklDWL+s3TcZaSTp?VG703q)0NtV-uWe{ zJ0ta1gnd;x!hwh6`&m-%r9D?kUY&p~i{2lqZnGnfjcKUKxK>G)a`~BRe$!ylbPn-O%234DEHTT~?$V>>-O$rme`b_YSEa(U3jj_My zlz`zN8MZQ!0b8ePg_46?r~3QKuWc-7$`Om{-d{?8E0p7aZbyP%lR9cb1NYD}a*i_g zbs$upDp4y7VRo~uVS^!7!-?&JwyHEEUma6cy3#Re&*7wGt@QB7lIA+xcI!Hg8ku`W z#bhaTG12$Z6amg6+nqp~865b>o#oOfFR6sfqxekaev|B_K|zIKeIveG!xv)>7(wQc zpTp@JIXCB$bx()XtOiW67!8vVB_#q$k`bWqaW>}^Xh|aJlCZ`sGa1r>red%1R5Tg~ z0tx`~q!5pH*6QS(a$5P8=da=-K)??#qQ;u-tZvQP;rgkmEQ&W?E7Pn)gWN&lQlY~2 zvYqbNCm-BYrszyLgUrj;w|H<3Ur&NXdO^GqSiq97pKJ-_`!AW-;7Z)RWNHSm2F>0Mk@r-wTHa?22PZ;l`kIt1gMGVlQp#Fn(Bf*4Qn#hg@PixHMP0sE)rkw`=yU5VY!+}2$~v(tpztelGa zlHzO~ZzI;~*g}R7y?v_5#$f*~B6m0U*X##Y#rHaU(#dIcJ82Q3J`+Q&(>lpXXS8Fs z2&b4B^F?y`pPLiB|6I{^i1Ix~p4stq(qIFhm|)1!lAxyRS(YR#FVLALw)AU9afP&jRpV|UBBQC5`hntm^W9s(PBD;cKm*L z-we(8WjR|jns?hh0c0TPc(F<4xBEplPF5SgXj@d3jl|g*Z0K1MW1tw~$kAd(=#=d; z&17A-xZLoHeX$We&9~h@1yfbd-GOkH6Bg}euqDNPBfsj@narm%CL%%v;2EQn`G&ojM~eyFgoQAD18ERfN9A~(zf@H)-s;Qw zy=RV&Ii)9&XDf5ORb{9g?;k+$JvZ1rk+bpORCXK~^ZpJZdNdg`#hU9+%}`Odg_||FC-4 z3DU~q8@*-0pgYY*S^Tc}`RM9l6SvGxy=FotIvZbWk5r`QRD5aVq;`jRZcXxZ!M>JF zIc#nb$xkqga9Hmtr$(~hWfuXNGARULtF+T5Z2;`23tW+$rOeI=E$48FzV-|frpTaf zJXH#IN;0wNZF)6yc{t9E#Zn}BB^(P!W#_ ze;ZcV$%)n5eJ)~iYY;X#{Tqg==iu3%nQMx7t50^+P>73)z{Nrf#v;5cDTQS;HHy@Vp03cJ(seR7Q_~aMu1A zWFm7WtqEfTAJ;2I(`8~_P*6=)bpB+}{?+aQZyE(h+=^epXP4Rq4tG2)qa{bAZmL{!xve~QYr@Xt}=vgGmW@xb~kK?Hor!?=aw? zt`kvn)$hB`o}#&RUg-6x02efP_*%_@?vS#2KaqIs%1aamPL<6w3P7j1h(i`eqA*$P zDpt&DBYd}IJ+$QOw)0URtzmXXE_wOxCA?rnOX2m-mowZ^A|0rZThX_zJi_j8uu8o`(hf$zg8ULY8B8glnHft84VEu1dy z8|KM=)z93Ge}wja4)2(OMbCIp`D9LZu;ZJY4?B+{g1I?Dg!phBdc+}jd{mg*l$_H7 zo%ZNG+F!CUYu>}~9emJ-gG~wH zz4+C8=I4m70)Y9-S|MHp zO&n5B=xvVSaeSSE8|TzW!E;=qdg_f)fGsa9*_c=y!0PEo{GV zdDq0uUwyUJc)lXf_6IP|d%LFB%7b+b>%hKsWUh*5I1ovoIF8l<(SLM80&>w*s+0E? z&9nWNl8cZ4ixEa%7!Z>z-n7k!e&;5#N~A^{Q(xUF^;9@8X8aec zgx&>FvgALmxYU}hBe*%O7T2wm*~uH32Kh5BB%|z zNisPH>Y?h}C6#>4GlP;$KuO8xa^RyTHfi|KtAxZ%H35FTSAc`W1af)i4m$-(7ce%p zyuHVn=oZ)0Lc-I9AF9o9gVtv8F}F=283LnUO!s81lJ7YM07di-$&e4rA=wOK*z)&) zvClsWpUTP@*ep1&H=(>V*NJv+fC~8|e4ybp^g_ru2vC4+5}~GuWkf=SxzX#8Dq&km ze&*Py?lNCqJdI6#T2FrZDqjl=A{Pc`mG3$+r}A(e9U63O_d2dRM*D|(<=0J^(?_Nj z`OFbE{4n9geF*az5b)kVhB<@OE~{)-ky4ixD_S8l-`!i?6}xdrt(Xo zf#SC;Bz%nS8#l3o_Y;d<=oD2Z6Dz&|fN8T-6@ht|D?GYv-SX@X*(ug~LJk6`Kw<(^XP;mcopa}X`)8$+0oDup7jhPzADPy zVuS7aqqAvD0&D~ZB2Vb{TQBMAHl=1`;#>5a*ZU{ZKdwD!_dPf>3$YEBSy*vW_-q=s zc5O@D{h@eSprM(7enq!k|97QR${Z%|eyN1NDwVw!d*%_vas|K8N&*K0yf?<1O(*lF zsYSY0+PiDv#%=_*!hviK1~%vLi5N?hHtFd-y(sBM_$I$^@dv?hFK-k+-X{fZv0g zpJJmayptl-zQ2)3v_Addtu*&-8Xq?s#nUNxvf=bH)Zs4<&E5H*#;hiE%+rGj=H@%i ztLZw}mFZ#BluKu&<0M=Wc8c~G5YmaLqxz9H`637yeN#5qhHBw9oHEvYGj~2fx?@-Y zNkKIH4oBPUW2~?o_^=8n;i>vPpaJTf(tB1+vS7iBo&be!q9v67U zuMnpFcpa+5&xe9%qRNp9IQ$(ZTzGz3!0~JLz%;YD=6RX>|7 z_~ZeztFQ8rI4nqEc)4ui5ODrB{XW^r*9J}nB z@4!86-(u%7{%Nvb47JywMLF19v>1niyv@#oJ&xTDP)&q$i3Ik$jLKc7&P;>}0Gp|l!p+#;W-^p6mv*dimqgMVT^r1hf^+t z;RY{iZFObFfoP{wt2-1~emNQbmDVtUkFds;1^Fa0k@<|v%LYj=!z!EOOj`?lF7ejT zy17&8_#?r?_2ev)VZ&W_+E2X?PgOesE^sb32`)x+#kJ<_qKF>!mjz2?S{7aizHHB} zSxko*8_iiOzpihuOOdM52lm6pMZ|8lnTsb3kD7PL5L?-~VQk$Lp-VA62et#?f-J`CpP`X z_FQLlEVDAFQdnU<7^ zP3*pLj)il9J4$PtOg^2<-G!Tz-!^gx&)_Po-+%QtLm-onJri!y)pi+0R64UH-Xd+U zeZjEI`N~DGac4p{x&U#Mfm$Xjg-J>NjK76Sub-b9O@i!5`re^8i$<)6JKeo#^03D9 zy!%Jo``G5lY}-hg?}L!Saqf9^1=_l-rw@mnq?Tk!bbNeF`;r=udu6SKJ(Ajl6FR?j zW86Rsfc91wX)LaMGhJ-I zU2B1k?XC{RFnzxcf9*?swyZF0mD9qgTU=d$PX6le_Tu;F;AeM#FM#Oz_Qr}>;%9jv z@M#6{2ZQ5wDd#b+v5)Vsw&AA$>bLy#9K*TPvxoz~D%w%;7esz2I&Q2VPrCT`%Hvl| zhPW_WFPJW4=OBZrd1uS3_FoM-RL98-G6Bi;hvmcGe^N40jg&ZLWZQbX`8z|fl!n8n znfmCtbKQ$A!{bIKrH&{sX@ZB*9C8J=a|!Gyuq3BM^CAnKn|^fH51Th6(0rH^f@@Xb za0j=xUc6n$R}fNZZ)RmD;3I0&3~~thMR{b00il(YZKXf{1;a?aNr9h3;dF}1x3bSk73{{BpRoIc++JJ2xX2wLlD!qG>$Bo-cJ3bn4`frleP;y4!C*9wVLJ-83`8`_EG&RyrN{!t;Bv~q zzhi>2Ku&n>PrGSOXJ`MM8O^W(QN$}0`d?u#9cH)A>06_=ifQm4J4z>Zc=ZOV;^c;$ zIKv(w!+HTrvo;QKkvoE`D(5=y;G}8w`g^2>G76TJy$%>0oQ#;d6Y+?alLFB@Io`{`?Fm$7GNx8f(FoxglG&4qX0 zWY?3KE%-E*$4!TCn#nugAdUqgh=SYCm4sw1?k)^x{sdu)rg{Gu(rej=TJY^@(>E;% z-2|OweBHq;U)y^%OUT;u^3CLNe5V$Q9I(2(nV5n2)TrO}E#EVU`OU)Z1EmoGAndVM zjbjv~hsqKe>i6bq=hq}HOm<2=G9cV=ZutCB5(g~tG%P5u4k(e8=`-f`d%`511&i|F zKdZ4t*NBrZ9zX0==_CSGPRzKH;E#1YmznLfX0|XoXR?GFwmMxCgItWS2eJjVA&+kM z4i788>yG&V;FG;>wBArYa@?4*K(~;A5Y5dom+W6~pnWZImpAhYWyz3nAo#tp+NKH2 zyhuPFe$d+?hM~Lr1;CCamPXn#@7CTZN#+*@bs$I}Nd#9#_`+c#b`hT10an`n9sOg$$Q1AMJ2v zYB}6E4ai`=`oS^R&nL2*YY2I}Y<*g&rtt1=_%xWZ@ib(Qa+i@z5TqOm`BP*hDw4nu3`Z9bs zTpsKqHXS$o3}{bHxq3pp@fUr~)1`1g$y5AuldCn70vMCXLbUc7QP@HhwqL-j`e`#6 zWQ6hPJI)Tw>fMZvNu6E?NWL!_pd4O0jZ?F;g#vm>cCkO;sn{XwLmJ@3VE4qA?dXZ% zANC<`@MJsS$j8LPmiNhw1d77{&H(LXe#9BN5`sh^5lLc6Dc{B$S`<0nW=c-!b zv0MlO1qB5t8ca@=^jq|SWn;~{eThw?9-nFS@)C0%dF*3D56A)rj_}lj$B2(p9xV*@ zl;5Sqbp`+Vu-6}aXdcN&=#uKA?PA!%`}ywT=*X__L%`w(bo2wazrm&}`5YmIpp786 z*x~G_*@s<=_Y0dl+2T~>eMmc(=0_q_C)Hv&&@9KlQXT)DqKQ(T^c<&*`OD8i^uq0c z`QRl=q?1$gU(HN>EejH2lq87@yS`0vHo~fEsT{90UlfD>_mNi*TYNKy`)o z6P9|_K?YaYSUzF7o0HG*Mqs zj}~@UTUiO(Z21&Dn^-RWXM-#v;kc4)9#yjtP18P99I0xrYzTMizebY~vQNVZf9*#gR4D{KMIW(-CeR=2v`6wf8Zf{IU&nerZnL3QI5IlHs_tC@mIdY-avM&c@1 zm`9UXN{pQ+EI1>~JY>njR~Ct&an@8iSn%#f@;)vAl(5e79W;u)+ma1SGVKa~#eMwF zLhOYNlVoXqx24O#2q~u4zBo+JpV~$x!i8p(h%-<`Uo`d)PtOmf;cT!>Q`VsB?Qr}z zY4-mZ>c0?b|NS0o-lr>n6P5+}k8uMBsKq0ZJ&ct9>?o3;A*lKnS(LpjBGjJvzwZ2EJzsjK(Gc%e;dg1p>*i{oLHkc9VR80v*x^>Gn zn}}s!MSYRnvWUb1L00dm?`z+`lNZYps;0DMvVgEP+m?_=f;w0_Ge ziPDD$z`V>&0NM*N*q$QU_NM*IC1IjkhW0;Z+b8E7pLAB2r>sDxLNW$HizqCD(?xxK zeMLoKfJOayxBq$M(E(*`?Uam+sOk3qqOyO;#{aIH|I0!CFWr6Rl5zBZK3mp$xPD}} zql|qKb2fNMN9XLkED1QpAgFyL71F zL_Cnj;qv3h^rh=<0qePzVVLK|K#(S0U3> z`7x8l$IIQFOP4^zjsOu65ukhjUS3gA(t4Hq-*oOjNAo|9%D<^z!iCjmCIZeoD*OyOE;qf$Re_j3= zdj;bkTe^f?@3X3YAd!o($aME^{S(G(3Hil(1B2dJ(kZJZBnl>`inwt(Qc_aH=xEF< zVN8>sn4%;>AHV{1lVHQOH8#7)QLf2nkJH~v?kfVGXC|V3Nf(CjU|ufF_mq+SS0++tgL6J%p}h{&e&L-O`&*-&c8^g`Iz^X zJzCZh5y`%s9OdxzwsFgP}|H))NVHGO3V`XPZ{}5?G%bc+pB9+PAyhTUEw&X z$j@se=Z#v|E*}qf7n9XbHW9k}Jcbdjw;R_^rt^^yeUC?^FWIu z0qg|$W;z1bn^>Y1j}L6z+9Kpimm`HGd!=C6hBy#4j+>$!8>5fB7 zZNc4ML1l%j0(MLxVdl>cyO{O%6;ZO-GkBOSOU20ZNgMYRK4v9n-HhvH1T9)AE!y6K zV~$ift%r^{$ktt`6O3@qJLU*i8MWCfWbwx%RnBMtyO`7}AREN0Dgje4Psjvf@yYS)xqi8QZA*8y%3CMOW`{rw?(-~O3k{qOeX->Ym~ z(k=-iY{D*)IARw?AYSMhKi|=!nPp>hEzrJ*5w1 z#bj8}tU|yK=!Z>lKOn59mVHK{PQ4IX{9`+q_|;kAWn@HIz^c76JpF!hd3pI-AG%I5sSmm>7g{=! z73`iq%RQ9Q*iwDwtN{Uc7Q@cnQcDi#-`<2n%lKB%(s9~sEm%=vpnl3CK#$uGZFO6) zK7V6C!0t#C%KmVB2AsqBx1+P>&_P8S%fd^WdtzI&7w) zlG<>NjJfO2Fm*hsZYVS;^44$G0)Tjy|VZyZf)}~MHIbI*PdO^q#XxiI7fGV7J@!oJ8i8|?}vz@S0eC8)^ zz7NuES9}R#*+HYf7@b+axtIE53O(OLcL65~P9US(WQ^Wp>lC7elm5KqevNpCNxmm` zUy9oJWtvm~;^TXGOQR>~V>Vjs<*3Dj3A1-ygP?#u#6R0={S9q!Tz8;ttzz_mr)uZi zi5xEMZmI1xHDhF*2^@dVga08G)QmZx#k8vUS~9K2aoSk@l5WCGs zW1E|!e6g>#K>zfMq&b88Br8Ik&t1ydQg`QF6mBewa}Lt1xUkAiX$e>8!^1;R5FEh0 z`04t@=6?V2z&=60>FT^N`*n90zf<{<25sTKVtn0oqVMX|0-L|xVE8q!)279N+NeUB zOLD!1x3_m@W+t>9|Bd7XD^FnVcfsFc!ife12M71}_gmnQATDasDEzYS_#G;Ae^4vq zZ?C`SySg6%IxUdgEn_&_;U63rc;jJFjRq37gZ1;=AGLtnjDdfaI=~x&-#tA|M+34C zpKbd8m>z)`BH;p#O0_VONk0-mCVTB04s+?5Y?t1k%|85Lu!yL>W2GztwLQgi4Z1f> z#8()SRsOZG&$rY);5n@Rxg$Qp6eyT;voPLB6enGG9PbAfu6p-qT898FdwNjqL56?i z#YB=Pwll|{k^20Mc*yoAh1=2C+1XiG7yxomqgW0O;2wD$s-)zgHK3BsH2X|0$Yv1- zJ$#EnE!2mfG6Ds@I^Miq5xu*+D=97A8BX6JuT%0vHvM$)At#WmZq+jxT^KwqjP_IE zCama(;>{6a(^GnFA%7H^lFI9&Aa`p=7Z)1~3nWxjn_X(henN|{EUa{mh^N$D5 z|9sP+Qwem_r216BMcV*Xgt>h7@{$i4ns+G{65QqGC3bk1lz7X{dZfia)m}&3P&vdz zMGp=RK6d@8MrmogW#hDz2$@g43Mws@AJGT@3IK2LB8BDU zho(xkoSmF{V#!u!XSF-WXJ>D2He&xZ1(h)DWT;#T_U9W?tChFaxkE|K5$Y-~S(ME4 zCRgIazZ~LOUamiWEa{fPlPK}+37L7TwIfkT&yD|2^jN}b(%hd(Q!8#;La+mgOD;=H zVT=xtFHCwb&TaE_5-Oywso8ott#@^G6&Dwm{pBpYl;x&~3JS0K$l2R%^e#%g+(s`- zqHJbu*}e0m6BD~wYgxL#4mXVdJNPu^4+)Eqc~57WkXOg~I;FMo&HYBfkA3DOh0QtM7?gg8&|?>f?M|3RIV#zC>9&^GJX}W{dE|3OgBi(8|~m= zy27ATnJ(syfUds2{Dh0FtgNPHl44<}IogY*-rOOq1iTM2J5oH|GE>@1f58uTn%os& z6rwZ;ON8y2KcSez4g80|R}z-CHeT-&NHhbX5>=s9;i?$paKuJKN;er1i-@fuT|Q92 zfyh7~@2n&F)#xgc6sfCv`0<32J^072dA3gj1Oln4`7=5?y0p~N(BKBG*a`X?iO;-V z8v->h73zyUY?Ly&_+C@9*yc?^r8w_0E_bUk)%p0K?4(^zR~~JET~Cd-myVDK*5lb^ z`Ga9LPm3Or>bgFb{uL~lUtC&xe=(tyIygBw$zeSWw5Qv*recA@?R&nY>{N5B}ylS6?mnrNdpu#@5pAaX0}ml)>aO z`aUxF=4w&_3Rc;+Rmhl%e<5QnyRZ02#gL2}N{WlCYiN|~)>}>dP*D3J-%ve zyr&AA6VXo9AvSL!Eg9$wS%Tuh7t|@gz^xgByO;~bY(di%ksz%(yFR|a4x+C z7-UhfCmi|6p!$O-1l8~fmJnN0u!LAnyukL-y>y%4fyK;q>+!;0)tYT+Ci)^8J~%h< zL3k}75+|Hj_CHo+aM5#NdAqq z8VE!%3<6yxx^)$3F~kmb0AGYoZ**NjpgZK3e^)@M=?{R$n{M(-GB+2lJh(^lP*)zr z2?9L^$xFY|@S4UTef>t;;P~wUPER}LTUzH&4(-B{A5pM7o59I`Mn6i^TFBE2Hzm)J zd6WC?F^d{0$*3jiofoXPC+TXuzH?b#SA~=kT92`hFF0Iv8LgFjNqPUv%L7q_WD_h6 zZY9`7MrJf1M`!Qh(X^X^LyLG@eLa`;7NffYIQ3Zp*+RFvvck&>{PVK-{1kv3T^>{Vd*88tRfG5X|^eA=<;OKs?%TNEX-v6_lD$}#;_j=ZnC#=DFGc$ z*=rCy-bjCYO%lI-cwm2k&v5Ur`?4-~nq?_r$Gf+lpT+%A=_%azu$Hwp893m#^!6~p zA(Fp}wL@#JsZVR75rO`ATBduFaJ*G;kSK`i`fHR31PUbY5H!YAS!8*xEh1_ht7_4^ zl>Rk5_eyhGv6mV2hN2 zAGa>|+&Dk*Jb1-mHFvVh1#K^Vv~RN0q+=K`^66KkO;*=|xLcDw#A-L@Ita9uP(5M$ zf_A@DjYGBXih;mH!10-D;>uxsInTHe&K7oXJ^AfJ;b-?or5IonG>=MSrDtYnlVm+b zvjPM>oeeW_BwEBhX`+ssv6)BT-v2trB*J7uqCS`E;{|!{Eko@CFp`eF=Zh=~g*v`{ ziDAcfztfKLZjZup2v;KCp#q-o%u9xab@CTyo=z<@aMh9kt9Dx}Pmk-QvVeP3TioyM?V^r&z6#uE7)1Q!q7kK=m9FGc2QU5}ry?U;!2vO$*f z9BN0-?IK%hOHO+R>j)P3e8$V%tEA0)x^dzwXG4kF;5pM%Dep)E5Xh|#P7kiwY(usC z2pBFEH%U1*9_RPa`wnu}yG}RmZXn)(5hwA7X0^hNR^`8~{i~Oio+^yW)!?<*t;_4w zcu#tNS+)&9`(c>7%)CdnpKJpz4yY6g4e=Z}xKGR0m?hHo=}{5VEm)1AmT++y0`~td z8;b3Irx4w=jxh4tDg@6soF3xO{MJgdGQZD#{#N?!}7$8OauJXz%KKRFhip`$a~P4+wR*_TVXE|t)BI3?{me>eihkh#}avNG@FoZ8aS zA!l1@UX6VsA^giLFQM`-ohO9d7o6r}t9^_-ye?RlO-pw;^-G<;Eajma5#tRjHp2A1 zDiypoZ&fI34>HJb8D&rmGG=^{SQ0yS^C}g?o6dQMH>k*rzB6vSB96{qe za}$VA9qPyicbu=9G=x%hEJ+>z;|8am&}L^GBLlB*|ANdNtMJb3;3~@jUAy%;#*Rty z;yz%~UQB1aZLYPxi&&{m+fiIKs2=N$bmT-hG$mZD!xX|<<2+GCQ~rIQO?HlH9PJV7 zCyy-RNTn<;8c@h>bLEcl}-dpuiBmbt}UweCO8B;$@_BW5H3_!2RKX2N~a_qcY; zX4#!?I*^ijmz(_jbety_OGgoR+Cz)NTa6gbARm>v< zX70v}tC~V18b7}8&qnd2oS#RAe2sm|ee4J6qaU*9tx!?iim88S(lVna29LpS6{r#DF($+zjlQ*uHl|FOP|>NorGHIc@(bmSnf!p&oCa{F3>qcj0zMtZU2}0!zY5Od zjd32Cqv=ot0%&0W=7#Pro$t{{$EN9troMp9ge&n_-^bQ9`oSFzcWfsB7lcgGy)V9s zW}ccA4J<^TaU`NgZvf5Hq8@i3G{BEHT#P~<`2BJ)KfO5#rfU#r0%1&Nu#85SJ2R9a z00M&E@S6$(UoX*@2ZkYm&EMOX9h;e6V|g4}e3#ey@+Xoxm~h;@=8x5SY!}@#+}wK9 zLy%iSIpSjaSyaIJ$@BZ5L5R9@rRXai%%w54n9BQAeHt(IY2kt3^K-3&ADE z0+1R>m);)^#>NOc)2pr*q~&2@hih>mvJ`nNKhVZ@NAq{$Egky~@H$rl7roh)4}J=i zdsv|Yuy>$br55E+K#yoj(;d&{53^wHZ}cKP6qL?1TjEYa7-y)AnHZ)b zCCeOz)bJ~N&LemYl+$0mMBfyZ+mf`>rEijUeGNbfSJBd(lhlk)pReWl`y8SHU$f?t zx!q|(e7lyD6KCCZ2PELWbNdmtg*X~1Tl>0X13C?L0+1;=Y0EQ)d{cY^%`(Tke2;ah zV(CgM@#psDyO1XNqe^D1w!+CC_muU6b`IvgP~+NG`v_0X?XwW+5HHFS@MaBVde9|Cd77u)wMt~0SfxvF$dC= z3Ol&L?nrcBq2xJMkYqxTuFO%a`XYTwQ6N0b?)0>Ppl|Xz9oCchP6Fx@H9%QkIBscwo2?$H(Uk6|rf`39+?KUePDW}7+v`5l zoQjkXF+h1)pKDABY_i0T745A%epNr2kEOKeshxsKY87`#9)!+FOaCa71k48hc#99<6o4rZRw-M7;)D?9aUJ& zaQ6{)Bz=?r2PF9g#Wt{_dQ)rq{632pX+@gj2PM>`Wi6~?cl;R{+_TOMwZx|cD`1Wr z%A^+-q##pO_LWsH;t9b6%m~Nlsvv|4C(t|ud1tdY5Qx%jeej(iK{818=U@WowZZy zV2V?zEk?Nv4u%;^QGx5{Z>EmB1i%HQ?&sp+1aeW`lyL~KT5<$Ow2v%ED3cjJT^f`` z?iWek)ImwVAJ&rPYKV-jO|F> z@ncYH%BLVnHR_sf!O#seG5+}>$MH?a<$;S>i6(z)Xer*uXKms5$k_kh!C3aW$kXS^|mWw>wZNDa~QkC>4BrPI756ETp^is!tMnZinL)&3j z=7%YYWz4mvGUQ?fp8p0pq4(F3o4Y(0DdV^q`01Vn`;EYujEFuvKTmm+^zIoCdfhe5 z`N~?nI2{Q%j|{-kH}zV6xnBlKKriJ8{hnqNJ^+dMuq(Tx$4kY@LElRG{C8<3zeZg7 z7L>nW4go;*@`zk*nCJMm)lbkjseN3B#$6Dt1Vz4>hn2bcvwqN^YV~+13B4t7X5y>} zbvhUctw^g5!OIR)phcNweG*x2EGbI_5*Y;2?n}!pfMt?-#zesM%WiiSnH*QD(lE}^ zknfz7_79-<4Kh+BqP_z(4FrKH-EH}*I$S=b-hSRmI zIFBXs1Pjd%_J_<{rumayNKlOK3bAs73EMNRA5nTN7gf$l?&N4Gb4~}yGn++Ku(!4Q z>LSxoXXZ^kMk@mA-~>C~ZJ#twN{WNAV(s!P1UJ(?PN?%U0@?#V5=gu4jT%1VlPtDG z-hlE9uL#Y4^h#TF3ZHqNSMuWrr&QsiQ2p7MM;7cJCmZ*vLhoPKd`>d3ofruW#JBx0 zR$8HU+EP+5y&XllgANNt*~-4XuSK4CT|hPE?2z&mQ0eFQ7mB%hXD?EY7Th>Q$XQZ5 zgk^M^9om+mih(f(*KY^Ce4jWJlu^|>m!-SxXIVVMmRI+zq0ZxUH!oR%q< zp*o}=%8TLDve4CRnC5nnQ1zb|!RA_e1hNN8}DijvxnzHap(Po~@`x_61pQQVLxjshn~Mc%+VN#G>!+hhG?- zdmgt*O$7tZ;_LJBl%8T{vRc*Mot7y*J^$jL;ZD9c^+rLC@Mri_{?RSX=^^_6S()iwzbq!nqut#`RmyG7e;uZyqdy*E5OX0=NczeK`zWZXE1fR?!9GEXrvw&|2-jWG9tpRNyk8> z{LOM_ll*A z9YvOg6)+d0p~E)GFSL`h+3jnJIW6dZZ`Sfx2j4CJE3>(6&H-evTtMcg2>aRcTjZC% z5Cg88sv!N%o$bvI6b0?LhF_OMg>vq$Nn%a_Hy=9a3t>PdIcVV>T`UV1ml8m?TEwTM zeA^2f+}dnNQ#^5dlr->dmb}DR?ik~IuagohI?w9eF(xnimsSv;XYsjrzQv0;{eFoE zIG+}WL47>Etnhhx(NwR|Hp#Z`v+ii2T-_T*HiMAEy}s)aDuXSJv~FD3zu)+3S$)LUXp~m9)iQr zSDW@GD1+AnC5jP{rMwIl_Gmgj%e#z#qzJmE^Waj>4*Wyb-F)O7d4-*RgK}g;KSvf|Mt1*d*9L{tE7JMtDkA?^;z4#G_Q}o(bd{i&|2ptvhUJ?gS7xPR1-_q875xk;y~X2 z^kE38+h5`cYYQXS7nG!Nsg<DGEJxqrYMTnARuDCBHH|#0h)H(KX&GrI@exa{ z+tYZi+PBGJleeGhp4S`F&3@ml%H>p%Pb{m}){2;cJT4(UjKS1K@OzMwZsuOqpYpNF zL(;AN#m~3o1X>$T5uM5*8<;KC0TJ7ZZ8Z3%6Ia(sGLgoGGS!J*2LX^c2F!Oc(!_Xf zaFRBm3ApC6@(3?k7_Bh%=52#%gTh)F(ei(wb9sVVo2I;{*pd?qju>Pp=nBQ@W;+B4 zxQ|@{l1@esU$}UK?gH2wKDRbW*=hrKcA&gZFiv)0E^{*zVs zE~Mw0c3;qDeEpS2S!!-9@jtLgjY#)T!&|wZFw_^mS(EGrW7G?`ipxv#b}KaiASKmT zjdQGl{pjT+Wh)xaqh7cV{#e?qDQ?%YYZ4s>AJ&Xp6xCEs6o95B^mC|r+bqi<{LUn? zgd*u_g`hR2F3~Oj-$@=HLw~uG4RplqGdku`Z4xv6I#dpKh5ov>>&(H;5_cus=ZUie zl^5ExnqbW*p<_{AQE^1i@x)2xU@+6Uh}#gNC%u9cg}2E%p2>e$&WT){V9S))OzEJt z-w-{Vx#9HsKcJKT)Hm=E3!=Ju`*j%dC!r`s+SC#DOS8~eEk>epaOSjch{abdQ{z0b zoAS_u=2zNVK*qUc-*`@+Li2I~SW&Id8iPIGs(7PH^Tx&+KLMG{I$z#CY`DgA%o#Mu zW_Ac4aWFFn7;NBZJNCI*`?E>_kzNJ{KeCt#ab4bXEB%)@2#ddeRZ01`{x&^a0pxp#cB5Nnl#{}h?ZD}@6O8l!SGvJ2+nNiR3luM_{9n?Q~2izdQ9eCTH2V)xncE)W!K z4csSau7EmZ6|`XRkcn&!ub+<7~0EPFh5%(Bwo+R#d`F$Xox; znQ?@mTwV`BnQ)}Ij~g@^UIF=TB<-`0t-=OV#ZJjI0Cy3<3-xCFP3kAvJbXo~bs1|T zQX0cSZq_Tr{pA2p4)_t3>XSn$YtJ_&(JE|~KAGCNTs;Yvx6^HC`${JyDopc|BiB4W z94L1{3M$Ht;66kTgnk3SDTLYMyK(o?<81xjnr@bkc}izd7nesdrhw|ixA$T9_#4@- zv#TP&+JlR|{b!7HKg8NeR(||S6cKg_XvNL#qPJd#Dm=rt6;X1~%SER_Vw41eo~lV+ zn0lvEILmuwz~EQime_?r(ut{K4vy-Aibpn{f{KTk;;AZD4`k0|OY+7VG^C}|+crq8 z*56)&=5BS_eIPc->S`sH)t-9fTRT%)p}$&{SpjIG{wV&cujDMv_?UTL6(ESluw6XO zXluJ4^tyeqtbW~I=edDT7Yw-g**~HJM*u9gW zv917c|2o<`3omYgG9+DDd^I9?Jx6J0y0F-=2K%Qj>I!GdvJw57 zKF`z4zal$bW zL$8F~NJBm8d$)9JV+*R0(?X(}fFA4da@0O_>SVfF|jtCnGwO01b7BE0g=9>VYRH zykxjbwl4KLB+V2AqHVr>7NDekQQHBz%*49$gF|(IgAiqV{lCa5TPTDg$4>lAd4M`L zkhP!eZ%$yR;IxO{o@K^*(_T+n9e)4y?<#}MKdTHXMHdPdk-o5KO2L%s`?dZ%xe>iY zAnQbdxr^9dqQ}l`Q|6`*=9)!+E}P|^c>+GlzN)Me@L!xXf( zRVXwiHEDjyK64Eeu;#p;LlK>??H_cT4uv=?{u)bJZ+YMYbOIS#>$9j2ZO{-3ffu9r z!Md#x`kF`RI2I$f&T zp!8d6mC%_jpTsX)JaO&qIj6+qI8hz&I&*T#2}UtW0`y3GWgshS_{4Cr2sU>MBqX3# zIgR0Oq|9q3Xi^K^*wijHvX!v25qY>%{YO>MNY+z#``&Mw2pvB3R|Pl*w2&Xl$dXec zE8VI!uV9#e<#G6uwviECaVuw3$vs^zn{yre+J=D2=#CBW%;wD^8QS>Y%{x0gog$Vd z=?4jK3P4Ba7^U0*HUF5zv_-e4 zg(u;;Tdl^Iobrvd4G?UUkeu_yNF*oH_rO{r!{os>4J1ixQ;n3=nX*_eJ&#YurrV=; zq(Kb;%gcDsFpZtb$Zq>P_0I$l=34nn7{GnHQmyPE=d|i)N+OYw$OS(ptsqmb(oF4= z-hDrS+o$F^fM~IkoWGvBQ}RXCLbRRxAJ`(rmAPY4DHU+mU*4(9_MnarXa^fW!(rU4 z9#q)9_&}=vLs8m}g0GL+_HUZ_YepJS0(!a=yAi(n5jHZZBNbeH@V0}}6kWBX{9Fa? zX%3DyAg71DvU1MU_+amOsXWm+C)GOV18i1$Mfsq>e3PY)nQ_C$dDQ-yb8Td`j$~ZF zv_#@>fQPSDOk$KCd-yJPH~`D01p%H0auKoOuDg;<c3{J4Pe>2mKl1f{q zx*Yk>S-u5=&f|G=viNn+KQCEs%mQoB_>gGGZ9fc$(}IDVMrlNeQ}!q7q>=Q4m9j67h#IG z7d2*TPdi^b;soWg(A!>W``YZVOQ9yGP3b9Duzi+TA%iOcNG~rMif42scw?X-kn$h| zx&@?|80hh_9O$KQ-ax`QPGMqBv*XIk{3zt1GA#NJe5%pFI-;msIxi9N3T4P8XkC`g zfTE?*aN1kqM?yafuKcaomeIpz&MhH8*URLNr@*sk|H$7j>u-No;Q&hcAEmy3Dfof@ zy(af>r)YKfcO!pG0sj}K{uuecHucA!|D9L=V(O1Sp#P0m|6=N&YMFog^Uq%Wi>ZIP zw14*MUrhZy1%Ge<&!+w!>i-^aASnOGiu$h(INznd^v_fHPow|$>iq9D`fmmN|Mi{x zpN{^2uhD<3&i{0j{-1%uf9lnL&)xq|bGH`Jz~cKe2!GBB2<9LVQ}Ea&=sjNkqJwFI z<$m72jO2PB|1|!mh&AYeqz3ZdnT@gHKTq%o2=Ly|&;S&Sexb#v=H}NSS2N!9iQ@QQ z2s{iKVlMADh3sL+dOYUW$UU(3$j03NsQ`VjgdhhQc10ND8yvGFCXB)7KR*&sM=RUl z=HLV3hqLo1CtpOd?_UhEH6D+T2e4%M{qkPT9ECb2H~y3gB|+eS$=xKTYeX+ZD)-h4 zZhLdL}Cd#q9)`(N84p^jPHjnGmE1mcL2(A)g`LR)PF1IzHcJpBVV+>)r`UV*;) zik>!(W)>qG9FG4Y?AcVV=-O^=+!!T#xEMa#caagN3bQ*qvZx99u4301dSzv9(cZ|u zEs%*6=8oJU{2)P|G(oC4b8eb5{??{MPq2c?@Y()NSDrg>-9L~g)z4TZk=VF3^Frs1 z1WcNFJsIMgzROe(nJ&I6WghY>xnZ0^_uymodN~>FBQex-bA%X?55u&9`R32d=({E9}e+X+7Nn-sPS4n(CNSh8^Yh@bvnLhEiy6o%c62y$LPh zaS1Ny*-`f5Iq?(uK6rw*The;L@JldKwTq^T)OH?IaSCc{ZRj(g^GfN_qZ zCjS&t@Mk`4kv$7;LQXrK>Th+7s5I=`ElbS|wMVZ+xw@y-5PN@|8)m44RD+#Jg6inf zCMD5t3j>fjP2EFfor1sl1Wq%f9?We)$wh`DB2DZ9&;hy?C0=!o610b%Gk2B_X>4ti zjomdrtZNdy%}XOHtx<(G8#|3fh_n>wJCA8{XeES<5|)Hp3-^fh8qiW7_87sHsK4 zejCBTfDvs>txXriibO*}IzeFo#w<5m<9p!Xf3luz9MI5ga1~sy6&W@M+h32k9onL* zy1h3J*TW%C_D1xfO^?)8h0=Y^-gXiy$*HaywM?RU9=vN1cKKvui;8J`8V_ifEQh!( z0W;Uf*n}A8zG(z%aT^U51pCYX?vV2GE}b`e?p!H$+3F>hDc7N|sKxn6)MFlYdg$0t z<=y4Cl#$kZ`!q|^x8JNhJgiZ?gZ~4fV{r=aH^0%w;n5xTMK`!uu<QN_3$a_5V%l_UZT9N>LnH__kOf0M{KQoNAgh>MnQ6}{TmLKQ<45E`7h zrk+UW2Z87t@y?N1=p;O(X7$@I<7nmqhkb!c_Up{!CYOf$Lh$TlSf?#Efh6>84PVds zj(A1mNOwcko6q{kqT@53@C>%GmxMmiH#no($G%QccR?E+c5=(WvSazQ(5Op?yO>P_ z7HQ@t`?7ai9pEGTv3JU;B{>Vsbxw3~bsjcxo);$PW68b;=;NI!{c$7kK=GV5j(W3U zwTI^rJ+-@BYa0NbDBrxxg`357?@o9xO}Jlha=2K`aoLtj?vH-7NDErAEv@;BR&CRN zKNE78wO=xY4x&1tRIfI%ixJ8o6*&z(e>NzKEXOtAORNxQE(4k31DVT3k;AXQwICXK zozD8B5#ZI5J(GC?zQ#Hmp!;ucs<8MmTUlg8(nG;8HM&dUpx@KY=T zv>!?tpAJtOuNv|U1boo)U5c2Z|yBb>S50`5I5H?(3pEJvyJ+PTv$>G;K3lJ9pYv8OkhRGFpQ z=@<%ik?!H{(X=R&&P_XQPVri~fV~3{jGkR&hR`#r`3%Ro7b7kz8wT{T(atiAyq{E< z7({;AzLh>&hMC)4w31%rn?p8Ti_0w+Xo-(k(^qU5pRUAaR9#xf8N0qN=hy(ngt@wt z^1Mr+f*!M>WTL-*mGp?QP3{ac+i8&VV4L2wIN&lvPu@ids-kw$zeF-$@blA(c|H4{ zb3`PXgy*SWQkS_@RC^f0tJ1ee10h&lb;zStb5!l{+r* z^R70C=p){%RCnnfjJg^hm$CS>kjLG*0d`VQjHVY8sxUmvOLrTVZ;b!w^ifE{Wt6pW z3g(K^-sz%Gt~(pi4w1XjStvZULXum3C7-U`)v=dQIBtDyvom~;gh$}`sT%1JtX3|i zENygxl#4#dn{8b*rC^r%^ia~c&Zosvs%J77hdtza;UlK#!o_~iI6E2oxqf05L1Q5- zu!Ls!RGZ%*Du>saxX>vU;V+44vRD)CRj8u+S-`Y z`RF6O;F+6`^*pZkCgRit|9RvCSGJ6C=pU)aawJDag zri|U|kq#5ZuH0`5ob9VQ=30cDi5_@$(|KZ=D)w<#J`4qU^~YNEKAV8`beAdPI9(k- zk-Jo{vvx~A6fvXO&fhc>t}u9k!SMDXKk8%Y5%0mI1qXU)_6{NChKo#}CRN%ohKWQlsH5hr? zKOsrP{(SRpxJ!ejREU01%*men>go8rl!U(xHXbI;eSXZ6hK2pq%-3IY>bw<&07rt8 zJCo{Nq1Ief2JXlAz>C?@*B%Obh5=yMO+57_VUuH$ED1Inm5kBZ<&p!WNo287Z zer1{wa7Jyn#& z8a&~0pG51H>^j)dB{i=e#zuM@4&8X>*K3A&sh%XkMCL0lY1nmC`Eck`96(L9avne@|ncN}ZQt=^umhrpvQnm=`eXL&V7&$O}d z?IKlbOZYC%U81B$E5zi1!Uri^F4^DX3_(0;YYps-@Aea|LLS&wQ?}3qgpH%pjO*7+ zey$H7CQ5Sl51W+_yZO{Z_z@l4DR>2B^eZ{|PVeE}=X)*WymSW?Vxn$eW03Qmq;)o< ztlK2NVxAfL6PtwNQGCOa-E9aZ8k)SF`U4byR;%y-zH@>&0DO!nK{ zAV=>yZ&~(&vyK7sv~xY@kMel3G>O@G@oFoUBfOe0nQ{is&)t)B!W;(LQwBy48y;MA>8$<=(`(UIEYE-K(e zWqGwx0K0gcyu%RDIrv>_wLjw&*!|i4wfjb=Bl@U;w6DXG(Pf7Y=h5nDK`RpUH~L86 zh0_cFv3BQVqx6P)sBN#}|5RgJJzd-aZdpSiTRdSJT+jbF%_>*P$UcCkA*ydPh8y2w zlcsIpCwRqfclZs%#o5n#=7BVnvJvFmw3h#-(bXGQgoak;$^?1bn4ym((hs2RR0utp9b5 zd{HUTH`_%%Z^K0y^LwC`xqb;AQrHzY3vr*lNdy@G?NyM(DVk3uv$;?yH)HDw?=r`ypPu4@-chy#5 z@q{2Ii>XQry4cmVp`5!iEMq`g2=E&iwjuKSOP0#z($WwUw=qLX;Jwr~m*Y07j0#uB zgX2Ti|iJ>qZh#VSh*}dnr0v^WgJ|Lt3#_ x7YEma{!}I-fSmUp&=Z&->mc*@iz^sB!Cmd;4@_(eWk3f=UPf8E?DhLk{{z|Oly?9C literal 44244 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 Live Triage Drive to bring up the main dialog. + +\image html live_triage_dialog.png + +Select the drive you want to use - any type of USB storage device will work. For best results use the fastest drive available. Once the process is complete the root folder will contain an Autopsy folder and a RunFromUSB.bat file. + +\section live_triage_usage Running Autopsy from the live triage drive + +Insert the drive into the target machine and browse to it in Windows Explorer. Right click on RunFromUSB.bat and select "Run as administrator". This is necessary to analyze the local drives. + +\image html live_triage_script.png + +Running the script will generate a few more directories on the USB drive. The configData directory stores all the data used by Autopsy - primarily configuration files and temporary files. You can make changes to the Autopsy settings and they will persist between runs. The cases directory is created as a recommended place to save your case data. You will need to browse to it when creating a case in Autopsy. + +Once Autopsy is running, proceed to create a case as normal, making sure to save it on the USB drive. + +\image html live_triage_case.png + +Then choose the Local Disk data source and select the desired drive. + +\image html live_triage_ds.png + +See the \ref ds_local page for more information on local disk data sources. + +*/ \ No newline at end of file diff --git a/docs/doxygen-user/main.dox b/docs/doxygen-user/main.dox index e4a1e2b3a9..a72256c7f6 100644 --- a/docs/doxygen-user/main.dox +++ b/docs/doxygen-user/main.dox @@ -60,6 +60,7 @@ The following topics are available here: - \subpage windows_authentication - \subpage multiuser_sec_page - \subpage multiuser_page +- \subpage live_triage_page - \subpage advanced_page If the topic you need is not listed, refer to the Autopsy Wiki or join the SleuthKit User List at SourceForge. From 3383f447fbdeb6b200341d509f2d4e4fc5f62ba4 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Wed, 14 Mar 2018 15:07:27 -0400 Subject: [PATCH 23/41] Added report indexing to dev docs --- .../keywordsearchservice/KeywordSearchService.java | 2 ++ docs/doxygen/modReport.dox | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/keywordsearchservice/KeywordSearchService.java b/Core/src/org/sleuthkit/autopsy/keywordsearchservice/KeywordSearchService.java index e3b36499f0..1a9e947b76 100644 --- a/Core/src/org/sleuthkit/autopsy/keywordsearchservice/KeywordSearchService.java +++ b/Core/src/org/sleuthkit/autopsy/keywordsearchservice/KeywordSearchService.java @@ -26,6 +26,8 @@ import org.sleuthkit.datamodel.TskCoreException; /** * An interface for implementations of a keyword search service. + * You can find the implementations by using Lookup, such as: + * Lookup.getDefault().lookup(KeywordSearchService.class) * * TODO (AUT-2158: This interface should not extend Closeable. */ diff --git a/docs/doxygen/modReport.dox b/docs/doxygen/modReport.dox index 1e28a5a78d..6199ce7560 100644 --- a/docs/doxygen/modReport.dox +++ b/docs/doxygen/modReport.dox @@ -75,6 +75,19 @@ Typically a general report module should interact with both the Blackboard API i You should call org.sleuthkit.autopsy.casemodule.Case.addReport() with the path to your report so that it is shown in the Autopsy tree. You can specify a specific file or folder and the user can then view it later. +\subsection report_create_module_indexing Indexing Reports + +After you have called org.sleuthkit.autopsy.casemodule.Case.addReport() and created a report, you can pass it to org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService.index() so that it is indexed and can then be found by a user. This is most commonly used when an Ingest Module runs a 3rd party tool and the output of that tool is added back into Autopsy as a report. Here is some example code: + +\code{.java} +KeywordSearchService searchService = Lookup.getDefault().lookup(KeywordSearchService.class); +if (null == searchService) { + logger.log(Level.WARNING, "Keyword search service not found. Report will not be indexed"); +} else { + searchService.index(report); +} +\endcode + \subsection report_create_module_layer Installing your Report Module Report modules developed using Java must be registered in a layer.xml file. This file allows Autopsy to find the report module. From c12f26f1bb4636b3fcf8907cab8e12efab6a6793 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 14 Mar 2018 16:25:27 -0400 Subject: [PATCH 24/41] Correctly support ingest of a subset of files from data source --- .../autopsy/datamodel/DirectoryNode.java | 11 +++- .../datamodel/SpecialDirectoryNode.java | 19 ++++-- .../autopsy/ingest/DataSourceIngestJob.java | 33 ++++++++-- .../sleuthkit/autopsy/ingest/IngestJob.java | 31 +++++++-- .../autopsy/ingest/IngestManager.java | 25 +++++++- .../autopsy/ingest/IngestTasksScheduler.java | 64 ++++++++++--------- .../RunIngestModulesAction.java | 38 ++++++----- .../autopsy/testutils/IngestJobRunner.java | 4 +- 8 files changed, 156 insertions(+), 69 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 5a2bb87660..e243173a2b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.logging.Level; import javax.swing.Action; import org.openide.util.NbBundle; import org.openide.util.Utilities; @@ -36,8 +37,8 @@ import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; /** @@ -95,7 +96,11 @@ public class DirectoryNode extends AbstractFsContentNode { actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator - actionsList.add(new RunIngestModulesAction(Collections.singletonList(content))); + try { + actionsList.add(new RunIngestModulesAction(content.getDataSource(), Collections.singletonList(content))); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, String.format("Failed to get data source for directory %s (objId=%d), RunIngestModulesAction omitted from context menu", content.getName(), content.getId()), ex); + } actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index 7bc23015ac..ed615587a7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2017-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,25 +21,31 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.logging.Level; import javax.swing.Action; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.SpecialDirectory; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; /** * Parent class for special directory types (Local and Virtual) */ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode { + private static final Logger logger = Logger.getLogger(SpecialDirectoryNode.class.getName()); + public SpecialDirectoryNode(SpecialDirectory sd) { super(sd); } - + /** * Right click action for this node * @@ -61,9 +67,12 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNodesingletonList(content))); + actions.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text())); + try { + actions.add(new RunIngestModulesAction(content.getDataSource(), Collections.singletonList(content))); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed to get data source for special directory %s (objId=%d), RunIngestModulesAction omitted from context menu", content.getName(), content.getId()), ex); + } actions.addAll(ContextMenuExtensionPoint.getActions()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java index 8ba34c9492..a41acd1c58 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java @@ -57,13 +57,16 @@ final class DataSourceIngestJob { /** * These fields define a data source ingest job: the parent ingest job, an - * ID, the user's ingest job settings, and the data source to be processed. + * ID, the user's ingest job settings, and the data source to be analyzed. + * Optionally, there is a set of files to be analyzed instead of analyzing + * all of the files in the data source. */ private final IngestJob parentJob; private static final AtomicLong nextJobId = new AtomicLong(0L); private final long id; private final IngestJobSettings settings; private final Content dataSource; + private final List files = new ArrayList<>(); /** * A data source ingest job runs in stages. @@ -171,7 +174,7 @@ final class DataSourceIngestJob { /** * Constructs an object that encapsulates a data source and the ingest - * module pipelines used to process it. + * module pipelines used to analyze it. * * @param parentJob The ingest job of which this data source ingest * job is a part. @@ -181,9 +184,27 @@ final class DataSourceIngestJob { * progress handles. */ DataSourceIngestJob(IngestJob parentJob, Content dataSource, IngestJobSettings settings, boolean runInteractively) { + this(parentJob, dataSource, Collections.emptyList(), settings, runInteractively); + } + + /** + * Constructs an object that encapsulates a data source and the ingest + * module pipelines used to analyze it. Either all of the files in the data + * source or a given subset of the files will be analyzed. + * + * @param parentJob The ingest job of which this data source ingest + * job is a part. + * @param dataSource The data source to be ingested. + * @param files A subset of the files for the data source. + * @param settings The settings for the ingest job. + * @param runInteractively Whether or not this job should use NetBeans + * progress handles. + */ + DataSourceIngestJob(IngestJob parentJob, Content dataSource, List files, IngestJobSettings settings, boolean runInteractively) { this.parentJob = parentJob; this.id = DataSourceIngestJob.nextJobId.getAndIncrement(); this.dataSource = dataSource; + this.files.addAll(files); this.settings = settings; this.doUI = runInteractively; this.createTime = new Date().getTime(); @@ -497,13 +518,13 @@ final class DataSourceIngestJob { */ if (this.hasFirstStageDataSourceIngestPipeline() && this.hasFileIngestPipeline()) { logger.log(Level.INFO, "Scheduling first stage data source and file level analysis tasks for {0} (jobId={1})", new Object[]{dataSource.getName(), this.id}); //NON-NLS - DataSourceIngestJob.taskScheduler.scheduleIngestTasks(this); + DataSourceIngestJob.taskScheduler.scheduleIngestTasks(this, this.files); } else if (this.hasFirstStageDataSourceIngestPipeline()) { logger.log(Level.INFO, "Scheduling first stage data source level analysis tasks for {0} (jobId={1}), no file level analysis configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS DataSourceIngestJob.taskScheduler.scheduleDataSourceIngestTask(this); } else { logger.log(Level.INFO, "Scheduling file level analysis tasks for {0} (jobId={1}), no first stage data source level analysis configured", new Object[]{dataSource.getName(), this.id}); //NON-NLS - DataSourceIngestJob.taskScheduler.scheduleFileIngestTasks(this); + DataSourceIngestJob.taskScheduler.scheduleFileIngestTasks(this, this.files); /** * No data source ingest task has been scheduled for this stage, and @@ -815,7 +836,7 @@ final class DataSourceIngestJob { void addFiles(List files) { if (DataSourceIngestJob.Stages.FIRST == this.stage) { for (AbstractFile file : files) { - DataSourceIngestJob.taskScheduler.scheduleFileIngestTask(this, file); + DataSourceIngestJob.taskScheduler.scheduleFastTrackedFileIngestTask(this, file); } } else { DataSourceIngestJob.logger.log(Level.SEVERE, "Adding files during second stage not supported"); //NON-NLS @@ -993,7 +1014,7 @@ final class DataSourceIngestJob { this.cancelled = true; this.cancellationReason = reason; DataSourceIngestJob.taskScheduler.cancelPendingTasksForIngestJob(this); - + if (this.doUI) { synchronized (this.dataSourceIngestProgressLock) { if (null != dataSourceIngestProgress) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java index 4393f18510..33d767fb00 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJob.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,13 +29,12 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.openide.util.NbBundle; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; /** - * Runs a collection of data sources through a set of ingest modules specified - * via ingest job settings. - *

- * This class is thread-safe. + * Analyzes one or more data sources using a set of ingest modules specified via + * ingest job settings. */ public final class IngestJob { @@ -69,7 +68,7 @@ public final class IngestJob { private volatile CancellationReason cancellationReason; /** - * Constructs an ingest job that runs a collection of data sources through a + * Constructs an ingest job that analyzes one or more data sources using a * set of ingest modules specified via ingest job settings. * * @param dataSources The data sources to be ingested. @@ -88,6 +87,26 @@ public final class IngestJob { cancellationReason = CancellationReason.NOT_CANCELLED; } + /** + * Constructs an ingest job that analyzes one data source using a set of + * ingest modules specified via ingest job settings. Either all of the files + * in the data source or a given subset of the files will be analyzed. + * + * @param dataSource The data source to be analyzed + * @param files A subset of the files for the data source. + * @param settings The ingest job settings. + * @param doUI Whether or not this job should use progress bars, + * message boxes for errors, etc. + */ + IngestJob(Content dataSource, List files, IngestJobSettings settings, boolean doUI) { + this.id = IngestJob.nextId.getAndIncrement(); + this.dataSourceJobs = new ConcurrentHashMap<>(); + DataSourceIngestJob dataSourceIngestJob = new DataSourceIngestJob(this, dataSource, files, settings, doUI); + this.dataSourceJobs.put(dataSourceIngestJob.getId(), dataSourceIngestJob); + incompleteJobsCount = new AtomicInteger(dataSourceJobs.size()); + cancellationReason = CancellationReason.NOT_CANCELLED; + } + /** * Gets the unique identifier assigned to this ingest job. * diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 13d67f9e9c..65d0162d6d 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -298,7 +298,7 @@ public class IngestManager { /** * Queues an ingest job for for one or more data sources. * - * @param dataSources The data sources to process. + * @param dataSources The data sources to analyze. * @param settings The settings for the ingest job. */ public void queueIngestJob(Collection dataSources, IngestJobSettings settings) { @@ -312,6 +312,25 @@ public class IngestManager { } } + /** + * Queues an ingest job for for a data source. Either all of the files in + * the data source or a given subset of the files will be analyzed. + * + * @param dataSource The data source to analyze. + * @param files A subset of the files for the data source. + * @param settings The settings for the ingest job. + */ + public void queueIngestJob(Content dataSource, List files, IngestJobSettings settings) { + if (caseIsOpen) { + IngestJob job = new IngestJob(dataSource, files, settings, RuntimeProperties.runningWithGUI()); + if (job.hasIngestPipeline()) { + long taskId = nextIngestManagerTaskId.incrementAndGet(); + Future task = startIngestJobsExecutor.submit(new StartIngestJobTask(taskId, job)); + startIngestJobFutures.put(taskId, task); + } + } + } + /** * Immdiately starts an ingest job for one or more data sources. * @@ -351,7 +370,7 @@ public class IngestManager { Case openCase; try { openCase = Case.getOpenCase(); - } catch (NoCurrentCaseException ex) { + } catch (NoCurrentCaseException ex) { return new IngestJobStartResult(null, new IngestManagerException("Exception while getting open case.", ex), Collections.emptyList()); //NON-NLS } if (openCase.getCaseType() == Case.CaseType.MULTI_USER_CASE) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java index a9ad8c7634..4c0457f112 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2017 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -143,15 +143,14 @@ final class IngestTasksScheduler { } /** - * Schedules a data source ingest task and file ingest tasks for an ingest - * job. + * Schedules a data source level ingest task and file level ingest tasks for + * an ingest job. Either all of the files in the data source or a given + * subset of the files will be scheduled. * - * @param job The job for which the tasks are to be scheduled. - * - * @throws InterruptedException if the calling thread is blocked due to a - * full tasks queue and is interrupted. + * @param job The data source ingest job. + * @param files A subset of the files for the data source. */ - synchronized void scheduleIngestTasks(DataSourceIngestJob job) { + synchronized void scheduleIngestTasks(DataSourceIngestJob job, List files) { if (!job.isCancelled()) { // Scheduling of both a data source ingest task and file ingest tasks // for a job must be an atomic operation. Otherwise, the data source @@ -159,14 +158,14 @@ final class IngestTasksScheduler { // resulting in a potential false positive when another thread checks // whether or not all the tasks for the job are completed. this.scheduleDataSourceIngestTask(job); - this.scheduleFileIngestTasks(job); + this.scheduleFileIngestTasks(job, files); } } /** - * Schedules a data source ingest task for an ingest job. + * Schedules a data source level ingest task for a data source ingest job. * - * @param job The job for which the tasks are to be scheduled. + * @param job The data source ingest job. */ synchronized void scheduleDataSourceIngestTask(DataSourceIngestJob job) { if (!job.isCancelled()) { @@ -186,16 +185,22 @@ final class IngestTasksScheduler { } /** - * Schedules file ingest tasks for an ingest job. + * Schedules file level ingest tasks for a data source ingest job. Either + * all of the files in the data source or a given subset of the files will + * be scheduled. * - * @param job The job for which the tasks are to be scheduled. + * @param job The data source ingest job. + * @param files A subset of the files for the data source. */ - synchronized void scheduleFileIngestTasks(DataSourceIngestJob job) { + synchronized void scheduleFileIngestTasks(DataSourceIngestJob job, List files) { if (!job.isCancelled()) { - // Get the top level files for the data source associated with this job - // and add them to the root directories priority queue. - List topLevelFiles = getTopLevelFiles(job.getDataSource()); - for (AbstractFile firstLevelFile : topLevelFiles) { + List candidateFiles = new ArrayList<>(); + if (files.isEmpty()) { + getTopLevelFiles(job.getDataSource(), candidateFiles); + } else { + candidateFiles.addAll(files); + } + for (AbstractFile firstLevelFile : candidateFiles) { FileIngestTask task = new FileIngestTask(job, firstLevelFile); if (IngestTasksScheduler.shouldEnqueueFileTask(task)) { this.tasksInProgress.add(task); @@ -207,12 +212,14 @@ final class IngestTasksScheduler { } /** - * Schedules a file ingest task for an ingest job. + * Schedules a file ingest task for a data source ingest job. The task that + * is created is added directly to the pending file tasks queues, i.e., it + * is "fast tracked." * - * @param job The job for which the tasks are to be scheduled. - * @param file The file to be associated with the task. + * @param job The data source ingest job. + * @param file A file. */ - synchronized void scheduleFileIngestTask(DataSourceIngestJob job, AbstractFile file) { + synchronized void scheduleFastTrackedFileIngestTask(DataSourceIngestJob job, AbstractFile file) { if (!job.isCancelled()) { FileIngestTask task = new FileIngestTask(job, file); if (IngestTasksScheduler.shouldEnqueueFileTask(task)) { @@ -279,12 +286,12 @@ final class IngestTasksScheduler { * files and virtual directories for a data source. Used to create file * tasks to put into the root directories queue. * - * @param dataSource The data source. + * @param dataSource The data source. + * @param topLevelFiles The top level files are added to this list. * * @return A list of top level files. */ - private static List getTopLevelFiles(Content dataSource) { - List topLevelFiles = new ArrayList<>(); + private static void getTopLevelFiles(Content dataSource, List topLevelFiles) { Collection rootObjects = dataSource.accept(new GetRootDirectoryVisitor()); if (rootObjects.isEmpty() && dataSource instanceof AbstractFile) { // The data source is itself a file to be processed. @@ -312,7 +319,6 @@ final class IngestTasksScheduler { } } } - return topLevelFiles; } /** @@ -405,7 +411,7 @@ final class IngestTasksScheduler { return false; } - /** + /* * Check if the file is a member of the file ingest filter that is being * applied to the current run of ingest, checks if unallocated space * should be processed inside call to fileIsMemberOf @@ -414,8 +420,8 @@ final class IngestTasksScheduler { return false; } -// Skip the task if the file is one of a select group of special, large -// NTFS or FAT file system files. + // Skip the task if the file is one of a select group of special, large + // NTFS or FAT file system files. if (file instanceof org.sleuthkit.datamodel.File) { final org.sleuthkit.datamodel.File f = (org.sleuthkit.datamodel.File) file; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index f728cbee23..bb99924836 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2017-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,7 @@ import java.awt.Cursor; import java.awt.event.ActionEvent; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; @@ -33,13 +34,12 @@ import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.Directory; /** - * This class is used to add the action to the run ingest modules menu item. - * When the data source is pressed, it should open the wizard for ingest - * modules. + * An action that invokes the Run Ingest Modules wizard for one or more data + * sources or a subset of the files in a single data source. */ public final class RunIngestModulesAction extends AbstractAction { @@ -51,6 +51,9 @@ public final class RunIngestModulesAction extends AbstractAction { * used instead of this wizard and is retained for backwards compatibility. */ private static final String EXECUTION_CONTEXT = "org.sleuthkit.autopsy.ingest.RunIngestModulesDialog"; + private final List dataSources = new ArrayList<>(); + private final IngestJobSettings.IngestType ingestType; + private final List files; /** * Display any warnings that the ingestJobSettings have. @@ -67,12 +70,10 @@ public final class RunIngestModulesAction extends AbstractAction { JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), warningMessage.toString()); } } - private final List dataSources = new ArrayList<>(); - private final IngestJobSettings.IngestType ingestType; /** - * Creates an action which will make a run ingest modules wizard when it is - * performed. + * Constructs an action that invokes the Run Ingest Modules wizard for one + * or more data sources. * * @param dataSources - the data sources you want to run ingest on */ @@ -80,18 +81,21 @@ public final class RunIngestModulesAction extends AbstractAction { this.putValue(Action.NAME, Bundle.RunIngestModulesAction_name()); this.dataSources.addAll(dataSources); this.ingestType = IngestJobSettings.IngestType.ALL_MODULES; + this.files = Collections.emptyList(); } /** - * Creates an action which will make a run ingest modules wizard when it is - * performed. + * Constructs an action that invokes the Run Ingest Modules wizard for a + * subset of the files in a single data source. * - * @param dir - the directory you want to run ingest on + * @param dataSource The data source. + * @param files The files. */ - public RunIngestModulesAction(Directory dir) { + public RunIngestModulesAction(Content dataSource, List files) { this.putValue(Action.NAME, Bundle.RunIngestModulesAction_name()); - this.dataSources.add(dir); + this.dataSources.add(dataSource); this.ingestType = IngestJobSettings.IngestType.FILES_ONLY; + this.files = new ArrayList<>(files); } /** @@ -118,7 +122,11 @@ public final class RunIngestModulesAction extends AbstractAction { if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { IngestJobSettings ingestJobSettings = wizard.getIngestJobSettings(); showWarnings(ingestJobSettings); - IngestManager.getInstance().queueIngestJob(this.dataSources, ingestJobSettings); + if (this.files.isEmpty()) { + IngestManager.getInstance().queueIngestJob(this.dataSources, ingestJobSettings); + } else { + IngestManager.getInstance().queueIngestJob(this.dataSources.get(0), this.files, ingestJobSettings); + } } } diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/IngestJobRunner.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/IngestJobRunner.java index 5597ce8500..f3587ab29a 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/IngestJobRunner.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/testutils/IngestJobRunner.java @@ -33,7 +33,7 @@ import org.sleuthkit.datamodel.Content; /** * A utility that runs an ingest job, blocking until the job is completed. */ -public final class IngestRunner { +public final class IngestJobRunner { /** * Runs an ingest job, blocking until the job is completed. @@ -70,7 +70,7 @@ public final class IngestRunner { /** * IngestRunner instances cannot be instatiated. */ - private IngestRunner() { + private IngestJobRunner() { } /** From 7f69132238768810f1e9777cbf8e968ed363d7b1 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 14 Mar 2018 16:31:28 -0400 Subject: [PATCH 25/41] Correctly support ingest of a subset of files from data source --- Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java index 4c0457f112..b9cee95687 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestTasksScheduler.java @@ -288,8 +288,6 @@ final class IngestTasksScheduler { * * @param dataSource The data source. * @param topLevelFiles The top level files are added to this list. - * - * @return A list of top level files. */ private static void getTopLevelFiles(Content dataSource, List topLevelFiles) { Collection rootObjects = dataSource.accept(new GetRootDirectoryVisitor()); From 7cd52701f9f1c2a0b0bfe921a36b1f4ebeaa5c2a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 14 Mar 2018 16:36:51 -0400 Subject: [PATCH 26/41] Added compatibility checks to getIngestJobSettingsPanel(). --- .../PhotoRecCarverIngestModuleFactory.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestModuleFactory.java index 47658b55e0..aae845164c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverIngestModuleFactory.java @@ -25,6 +25,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel; +import org.sleuthkit.autopsy.ingest.NoIngestModuleIngestJobSettings; /** * A factory for creating instances of file ingest modules that carve @@ -81,7 +82,17 @@ public class PhotoRecCarverIngestModuleFactory extends IngestModuleFactoryAdapte @Override public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) { - return new PhotoRecCarverIngestJobSettingsPanel((PhotoRecCarverIngestJobSettings) settings); + if (settings instanceof PhotoRecCarverIngestJobSettings) { + return new PhotoRecCarverIngestJobSettingsPanel((PhotoRecCarverIngestJobSettings) settings); + } + /* + * Compatibility check for older versions. + */ + if (settings instanceof NoIngestModuleIngestJobSettings) { + return new PhotoRecCarverIngestJobSettingsPanel(new PhotoRecCarverIngestJobSettings()); + } + + throw new IllegalArgumentException("Expected settings argument to be an instance of PhotoRecCarverIngestJobSettings"); } } From ae3bfc83e88cd1273d3dcb860f73a5fedc50bdcf Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 14 Mar 2018 18:10:54 -0400 Subject: [PATCH 27/41] Correctly support ingest of a subset of files from data source --- .../autopsy/datamodel/DirectoryNode.java | 12 +---- .../datamodel/SpecialDirectoryNode.java | 14 +---- .../RunIngestModulesAction.java | 52 ++++++++++++++----- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index e243173a2b..9dd1296ae1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -20,17 +20,14 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.logging.Level; import javax.swing.Action; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -38,7 +35,6 @@ import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Directory; -import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; /** @@ -47,8 +43,6 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; */ public class DirectoryNode extends AbstractFsContentNode { - private static final Logger LOGGER = Logger.getLogger(DirectoryNode.class.getName()); - public static final String DOTDOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.parFolder.text"); public static final String DOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.curFolder.text"); @@ -96,11 +90,7 @@ public class DirectoryNode extends AbstractFsContentNode { actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator - try { - actionsList.add(new RunIngestModulesAction(content.getDataSource(), Collections.singletonList(content))); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, String.format("Failed to get data source for directory %s (objId=%d), RunIngestModulesAction omitted from context menu", content.getName(), content.getId()), ex); - } + actionsList.add(new RunIngestModulesAction(content)); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index ed615587a7..e57febe1bf 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -19,28 +19,20 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.logging.Level; import javax.swing.Action; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.SpecialDirectory; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; /** * Parent class for special directory types (Local and Virtual) */ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode { - - private static final Logger logger = Logger.getLogger(SpecialDirectoryNode.class.getName()); public SpecialDirectoryNode(SpecialDirectory sd) { super(sd); @@ -68,11 +60,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNodesingletonList(content))); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Failed to get data source for special directory %s (objId=%d), RunIngestModulesAction omitted from context menu", content.getName(), content.getId()), ex); - } + actions.add(new RunIngestModulesAction(content)); actions.addAll(ContextMenuExtensionPoint.getActions()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index bb99924836..b813b8c3bb 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -24,6 +24,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JOptionPane; @@ -32,19 +33,24 @@ import org.openide.DialogDisplayer; import org.openide.WizardDescriptor; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel.SpecialDirectoryNode; import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; /** * An action that invokes the Run Ingest Modules wizard for one or more data - * sources or a subset of the files in a single data source. + * sources or for the children of a file. */ public final class RunIngestModulesAction extends AbstractAction { @Messages("RunIngestModulesAction.name=Run Ingest Modules") private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(SpecialDirectoryNode.class.getName()); /* * Note that the execution context is the name of the dialog that used to be @@ -53,7 +59,7 @@ public final class RunIngestModulesAction extends AbstractAction { private static final String EXECUTION_CONTEXT = "org.sleuthkit.autopsy.ingest.RunIngestModulesDialog"; private final List dataSources = new ArrayList<>(); private final IngestJobSettings.IngestType ingestType; - private final List files; + private final AbstractFile parentFile; /** * Display any warnings that the ingestJobSettings have. @@ -81,21 +87,25 @@ public final class RunIngestModulesAction extends AbstractAction { this.putValue(Action.NAME, Bundle.RunIngestModulesAction_name()); this.dataSources.addAll(dataSources); this.ingestType = IngestJobSettings.IngestType.ALL_MODULES; - this.files = Collections.emptyList(); + this.parentFile = null; } /** - * Constructs an action that invokes the Run Ingest Modules wizard for a - * subset of the files in a single data source. + * Constructs an action that invokes the Run Ingest Modules wizard for the + * children of a file. * - * @param dataSource The data source. - * @param files The files. + * @param file The file. */ - public RunIngestModulesAction(Content dataSource, List files) { + public RunIngestModulesAction(AbstractFile parentFile) { this.putValue(Action.NAME, Bundle.RunIngestModulesAction_name()); - this.dataSources.add(dataSource); + this.parentFile = parentFile; this.ingestType = IngestJobSettings.IngestType.FILES_ONLY; - this.files = new ArrayList<>(files); + try { + this.setEnabled(parentFile.hasChildren()); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed to get children count for parent file %s (objId=%d), RunIngestModulesAction disabled", parentFile.getName(), parentFile.getId()), ex); + MessageNotifyUtil.Message.error(Bundle.RunIngestModulesAction_actionPerformed_errorMessage()); + } } /** @@ -103,6 +113,9 @@ public final class RunIngestModulesAction extends AbstractAction { * * @param e the action event */ + @Messages({ + "RunIngestModulesAction.actionPerformed.errorMessage=Error querying the case database for the selected item." + }) @Override public void actionPerformed(ActionEvent e) { /** @@ -122,10 +135,25 @@ public final class RunIngestModulesAction extends AbstractAction { if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { IngestJobSettings ingestJobSettings = wizard.getIngestJobSettings(); showWarnings(ingestJobSettings); - if (this.files.isEmpty()) { + if (this.parentFile == null) { IngestManager.getInstance().queueIngestJob(this.dataSources, ingestJobSettings); } else { - IngestManager.getInstance().queueIngestJob(this.dataSources.get(0), this.files, ingestJobSettings); + try { + Content dataSource = parentFile.getDataSource(); + List children = parentFile.getChildren(); + List files = new ArrayList<>(); + for (Content child : children) { + if (child instanceof AbstractFile && child.getSize() > 0) { + files.add((AbstractFile) child); + } + } + if (files.isEmpty() == false) { + IngestManager.getInstance().queueIngestJob(dataSource, files, ingestJobSettings); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed to get data source or children for parent file %s (objId=%d), action failed", parentFile.getName(), parentFile.getId()), ex); + MessageNotifyUtil.Message.error(Bundle.RunIngestModulesAction_actionPerformed_errorMessage()); + } } } } From 2b36a5141a0d93d6679eaf6a94836a875b40c938 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 14 Mar 2018 18:33:19 -0400 Subject: [PATCH 28/41] Correctly support ingest of a subset of files from data source --- .../ingest/runIngestModuleWizard/RunIngestModulesAction.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index b813b8c3bb..4b92da55b4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -103,6 +103,7 @@ public final class RunIngestModulesAction extends AbstractAction { try { this.setEnabled(parentFile.hasChildren()); } catch (TskCoreException ex) { + this.setEnabled(false); logger.log(Level.SEVERE, String.format("Failed to get children count for parent file %s (objId=%d), RunIngestModulesAction disabled", parentFile.getName(), parentFile.getId()), ex); MessageNotifyUtil.Message.error(Bundle.RunIngestModulesAction_actionPerformed_errorMessage()); } From 2fbca0643530f41d371fa9f3d93bbcdb56754bfa Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 15 Mar 2018 13:06:10 +0100 Subject: [PATCH 29/41] fix codacy issues and Netbeans hints --- .../communications/VisualizationPanel.java | 2 +- .../DataContentTopComponent.java | 3 +- .../datamodel/BlackboardArtifactNode.java | 17 +-- .../autopsy/datamodel/accounts/Accounts.java | 141 +++++++++--------- ruleset.xml | 5 +- 5 files changed, 81 insertions(+), 87 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java index cd56e93393..ca6973573b 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/VisualizationPanel.java @@ -129,7 +129,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider private final mxGraphComponent graphComponent; private final CommunicationsGraph graph; - private mxUndoManager undoManager = new mxUndoManager(); + private final mxUndoManager undoManager = new mxUndoManager(); private final mxRubberband rubberband; private final mxFastOrganicLayout fastOrganicLayout; private final mxCircleLayout circleLayout; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java index b5dd60c395..210a781c68 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentTopComponent.java @@ -185,7 +185,8 @@ public final class DataContentTopComponent extends TopComponent implements DataC } catch (NoCurrentCaseException ex) { return true; } - return (!this.isDefault) || openCase.hasData() == false; + + return (this.isDefault ==false) ||( openCase.hasData() == false); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 020c133ef4..e042c196a4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -407,19 +407,19 @@ public class BlackboardArtifactNode extends AbstractContentNode(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"), "", - file != null ? ContentUtils.getStringTime(file.getMtime(), file) : "")); + file == null ? "" : ContentUtils.getStringTime(file.getMtime(), file))); ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"), "", - file != null ? ContentUtils.getStringTime(file.getCtime(), file) : "")); + file == null ? "" : ContentUtils.getStringTime(file.getCtime(), file))); ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"), "", - file != null ? ContentUtils.getStringTime(file.getAtime(), file) : "")); + file == null ? "" : ContentUtils.getStringTime(file.getAtime(), file))); ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"), "", - file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : "")); + file == null ? "" : ContentUtils.getStringTime(file.getCrtime(), file))); ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"), "", @@ -427,7 +427,7 @@ public class BlackboardArtifactNode extends AbstractContentNode(Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(), Bundle.BlackboardArtifactNode_createSheet_artifactMD5_displayName(), "", - file != null ? StringUtils.defaultString(file.getMd5Hash()) : "")); + file == null ? "" : StringUtils.defaultString(file.getMd5Hash()))); } } else { String dataSourceStr = ""; @@ -456,16 +456,15 @@ public class BlackboardArtifactNode extends AbstractContentNode tags = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index f25541839c..3b6878ce23 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -88,7 +88,7 @@ import org.sleuthkit.datamodel.TskData.DbType; final public class Accounts implements AutopsyVisitableItem { private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName()); - private static final String iconBasePath = "/org/sleuthkit/autopsy/images/"; //NON-NLS + private static final String ICON_BASE_PATH = "/org/sleuthkit/autopsy/images/"; //NON-NLS @NbBundle.Messages("AccountsRootNode.name=Accounts") final public static String NAME = Bundle.AccountsRootNode_name(); @@ -96,10 +96,8 @@ final public class Accounts implements AutopsyVisitableItem { private SleuthkitCase skCase; private final EventBus reviewStatusBus = new EventBus("ReviewStatusBus"); - /** - * Should rejected accounts be shown in the accounts section of the tree. - */ - private boolean showRejected = false; + /* Should rejected accounts be shown in the accounts section of the tree. */ + private boolean showRejected = false; //NOPMD redundant initializer private final RejectAccounts rejectActionInstance; private final ApproveAccounts approveActionInstance; @@ -717,8 +715,8 @@ final public class Accounts implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - String query - = "SELECT blackboard_artifacts.obj_id," //NON-NLS + String query = + "SELECT blackboard_artifacts.obj_id," //NON-NLS + " solr_attribute.value_text AS solr_document_id, "; //NON-NLS if (skCase.getDatabaseType().equals(DbType.POSTGRESQL)) { query += " string_agg(blackboard_artifacts.artifact_id::character varying, ',') AS artifact_IDs, " //NON-NLS @@ -739,14 +737,14 @@ final public class Accounts implements AutopsyVisitableItem { + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS + " ORDER BY hits DESC "; //NON-NLS try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); - ResultSet rs = results.getResultSet();) { - while (rs.next()) { + ResultSet resultSet = results.getResultSet();) { + while (resultSet.next()) { list.add(new FileWithCCN( - rs.getLong("obj_id"), //NON-NLS - rs.getString("solr_document_id"), //NON-NLS - unGroupConcat(rs.getString("artifact_IDs"), Long::valueOf), //NON-NLS - rs.getLong("hits"), //NON-NLS - new HashSet<>(unGroupConcat(rs.getString("review_status_ids"), id -> BlackboardArtifact.ReviewStatus.withID(Integer.valueOf(id)))))); //NON-NLS + resultSet.getLong("obj_id"), //NON-NLS + resultSet.getString("solr_document_id"), //NON-NLS + unGroupConcat(resultSet.getString("artifact_IDs"), Long::valueOf), //NON-NLS + resultSet.getLong("hits"), //NON-NLS + new HashSet<>(unGroupConcat(resultSet.getString("review_status_ids"), reviewStatusID -> BlackboardArtifact.ReviewStatus.withID(Integer.valueOf(reviewStatusID)))))); //NON-NLS } } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS @@ -794,8 +792,8 @@ final public class Accounts implements AutopsyVisitableItem { "# {0} - number of children", "Accounts.ByFileNode.displayName=By File ({0})"}) private void updateDisplayName() { - String query - = "SELECT count(*) FROM ( SELECT count(*) AS documents " + String query = + "SELECT count(*) FROM ( SELECT count(*) AS documents " + " FROM blackboard_artifacts " //NON-NLS + " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS + " AND solr_attribute.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID.getTypeID() //NON-NLS @@ -806,12 +804,12 @@ final public class Accounts implements AutopsyVisitableItem { + getRejectedArtifactFilterClause() + " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo"; try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); - ResultSet rs = results.getResultSet();) { - while (rs.next()) { + ResultSet resultSet = results.getResultSet();) { + while (resultSet.next()) { if (skCase.getDatabaseType().equals(DbType.POSTGRESQL)) { - setDisplayName(Bundle.Accounts_ByFileNode_displayName(rs.getLong("count"))); + setDisplayName(Bundle.Accounts_ByFileNode_displayName(resultSet.getLong("count"))); } else { - setDisplayName(Bundle.Accounts_ByFileNode_displayName(rs.getLong("count(*)"))); + setDisplayName(Bundle.Accounts_ByFileNode_displayName(resultSet.getLong("count(*)"))); } } } catch (TskCoreException | SQLException ex) { @@ -872,7 +870,7 @@ final public class Accounts implements AutopsyVisitableItem { && eventData.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { reviewStatusBus.post(eventData); } - } catch (NoCurrentCaseException notUsed) { + } catch (NoCurrentCaseException notUsed) { //NOPMD empy catch clause // Case is closed, do nothing. } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) @@ -887,15 +885,14 @@ final public class Accounts implements AutopsyVisitableItem { Case.getOpenCase(); refresh(true); - } catch (NoCurrentCaseException notUsed) { + } catch (NoCurrentCaseException notUsed) { //NOPMD empy catch clause // Case is closed, do nothing. } - } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { + } else if (eventType.equals(Case.Events.CURRENT_CASE.toString()) + && (evt.getNewValue() == null)) { // case was closed. Remove listeners so that we don't get called with a stale case handle - if (evt.getNewValue() == null) { - removeNotify(); - skCase = null; - } + removeNotify(); + skCase = null; } } }; @@ -931,8 +928,8 @@ final public class Accounts implements AutopsyVisitableItem { RangeMap binRanges = TreeRangeMap.create(); - String query - = "SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS + String query = + "SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS + " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS @@ -941,8 +938,8 @@ final public class Accounts implements AutopsyVisitableItem { + getRejectedArtifactFilterClause() + " GROUP BY BIN " //NON-NLS + " ORDER BY BIN "; //NON-NLS - try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query)) { - ResultSet resultSet = results.getResultSet(); + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); + ResultSet resultSet = results.getResultSet();) { //sort all te individual bins in to the ranges while (resultSet.next()) { final Integer bin = Integer.valueOf(resultSet.getString("BIN")); @@ -956,16 +953,15 @@ final public class Accounts implements AutopsyVisitableItem { count += previousResult.getCount(); } - if (binRange != null) { - binRanges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), new BinResult(count, binRange)); - } else { + if (binRange == null) { binRanges.put(Range.closed(bin, bin), new BinResult(count, bin, bin)); + } else { + binRanges.put(Range.closed(binRange.getBINstart(), binRange.getBINend()), new BinResult(count, binRange)); } } binRanges.asMapOfRanges().values().forEach(list::add); } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS - } return true; @@ -999,15 +995,15 @@ final public class Accounts implements AutopsyVisitableItem { "# {0} - number of children", "Accounts.ByBINNode.displayName=By BIN ({0})"}) private void updateDisplayName() { - String query - = "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS + String query = + "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS + " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER.getTypeID() //NON-NLS + getRejectedArtifactFilterClause(); //NON-NLS - try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query)) { - ResultSet resultSet = results.getResultSet(); + try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); + ResultSet resultSet = results.getResultSet();) { while (resultSet.next()) { setDisplayName(Bundle.Accounts_ByBINNode_displayName(resultSet.getLong("BINs"))); } @@ -1188,7 +1184,8 @@ final public class Accounts implements AutopsyVisitableItem { * @param key The FileWithCCN that backs this node. * @param content The Content object the key represents. * @param lookupContents The contents of this Node's lookup. It should - * contain the content object and the account artifacts. + * contain the content object and the account + * artifacts. */ @NbBundle.Messages({ "# {0} - raw file name", @@ -1226,29 +1223,29 @@ final public class Accounts implements AutopsyVisitableItem { "Accounts.FileWithCCNNode.statusProperty.displayName=Status", "Accounts.FileWithCCNNode.noDescription=no description"}) protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); + Sheet sheet = super.createSheet(); + Sheet.Set propSet = sheet.get(Sheet.PROPERTIES); + if (propSet == null) { + propSet = Sheet.createPropertiesSet(); + sheet.put(propSet); } - ss.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_nameProperty_displayName(), + propSet.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_nameProperty_displayName(), Bundle.Accounts_FileWithCCNNode_nameProperty_displayName(), Bundle.Accounts_FileWithCCNNode_noDescription(), fileName)); - ss.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_accountsProperty_displayName(), + propSet.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_accountsProperty_displayName(), Bundle.Accounts_FileWithCCNNode_accountsProperty_displayName(), Bundle.Accounts_FileWithCCNNode_noDescription(), fileKey.getHits())); - ss.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(), + propSet.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(), Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(), Bundle.Accounts_FileWithCCNNode_noDescription(), fileKey.getStatuses().stream() .map(BlackboardArtifact.ReviewStatus::getDisplayName) .collect(Collectors.joining(", ")))); //NON-NLS - return s; + return sheet; } @Override @@ -1292,8 +1289,8 @@ final public class Accounts implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - String query - = "SELECT blackboard_artifacts.artifact_id " //NON-NLS + String query = + "SELECT blackboard_artifacts.artifact_id " //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS @@ -1339,9 +1336,7 @@ final public class Accounts implements AutopsyVisitableItem { final public class BINNode extends DisplayableItemNode { - /** - * Creates the nodes for the credit card numbers - */ + /** Creates the nodes for the credit card numbers */ private final BinResult bin; private BINNode(BinResult bin) { @@ -1365,8 +1360,8 @@ final public class Accounts implements AutopsyVisitableItem { } private void updateDisplayName() { - String query - = "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS + String query = + "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS + " FROM blackboard_artifacts " //NON-NLS + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS + " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID() //NON-NLS @@ -1374,9 +1369,9 @@ final public class Accounts implements AutopsyVisitableItem { + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS + getRejectedArtifactFilterClause(); try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query); - ResultSet rs = results.getResultSet();) { - while (rs.next()) { - setDisplayName(getBinRangeString(bin) + " (" + rs.getLong("count") + ")"); //NON-NLS + ResultSet resultSet = results.getResultSet();) { + while (resultSet.next()) { + setDisplayName(getBinRangeString(bin) + " (" + resultSet.getLong("count") + ")"); //NON-NLS } } catch (TskCoreException | SQLException ex) { LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS @@ -1506,9 +1501,7 @@ final public class Accounts implements AutopsyVisitableItem { return true; } - /** - * The number of accounts with this BIN - */ + /** The number of accounts with this BIN */ private final long count; private final BINRange binRange; @@ -1598,7 +1591,7 @@ final public class Accounts implements AutopsyVisitableItem { private AccountArtifactNode(BlackboardArtifact artifact) { super(artifact, "org/sleuthkit/autopsy/images/credit-card.png"); //NON-NLS this.artifact = artifact; - setName("" + this.artifact.getArtifactID()); + setName(Long.toString(this.artifact.getArtifactID())); reviewStatusBus.register(this); } @@ -1728,7 +1721,7 @@ final public class Accounts implements AutopsyVisitableItem { selectedPaths.forEach(path -> { try { toArray.add(NodeOp.findPath(rootNode, path)); - } catch (NodeNotFoundException ex) { + } catch (NodeNotFoundException ex) { //NOPMD empty catch clause //just ingnore paths taht don't exist. this is expected since we are rejecting } }); @@ -1772,25 +1765,25 @@ final public class Accounts implements AutopsyVisitableItem { public static String getIconFilePath(Account.Type type) { if (type.equals(Account.Type.CREDIT_CARD)) { - return iconBasePath + "credit-card.png"; + return ICON_BASE_PATH + "credit-card.png"; } else if (type.equals(Account.Type.DEVICE)) { - return iconBasePath + "image.png"; + return ICON_BASE_PATH + "image.png"; } else if (type.equals(Account.Type.EMAIL)) { - return iconBasePath + "email.png"; + return ICON_BASE_PATH + "email.png"; } else if (type.equals(Account.Type.FACEBOOK)) { - return iconBasePath + "facebook.png"; + return ICON_BASE_PATH + "facebook.png"; } else if (type.equals(Account.Type.INSTAGRAM)) { - return iconBasePath + "instagram.png"; + return ICON_BASE_PATH + "instagram.png"; } else if (type.equals(Account.Type.MESSAGING_APP)) { - return iconBasePath + "messaging.png"; + return ICON_BASE_PATH + "messaging.png"; } else if (type.equals(Account.Type.PHONE)) { - return iconBasePath + "phone.png"; + return ICON_BASE_PATH + "phone.png"; } else if (type.equals(Account.Type.TWITTER)) { - return iconBasePath + "twitter.png"; + return ICON_BASE_PATH + "twitter.png"; } else if (type.equals(Account.Type.WEBSITE)) { - return iconBasePath + "web-file.png"; + return ICON_BASE_PATH + "web-file.png"; } else if (type.equals(Account.Type.WHATSAPP)) { - return iconBasePath + "WhatsApp.png"; + return ICON_BASE_PATH + "WhatsApp.png"; } else { //there could be a default icon instead... throw new IllegalArgumentException("Unknown Account.Type: " + type.getTypeName()); diff --git a/ruleset.xml b/ruleset.xml index ba1bfa6374..f1b0b509af 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -56,9 +56,10 @@ - + - + +