Version 0.2.0 - PREVERSION - Ajout READ de l'explorateur
All checks were successful
Neutral/pipeline/head This commit looks good

This commit is contained in:
CICD - Pipeline 2023-11-03 14:25:39 +01:00
parent 9c1074de80
commit 5e97ff4853
12 changed files with 782 additions and 24 deletions

53
bin/files.js Normal file
View File

@ -0,0 +1,53 @@
const { LogType } = require("loguix")
const fs = require("fs")
const path = require("path")
const { __glob } = require("./global-variables")
const clog = new LogType("Fichier")
const os = require("os");
const uuid = require('uuid');
var mime = require('mime-types');
module.exports.getFiles = function(root) {
var response = new Object()
response.content = new Array()
response.root = root
response.parent = path.dirname(root)
try{
if(root == "homepath") {
root = os.homedir()
response.root = root
}
if(!fs.existsSync(root)) {
response.content = "NOT_EXIST"
} else {
for(var file of fs.readdirSync(root)) {
const stat = fs.statSync(root + path.sep + file)
response.content.push({"name":file, id: uuid.v4().toString() ,"fileDirectory" : root + path.sep + file , "type":mime.lookup(file), "size":stat.size, "lastedition":stat.mtimeMs, "directory":stat.isDirectory()})
}
}
}catch(err) {
response.content = "NOT_PERMITTED"
}
return response
}

View File

@ -3,6 +3,7 @@ const fs = require("fs")
const path = require("path")
const { __glob } = require("./global-variables")
const auth = require("./auth")
const files = require("./files")
const plog = new LogType("Web")
const cook = require("cookie")
const http = require("http")
@ -39,7 +40,10 @@ module.exports.serverIO = function(server) {
GetAnswer("USERINFO", {username: user.username, display_name: user.display_name ,picture: user.picture, permission: user.permission})
})
PostRequest("FX_GET", (root) => {
PostAnswer("FX_GET", files.getFiles(root))
})
socket.on("disconnect", () => {
@ -62,6 +66,21 @@ module.exports.serverIO = function(server) {
}
function PostRequest(GQname, GQcallback) {
socket.on("POST/" + GQname, (value) => {
plog.log(user.username + " - Socket : " + socket.id + " - POST/" + GQname + " - [RECIEVED]")
GQcallback(value)
})
}
function PostAnswer(GRname, GRvalue) {
plog.log(user.username + " - Socket : " + socket.id + " - POST/" + GRname + " - [ANSWERED]")
socket.emit("ANSWER/POST/" + GRname, GRvalue)
}
} else {
socket.disconnect()

View File

@ -2,7 +2,7 @@ const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const favicon = require('express-favicon');
var favicon = require('serve-favicon');
const app = express();
const fs = require("fs");
const log = require("loguix")
@ -48,7 +48,7 @@ function setup() {
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(favicon(__glob.ICON));
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
getRouters()
users.fetchUsers()

64
package-lock.json generated
View File

@ -14,10 +14,10 @@
"debug": "~2.6.9",
"ejs": "~2.6.1",
"express": "~4.16.1",
"express-favicon": "^2.0.4",
"http-errors": "~1.6.3",
"loguix": "1.4.1",
"nodemon": "^3.0.1",
"serve-favicon": "^2.0.4",
"socket.io": "^4.7.2",
"uuid": "^9.0.1"
}
@ -384,14 +384,6 @@
"node": ">= 0.10.0"
}
},
"node_modules/express-favicon": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/express-favicon/-/express-favicon-2.0.4.tgz",
"integrity": "sha512-JDGzumJdwF+WcJf+qwyhdpF1yzducuMCxZa+G6hxR3hor7ae/1CqpAPj8FXCGaGtqBA6ExDMfeszjuYRw5GUuQ==",
"engines": {
"node": ">=4"
}
},
"node_modules/express/node_modules/cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
@ -855,6 +847,31 @@
"node": ">= 0.8.0"
}
},
"node_modules/serve-favicon": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz",
"integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==",
"dependencies": {
"etag": "~1.8.1",
"fresh": "0.5.2",
"ms": "2.1.1",
"parseurl": "~1.3.2",
"safe-buffer": "5.1.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/serve-favicon/node_modules/ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"node_modules/serve-favicon/node_modules/safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"node_modules/serve-static": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
@ -1385,11 +1402,6 @@
}
}
},
"express-favicon": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/express-favicon/-/express-favicon-2.0.4.tgz",
"integrity": "sha512-JDGzumJdwF+WcJf+qwyhdpF1yzducuMCxZa+G6hxR3hor7ae/1CqpAPj8FXCGaGtqBA6ExDMfeszjuYRw5GUuQ=="
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@ -1719,6 +1731,30 @@
"statuses": "~1.4.0"
}
},
"serve-favicon": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz",
"integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==",
"requires": {
"etag": "~1.8.1",
"fresh": "0.5.2",
"ms": "2.1.1",
"parseurl": "~1.3.2",
"safe-buffer": "5.1.1"
},
"dependencies": {
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
}
}
},
"serve-static": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",

