Compare commits
	
		
			14 Commits
		
	
	
		
			ablesov/fi
			...
			pixeebot/d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					7879dd3aac | ||
| 
						 | 
					3ff9520114 | ||
| 
						 | 
					cf5808cf71 | ||
| 
						 | 
					052ce4cd9c | ||
| 
						 | 
					1eecd892f7 | ||
| 
						 | 
					f9be1daccb | ||
| 
						 | 
					6d0560c311 | ||
| 
						 | 
					dfdbff5100 | ||
| 
						 | 
					e93a4c16de | ||
| 
						 | 
					bd2c567151 | ||
| 
						 | 
					4f989dcd94 | ||
| 
						 | 
					c3f09469b9 | ||
| 
						 | 
					69512ba605 | ||
| 
						 | 
					bd4ab27c21 | 
							
								
								
									
										19
									
								
								.github/workflows/snorkell-auto-documentation.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,19 @@
 | 
			
		||||
# This workflow will improvise current file with AI genereated documentation and Create new PR
 | 
			
		||||
 | 
			
		||||
name: Snorkell.ai - Revolutionizing Documentation on GitHub
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches: ["main"]
 | 
			
		||||
  workflow_dispatch:
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  Documentation:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - name: Snorkell DocGen Client
 | 
			
		||||
      uses: SingularityX-ai/snorkell-documentation-client@v1.0.0
 | 
			
		||||
      with:
 | 
			
		||||
        client_id: ${{ secrets.SNORKELL_CLIENT_ID }}
 | 
			
		||||
        api_key: ${{ secrets.SNORKELL_API_KEY }}
 | 
			
		||||
        branch_name: "main"
 | 
			
		||||
@@ -1,178 +1,178 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
from json import loads, dumps
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from traceback import print_exc
 | 
			
		||||
 | 
			
		||||
