mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 07:56:16 +00:00
Added ability to search for MD5
This commit is contained in:
parent
80df57654b
commit
9f95239cc4
@ -56,3 +56,5 @@ SizeSearchPanel.sizeCompareComboBox.lessThan=less than
|
|||||||
MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected
|
MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected
|
||||||
FileSearchPanel.searchButton.text=Search
|
FileSearchPanel.searchButton.text=Search
|
||||||
MimeTypePanel.mimeTypeCheckBox.text=MIME Type:
|
MimeTypePanel.mimeTypeCheckBox.text=MIME Type:
|
||||||
|
HashSearchPanel.md5CheckBox.text=MD5:
|
||||||
|
HashSearchPanel.emptyHashMsg.text=Must enter something for hash search.
|
@ -95,6 +95,8 @@ class FileSearchPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.knownStatus"), new KnownStatusSearchFilter()));
|
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "FileSearchPanel.filterTitle.knownStatus"), new KnownStatusSearchFilter()));
|
||||||
|
|
||||||
|
this.filterAreas.add(new FilterArea(NbBundle.getMessage(this.getClass(), "HashSearchPanel.md5CheckBox.text"), new HashSearchFilter()));
|
||||||
|
|
||||||
for (FilterArea fa : this.filterAreas) {
|
for (FilterArea fa : this.filterAreas) {
|
||||||
fa.setMaximumSize(new Dimension(Integer.MAX_VALUE, fa.getMinimumSize().height));
|
fa.setMaximumSize(new Dimension(Integer.MAX_VALUE, fa.getMinimumSize().height));
|
||||||
fa.setAlignmentX(Component.LEFT_ALIGNMENT);
|
fa.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
66
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java
Executable file
66
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java
Executable file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2017 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> 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.filesearch;
|
||||||
|
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class HashSearchFilter extends AbstractFileSearchFilter<HashSearchPanel> {
|
||||||
|
|
||||||
|
private static final String EMPTY_HASH_MESSAGE = NbBundle
|
||||||
|
.getMessage(HashSearchFilter.class, "HashSearchPanel.emptyHashMsg.text");
|
||||||
|
|
||||||
|
public HashSearchFilter() {
|
||||||
|
this(new HashSearchPanel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashSearchFilter(HashSearchPanel component) {
|
||||||
|
super(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return this.getComponent().getHashCheckBox().isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPredicate() throws FilterValidationException {
|
||||||
|
String md5Hash = this.getComponent().getSearchTextField().getText();
|
||||||
|
|
||||||
|
if (md5Hash.isEmpty()) {
|
||||||
|
throw new FilterValidationException(EMPTY_HASH_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "md5 = '" + md5Hash.toLowerCase() + "'"; //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addActionListener(ActionListener l) {
|
||||||
|
getComponent().addActionListener(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return !this.getComponent().getSearchTextField().getText().isEmpty();
|
||||||
|
}
|
||||||
|
}
|
104
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchPanel.form
Executable file
104
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchPanel.form
Executable file
@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<NonVisualComponents>
|
||||||
|
<Container class="javax.swing.JPopupMenu" name="rightClickMenu">
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout">
|
||||||
|
<Property name="useNullLayout" type="boolean" value="true"/>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<MenuItem class="javax.swing.JMenuItem" name="cutMenuItem">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.cutMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem class="javax.swing.JMenuItem" name="copyMenuItem">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.copyMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem class="javax.swing.JMenuItem" name="pasteMenuItem">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.pasteMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem class="javax.swing.JMenuItem" name="selectAllMenuItem">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.selectAllMenuItem.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</MenuItem>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</NonVisualComponents>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
<Component id="hashCheckBox" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="searchTextField" min="-2" pref="247" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="hashCheckBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="searchTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JCheckBox" name="hashCheckBox">
|
||||||
|
<Properties>
|
||||||
|
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||||
|
<FontInfo relative="true">
|
||||||
|
<Font bold="false" component="hashCheckBox" property="font" relativeSize="false" size="11"/>
|
||||||
|
</FontInfo>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="HashSearchPanel.md5CheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="hashCheckBoxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JTextField" name="searchTextField">
|
||||||
|
<Properties>
|
||||||
|
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
|
||||||
|
<FontInfo relative="true">
|
||||||
|
<Font bold="false" component="searchTextField" property="font" relativeSize="false" size="11"/>
|
||||||
|
</FontInfo>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.searchTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
176
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchPanel.java
Executable file
176
Core/src/org/sleuthkit/autopsy/filesearch/HashSearchPanel.java
Executable file
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> 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.filesearch;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import javax.swing.JCheckBox;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class HashSearchPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new form HashSearchPanel
|
||||||
|
*/
|
||||||
|
HashSearchPanel() {
|
||||||
|
initComponents();
|
||||||
|
customizeComponents();
|
||||||
|
setComponentsEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void customizeComponents() {
|
||||||
|
|
||||||
|
searchTextField.setComponentPopupMenu(rightClickMenu);
|
||||||
|
ActionListener actList = new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
JMenuItem jmi = (JMenuItem) e.getSource();
|
||||||
|
if (jmi.equals(cutMenuItem)) {
|
||||||
|
searchTextField.cut();
|
||||||
|
} else if (jmi.equals(copyMenuItem)) {
|
||||||
|
searchTextField.copy();
|
||||||
|
} else if (jmi.equals(pasteMenuItem)) {
|
||||||
|
searchTextField.paste();
|
||||||
|
} else if (jmi.equals(selectAllMenuItem)) {
|
||||||
|
searchTextField.selectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cutMenuItem.addActionListener(actList);
|
||||||
|
copyMenuItem.addActionListener(actList);
|
||||||
|
pasteMenuItem.addActionListener(actList);
|
||||||
|
selectAllMenuItem.addActionListener(actList);
|
||||||
|
this.searchTextField.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JCheckBox getHashCheckBox() {
|
||||||
|
return hashCheckBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
JTextField getSearchTextField() {
|
||||||
|
return searchTextField;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setComponentsEnabled() {
|
||||||
|
boolean enabled = hashCheckBox.isSelected();
|
||||||
|
this.searchTextField.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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")
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
rightClickMenu = new javax.swing.JPopupMenu();
|
||||||
|
cutMenuItem = new javax.swing.JMenuItem();
|
||||||
|
copyMenuItem = new javax.swing.JMenuItem();
|
||||||
|
pasteMenuItem = new javax.swing.JMenuItem();
|
||||||
|
selectAllMenuItem = new javax.swing.JMenuItem();
|
||||||
|
hashCheckBox = new javax.swing.JCheckBox();
|
||||||
|
searchTextField = new javax.swing.JTextField();
|
||||||
|
|
||||||
|
cutMenuItem.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.cutMenuItem.text")); // NOI18N
|
||||||
|
rightClickMenu.add(cutMenuItem);
|
||||||
|
|
||||||
|
copyMenuItem.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.copyMenuItem.text")); // NOI18N
|
||||||
|
rightClickMenu.add(copyMenuItem);
|
||||||
|
|
||||||
|
pasteMenuItem.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.pasteMenuItem.text")); // NOI18N
|
||||||
|
rightClickMenu.add(pasteMenuItem);
|
||||||
|
|
||||||
|
selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.selectAllMenuItem.text")); // NOI18N
|
||||||
|
rightClickMenu.add(selectAllMenuItem);
|
||||||
|
|
||||||
|
hashCheckBox.setFont(hashCheckBox.getFont().deriveFont(hashCheckBox.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
|
||||||
|
hashCheckBox.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "HashSearchPanel.md5CheckBox.text")); // NOI18N
|
||||||
|
hashCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
hashCheckBoxActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
searchTextField.setFont(searchTextField.getFont().deriveFont(searchTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
|
||||||
|
searchTextField.setText(org.openide.util.NbBundle.getMessage(HashSearchPanel.class, "NameSearchPanel.searchTextField.text")); // NOI18N
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
|
this.setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addGap(0, 0, 0)
|
||||||
|
.addComponent(hashCheckBox)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 247, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addGap(0, 0, 0))
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(hashCheckBox)
|
||||||
|
.addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
|
);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void hashCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashCheckBoxActionPerformed
|
||||||
|
setComponentsEnabled();
|
||||||
|
firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null);
|
||||||
|
}//GEN-LAST:event_hashCheckBoxActionPerformed
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JMenuItem copyMenuItem;
|
||||||
|
private javax.swing.JMenuItem cutMenuItem;
|
||||||
|
private javax.swing.JCheckBox hashCheckBox;
|
||||||
|
private javax.swing.JMenuItem pasteMenuItem;
|
||||||
|
private javax.swing.JPopupMenu rightClickMenu;
|
||||||
|
private javax.swing.JTextField searchTextField;
|
||||||
|
private javax.swing.JMenuItem selectAllMenuItem;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
void addActionListener(ActionListener l) {
|
||||||
|
searchTextField.addActionListener(l);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user