View File

@ -25,7 +25,7 @@
"debug": "~2.6.9",
"ejs": "~2.6.1",
"express": "~4.16.1",
"express-favicon": "^2.0.4",
"serve-favicon": "^2.0.4",
"http-errors": "~1.6.3",
"loguix": "1.4.1",
"nodemon": "^3.0.1",

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,5 +1,8 @@
// Get Document ID
/**
* Récupère depuis le document l'identifiant de l'élément
* @param {string} id Identifiant de l'élément `id='identifiant'`
@ -43,3 +46,223 @@ class InfoPop {
}
const viewsAccessible = new Map()
var xMousePos = null;
var yMousePos = null;
document.onmousemove = function(e) {
xMousePos = e.clientX + window.scrollX;
yMousePos = e.clientY + window.scrollY;
}
document.oncontextmenu = function(e) {
xMousePos = e.clientX + window.scrollX;
yMousePos = e.clientY + window.scrollY;
}
class ViewWindow {
ViewHTML = null
ViewProperties =null
ViewSpanInteger = null
constructor(properties) {
if(!viewsAccessible.has(properties.title)) {
this.ViewProperties = properties
viewsAccessible.set(properties.title, true)
this.ViewHTML = `
<div draggable="true" id='${properties.title}_window' style='width: ${properties.width}; height: ${properties.height}' class='view-window'>
<div id='${properties.title}_header' class='view-window-header'>
<span style='width: 40px'></span>
<p>${properties.title}</p>
<button id='${properties.title}_close' class='btn min red'><span><i class='fa fa-xmark'></i></span></button>
</div>
<div id='${properties.title}_content' class='view-window-content'>
</div>
</div>
`
this.ViewSpanInteger = document.createElement("div")
document.body.appendChild(this.ViewSpanInteger);
this.ViewSpanInteger.outerHTML = this.ViewHTML
const closeWindow = document.getElementById(properties.title + "_close")
closeWindow.addEventListener("click", () => {
this.destroy()
})
const header = document.getElementById(properties.title + "_header")
const windowDiv = document.getElementById(properties.title + "_window")
let isDragging = false;
let offsetX, offsetY;
header.addEventListener('mousedown', (e) => {
isDragging = true;
// Enregistrez la position de la souris par rapport à la fenêtre
offsetX = e.clientX - windowDiv.getBoundingClientRect().left;
offsetY = e.clientY - windowDiv.getBoundingClientRect().top;
});
// Gérer le déplacement
document.addEventListener('mousemove', (e) => {
if (isDragging) {
header.style.cursor = "grab"
// Calculez la nouvelle position de la fenêtre en fonction de la position de la souris
const newLeft = e.clientX - offsetX;
const newTop = e.clientY - offsetY;
// Limitation de la position pour éviter un débordement
const maxX = window.innerWidth - windowDiv.offsetWidth;
const maxY = window.innerHeight - windowDiv.offsetHeight;
windowDiv.style.left = Math.min(Math.max(newLeft, 0), maxX) + 'px';
windowDiv.style.top = Math.min(Math.max(newTop, 0), maxY) + 'px';
}
});
// Gérer la fin du glisser-déposer
document.addEventListener('mouseup', () => {
header.style.cursor = "unset"
isDragging = false;
});
}
}
destroy() {
const win = getID(`${this.ViewProperties.title}_window`)
win.outerHTML = ""
viewsAccessible.delete(this.ViewProperties.title)
}
setContent(text) {
const contentDiv = document.getElementById(this.ViewProperties.title + "_content")
contentDiv.innerHTML = text
}
getViewTitle() {
return this.ViewProperties.title
}
}
createView("files_explorer")
function createView(viewType) {
if(viewType == 'files_explorer') {
generateFileExplorer()
}
if(viewType == 'service') {
const View = new ViewWindow({
title: "Gestionnaire des services",
width: "1000px",
height: "600px"
})
}
}
class DroppableMenu {
options = new Array()
id = null
DMSpanInteger = null
constructor(properties) {
this.id = properties.id
this.options.push(`<div id='dm-${this.id}' class='dm-menu'>`)
}
add(action, string) {
this.options.push("<div id='" + this.id + "_" + action + "' class='dm-element'>" + string + "</div>")
}
show() {
this.options.push(`</div>`)
if(xMousePos && yMousePos) {
this.DMSpanInteger = document.createElement("span")
document.body.appendChild(this.DMSpanInteger);
this.DMSpanInteger.outerHTML = this.options.join('')
const menu = getID(`dm-${this.id}`)
menu.style.left = (xMousePos - 40) + "px"
menu.style.top = (yMousePos - 40) + "px"
menu.addEventListener('mouseleave', () => {
menu.outerHTML = ""
})
}
}
}
function getFormattedDate(GetDate) {
const date = new Date(GetDate)
var gmonth = date.getMonth() + 1
var gday = date.getDate()
var gHour = date.getHours()
var gMinute = date.getMinutes()
var gSecondes = date.getSeconds()
if(date.getMonth() + 1 < 10) {
gmonth = "0" + (date.getMonth() + 1)
}
if(date.getDate() + 1 <= 10) {
gday = "0" + date.getDate()
}
if(date.getHours() + 1 <= 10) {
gHour = "0" + date.getHours()
}
if(date.getMinutes() + 1 <= 10) {
gMinute = "0" + date.getMinutes()
}
if(date.getSeconds() + 1 <= 10) {
gSecondes = "0" + date.getSeconds()
}
return gday + "/" + gmonth + "/" + date.getFullYear() + " - " + gHour + ":" + gMinute
}

View File

@ -0,0 +1,232 @@
document.addEventListener("contextmenu", (e) => {
e.preventDefault()
})
function generateFileExplorer() {
const View = new ViewWindow({
title: `<i class="fa fa-folder"></i> Gestionnaire de fichiers`,
width: "1000px",
height: "600px"
})
goHomePath()
function goHomePath() {
const rFiles = post("FX_GET", "homepath")
rFiles.then((result) => {
loadFiles(result)
})
}
View.setContent(`
<div class="fx-window">
<div class='fx-bar'>
<span id='fx-home' class='btn-cover'><i class='fa fa-home'></i></span>
<input class='fx-root-input' type="text" id='${View.getViewTitle()}_rootInput'>
<div class='fx-bar-actions'>
<button class='btn blue'><span><i class='fa fa-folder'></i> Nouv. dossier</span></button>
<button class='btn blue'><span><i class="fa-solid fa-file-arrow-up"></i> Upload</span></button>
</div>
</div>
<div id='${View.getViewTitle()}_explorer' class='fx-explorer'>
</div>
</div>
`)
const rootInput = getID(View.getViewTitle() + '_rootInput')
const explorer = getID(View.getViewTitle() + '_explorer')
rootInput.addEventListener("change", () => {
const reqFiles = post("FX_GET", rootInput.value)
reqFiles.then((result) => {
loadFiles(result)
})
})
function loadFiles(files) {
rootInput.value = files.root
var fileElements = new Array()
if(files.content == "NOT_PERMITTED") {
fileElements.unshift(`<div id='fx-parent' class='fx-element'><p><i class="fa-solid fa-rotate-left"></i> Revenir au dossier parent </p></div>`)
fileElements.push("<p class='yellow' style='text-align: center;'><i class='fa fa-warning'></i> Vous n'avez pas les permissions pour accéder à ce dossier.</p>")
} else if(files.content == "NOT_EXIST") {
fileElements.unshift(`<div id='fx-parent' class='fx-element'><p><i class="fa-solid fa-rotate-left"></i> Revenir au dossier parent </p></div>`)
explorer.innerHTML = "<p class='yellow' style='text-align: center;'><i class='fa fa-warning'></i> Ce dossier n'existe pas.</p>"
} else {
fileElements.unshift(`<div id='fx-parent' class='fx-element'><p><i class="fa-solid fa-rotate-left"></i> Revenir au dossier parent </p></div>`)
for(const file of files.content) {
// Convert all file.size to a human readable format with units
file.size = bytesToSize(file.size)
//Tell if the file is a directory or not
if(file.directory) {
file.size = "Dossier"
}
fileElements.push(`<div id='${file.id}' oncontextmenu='createFileMenu("${file.id}")' class='fx-element'>
<div>
${getIcon(file)}
<p>${file.name}</p>
</div>
<p>Taille : ${file.size}</p>
<p>Date de modification : ${getFormattedDate(file.lastedition)}</p>
</div>`)
}
}
explorer.innerHTML = fileElements.join("")
const parent = document.getElementById("fx-parent")
const home = document.getElementById("fx-home")
home.addEventListener("click", () => {
goHomePath()
})
parent.addEventListener("click", () => {
const reqFiles = post("FX_GET", files.parent)
reqFiles.then((result) => {
loadFiles(result)
})
})
if(files.content != "NOT_PERMITTED" && files.content != "NOT_EXIST") {
// If it's a directory, get the file directory and make the request to get the files in it and loadIt
for(const file of files.content) {
if(file.directory) {
const element = document.getElementById(file.id)
element.addEventListener("click", () => {
const reqFiles = post("FX_GET", file.fileDirectory)
reqFiles.then((result) => {
loadFiles(result)
})
})
}
}
}
}
}
function createFileMenu(idCreated) {
const dropMenu = new DroppableMenu({
"id": idCreated
})
dropMenu.add("rename", "<i class='fa-solid fa-file-signature'></i> Renommer")
dropMenu.add("share", "<i class='fa fa-share'></i> Partager")
dropMenu.add("delete", "<i class='fa fa-trash'></i> Supprimer")
dropMenu.show()
}
function getIcon(file) {
if(file.type == "application/json") {
return '<i style="color:rgb(179, 141, 4);" class="fa-sharp fa-code"></i>'
}
if(file.type == "application/msword" | file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document") {
return '<i style="color:rgb(47, 94, 247);" class="fa-solid fa-file-word"></i>'
}
if(file.type == "application/vnd.ms-powerpoint") {
return '<i style="color:rgb(255, 112, 51);" class="fa-solid fa-file-powerpoint"></i>'
}
if(file.type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | file.type == "application/vnd.ms-excel") {
return '<i style="color:rgb(51, 255, 61);" class="fa-solid fa-file-excel"></i>'
}
if(file.type == "application/java-archive") {
return '<i style="color:rgb(255, 202, 150);" class="fa-brands fa-java"></i>'
}
if(file.type == "application/x-sh") {
return '<i style="color:rgb(171, 226, 255);" class="fa-solid fa-file-code"></i>'
}
if(file.type == "application/x-msdos-program" | file.type == "application/x-msdownload") {
return'<i style="color:rgb(53, 191, 255);" class="fa-brands fa-windows"></i>'
}
if(file.type == "application/javascript") {
return '<i style="color:rgb(179, 141, 4);" class="fa-brands fa-js">'
}
if(file.type == "image/png" | file.type == "image/jpeg") {
return '<i style="color:rgb(189, 104, 189);" class="fa-solid fa-file-image"></i>'
}
if(file.type == "text/html") {
return '<i style="color:tomato;" class="fa-brands fa-html5"></i>'
}
if(file.type == "text/css") {
return '<i style="color:rgb(66, 135, 245);" class="fa-brands fa-css3-alt"></i>'
}
if(file.type == "application/zip") {
return '<i style="color:rgb(255, 139, 38);" class="fa-solid fa-file-zipper"></i>'
}
if(file.type == "audio/mpeg") {
return '<i style="color:rgb(38, 222, 255);" class="fa-solid fa-file-audio"></i>'
}
if(file.type == "application/pdf") {
return '<i style="color:rgb(255, 71, 51);" class="fa-solid fa-file-pdf"></i>'
}
if(file.directory) {
return '<i style="color:yellow;" class="fa fa-folder"></i>'
} else {
return '<i class="fa fa-file"></i>'
}
}
function bytesToSize(bytes) {
var sizes = ['o', 'Ko', 'Mo', 'Go', 'To'];
if (bytes == 0) return '0 o';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
}

View File

@ -19,13 +19,13 @@ REQ_user.then((ANS_user) => {
permissions.forEach((permValue) => {
if(permValue == "FILES_EXPLORER") {
AvailableViews.push(`<div class="view">
AvailableViews.push(`<div onclick="createView('files_explorer')" class="view">
<span class="view-image"><i class="fa-solid fa-folder"></i></span>
<p class="view-text">Gestionnaire de fichiers</p>
</div>`)
}
if(permValue == "SERVICES") {
AvailableViews.push(`<div class="view">
AvailableViews.push(`<div onclick="createView('service')" class="view">
<span class="view-image"><i class="fa-solid fa-layer-group"></i></span>
<p class="view-text">Gestion des services</p>
</div>`)

View File

@ -36,6 +36,27 @@ function get(request) {
}
function post(request, value) {
return new Promise((resolve, reject) => {
socket.emit("POST/" + request, value)
console.log("Envoi de la requête POST : " + request)
socket.once("ANSWER/POST/" + request, (answer) => {
console.log("Réponse pour la requête : " + request)
resolve(answer)
})
})
}
function getSocket() {
return socket

View File

@ -6,7 +6,7 @@ body {
color: white;
font-size: 20px;
font-family: 'Roboto', sans-serif !important;
overflow: hidden;
}
html {
@ -58,6 +58,21 @@ html {
text-decoration: none;
}
.btn-cover {
color: white;
transition: 0.1s;
cursor: pointer;
}
.btn-cover:hover {
color: rgba(255, 255, 255, 0.675);
}
.btn-cover:active {
color: rgba(255, 255, 255, 0.575);
}
/* Miniaturiez Button */
.min {
@ -405,3 +420,159 @@ a {
font-size: 72px;
}
/*ViewWindow*/
.view-window {
position: absolute;
z-index: 1;
background-color: #605e58c1;
backdrop-filter: blur(10px);
border-radius: 0.5vw;
-webkit-user-drag: auto;
}
.view-window-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: rgba(33, 32, 33, 0.753);
border-top-right-radius: 0.5vw;
border-top-left-radius: 0.5vw;
user-select: none;
}
/* Files Explorer */
.fx-window {
display: flex;
flex-direction: column;
}
.fx-root-input {
background-color: #323031;
border: solid 1px #323031;
border-radius: 0.5vw;
padding: 1%;
color: white;
outline:0px;
width: 100%;
}
.fx-explorer {
display: flex;
flex-direction: column;
overflow-y: auto ;
height: 450px;
gap: 20px
}
.fx-element {
display: grid;
grid-template-columns: 3fr 1fr 2fr;
grid-column-gap: 10px;
align-items: center;
padding: 5px;
padding-left: 30px;
padding-right: 30px;
font-size: 14px;
transition: 0.1s;
}
.fx-element div {
display: flex;
justify-content: start;
gap: 10px;
align-items: center;
}
.fx-element:hover {
background-color: rgba(44, 40, 42, 0.614);
}
.fx-actions {
justify-content: end !important;
width: 100%;
}
.fx-bar {
margin: 1%;
display: flex;
gap: 10px;
align-items: center;
}
.fx-bar-actions {
width: 30%;
display: flex;
flex-direction: row;
gap: 10px;
}
/* ===== Scrollbar CSS ===== */
/* Firefox */
* {
scrollbar-width: auto;
scrollbar-color: #ff5d51 #ffffff;
}
/* Chrome, Edge, and Safari */
*::-webkit-scrollbar {
width: 13px;
}
*::-webkit-scrollbar-track {
background: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: #ff5d51;
border-radius: 17px;
border: 2px solid transparent;
}
/* Dropable Menu */
.dm-menu {
position: absolute;
display: flex;
flex-direction: column;
width: 150px;
border-radius: 0.5vw;
z-index: 3;
height: auto;
}
.dm-element {
background-color: #1a1819c9;
padding: 10px;
cursor: pointer;
font-size: 14px;
display: grid;
grid-template-columns: 0.2fr 0.8fr;
}
.dm-element:hover {
background-color: #ffffffc9;
color:black
}

View File

@ -56,8 +56,11 @@
<script src="/socket.io/socket.io.js"></script>
<script defer="" src="https://use.fontawesome.com/releases/v6.4.2/js/all.js" crossorigin="anonymous"></script>
<script src="/javascripts/basics.js"></script>
<script src="/javascripts/io.js"></script>
<script src="/javascripts/filexplorer.js"></script>
<script src="/javascripts/basics.js"></script>
<script src="/javascripts/indexscript.js"></script>
</body>