# Taken from https://github.com/dgunter/ParseZeekLogs <3
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParseZeekLogs(object):
 | 
			
		||||
    """
 | 
			
		||||
        Class that parses Zeek logs and allows log data to be output in CSV or json format.
 | 
			
		||||
        Attributes: filepath: Path of Zeek log file to read
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, filepath, batchsize=500, fields=None, output_format=None, ignore_keys=[], meta={}, safe_headers=False):
 | 
			
		||||
        self.fd = open(filepath, "r")
 | 
			
		||||
        self.options = OrderedDict()
 | 
			
		||||
        self.firstRun = True
 | 
			
		||||
        self.filtered_fields = fields
 | 
			
		||||
        self.batchsize = batchsize
 | 
			
		||||
        self.output_format = output_format
 | 
			
		||||
        self.ignore_keys = ignore_keys
 | 
			
		||||
        self.meta = meta
 | 
			
		||||
        self.safe_headers = safe_headers
 | 
			
		||||
 | 
			
		||||
        # Convert ' to " in meta string
 | 
			
		||||
        meta = loads(dumps(meta).replace("'", '"'))
 | 
			
		||||
 | 
			
		||||
        # Read the header option lines
 | 
			
		||||
        l = self.fd.readline().strip()
 | 
			
		||||
        while l.strip().startswith("#"):
 | 
			
		||||
            # Parse the options out
 | 
			
		||||
            if l.startswith("#separator"):
 | 
			
		||||
                key = str(l[1:].split(" ")[0])
 | 
			
		||||
                value = str.encode(l[1:].split(
 | 
			
		||||
                    " ")[1].strip()).decode('unicode_escape')
 | 
			
		||||
                self.options[key] = value
 | 
			
		||||
            elif l.startswith("#"):
 | 
			
		||||
                key = str(l[1:].split(self.options.get('separator'))[0])
 | 
			
		||||
                value = l[1:].split(self.options.get('separator'))[1:]
 | 
			
		||||
                self.options[key] = value
 | 
			
		||||
 | 
			
		||||
            # Read the next line
 | 
			
		||||
            l = self.fd.readline().strip()
 | 
			
		||||
 | 
			
		||||
        self.firstLine = l
 | 
			
		||||
 | 
			
		||||
        # Save mapping of fields to values:
 | 
			
		||||
        self.fields = self.options.get('fields')
 | 
			
		||||
        self.types = self.options.get('types')
 | 
			
		||||
 | 
			
		||||
        self.data_types = {}
 | 
			
		||||
        for i, val in enumerate(self.fields):
 | 
			
		||||
            # Convert field names if safe_headers is enabled
 | 
			
		||||
            if self.safe_headers is True:
 | 
			
		||||
                self.fields[i] = self.fields[i].replace(".", "_")
 | 
			
		||||
 | 
			
		||||
            # Match types with each other
 | 
			
		||||
            self.data_types[self.fields[i]] = self.types[i]
 | 
			
		||||
 | 
			
		||||
    def __del__(self):
 | 
			
		||||
        self.fd.close()
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    def __next__(self):
 | 
			
		||||
        retVal = ""
 | 
			
		||||
        if self.firstRun is True:
 | 
			
		||||
            retVal = self.firstLine
 | 
			
		||||
            self.firstRun = False
 | 
			
		||||
        else:
 | 
			
		||||
            retVal = self.fd.readline().strip()
 | 
			
		||||
 | 
			
		||||
        # If an empty string is returned, readline is done reading
 | 
			
		||||
        if retVal == "" or retVal is None:
 | 
			
		||||
            raise StopIteration
 | 
			
		||||
 | 
			
		||||
        # Split out the data we are going to return
 | 
			
		||||
        retVal = retVal.split(self.options.get('separator'))
 | 
			
		||||
 | 
			
		||||
        record = None
 | 
			
		||||
        # Make sure we aren't dealing with a comment line
 | 
			
		||||
        if len(retVal) > 0 and not str(retVal[0]).strip().startswith("#") \
 | 
			
		||||
                and len(retVal) is len(self.options.get("fields")):
 | 
			
		||||
            record = OrderedDict()
 | 
			
		||||
            # Prepare fields for conversion
 | 
			
		||||
            for x in range(0, len(retVal)):
 | 
			
		||||
                if self.safe_headers is True:
 | 
			
		||||
                    converted_field_name = self.options.get(
 | 
			
		||||
                        "fields")[x].replace(".", "_")
 | 
			
		||||
                else:
 | 
			
		||||
                    converted_field_name = self.options.get("fields")[x]
 | 
			
		||||
                if self.filtered_fields is None or converted_field_name in self.filtered_fields:
 | 
			
		||||
                    # Translate - to "" to fix a conversation error
 | 
			
		||||
                    if retVal[x] == "-":
 | 
			
		||||
                        retVal[x] = ""
 | 
			
		||||
                    # Save the record field if the field isn't filtered out
 | 
			
		||||
                    record[converted_field_name] = retVal[x]
 | 
			
		||||
 | 
			
		||||
            # Convert values to the appropriate record type
 | 
			
		||||
            record = self.convert_values(
 | 
			
		||||
                record, self.ignore_keys, self.data_types)
 | 
			
		||||
 | 
			
		||||
            if record is not None and self.output_format == "json":
 | 
			
		||||
                # Output will be json
 | 
			
		||||
 | 
			
		||||
                # Add metadata to json
 | 
			
		||||
                for k, v in self.meta.items():
 | 
			
		||||
                    record[k] = v
 | 
			
		||||
 | 
			
		||||
                retVal = record
 | 
			
		||||
            elif record is not None and self.output_format == "csv":
 | 
			
		||||
                retVal = ""
 | 
			
		||||
                # Add escaping to csv format
 | 
			
		||||
                for k, v in record.items():
 | 
			
		||||
                    # Add escaping to string values
 | 
			
		||||
                    if isinstance(v, str):
 | 
			
		||||
                        retVal += str("\"" + str(v).strip() + "\"" + ",")
 | 
			
		||||
                    else:
 | 
			
		||||
                        retVal += str(str(v).strip() + ",")
 | 
			
		||||
                # Remove the trailing comma
 | 
			
		||||
                retVal = retVal[:-1]
 | 
			
		||||
        else:
 | 
			
		||||
            retVal = None
 | 
			
		||||
 | 
			
		||||
        return retVal
 | 
			
		||||
 | 
			
		||||
    def convert_values(self, data, ignore_keys=[], data_types={}):
 | 
			
		||||
        keys_to_delete = []
 | 
			
		||||
        for k, v in data.items():
 | 
			
		||||
            # print("evaluating k: " + str(k) + " v: " + str(v))
 | 
			
		||||
 | 
			
		||||
            if isinstance(v, dict):
 | 
			
		||||
                data[k] = self.convert_values(v)
 | 
			
		||||
            else:
 | 
			
		||||
                if data_types.get(k) is not None:
 | 
			
		||||
                    if (data_types.get(k) == "port" or data_types.get(k) == "count"):
 | 
			
		||||
                        if v != "":
 | 
			
		||||
                            data[k] = int(v)
 | 
			
		||||
                        else:
 | 
			
		||||
                            keys_to_delete.append(k)
 | 
			
		||||
                    elif (data_types.get(k) == "double" or data_types.get(k) == "interval"):
 | 
			
		||||
                        if v != "":
 | 
			
		||||
                            data[k] = float(v)
 | 
			
		||||
                        else:
 | 
			
		||||
                            keys_to_delete.append(k)
 | 
			
		||||
                    elif data_types.get(k) == "bool":
 | 
			
		||||
                        data[k] = bool(v)
 | 
			
		||||
                    else:
 | 
			
		||||
                        data[k] = v
 | 
			
		||||
 | 
			
		||||
        for k in keys_to_delete:
 | 
			
		||||
            del data[k]
 | 
			
		||||
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def get_fields(self):
 | 
			
		||||
        """Returns all fields present in the log file
 | 
			
		||||
        Returns:
 | 
			
		||||
            A python list containing all field names in the log file
 | 
			
		||||
        """
 | 
			
		||||
        field_names = ""
 | 
			
		||||
        if self.output_format == "csv":
 | 
			
		||||
            for i, v in enumerate(self.fields):
 | 
			
		||||
                if self.filtered_fields is None or v in self.filtered_fields:
 | 
			
		||||
                    field_names += str(v) + ","
 | 
			
		||||
            # Remove the trailing comma
 | 
			
		||||
            field_names = field_names[:-1].strip()
 | 
			
		||||
        else:
 | 
			
		||||
            field_names = []
 | 
			
		||||
            for i, v in enumerate(self.fields):
 | 
			
		||||
                if self.filtered_fields is None or v in self.filtered_fields:
 | 
			
		||||
                    field_names.append(v)
 | 
			
		||||
        return field_names
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
from json import loads, dumps
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from traceback import print_exc
 | 
			
		||||
 | 
			
		||||
# Taken from https://github.com/dgunter/ParseZeekLogs <3
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParseZeekLogs(object):
 | 
			
		||||
    """
 | 
			
		||||
        Class that parses Zeek logs and allows log data to be output in CSV or json format.
 | 
			
		||||
        Attributes: filepath: Path of Zeek log file to read
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, filepath, batchsize=500, fields=None, output_format=None, ignore_keys=[], meta={}, safe_headers=False):
 | 
			
		||||
        self.fd = open(filepath, "r")
 | 
			
		||||
        self.options = OrderedDict()
 | 
			
		||||
        self.firstRun = True
 | 
			
		||||
        self.filtered_fields = fields
 | 
			
		||||
        self.batchsize = batchsize
 | 
			
		||||
        self.output_format = output_format
 | 
			
		||||
        self.ignore_keys = ignore_keys
 | 
			
		||||
        self.meta = meta
 | 
			
		||||
        self.safe_headers = safe_headers
 | 
			
		||||
 | 
			
		||||
        # Convert ' to " in meta string
 | 
			
		||||
        meta = loads(dumps(meta).replace("'", '"'))
 | 
			
		||||
 | 
			
		||||
        # Read the header option lines
 | 
			
		||||
        l = self.fd.readline(5_000_000).strip()
 | 
			
		||||
        while l.strip().startswith("#"):
 | 
			
		||||
            # Parse the options out
 | 
			
		||||
            if l.startswith("#separator"):
 | 
			
		||||
                key = str(l[1:].split(" ")[0])
 | 
			
		||||
                value = str.encode(l[1:].split(
 | 
			
		||||
                    " ")[1].strip()).decode('unicode_escape')
 | 
			
		||||
                self.options[key] = value
 | 
			
		||||
            elif l.startswith("#"):
 | 
			
		||||
                key = str(l[1:].split(self.options.get('separator'))[0])
 | 
			
		||||
                value = l[1:].split(self.options.get('separator'))[1:]
 | 
			
		||||
                self.options[key] = value
 | 
			
		||||
 | 
			
		||||
            # Read the next line
 | 
			
		||||
            l = self.fd.readline(5_000_000).strip()
 | 
			
		||||
 | 
			
		||||
        self.firstLine = l
 | 
			
		||||
 | 
			
		||||
        # Save mapping of fields to values:
 | 
			
		||||
        self.fields = self.options.get('fields')
 | 
			
		||||
        self.types = self.options.get('types')
 | 
			
		||||
 | 
			
		||||
        self.data_types = {}
 | 
			
		||||
        for i, val in enumerate(self.fields):
 | 
			
		||||
            # Convert field names if safe_headers is enabled
 | 
			
		||||
            if self.safe_headers is True:
 | 
			
		||||
                self.fields[i] = self.fields[i].replace(".", "_")
 | 
			
		||||
 | 
			
		||||
            # Match types with each other
 | 
			
		||||
            self.data_types[self.fields[i]] = self.types[i]
 | 
			
		||||
 | 
			
		||||
    def __del__(self):
 | 
			
		||||
        self.fd.close()
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    def __next__(self):
 | 
			
		||||
        retVal = ""
 | 
			
		||||
        if self.firstRun is True:
 | 
			
		||||
            retVal = self.firstLine
 | 
			
		||||
            self.firstRun = False
 | 
			
		||||
        else:
 | 
			
		||||
            retVal = self.fd.readline().strip()
 | 
			
		||||
 | 
			
		||||
        # If an empty string is returned, readline is done reading
 | 
			
		||||
        if retVal == "" or retVal is None:
 | 
			
		||||
            raise StopIteration
 | 
			
		||||
 | 
			
		||||
        # Split out the data we are going to return
 | 
			
		||||
        retVal = retVal.split(self.options.get('separator'))
 | 
			
		||||
 | 
			
		||||
        record = None
 | 
			
		||||
        # Make sure we aren't dealing with a comment line
 | 
			
		||||
        if len(retVal) > 0 and not str(retVal[0]).strip().startswith("#") \
 | 
			
		||||
                and len(retVal) is len(self.options.get("fields")):
 | 
			
		||||
            record = OrderedDict()
 | 
			
		||||
            # Prepare fields for conversion
 | 
			
		||||
            for x in range(0, len(retVal)):
 | 
			
		||||
                if self.safe_headers is True:
 | 
			
		||||
                    converted_field_name = self.options.get(
 | 
			
		||||
                        "fields")[x].replace(".", "_")
 | 
			
		||||
                else:
 | 
			
		||||
                    converted_field_name = self.options.get("fields")[x]
 | 
			
		||||
                if self.filtered_fields is None or converted_field_name in self.filtered_fields:
 | 
			
		||||
                    # Translate - to "" to fix a conversation error
 | 
			
		||||
                    if retVal[x] == "-":
 | 
			
		||||
                        retVal[x] = ""
 | 
			
		||||
                    # Save the record field if the field isn't filtered out
 | 
			
		||||
                    record[converted_field_name] = retVal[x]
 | 
			
		||||
 | 
			
		||||
            # Convert values to the appropriate record type
 | 
			
		||||
            record = self.convert_values(
 | 
			
		||||
                record, self.ignore_keys, self.data_types)
 | 
			
		||||
 | 
			
		||||
            if record is not None and self.output_format == "json":
 | 
			
		||||
                # Output will be json
 | 
			
		||||
 | 
			
		||||
                # Add metadata to json
 | 
			
		||||
                for k, v in self.meta.items():
 | 
			
		||||
                    record[k] = v
 | 
			
		||||
 | 
			
		||||
                retVal = record
 | 
			
		||||
            elif record is not None and self.output_format == "csv":
 | 
			
		||||
                retVal = ""
 | 
			
		||||
                # Add escaping to csv format
 | 
			
		||||
                for k, v in record.items():
 | 
			
		||||
                    # Add escaping to string values
 | 
			
		||||
                    if isinstance(v, str):
 | 
			
		||||
                        retVal += str("\"" + str(v).strip() + "\"" + ",")
 | 
			
		||||
                    else:
 | 
			
		||||
                        retVal += str(str(v).strip() + ",")
 | 
			
		||||
                # Remove the trailing comma
 | 
			
		||||
                retVal = retVal[:-1]
 | 
			
		||||
        else:
 | 
			
		||||
            retVal = None
 | 
			
		||||
 | 
			
		||||
        return retVal
 | 
			
		||||
 | 
			
		||||
    def convert_values(self, data, ignore_keys=[], data_types={}):
 | 
			
		||||
        keys_to_delete = []
 | 
			
		||||
        for k, v in data.items():
 | 
			
		||||
            # print("evaluating k: " + str(k) + " v: " + str(v))
 | 
			
		||||
 | 
			
		||||
            if isinstance(v, dict):
 | 
			
		||||
                data[k] = self.convert_values(v)
 | 
			
		||||
            else:
 | 
			
		||||
                if data_types.get(k) is not None:
 | 
			
		||||
                    if (data_types.get(k) == "port" or data_types.get(k) == "count"):
 | 
			
		||||
                        if v != "":
 | 
			
		||||
                            data[k] = int(v)
 | 
			
		||||
                        else:
 | 
			
		||||
                            keys_to_delete.append(k)
 | 
			
		||||
                    elif (data_types.get(k) == "double" or data_types.get(k) == "interval"):
 | 
			
		||||
                        if v != "":
 | 
			
		||||
                            data[k] = float(v)
 | 
			
		||||
                        else:
 | 
			
		||||
                            keys_to_delete.append(k)
 | 
			
		||||
                    elif data_types.get(k) == "bool":
 | 
			
		||||
                        data[k] = bool(v)
 | 
			
		||||
                    else:
 | 
			
		||||
                        data[k] = v
 | 
			
		||||
 | 
			
		||||
        for k in keys_to_delete:
 | 
			
		||||
            del data[k]
 | 
			
		||||
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def get_fields(self):
 | 
			
		||||
        """Returns all fields present in the log file
 | 
			
		||||
        Returns:
 | 
			
		||||
            A python list containing all field names in the log file
 | 
			
		||||
        """
 | 
			
		||||
        field_names = ""
 | 
			
		||||
        if self.output_format == "csv":
 | 
			
		||||
            for i, v in enumerate(self.fields):
 | 
			
		||||
                if self.filtered_fields is None or v in self.filtered_fields:
 | 
			
		||||
                    field_names += str(v) + ","
 | 
			
		||||
            # Remove the trailing comma
 | 
			
		||||
            field_names = field_names[:-1].strip()
 | 
			
		||||
        else:
 | 
			
		||||
            field_names = []
 | 
			
		||||
            for i, v in enumerate(self.fields):
 | 
			
		||||
                if self.filtered_fields is None or v in self.filtered_fields:
 | 
			
		||||
                    field_names.append(v)
 | 
			
		||||
        return field_names
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 805 KiB After Width: | Height: | Size: 674 KiB  | 
| 
		 Before Width: | Height: | Size: 784 KiB After Width: | Height: | Size: 660 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.5 KiB  | 
