HTML-filereport generator
15.10.2020, 12:04 - Autor: Mark B.
In case you go for multiple logical recovery attempts to maximize the count of useable files you need to merge folders and preserve the folder-structure but you also need to check if files differ from each other! This script merge the folders and check each files MD5-sum to differentiate between alternative versions of a file and duplicates.
To do that you slould create a folder-structure like that:
D:\DE\case12345\a
D:\DE\case12345\b
D:\DE\case12345\c
... each recovery with each tool into it's own folder and that folders collected in a case-folder.
The folder-names (
a,
b and
c in that example) can be named as you like. They will be processed alphabetically and so if you prefer to start with an specific attempt you should make sure that's the first processed folder!
When you start the tool you get an propt to select the base-folder. That would be in that example from above
D:\DE\case12345.
The tool will create a log-file with all MD5-checksums and a folder named
000_merged which will be skipped when processing. So in case you have to stop the tool and rerun it later your sorting will be fine and the tool will skip all previously processed files.
Source:
import os, codecs
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog
LOGO_URL = "https://data-recovery-prague.com/img/LOGO_FINAL.png"
def read_folder(folder, f):
global ctr
global fctr
global sum_bytes
ctr += 1
try:
dir_contents = os.listdir(folder)
n = os.path.basename(folder)
if n == "":
n = "Root"
f.write('<div class="f" id="d' + str(ctr) + '" onclick="t(' + str(ctr) + ');"><b>[+]</b> <span class="icn dir"></span> ' + n + "</div>")
f.write('<div class="c" id="c' + str(ctr) + '">')
print(f"#{ctr} ... {folder}")
for directory in sorted(dir_contents):
dir_path = os.path.join(folder, directory)
if os.path.isdir(dir_path) and not os.path.islink(dir_path):
read_folder(dir_path, f)
elif os.path.isdir(dir_path) and os.path.islink(dir_path):
f.write('<span class="icn dir" style="margin-left: 32px;"><span class="icn link" style="margin-left: 0px;"></span></span> ' + directory + " -> " + os.readlink(dir_path) + "<br>")
for fname in sorted(dir_contents):
if not os.path.isdir(os.path.join(folder, fname)):
try:
try:
css_class = fname.split(".")[-1].lower()
except:
css_class= "none"
if css_class in ("mov", "mp4", "avi", "3gp", "3g2", "m2v", "mkv", "m4v", "mpe", "mpg", "mpeg", "ogv", "rm", "vob", "webm", "wmv", "qt", "ra", "ram", "f4v", "flv"):
css_class = "mov"
elif css_class in ("mp3", "3ga", "aa", "aac", "aif", "aifc", "aiff", "amr", "asx", "au", "flac", "iff", "m3u", "m3u8", "m4a", "m4r", "mid", "midi", "mod", "mp2", "mpa", "mpga", "ogg", "wav", "wma"):
css_class = "snd"
elif css_class in ("exe", "com", "app", "apk", "jar", "pyc", "sys"):
css_class = "exe"
elif css_class in ("doc", "docb", "docm", "docx", "dot", "dotm", "dotx", "odt", "rtf"):
css_class = "doc"
elif css_class in ("xls", "xlb", "xlc", "xlm", "xlsb", "xlsm", "xlsx", "xlt", "xltm", "xltx", "ods"):
css_class = "xls"
elif css_class in ("potx", "pps", "ppsx", "ppt", "pptm", "pptx", "odp"):
css_class = "ppt"
elif css_class in ("raw", "cr2", "orf", "dng", "nef"):
css_class = "raw"
elif css_class in ("jpg", "png", "bmp", "bpg", "gif", "heic", "image", "jpe", "jpeg", "psd", "psp", "tif", "tiff", "tga", "webp", "xcf"):
css_class = "img"
elif css_class in ("pdf", "ps"):
css_class = "pdf"
elif css_class in ("zip", "rar", "tar", "7z", "ace", "bz2", "gz", "cab", "sit", "xz", "z"):
css_class = "zip"
elif css_class in ("htm", "html", "xml", "xsl", "xps", "xaml", "rdl", "dtd"):
css_class = "xml"
elif css_class in ("c", "cpp", "php", "py", "java", "lua", "js", "applescript", "asax", "ascx", "ashx", "asmx", "asp", "aspx", "bash", "sh", "bat", "cfm", "cfml", "class", "cs", "csh", "go", "h", "iml", "json", "jsp", "jsx", "lisp", "pl", "pm", "rb", "ru", "rub", "swift", "vb", "zsh", "asm"):
css_class = "code"
elif css_class in ("sql", "db", "accdb", "accdt", "adn", "dbf", "dsn", "mdb", "odb", "pdb", "sdf", "sqlite", "edb"):
css_class = "db"
elif css_class in ("deb", "rpm", "dmg", "msi", "msu", "pkg", "xrb"):
css_class = "pkg"
elif css_class in ("dwg", "cad", "dgn", "dxf", "stl", "scad", "step"):
css_class = "cad"
elif css_class in ("ai", "eps", "svg"):
css_class = "eps"
elif css_class in ("ttf", "otf", "eot", "fnt", "fon", "woff", "woff2"):
css_class = "fnt"
elif css_class in ("eml", "pst", "ost"):
css_class = "eml"
elif css_class in ("txt", "log", "ini", "yaml", "yml", "asc", "dist", "readme", "me", "pid", "rdf", "tex"):
css_class = "txt"
elif css_class in ("bin", "img", "dd", "iso"):
css_class = "bin"
else:
css_class = "other"
f.write('<p><span class="icn ' + css_class + '"></span> ' + fname + "</p>")
try:
fsize = os.path.getsize(os.path.join(folder, fname))
except FileNotFoundError:
fsize = 1
sum_bytes += fsize
fctr += 1
except UnicodeEncodeError:
pass
f.write('</div>')
except PermissionError:
f.write('<div class="f" id="d' + str(ctr) + '" onclick="t(' + str(ctr) + ');"><b>[+]</b> <span class="icn lock"></span> ' + os.path.basename(folder) + " :: PERMISSION DENIED</div>")
root = tk.Tk()
root.withdraw()
dirname = filedialog.askdirectory(parent=root, initialdir="/", title='Please select the restore-directory')
projectname = simpledialog.askstring(title="Please specify", prompt="Project name: ")
ctr = 0
fctr = 0
sum_bytes = 0
if dirname is not None:
html_path = filedialog.asksaveasfilename(parent=root, initialdir=dirname, title='Select a place to save the HTML-File', defaultextension=".html")
f = codecs.open(html_path, "w", "UTF-8")
if f is not None:
f.write('<!DOCTYPE html>')
f.write('<html>')
f.write('<head>')
f.write('<meta charset="UTF-8">')
f.write('<title>Recovery-Report for ' + dirname + '</title>')
f.write('<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>')
f.write('<link href="https://fonts.googleapis.com/css?family=PT+Mono&display=swap" rel="stylesheet" type="text/css">')
#f.write('<link rel="stylesheet" href="https://rawcdn.githack.com/dmhendricks/file-icon-vectors/master/dist/file-icon-high-contrast.min.css">')
f.write('<style>')
f.write('body{ font-family: "PT Mono", monospace; font-size: 10pt; line-height: 135%; }')
f.write('.f{ font-weight: bold; cursor: pointer; }')
f.write('.c{ display: none; padding-left: 32px; margin-bottom: 12px; }')
f.write('p{ margin-block-start: 0.1em; margin-block-end: 0.1em; }')
f.write('.icn { position: relative; display: inline-block; margin-left: 32px; height: 1em; width: 1em; background-position: center center; background-size: 100% auto; }')
# Movies
f.write('.mov { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMCA3LjVoMTUuNXYxMi4zSDBWNy41em0yMC41IDB2ODVoNTkuMnYtODVIMjAuNXptMTQuNCAxOC45Yy41IDAgMSAuMSAxLjQuNGwxNSAxMC42IDE1IDEwLjZjMS4yLjggMS41IDIuNi44IDMuOS0uMi40LS41LjctLjguOWwtMTUgMTAuNi0xNSAxMC42Yy0xLjIuOC0yLjcuNC0zLjQtLjktLjMtLjUtLjQtMS0uNC0xLjVWMjkuMmMwLTEuNSAxLTIuNyAyLjQtMi44ek04NC44IDcuNUgxMDB2MTIuM0g4NC44VjcuNXpNMCAyNS40aDE1LjVWMzhIMFYyNS40em04NC44IDBIMTAwVjM4SDg0LjhWMjUuNHpNMCA0My43aDE1LjV2MTIuNkgwVjQzLjd6bTg0LjggMEgxMDB2MTIuNkg4NC44VjQzLjd6TTAgNjEuOWgxNS41djEyLjZIMFY2MS45em04NC44IDBIMTAwdjEyLjZIODQuOFY2MS45ek0wIDgwLjFoMTUuNXYxMi4zSDBWODAuMXptODQuOCAwSDEwMHYxMi4zSDg0LjhWODAuMXoiIGZpbGw9IiM2YWU1YjkiLz48L3N2Zz4=); }')
# Sound
f.write('.snd { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMTYuNyAyNi45SDB2NDYuM2gxNi43bDM5IDI2LjhWMGwtMzkgMjYuOU04OS42IDUwYzAgMTIuNi02LjkgMjMuNS0xNi45IDI5LjNsNS4yIDkuMWMxMy4xLTcuNiAyMi0yMS45IDIyLTM4LjMgMC0xNi4zLTguOS0zMC43LTIyLTM4LjNsLTUuMiA5LjFDODIuOCAyNi41IDg5LjYgMzcuNCA4OS42IDUwem0tMTguMSAwYzAgNS45LTMuMSAxMC45LTggMTMuN2w1IDguN2M3LjgtNC40IDEzLTEyLjggMTMtMjIuNHMtNS4yLTE4LTEzLTIyLjRsLTUgOC43YzQuOCAyLjggOCA3LjggOCAxMy43eiIgZmlsbD0iI2M2ZiIvPjwvc3ZnPg==); }')
# Executable
f.write('.exe { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNOTguMiA1OS44Yy00LjMtMS40LTYuOS01LjMtNi45LTkuOHMyLjktOC4zIDYuOS05LjhjMS4yLS40IDItMS44IDEuNi0zLjEtMS4yLTQuNy0zLjEtOS01LjUtMTMuMi0uNi0xLjItMi4yLTEuNi0zLjUtMS0xLjQuOC0zLjMgMS4yLTQuOSAxLjItNS43IDAtMTAuMi00LjctMTAuMi0xMC4yIDAtMS42LjQtMy41IDEuMi00LjkuNi0xLjIuMi0yLjYtMS0zLjVDNzIgMy4yIDY3LjUgMS40IDYyLjguMmMtMS4yLS40LTIuNi40LTMuMSAxLjYtMS40IDQuMy01LjMgNi45LTkuOCA2LjlzLTguMy0yLjktOS44LTYuOUMzOS43LjYgMzguMy0uMiAzNyAuMmMtNC43IDEuMi05IDMuMS0xMy4yIDUuNS0xLjIuNi0xLjYgMi4yLTEgMy41LjggMS40IDEuMiAzLjMgMS4yIDQuOSAwIDUuNy00LjcgMTAuMi0xMC4yIDEwLjItMS42IDAtMy41LS40LTQuOS0xLjItMS4yLS42LTIuNi0uMi0zLjUgMUMzIDI4LjIgMS4xIDMyLjctLjEgMzcuM2MtLjQgMS4yLjQgMi42IDEuNiAzLjEgNC4zIDEuNCA2LjkgNS4zIDYuOSA5LjhTNS41IDU4LjUgMS41IDYwYy0xLjIuNC0yIDEuOC0xLjYgMy4xIDEuMiA0LjcgMy4xIDkgNS41IDEzLjIuNiAxLjIgMi4yIDEuNiAzLjUgMSAxLjQtLjggMy4zLTEuMiA0LjktMS4yIDUuNyAwIDEwLjIgNC43IDEwLjIgMTAuMiAwIDEuNi0uNCAzLjUtMS4yIDQuOS0uNiAxLjItLjIgMi42IDEgMy41IDQuMSAyLjQgOC42IDQuMyAxMy4yIDUuNWguNmMxIDAgMi0uNiAyLjQtMS44IDEuNC00LjMgNS4zLTYuOSA5LjgtNi45czguMyAyLjkgOS44IDYuOWMuNCAxLjIgMS44IDIgMy4xIDEuNiA0LjctMS4yIDktMy4xIDEzLjItNS41IDEuMi0uNiAxLjYtMi4yIDEtMy41LS44LTEuNC0xLjItMy4zLTEuMi00LjkgMC01LjcgNC43LTEwLjIgMTAuMi0xMC4yIDEuNiAwIDMuNS40IDQuOSAxLjIgMS4yLjYgMi42LjIgMy41LTEgMi40LTQuMSA0LjMtOC42IDUuNS0xMy4yLjUtMS4yLS4xLTIuNy0xLjYtMy4xem0tNDggNS43Yy04LjYgMC0xNS41LTYuOS0xNS41LTE1LjVzNi45LTE1LjUgMTUuNS0xNS41UzY1LjcgNDEuNCA2NS43IDUwcy03IDE1LjUtMTUuNSAxNS41eiIgZmlsbD0iI2FiYjNkNiIvPjwvc3ZnPg==); }')
# Documents
f.write('.doc { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNOTIuOCA4Mi40SDUxLjVjLTEuNiAwLTIuOS0xLjMtMi45LTIuOVYyMC42YzAtMS42IDEuMy0yLjkgMi45LTIuOWg0MS4zYzEuNiAwIDIuOSAxLjMgMi45IDIuOXY1OC45YzAgMS42LTEuMyAyLjktMi45IDIuOXoiIGZpbGw9IiNlOGU4ZTgiLz48cGF0aCBkPSJNODEgMzUuM0g1MS41Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjlzMS4zLTIuOSAyLjktMi45SDgxYzEuNiAwIDIuOSAxLjMgMi45IDIuOSAwIDEuNS0xLjMgMi45LTIuOSAyLjl6bTAgMTEuOEg1MS41Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjlzMS4zLTIuOSAyLjktMi45SDgxYzEuNiAwIDIuOSAxLjMgMi45IDIuOXMtMS4zIDIuOS0yLjkgMi45em0wIDExLjdINTEuNWMtMS42IDAtMi45LTEuMy0yLjktMi45czEuMy0yLjkgMi45LTIuOUg4MWMxLjYgMCAyLjkgMS4zIDIuOSAyLjlzLTEuMyAyLjktMi45IDIuOXptMCAxMS44SDUxLjVjLTEuNiAwLTIuOS0xLjMtMi45LTIuOXMxLjMtMi45IDIuOS0yLjlIODFjMS42IDAgMi45IDEuMyAyLjkgMi45cy0xLjMgMi45LTIuOSAyLjl6IiBmaWxsPSIjYjJiMmIyIi8+PHBhdGggZD0iTTU5LjMgOTcuMmwtNTUtMTAuNVYxMy4ybDU1LTEwLjV2OTQuNXoiIGZpbGw9IiMwZDQ3YTEiLz48cGF0aCBkPSJNNDMuNyA2OGgtN2wtNC42LTIzLjFjLS4zLTEuMy0uNC0yLjctLjQtNGgtLjFjLS4xIDEuNi0uMyAzLS41IDRMMjYuMyA2OEgxOWwtNy4zLTM2aDYuOWwzLjkgMjRjLjIgMSAuMyAyLjQuNCA0LjFoLjFjMC0xLjMuMy0yLjcuNi00LjJsNS0yMy45aDYuN2w0LjYgMjQuMmMuMi45LjMgMi4yLjQgMy45aC4xYy4xLTEuMy4yLTIuNi40LTRsMy45LTI0SDUxTDQzLjcgNjh6IiBmaWxsPSIjZmZmIi8+PC9zdmc+); }')
# Spreadsheets
f.write('.xls { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDF7ZmlsbDojZmZmfTwvc3R5bGU+PHBhdGggZD0iTTk0LjYgMTMuMmgtNDJ2NzMuNWg0MmMxLjUgMCAyLjYtMS4yIDIuNi0yLjZWMTUuOWMwLTEuNS0xLjEtMi43LTIuNi0yLjd6IiBmaWxsPSIjNGNhZjUwIi8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTcxIDI2LjRoMTguNHY3LjlINzF6bTAgMjYuMmgxOC40djcuOUg3MXptMCAxMy4xaDE4LjR2Ny45SDcxem0wLTI2LjJoMTguNHY3LjlINzF6TTUyLjYgMjYuNGgxMy4xdjcuOUg1Mi42em0wIDI2LjJoMTMuMXY3LjlINTIuNnptMCAxMy4xaDEzLjF2Ny45SDUyLjZ6bTAtMjYuMmgxMy4xdjcuOUg1Mi42eiIvPjxwYXRoIGZpbGw9IiMyZTdkMzIiIGQ9Ik01Ny45IDk3LjNMMi44IDg2LjhWMTMuMkw1Ny45IDIuN3oiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMzcuMSA2OGwtNi4yLTExLjdjLS4yLS40LS41LTEuMi0uNy0yLjRIMzBjLS4xLjYtLjQgMS40LS44IDIuNUwyMyA2OGgtOS43bDExLjUtMTgtMTAuNS0xOGg5LjlsNS4yIDEwLjhjLjQuOS44IDEuOSAxLjEgM2guMWMuMi0uNy42LTEuNyAxLjEtMy4xTDM3LjMgMzJoOUwzNS42IDQ5LjggNDYuNyA2OGgtOS42eiIvPjwvc3ZnPg==); }')
# Presentations
f.write('.ppt { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDF7ZmlsbDojZmJlOWU3fTwvc3R5bGU+PHBhdGggZD0iTTk0LjYgMTMuMmgtNDJ2NzMuNWg0MmMxLjUgMCAyLjYtMS4yIDIuNi0yLjZWMTUuOWMwLTEuNS0xLjEtMi43LTIuNi0yLjd6IiBmaWxsPSIjZmY4YTY1Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTUwIDYzLjFoMzYuOHY1LjJINTB6bTAgMTAuNWgzNi44djUuM0g1MHptMTUuOC00Ny4yYy04LjcgMC0xNS44IDcuMS0xNS44IDE1LjhDNTAgNTAuOSA1Ny4xIDU4IDY1LjggNThzMTUuOC03LjEgMTUuOC0xNS44SDY1LjhWMjYuNHoiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNNzEgMjEuMXYxNS44aDE1LjhjMC04LjctNy4xLTE1LjgtMTUuOC0xNS44eiIvPjxwYXRoIGZpbGw9IiNlNjRhMTkiIGQ9Ik01Ny45IDk3LjNMMi44IDg2LjhWMTMuMkw1Ny45IDIuN3oiLz48cGF0aCBkPSJNMzEuMiAzMkgxOC44djM2aDcuN1Y1NS42aDRjNC4zIDAgNy43LTEuMSAxMC4yLTMuNCAyLjUtMi4yIDMuOC01LjIgMy44LTguOEM0NC41IDM1LjggNDAgMzIgMzEuMiAzMnptLTEuNCAxNy40aC0zLjNWMzguMmgzLjNjNC4yIDAgNi4zIDEuOCA2LjMgNS41IDAgMy45LTIuMSA1LjctNi4zIDUuN3oiIGZpbGw9IiNmZmYiLz48L3N2Zz4=); }')
# RAW Images
f.write('.raw { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDF7ZmlsbDojZmJlOWU3fTwvc3R5bGU+PHBhdGggZD0iTTk0LjYgMTMuMmgtNDJ2NzMuNWg0MmMxLjUgMCAyLjYtMS4yIDIuNi0yLjZWMTUuOWMwLTEuNS0xLjEtMi43LTIuNi0yLjd6IiBmaWxsPSIjZmY4YTY1Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTUwIDYzLjFoMzYuOHY1LjJINTB6bTAgMTAuNWgzNi44djUuM0g1MHptMTUuOC00Ny4yYy04LjcgMC0xNS44IDcuMS0xNS44IDE1LjhDNTAgNTAuOSA1Ny4xIDU4IDY1LjggNThzMTUuOC03LjEgMTUuOC0xNS44SDY1LjhWMjYuNHoiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNNzEgMjEuMXYxNS44aDE1LjhjMC04LjctNy4xLTE1LjgtMTUuOC0xNS44eiIvPjxwYXRoIGZpbGw9IiNlNjRhMTkiIGQ9Ik01Ny45IDk3LjNMMi44IDg2LjhWMTMuMkw1Ny45IDIuN3oiLz48cGF0aCBkPSJNMzEuMiAzMkgxOC44djM2aDcuN1Y1NS42aDRjNC4zIDAgNy43LTEuMSAxMC4yLTMuNCAyLjUtMi4yIDMuOC01LjIgMy44LTguOEM0NC41IDM1LjggNDAgMzIgMzEuMiAzMnptLTEuNCAxNy40aC0zLjNWMzguMmgzLjNjNC4yIDAgNi4zIDEuOCA2LjMgNS41IDAgMy45LTIuMSA1LjctNi4zIDUuN3oiIGZpbGw9IiNmZmYiLz48L3N2Zz4=); }')
# Images
f.write('.img { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMTMuNiA0MC45YzMuOCAwIDctMS4zIDkuNy00IDIuNy0yLjcgNC01LjkgNC05LjcgMC0zLjgtMS4zLTctNC05LjctMi43LTIuNy01LjktNC05LjctNC0zLjggMC03IDEuMy05LjcgNC0yLjcgMi43LTQgNS45LTQgOS43IDAgMy44IDEuMyA3IDQgOS43IDIuNyAyLjcgNS45IDQgOS43IDR6bTIwLjUgMjAuNUwyMi43IDUwIDAgNzIuN3YxMy42aDEwMFY1NC41TDcwLjUgMjUgMzQuMSA2MS40eiIgZmlsbD0iI2U4OTEzMSIvPjwvc3ZnPg==); }')
# Vector
f.write('.eps { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMjYuNSAzNC44TDIuOCA4NS4zbDQuNSA0LjUgMjkuNi0yOS42Yy0xLjEtMi40LS43LTUuMyAxLjMtNy4zIDIuNS0yLjUgNi41LTIuNSA5LjEgMHMyLjUgNi41IDAgOS4xYy0yIDItNC45IDIuNC03LjMgMS4zTDEwLjQgOTIuN2w0LjUgNC41IDUwLjUtMjMuOCAxMC43LTMwLjItMTkuNC0xOS4zLTMwLjIgMTAuOXptNjkuMy02TDcxLjIgNC4yYy0yLTItNS4zLTItNy4zIDBMNTguMSAxMGMtMiAyLTIgNS4zIDAgNy4zbDI0LjUgMjQuNWMyIDIgNS4zIDIgNy4zIDBsNS44LTUuOGMyLTIgMi01LjIuMS03LjJ6IiBmaWxsPSIjZmVhNTAwIi8+PC9zdmc+); }')
# Fonts
f.write('.fnt { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDB7ZmlsbDojOTNkM2Y2fS5zdDF7ZmlsbDojNTZiNWYwfTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MCIgZD0iTTg3LjUgNzhsLS42LTMuMmgtLjNDODQgNzggNzkuNSA4MC4xIDc0IDgwLjFjLTguNSAwLTEzLjQtNi4zLTEzLjQtMTIuNyAwLTEwLjYgOC45LTE2LjMgMjUtMTYuMXYtLjZjMC0yLjctMS4xLTcuNC04LjUtNy40LTQuMiAwLTguNSAxLjMtMTEuMyAzLjFsLTIuMS02LjljMy4xLTEuOSA4LjktMy43IDE1LjUtMy43IDEzLjUgMCAxNy43IDguNSAxNy43IDE3Ljd2MTUuM2MwIDMuOS0uMyA3LjkuMiA5LjVoLTkuNWwtLjEtLjN6bS0xLjgtMjBjLTYuNC0uMi0xNC41IDEuNC0xNC41IDcuOSAwIDQuMiAyLjcgNi4xIDYuMSA2LjEgNC4yIDAgNy4zLTIuNyA4LjItNS44LjMtLjguMi0xLjYuMi0yLjRWNTh6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTk3IDY4LjVWNTMuMWMwLTMuNy0uNi03LjctMi42LTEwLjYtLjggNi4xLTMuOSAxMS44LTguNyAxNS44djUuM2MwIC42LjIgMS42LS4yIDIuNC0xIDMuMS00IDUuOC04LjIgNS44LTMuNCAwLTYuMS0xLjktNi4xLTYuMXYtLjZjLTEgLjItMS44LjItMi45LjItMi42IDAtNS0uMy03LjMtMS4xLS4yLjgtLjIgMS44LS4yIDIuNiAwIDYuNCA0LjggMTIuOSAxMy4yIDEyLjkgNS41IDAgOS44LTIuMSAxMi42LTUuM2guNGwuNiAzLjJoOS43Yy0uNi0xLjMtLjMtNS4zLS4zLTkuMXoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTguNyA2MS44bC01IDE2LjFoLTExbDE4LjctNThoMTMuN2wxOSA1OEg0Mi43bC01LjMtMTYuMUgxOC43em0xNi43LThsLTQuNy0xNC43Yy0xLjEtMy41LTIuMS02LjMtMi45LTExLjFoLS4yYy0uOCA0LjgtMS44IDcuNy0yLjcgMTEuMWwtNC41IDE0LjdoMTV6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTQyLjUgNDIuOGMtMS42IDQtNCA3LjctNy4xIDEwLjZ2LjJoLS4yYy00IDQuOC05IDYuNC0xNC44IDguMWgxNi44bDUuMyAxNi4xaDExLjRsLTExLjQtMzV6Ii8+PC9zdmc+); }')
# PDF
f.write('.pdf { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNOTUuMiA2My4yYy0yLjgtMy04LjQtNC43LTE2LjQtNC43LTQuMyAwLTkuMi40LTE0LjYgMS40LTMtMy02LjEtNi41LTktMTAuNi0yLjEtMi45LTMuOS01LjktNS41LTguOSAzLjItOS45IDQuNy0xNy45IDQuNy0yMy43IDAtNi41LTIuMy0xMy4zLTkuMS0xMy4zLTIuMSAwLTQuMSAxLjMtNS4yIDMuMS0zIDUuNS0xLjcgMTcuNSAzLjYgMjkuMy0yIDUuOS00IDExLjYtNi42IDE3LjktMi4yIDUuMy00LjggMTAuOS03LjUgMTUuOS0xNS4yIDYuMi0yNSAxMy40LTI1LjkgMTktLjQgMi4xLjMgNC4xIDEuOCA1LjYuNS40IDIuNSAyLjEgNS44IDIuMSAxMC4xIDAgMjAuNy0xNi42IDI2LjEtMjYuNyA0LjEtMS40IDguMy0yLjcgMTIuNC0zLjkgNC41LTEuMyA5LjEtMi4zIDEzLjItM0M3My42IDcyLjQgODMgNzQgODcuNyA3NGM1LjggMCA3LjktMi40IDguNi00LjQgMS4xLTIuNS4zLTUuMy0xLTYuOGwtLjEuNHptLTUuNCA0LjFjLS40IDIuMS0yLjUgMy41LTUuNCAzLjUtLjggMC0xLjUtLjEtMi4zLS4zLTUuMy0xLjMtMTAuMi00LTE1LjItOC4yIDQuOS0uOCA5LTEgMTEuNi0xIDIuOSAwIDUuNC4xIDcgLjYgMS45LjQgNC45IDEuNyA0LjMgNS40em0tMjkuMy02LjZjLTMuNi43LTcuNCAxLjYtMTEuNCAyLjctMy4yLjktNi41IDEuOC05LjggMyAxLjgtMy41IDMuMy02LjkgNC43LTEwLjEgMS43LTQgMy04IDQuNC0xMS44IDEuNCAyLjQgMi45IDQuOCA0LjQgNi45IDIuNSAzLjMgNS4xIDYuNSA3LjcgOS4zek00Mi40IDguMmMuNi0xLjEgMS43LTEuNyAyLjYtMS43IDIuOSAwIDMuNCAzLjQgMy40IDYuMSAwIDQuNS0xLjQgMTEuNC0zLjcgMTkuMy00LTExLTQuMy0yMC4xLTIuMy0yMy43ek0yNy4zIDczLjljLTcgMTEuOC0xMy44IDE5LjItMTcuOSAxOS4yLS44IDAtMS41LS4zLTIuMS0uNy0uOC0uOC0xLjItMS44LTEtMyAuOC00LjIgOC43LTEwLjEgMjEtMTUuNXoiIGZpbGw9IiNlYjFkMjUiIHN0cm9rZT0iI2ViMWQyNSIgc3Ryb2tlLXdpZHRoPSIuNzUiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPjwvc3ZnPg==); }')
# XML
f.write('.xml { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMSA0NC4zTDI4LjkgMTV2MTQuOWwtMTkgMTkuM3YuMmwxOC45IDE5LjN2MTQuOUwxIDU0LjJ2LTkuOXpNNTMuNiA3LjVINjFsLTE0LjQgODVoLTcuMmMtLjEgMCAxNC4yLTg1IDE0LjItODV6bTE3LjUgNjEuM0w5MCA0OS41di0uMkw3MS4xIDMwLjFWMTUuMkw5OSA0NC42djEwLjNMNzEuMSA4NC4xVjY4Ljh6IiBmaWxsPSIjYmFiYWJhIiBzdHJva2U9IiNiYWJhYmEiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+PC9zdmc+); }')
# Code
f.write('.code { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMyA1NC45VjQ1YzIuMi0uMiAzLjktLjMgNC45LTEgMS0uMyAxLjgtMS4zIDIuNy0yLjMuOC0xLjIgMS4zLTIuNSAxLjctNC40LjItMS4zLjUtMy41LjUtNi43IDAtNS40LjItOSAuOC0xMS4yLjUtMiAxLjUtMy45IDIuNy01IDEuMy0xLjIgMy40LTIuMiA1LjktMyAxLjctLjMgNC40LS44IDguMi0uOGgyLjN2OS43Yy0zLjIgMC01LjQuMi02LjIuNy0uOC4zLTEuNS44LTIuMiAxLjctLjUuNy0uNyAxLjgtLjcgMy41cy0uMiA1LS41IDkuN2MtLjIgMi44LS41IDUtMSA2LjUtLjcgMS43LTEuNSAzLTIuMyA0LjItLjggMS0yLjMgMi4yLTQuMiAzLjQgMS43IDEgMy4yIDIgNC4yIDMuMiAxIDEuMiAxLjggMi44IDIuNSA0LjUuNyAxLjggMSA0LjIgMSA3LjIuMiA0LjUuMiA3LjQuMiA4LjcgMCAxLjguMiAzIC43IDMuOS41LjggMS4zIDEuMiAyLjIgMS43LjguMyAzIC43IDYuMi43djkuN2gtMi4zYy0zLjkgMC03LS4yLTguOS0uOC0yLjItLjctMy45LTEuNy01LjQtMy0xLjUtMS4zLTIuMy0zLTMtNS0uNS0yLS43LTUuMi0uNy05LjYgMC01LS4yLTguNC0uNy05LjctLjctMi4yLTEuNy0zLjktMy00LjktLjktMS0yLjktMS43LTUuNi0xLjd6bTkzLjcgMGMtMi4yLjItMy45LjMtNC45IDEtMSAuMy0xLjggMS4zLTIuNyAyLjMtLjggMS4yLTEuMyAyLjUtMS43IDQuNC0uMiAxLjMtLjUgMy41LS41IDYuNyAwIDUuNC0uMiA5LS44IDExLjItLjUgMi4yLTEuNSAzLjktMi43IDUtMS4zIDEuMi0zLjQgMi4yLTUuOSAzLTEuNy4zLTQuNC44LTguMi44SDY3di05LjdjMy4yIDAgNS0uMiA2LjItLjcgMS0uMyAxLjctMSAyLjItMS43cy43LTEuOC43LTMuNS4yLTQuOS41LTkuNmMuMi0yLjguNy01LjIgMS4zLTYuNy43LTEuOCAxLjUtMy4yIDIuNS00LjQgMS0xLjIgMi4zLTIuMiA0LTMuMi0yLjctMS43LTQuNC0yLjgtNS4yLTQtMS4zLTEuOC0yLjMtNC4yLTIuNy02LjctLjUtMi0uNy02LjItLjctMTIuNiAwLTItLjItMy40LS43LTQuMi0uNS0uNy0xLTEuMi0xLjgtMS43LS44LS4zLTMtLjctNi40LS43di05LjdoMi4zYzMuOSAwIDcgLjIgOC45LjggMi4yLjcgMy45IDEuNyA1LjQgMyAxLjUgMS4zIDIuMyAzIDMgNSAuNSAyIC44IDUuMi44IDkuNiAwIDUgLjIgOC4yLjcgOS43LjcgMi4yIDEuNyAzLjkgMyA0LjUgMS4zIDEgMy40IDEuMyA1LjkgMS43djkuOWwtLjIuNXoiIGZpbGw9IiM3MDU4YzYiIHN0cm9rZT0iIzYyNDlhNSIgc3Ryb2tlLXdpZHRoPSIuNzUiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPjwvc3ZnPg==); }')
# Databases
f.write('.db { background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDB7ZmlsbDojMGNmfTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MCIgZD0iTTMuMyA2MS43YzAgOC4zIDIwLjkgMTUgNDYuNyAxNSAyNS43IDAgNDYuNi02LjcgNDYuNy0xNVY0OS44Qzg3LjEgNTYuNyA2OC41IDYwIDUwIDYwYy0xOC41IDAtMzcuMS0zLjMtNDYuNy0xMC4zdjEyeiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik05Ni43IDczQzg3LjEgODAgNjguNSA4My4zIDUwIDgzLjMgMzEuNSA4My4zIDEyLjkgODAgMy4zIDczdjEzLjZDNS45IDk0LjIgMjYgMTAwIDUwIDEwMHM0NC4xLTUuOCA0Ni43LTEzLjNWNzN6TTMuMyAzOC4zYzAgOC4zIDIwLjkgMTUgNDYuNyAxNSAyNS43IDAgNDYuNi02LjcgNDYuNy0xNVYyNi40Yy05LjYgNy0yOC4yIDEwLjMtNDYuNyAxMC4zLTE4LjUgMC0zNy4xLTMuMy00Ni43LTEwLjN2MTEuOXoiLz48ZWxsaXBzZSBjbGFzcz0ic3QwIiBjeD0iNTAiIGN5PSIxNSIgcng9IjQ2LjciIHJ5PSIxNSIvPjwvc3ZnPg==); }')
# Compressed archive
f.write('.zip { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNOTEuNiAyOC43SDc2LjlWMTQuMWwxNC43IDE0LjZ6TTUyLjEgMTQuMXY1My4zaDM5LjZWMzIuMkg3My40VjEzLjlINTIuMXYuMnpNNTguMiAwSDE0LjV2MTAuNGgxNy4ybC0xMC45IDguM3Y4LjlsMTUuOS0xMi4ydi01aDU1LjdWNi4xTDU4LjIgMHpNMzYuOSAyMi40TDIxIDM0LjZ2OC45bDE1LjktMTIuMnYtOC45em0tMTYuMSAzN2wxNS45LTEyLjJ2LTguOUwyMC44IDUwLjZ2OC44em0xNi4xIDMuN3YtOC45TDIxIDY2LjV2NC44aC02LjN2MTAuNGg5Ljh2N2gtNS45Yy0xLjEtMS45LTMtMy01LjItMy0zLjMgMC01LjkgMi42LTUuOSA1LjkgMCAzLjMgMi42IDUuOSA1LjkgNS45IDIuMiAwIDQuMS0xLjEgNS4yLTNoNS43djUuNGg4Ljl2LTUuNEgzOWMxLjEgMS45IDMgMyA1LjIgMyAzLjMgMCA1LjktMi42IDUuOS01LjkgMC0zLjMtMi42LTUuOS01LjktNS45LTIuMiAwLTQuMSAxLjEtNS4yIDNoLTUuN3YtN2gyNWwzNC4zLTYuMXYtNC4zSDI2LjJsMTAuNy04LjJ6IiBmaWxsPSIjZmMzIi8+PC9zdmc+); }')
# Package file
f.write('.pkg { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNNjUuOCA1My45TDUwIDQ2LjVsMzEuNS0xNC43IDE1LjggNy40LTE1LjggNy40YzAtLjEtMTUuNyA3LjMtMTUuNyA3LjN6bTE1LjctMzYuN0w2NS44IDkuOCA1MCAxNy4ybDMxLjUgMTQuNyAxNS44LTcuNC0xNS44LTcuM3pNMzQuMiAzOS4xbC0xNS43LTcuNC0xNS43IDcuNCAzMS41IDE0LjdMNTAgNDYuNWwtMTUuOC03LjR6bTAtMTQuNkw1MCAxNy4yIDM0LjIgOS44IDIuOCAyNC41bDE1LjcgNy40IDE1LjctNy40em00Ny4zIDI2LjNsLTE0LjEgNi41LTEuNy44LTEuNy0uOC0xNC02LjUtMTQuMSA2LjUtMS43LjgtMS43LS44LTE0LjEtNi41djIzTDUwIDkwLjJsMzEuNS0xNi40di0yM3oiIGZpbGw9IiNkY2U2NzUiLz48L3N2Zz4=); }')
# Email
f.write('.eml { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNNjIuMyA1Mkw1MCA2NC4xIDM3LjcgNTJsLTMxIDM0LjJoODYuNUw2Mi4zIDUyek0yLjggMTcuOHY2NC41bDMxLTM0LjItMzEtMzAuM3ptNjMuNSAzMC4zbDMxIDM0LjJWMTcuOGwtMzEgMzAuM3pNNi42IDEzLjhMNTAgNTYuM2w0My40LTQyLjQtODYuOC0uMXoiIGZpbGw9IiM5MGM5YzQiLz48L3N2Zz4=); }')
# Text
f.write('.txt { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMCA4NC44aDU2LjlWMTAwSDBWODQuOG0wLTU2LjVoMTAwdjE1LjJIMFYyOC4zek0wIDBoMTAwdjE1LjJIMFYwem0wIDU2LjZoMTAwdjE1LjJIMFY1Ni42eiIgZmlsbD0iI2JhYmFiYSIvPjwvc3ZnPg==); }')
# Binary files / binary images
f.write('.bin { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNMjAuNCA5LjRoLTEwdjEwaDV2MjUuMWgxMHYtMzBjMC0yLjgtMi4yLTUuMS01LTUuMXptMzkuNiAwSDQwYy0yLjggMC01IDIuMi01IDV2MjUuMWMwIDIuOCAyLjIgNSA1IDVoMjBjMi44IDAgNS0yLjIgNS01di0yNWMwLTIuOC0yLjItNS4xLTUtNS4xem0tNSAyNS4xSDQ1di0xNWgxMHYxNXpNODIuOCA5LjRoLTEwdjEwaDV2MjUuMWgxMHYtMzBjMC0yLjgtMi4yLTUuMS01LTUuMXptLTUyLjcgNDZIMTBjLTIuOCAwLTUgMi4yLTUgNXYyNS4xYzAgMi44IDIuMiA1IDUgNWgyMC4xYzIuOCAwIDUtMi4yIDUtNXYtMjVjMC0yLjgtMi4yLTUuMS01LTUuMXptLTUgMjUuMUgxNXYtMTVoMTBsLjEgMTV6bTI2LjMtMjVoLTEwdjEwaDV2MjUuMWgxMFY2MC41Yy4xLTIuOC0yLjItNS01LTV6bTM4LjYgMEg2OS45Yy0yLjggMC01IDIuMi01IDV2MjUuMWMwIDIuOCAyLjIgNSA1IDVIOTBjMi44IDAgNS0yLjIgNS01VjYwLjVjMC0yLjgtMi4zLTUtNS01em0tNSAyNUg3NXYtMTVoMTB2MTV6IiBmaWxsPSIjYmFiYWJhIi8+PC9zdmc+); }')
# CAD
f.write('.cad { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNODkuMSA1MC45Yy0xLjItLjUtMi43IDAtMy4yIDEuMi0yLjcgNi4xLTYuOSAxMS40LTEyLjMgMTUuNUw1Ny40IDM0LjdjMi41LTIgMy45LTQuOCAzLjktOC4yIDAtNS4yLTMuNi05LjQtOC41LTEwLjNWOGMwLTEuMi0uOS0yLjUtMi41LTIuNS0xLjIgMC0yLjUuOS0yLjUgMi41djguMmMtNC44LjktOC41IDUuMy04LjUgMTAuMyAwIDMuNCAxLjQgNi4yIDMuOSA4LjJMMjcgNjcuNmMtNS4zLTQuMS05LjYtOS4zLTEyLjMtMTUuNS0uNS0xLjItMi0xLjgtMy4yLTEuMi0xLjIuNS0xLjggMi0xLjIgMy4yIDMuMiA3LjMgOC4yIDEzIDE0LjYgMTcuNmwtOS42IDE5LjRjLS41IDEuMiAwIDIuNy45IDMuMi4yIDAgLjcuMi45LjIuNyAwIDEuOC0uNSAyLjEtMS4ybDkuMy0xOC45YzYuNiAzLjYgMTMuNSA1LjMgMjEgNS4zczE0LjYtMiAyMS01LjNsOS4zIDE4LjljLjIuNyAxLjIgMS4yIDIuMSAxLjIuMiAwIC43IDAgLjktLjIgMS4yLS41IDEuOC0yIC45LTMuMmwtOS40LTE5LjRjNi4yLTQuMyAxMS40LTEwLjcgMTQuNi0xNy42IDEuNi0xLjMgMS4xLTIuNy4yLTMuMnpNNTAuMyAyMC41YzMuNCAwIDYuMSAyLjcgNi4xIDYuMXMtMi43IDYuMS02LjEgNi4xLTYuMS0yLjctNi4xLTYuMSAzLjEtNi4xIDYuMS02LjF6bTAgNTQuNmMtNi44IDAtMTMtMS44LTE4LjktNC44bDE2LjQtMzMuMWMuNy4yIDEuOC4yIDIuNy4yczEuOCAwIDIuNy0uMmwxNi42IDMzLjFjLTYuMSAzLjItMTIuNyA0LjgtMTkuNSA0Ljh6IiBmaWxsPSIjNDk5MmM0IiBzdHJva2U9IiM0OTkyYzQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+PC9zdmc+); }')
# Link
f.write('.link { width: 0.75em; height: 0.75em; background-position: bottom right; margin-left: 0.2em !important; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNNTQuNCAxMC43TDM4IDI3LjFjNC44LTEuNCAxMC0xLjQgMTUtLjIuNy4yIDEuNC41IDEuOS43bDguMS04LjFjNC44LTQuOCAxMi42LTQuOCAxNy40IDAgNC44IDQuOCA0LjggMTIuNiAwIDE3LjRsLTExIDExLTYuNCA2LjRjLTEuNiAxLjYtMy40IDIuNi01LjUgMy4xLTQuMSAxLTguNi4yLTExLjktMy4xLTIuMi0yLjItMy4zLTUtMy40LTcuOC0xIC4zLTEuOS45LTIuNiAxLjdMMzIgNTUuOWMxLjIgMi42IDIuOCA1LjIgNSA3LjIgMy4xIDMuMSA3LjEgNS4zIDExIDYuNCA2LjQgMS43IDEzLjMuOSAxOC45LTIuNiAxLjctMSAzLjQtMi4yIDQuOC0zLjhsMTcuNC0xNy40YzkuNi05LjYgOS42LTI1LjMgMC0zNS05LjQtOS42LTI1LjEtOS42LTM0LjcgMHpNNjIgNzIuOWMtNS41IDEuNi0xMS40IDEuNC0xNi45LS41TDM3IDgwLjVjLTQuOCA0LjgtMTIuNiA0LjgtMTcuNCAwcy00LjgtMTIuNiAwLTE3LjRMMzcgNDUuN2MxLjYtMS42IDMuNC0yLjYgNS41LTMuMSA0LjEtMSA4LjYtLjIgMTEuOSAzLjEgMi4yIDIuMiAzLjMgNSAzLjQgNy45LjktLjMgMS43LTEgMi42LTEuN2w3LjYtNy42Yy0xLjItMi42LTIuOC01LjItNS03LjItMy4zLTMuMS03LjEtNS4zLTExLTYuNC02LjQtMS43LTEzLjMtLjktMTkgMi42LTEuNyAxLTMuNCAyLjItNC44IDMuOEwxMC44IDU0LjNjLTkuNiA5LjYtOS42IDI1LjMgMCAzNXMyNS4zIDkuNiAzNSAwTDYyIDcyLjl6IiBmaWxsPSIjNjY2NjY2Ii8+PC9zdmc+); }')
# Others
f.write('.other { background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNODYgMjYuNUw2My4zIDMuOGMtLjctLjctMS41LTEtMi40LTFIMTYuM2MtMS45IDAtMy40IDEuNS0zLjQgMy40djg3LjZjMCAxLjkgMS41IDMuNCAzLjQgMy40aDY3LjRjMS45IDAgMy40LTEuNSAzLjQtMy40di02NWMtLjEtLjgtLjQtMS42LTEuMS0yLjN6bS02LjcgMy45SDU5LjRWMTAuNWwxOS45IDE5Ljl6bS4yIDU5LjJoLTU5VjEwLjNoMzEuN3YyMi44YzAgMi40IDIuMSA0LjUgNC41IDQuNWgyMi44djUyeiIgZmlsbD0iI2JhYmFiYSIgc3Ryb2tlPSIjYmFiYWJhIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz48L3N2Zz4=); }')
# Directory
f.write('.dir{ margin-left: 0px; background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHN0eWxlPi5zdDF7ZmlsbDojOTY3YTQ0fTwvc3R5bGU+PHBhdGggZmlsbD0iI2RiYjA2NSIgZD0iTTEuMyA5MC44VjkuMmgyNy4xbDcuOSA3LjloNjIuNHY3My43eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0yNy45IDEwLjVsNy4xIDcuMS44LjhoNjEuNnY3MS4xSDIuNnYtNzloMjUuM20xLTIuNkgwdjg0LjJoMTAwVjE1LjhIMzYuOGwtNy45LTcuOXoiLz48cGF0aCBmaWxsPSIjZjVjZTg1IiBkPSJNMS4zIDkwLjhWMjIuNGgyOGw3LjktNS4zaDYxLjV2NzMuN3oiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNOTcuNCAxOC40djcxLjFIMi42VjIzLjdoMjcuMWwuNy0uNCA3LjItNC44aDU5LjhtMi42LTIuN0gzNi44bC03LjkgNS4zSDB2NzEuMWgxMDBWMTUuOHoiLz48L3N2Zz4=); }')
# Locked
f.write('.lock{ margin-left: 0px; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBkPSJNODMuNCAxNi42Yy0xOC41LTE4LjUtNDguMy0xOC41LTY2LjggMHMtMTguNSA0OC4zIDAgNjYuOCA0OC4zIDE4LjUgNjYuOCAwIDE4LjMtNDguMyAwLTY2Ljh6TTIwLjggNjguOWMtOC43LTEzLjQtNy4yLTMxLjcgNC43LTQzLjQgMTEuOS0xMS45IDMwLTEzLjQgNDMuNC00LjdMMjAuOCA2OC45em0xMC40IDEwLjNsNDguMS00OC4xYzguNyAxMy40IDcuMiAzMS43LTQuNyA0My40LTExLjcgMTEuOS0zMCAxMy40LTQzLjQgNC43eiIgZmlsbD0iIzY2NjY2NiIvPjwvc3ZnPg==); }')
f.write('</style>')
f.write('<script>')
# Toggle sign and search function
f.write("""
function t(nr){
$('#c' + nr).slideToggle('fast', function(){
var display = $("#c" + nr).css("display");
if(display == "none"){
$('#d' + nr + " b").html("[+]");
}
else{
$('#d' + nr + " b").html("[-]");
}
});
}
function clearPath(inner_html){
inner_html = inner_html.replace(/<[^>]*>?/gm, '');
inner_html = inner_html.replace('[+]', '');
inner_html = inner_html.replace('[-]', '');
inner_html = inner_html.trim();
return inner_html;
}
function doSearch(event){
event.preventDefault();
document.getElementById("searchOutput").innerHTML = "Searching ...<br><br>";
setTimeout(runSearch, 1000);
return False;
}
function genDropdown(){
var fList = document.getElementById("c1").childNodes;
var dd = document.getElementById("dd");
var form = document.forms[0];
for(var i = 0; i < fList.length; i++){
if(fList[i].className == "f"){
id = fList[i].id.replace("d", "c");
txt = "Root\\\\" + clearPath(fList[i].innerHTML) + "\\\\";
e = document.createElement("option");
e.value = id;
e.innerHTML = txt;
dd.appendChild(e);
}
}
}
function runSearch(event){
var out = document.getElementById("searchOutput");
var dd = document.getElementById("dd");
var all = document.getElementById(dd.value).getElementsByTagName("p");
var ctr = 0;
var color = "";
var q = document.getElementById("q").value;
if(q == ""){
out.innerHTML = '<b style="color: #900;">Enter a search-text first...</b><br><br>';
return False;
}
if(q.includes(".")){
q = q + "$";
}
q = q.replace(".", "\\.");
q = q.replace("*", ".*");
var re = new RegExp(q, "i");
var out2 = document.createElement("div");
for(var i=0; i < all.length; i++){
if(clearPath(all[i].innerHTML).search(re) != -1){
ctr++;
var path = clearPath(all[i].innerHTML);
var id = "";
var elem = all[i]
while(id != "d1"){
id = elem.parentElement.id;
id = id.replace("c", "d");
elem = document.getElementById(id);
path = path + "/:/" + clearPath(elem.innerHTML);
}
tmp = path.split("/:/");
path = tmp[tmp.length - 1]
for(var j = tmp.length - 2; j >= 0; j--){
path = path + '<b style="color: #900;">\\\\</b>' + tmp[j];
}
if(ctr % 2 == 0){
color = "#eee";
}
else{
color = "#fff";
}
var div = document.createElement("div");
div.innerHTML = path;
div.style.backgroundColor = color;
out2.appendChild(div);
}
}
if(out2.innerHTML == ""){
out.innerHTML = '<b style="color: #900;">No files found!</b><br><br>';
}
else{
var br = document.createElement("br");
out2.appendChild(br);
out2.appendChild(br);
out.innerHTML = "";
out.appendChild(out2);
}
}""")
f.write('</script>')
f.write('</head>')
f.write('<body onload="genDropdown()">')
f.write('<img src="' + LOGO_URL + '" style="width: 200px;"><br>')
f.write('<h1>FILE-REPORT</h1>')
f.write('<h2>PROJECT: ' + projectname + '</h2><br><hr><br><br>')
f.write('<form onsubmit="return doSearch(event);" style="margin-bottom: 25px;">')
f.write('<input type="text" name="q" id="q" style="min-width: 200px;"> ')
f.write('<select size="1" name="dd" id="dd" style="min-width: 200px;"><option value="c1">Root\\</option></select> ')
f.write('<input type="submit" value="search...">')
f.write('</form>')
f.write('<div id="searchOutput"></div>')
read_folder(dirname, f)
f.write("<br><hr><br>")
f.write(f"<table><tr><td><b>Files:</b> </td><td>{fctr}</td></tr> <tr><td><b>Folders:</b> </td><td>{ctr}</td></tr> <tr><td><b>Recovered:</b> </td><td>{sum_bytes/1024/1024/1024:.2f} GB</td></tr></table>")
f.write("</body>")
f.write("</html>")
f.close()
messagebox.showinfo("Finnish", f"HTML-report was generated successfully!\n\nFiles: {fctr}\nFolders: {ctr}")
Download
DEMO report
System requrements:
Windows, OSX or Linux with