| 
		 Before Width: | Height: | Size: 315 KiB After Width: | Height: | Size: 185 KiB  | 
| 
		 Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 92 KiB  | 
| 
		 Before Width: | Height: | Size: 805 KiB After Width: | Height: | Size: 674 KiB  | 
| 
		 Before Width: | Height: | Size: 784 KiB After Width: | Height: | Size: 660 KiB  | 
| 
		 Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 14 KiB  | 
@@ -1,4 +1 @@
 | 
			
		||||
<svg width="112" height="195" viewBox="0 0 112 195" fill="none" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<line x1="3.5" y1="3.5" x2="3.50001" y2="191.5" stroke="black" stroke-width="7" stroke-linecap="round" stroke-linejoin="round"/>
 | 
			
		||||
<rect x="7" width="105" height="195" fill="#F7F8F9"/>
 | 
			
		||||
</svg>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="112" height="195" fill="none" viewBox="0 0 112 195"><line x1="3.5" x2="3.5" y1="3.5" y2="191.5" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="7"/><rect width="105" height="195" x="7" fill="#F7F8F9"/></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 294 B After Width: | Height: | Size: 281 B  | 
@@ -1,16 +1 @@
 | 
			
		||||
<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
			
		||||
   width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
 | 
			
		||||
  <path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
 | 
			
		||||
    s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
 | 
			
		||||
    c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
 | 
			
		||||
  <path fill="#f7f8f9" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
 | 
			
		||||
    C22.32,8.481,24.301,9.057,26.013,10.047z">
 | 
			
		||||
    <animateTransform attributeType="xml"
 | 
			
		||||
      attributeName="transform"
 | 
			
		||||
      type="rotate"
 | 
			
		||||
      from="0 20 20"
 | 
			
		||||
      to="360 20 20"
 | 
			
		||||
      dur="0.5s"
 | 
			
		||||
      repeatCount="indefinite"/>
 | 
			
		||||
    </path>
 | 
			
		||||
  </svg>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="loader-1" width="40" height="40" x="0" y="0" enable-background="new 0 0 40 40" version="1.1" viewBox="0 0 40 40" xml:space="preserve"><path fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946 s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634 c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z" opacity=".2"/><path fill="#f7f8f9" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0 C22.32,8.481,24.301,9.057,26.013,10.047z"><animateTransform attributeName="transform" attributeType="xml" dur="0.5s" from="0 20 20" repeatCount="indefinite" to="360 20 20" type="rotate"/></path></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 970 B After Width: | Height: | Size: 874 B  | 
@@ -1,5 +1 @@
 | 
			
		||||
<svg width="106" height="106" viewBox="0 0 106 106" fill="none" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<circle cx="53" cy="53" r="53" fill="#40D8A1"/>
 | 
			
		||||
<path d="M29 52.5L47.5 70.5" stroke="white" stroke-width="10" stroke-linecap="round" stroke-linejoin="round"/>
 | 
			
		||||
<line x1="79" y1="40.0711" x2="48.0711" y2="71" stroke="white" stroke-width="10" stroke-linecap="round"/>
 | 
			
		||||
</svg>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="106" height="106" fill="none" viewBox="0 0 106 106"><circle cx="53" cy="53" r="53" fill="#40D8A1"/><path stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="10" d="M29 52.5L47.5 70.5"/><line x1="79" x2="48.071" y1="40.071" y2="71" stroke="#fff" stroke-linecap="round" stroke-width="10"/></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 363 B  | 
@@ -1,6 +1 @@
 | 
			
		||||
<svg width="548" height="199" viewBox="0 0 548 199" fill="none" xmlns="http://www.w3.org/2000/svg">
 | 
			
		||||
<rect x="403" y="27" width="142" height="145" rx="8" fill="white" stroke="black" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
 | 
			
		||||
<path d="M0 30C0 13.4315 13.4315 0 30 0H428C432.418 0 436 3.58172 436 8V191C436 195.418 432.418 199 428 199H30C13.4315 199 0 185.569 0 169V30Z" fill="black"/>
 | 
			
		||||
<rect x="477" y="55" width="26" height="26" fill="white" stroke="black" stroke-width="6"/>
 | 
			
		||||
<rect x="477" y="117" width="26" height="26" fill="white" stroke="black" stroke-width="6"/>
 | 
			
		||||
</svg>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="548" height="199" fill="none" viewBox="0 0 548 199"><rect width="142" height="145" x="403" y="27" fill="#fff" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="6" rx="8"/><path fill="#000" d="M0 30C0 13.4315 13.4315 0 30 0H428C432.418 0 436 3.58172 436 8V191C436 195.418 432.418 199 428 199H30C13.4315 199 0 185.569 0 169V30Z"/><rect width="26" height="26" x="477" y="55" fill="#fff" stroke="#000" stroke-width="6"/><rect width="26" height="26" x="477" y="117" fill="#fff" stroke="#000" stroke-width="6"/></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 602 B After Width: | Height: | Size: 583 B  | 
@@ -1,11 +1 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
 | 
			
		||||
<circle cx="50" cy="50" r="0" fill="none" stroke="#f3f3f3" stroke-width="2">
 | 
			
		||||
  <animate attributeName="r" repeatCount="indefinite" dur="1.4925373134328357s" values="0;30" keyTimes="0;1" keySplines="0 0.2 0.8 1" calcMode="spline" begin="-0.7462686567164178s"></animate>
 | 
			
		||||
  <animate attributeName="opacity" repeatCount="indefinite" dur="1.4925373134328357s" values="1;0" keyTimes="0;1" keySplines="0.2 0 0.8 1" calcMode="spline" begin="-0.7462686567164178s"></animate>
 | 
			
		||||
</circle>
 | 
			
		||||
<circle cx="50" cy="50" r="0" fill="none" stroke="#d8dddf" stroke-width="2">
 | 
			
		||||
  <animate attributeName="r" repeatCount="indefinite" dur="1.4925373134328357s" values="0;30" keyTimes="0;1" keySplines="0 0.2 0.8 1" calcMode="spline"></animate>
 | 
			
		||||
  <animate attributeName="opacity" repeatCount="indefinite" dur="1.4925373134328357s" values="1;0" keyTimes="0;1" keySplines="0.2 0 0.8 1" calcMode="spline"></animate>
 | 
			
		||||
</circle>
 | 
			
		||||
<!-- [ldio] generated by https://loading.io/ --></svg>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin:auto;background:0 0;display:block;shape-rendering:auto" width="200" height="200" preserveAspectRatio="xMidYMid" viewBox="0 0 100 100"><circle cx="50" cy="50" r="0" fill="none" stroke="#f3f3f3" stroke-width="2"><animate attributeName="r" begin="-0.7462686567164178s" calcMode="spline" dur="1.4925373134328357s" keySplines="0 0.2 0.8 1" keyTimes="0;1" repeatCount="indefinite" values="0;30"/><animate attributeName="opacity" begin="-0.7462686567164178s" calcMode="spline" dur="1.4925373134328357s" keySplines="0.2 0 0.8 1" keyTimes="0;1" repeatCount="indefinite" values="1;0"/></circle><circle cx="50" cy="50" r="0" fill="none" stroke="#d8dddf" stroke-width="2"><animate attributeName="r" calcMode="spline" dur="1.4925373134328357s" keySplines="0 0.2 0.8 1" keyTimes="0;1" repeatCount="indefinite" values="0;30"/><animate attributeName="opacity" calcMode="spline" dur="1.4925373134328357s" keySplines="0.2 0 0.8 1" keyTimes="0;1" repeatCount="indefinite" values="1;0"/></circle></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 64 KiB  | 
| 
		 Before Width: | Height: | Size: 775 KiB After Width: | Height: | Size: 540 KiB  | 
| 
		 Before Width: | Height: | Size: 405 KiB After Width: | Height: | Size: 324 KiB  | 
| 
		 Before Width: | Height: | Size: 315 KiB After Width: | Height: | Size: 185 KiB  | 
@@ -2,9 +2,9 @@ pymisp==2.4.165.1
 | 
			
		||||
sqlalchemy==1.4.48
 | 
			
		||||
ipwhois==1.2.0
 | 
			
		||||
netaddr==0.8.0
 | 
			
		||||
flask==1.1.2
 | 
			
		||||
flask==2.2.5
 | 
			
		||||
flask_httpauth==4.8.0
 | 
			
		||||
pyjwt==1.7.1
 | 
			
		||||
pyjwt==2.4.0
 | 
			
		||||
psutil==5.8.0
 | 
			
		||||
pydig==0.4.0
 | 
			
		||||
pyudev==0.24.0
 | 
			
		||||
 
 | 
			
		||||