HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css"></>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<div class="container">
<div class="sidebar">
<div class="title">
IT154-1L/EM01 Project
</div>
<div id="processes-list">
</div>
<div id="add-process-btn"
onclick="openModal()">
<i class="fas fa-plus"></i>
Create processes
</div>
</div>
<div class="main-content">
<div class="header">
<div class="controls">
<div id="run-sim-btn"
class="controls__run-sim"
onclick="runSim()">
<i class="fas fa-play"></i>
Run
</div>
<div id="next-frame-btn"
class="controls__run-sim"
onclick="frame()">
<i class="fas fa-fast-forward"></i>
Next
</div>
<div class="controls__algorithms">
<i class="fas fa-calculator"></i>
<select name="algorithms"
id="algorithms"
onChange="reset()">
<option value="first-fit">First-fit</option>
<option value="best-fit">Best-fit</option>
<option value="worst-fit">Worst-fit</option>
</select>
</div>
<div class="controls__memory-size">
<i class="fas fa-memory"></i>
<select name="total-memory-size"
id="total-memory-size"
onChange="reset()">
<option value="256">256kB</option>
<option value="512">512kB</option>
<option value="1024">1GB</option>
<option value="2048">2GB</option>
</select>
</div>
<div class="controls__memory-size">
<i class="fas fa-memory"></i>
<select name="memory-size"
id="num-of-blocks"
onChange="reset()">
<option value="2">2 blocks</option>
<option value="3">3 blocks</option>
<option value="4">4 blocks</option>
<option value="5">5 blocks</option>
<option value="6">6 blocks</option>
<option value="7">7 blocks</option>
<option value="8">8 blocks</option>
</select>
</div>
<div class="controls__compaction"
onclick="compaction()">Compaction</div>
<div class="controls__coalesce"
onclick="coalesce()">Coalesce</div>
</div> <!-- END controls -->
</div>
<div class="content">
<div class="left-side">
<div id="current-process">
<div class="header">
<div>
Process Log
</div>
<div class="state-container">
Cycle:
<span id="cycle-count">0</span>
</div>
</div>
<div id="current-process-info">
Not running
</div>
</div>
<div id="status">
<div class="header">
<div>
<span class="green">
Queued
</span> Processes
</div>
</div>
<div id="active-processes">
</div>
</div>
</div>
<div id="memory">
<div class="header">
Memory Allocation Simulation
<span class="state-container">Status:
<span id="state" class="inactive">Not running</span>
</span>
</div>
<div id="active-memory">
</div>
</div>
</div>
</div> <!-- END main-content -->
<!-- Create processes modal -->
<div id="create-processes-modal">
<div class="modal-header">
<div class="modal-title">
Create Processes
</div>
<div class="modal-close-btn"
onclick="closeModal()">x</div>
</div>
<div class="modal-body">
<div class="modal-container">
<div class="form-control">
<label for="number-of-processes">
Number of processes
<input id="number-of-processes"
name="number-of-processes"
type="text"
value="1"
onfocus="var temp_value=this.value; this.value=''; this.value=temp_value"
oninput="validate(this)">
</label>
<div class="button"
onclick="createRandomProcesses()">
Create Random
</div>
<div class="button button--create"
onclick="createProcesses()">
Create
</div>
</div>
<div id="process-forms-container">
<div id="fid-1" class="process-form">
<div class="form-input-container">
<label for="process-size">
Size (in kB)
</label>
<input id="process-size"
name="process-size"
type="text"
value="15"
onfocus="var temp_value=this.value; this.value=''; this.value=temp_value"
oninput="validate(this)"/>
</div>
<div class="form-input-container">
<label for="number-of-cycles">
Cycles
</label>
<input id="number-of-cycles"
name="number-of-cycles"
type="text"
value="12"
onfocus="var temp_value=this.value; this.value=''; this.value=temp_value"
oninput="validate(this)"/>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- END Create processes modal -->
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
$grey: #333642;
$grey-hover: #4d5162;
$light-grey: #444857;
$mint-green: #4e9d84;
$mint-green-hover: #5bbd9e;
$blue: #4c719f;
$blue-hover: #5b86bd;
$yellow: #ffdd40;
html,
body {
padding: 0;
margin: 0;
width: 100vh;
}
.green { color: limegreen; }
.active { color: highlight-yellow; }
.inactive { color: red; }
.active-btn { border-bottom: 3px solid $yellow; }
.button {
color: white;
text-align: center;
font-weight: 700;
padding: 1em;
background-color: $blue;
cursor: pointer;
&:hover {
background-color: $blue-hover;
}
&--create {
background-color: $mint-green;
&:hover {
background-color: $mint-green-hover;
}
}
}
.state-indicator { padding: 0.5em; }
.container {
font-family: 'Lato', 'Lucida Grande', 'Lucida Sans Unicode', Tahoma, Sans-Serif;
height: 100vh;
width: 100vw;
display: flex;
.main-content {
flex: 1;
display: flex;
flex-flow: column;
}
.header {
display: flex;
.controls {
width: 100%;
color: snow;
background-color: $grey;
display: flex;
justify-content: space-evenly;
&__run-sim {
cursor: pointer;
&:hover {
background-color: $light-grey;
}
&:active {
background-color: $light-grey;
}
}
&__compaction {
cursor: pointer;
&:hover {
background-color: $light-grey;
}
}
&__coalesce {
cursor: pointer;
&:hover {
background-color: $light-grey;
}
}
div {
padding: 1.5em 1.5em;
white-space: nowrap;
border-bottom: 3px solid $light-grey;
}
}
div { display: inline-block; }
}
.sidebar {
display: flex;
flex-flow: column;
height: 100%;
min-width: 285px;
background-color: $grey;
.title {
color: snow;
background: $mint-green;
padding: 1.5em 2em;
border-bottom: 5px solid $mint-green;
white-space: nowrap;
font-weight: bold;
}
#processes-list {
flex: 1;
background: snow;
border-radius: 0.15em;
margin: 2em;
margin-bottom: 3em;
overflow: auto;
div {
padding: 0.2em 0.5em;
&:nth-child(even) {
background-color: rgba(173, 216, 230, 0.24);
}
}
}
#add-process-btn {
padding: 0.75em;
color: snow;
background-color: $light-grey;
border: none;
cursor: pointer;
text-align: center;
&:hover {
background-color: $light-grey;
}
&:active {
background-color: $light-grey;
}
}
}
.content {
flex: 1;
display: flex;
flex-flow: row;
#active-processes {
flex: 1;
margin: 1em 0 0 0;
text-decoration: none;
list-style: none;
color: $grey;
background-color: white;
div {
padding: 0.2em 0.5em;
&:nth-child(even) {
background-color: rgba(173, 216, 230, 0.24);
}
}
}
}
.left-side {
display: flex;
flex-flow: column;
}
#current-process {
margin: 1em;
padding: 0.75em;
color: snow;
background-color: $grey;
display: flex;
flex-flow: column;
white-space: nowrap;
min-width: 300px;
.header {
display: flex;
justify-content: space-between;
.state-container { min-width: 70px; }
}
}
#current-process-info {
color: $grey;
background-color: white;
margin-top: 1em;
div {
padding: 0.2em 0.5em;
font-weight: 700;
&:nth-child(even) {
background-color: rgba(173, 216, 230, 0.24);
}
}
}
#status {
flex: 1;
margin: 1em;
padding: 0.75em;
color: snow;
background-color: $grey;
display: flex;
flex-flow: column;
white-space: nowrap;
min-width: 300px;
.header {
display: flex;
justify-content: space-between;
.state-container { min-width: 70px; }
}
}
#memory {
flex: 1;
margin: 1em;
padding: 0.75em;
color: snow;
background-color: $grey;
display: flex;
flex-flow: column;
white-space: nowrap;
.header {
display: flex;
justify-content: space-between;
.state-container { display: none; min-width: 156px; }
}
}
#active-memory {
flex: 1;
color: $grey;
background-color: white;
padding: 0.75em;
margin-top: 1em;
overflow: scroll;
}
}
.memory-block {
font-weight: 700;
color: white;
border: 1px solid black;
box-shadow: inset 0 0 0.25em black;
text-align: center;
display: flex;
flex-direction: column;
&--process {
display: flex;
flex-direction: column;
justify-content: center;
}
&--unallocated {
background-color: #758184;
justify-content: center;
}
}
#create-processes-modal {
position: absolute;
top: 50%;
left: 50%;
height: 60%;
width: 700px;
transform: translate(-50%, -50%);
background-color: snow;
box-shadow: 0 3px 5px #4a4a4a;
display: none;
flex-direction: column;
.modal-header {
display: flex;
justify-content: space-between;
background-color: $grey;
color: white;
.modal-title {
font-size: 1.1em;
font-weight: 700;
padding: 1em;
}
.modal-close-btn {
cursor: pointer;
font-weight: 700;
padding: 1em;
}
}
.modal-body {
flex: 1;
padding: 1em;
position: relative;
overflow: auto;
.modal-container {
height: 100%;
overflow: auto;
input {
text-align: right;
}
.form-control {
display: flex;
justify-content: space-between;
align-items: baseline;
position: sticky;
top: 0;
background-color: white;
padding-bottom: 1em;
}
#process-forms-container {
display: flex;
flex-wrap: wrap;
margin-top: -1em;
}
.process-form {
color: white;
background-color: $grey;
flex: 1;
display: flex;
flex-direction: column;
box-shadow: 0 5px 5px #c1c1c1;
margin: 1em;
padding: 1em;
max-width: 160px;
}
.form-input-container {
margin: 0.25em;
}
.process-label {
font-weight: 700;
}
}
}
}
let processList = document.getElementById("processes-list");
let currentProcess = document.getElementById("current-process-info");
let activeProcessesElem = document.getElementById("active-processes");
let activeMemory = document.getElementById("active-memory");
let memoryState = document.getElementById("state");
let cycleCountElem = document.getElementById("cycle-count");
let cycleCount = parseInt(cycleCountElem.innerHTML);
// List of all process elements
let processes = [];
// List of active processes (loaded into memory)
let activeProcesses = [];
// List of waiting processes
let waitingProcesses = [];
// List of current processes
let currentProcessWindow = [];
// List of all memory blocks
let memoryBlocks = [];
let runSimBtn = document.getElementById("run-sim-btn");
let simRunning = false;
let stopSim = false;
const animationDelay = 1000;
let blockColors = [
"#A0332F",
"#CB7B42",
"#DCBF53",
"#93A864",
"#5E89A8",
"#524A66",
"#679186",
"#264e70",
"#9ab5c1",
"#3c9099"
];
function addProcess(process) {
processList.appendChild(process);
}
// param: Process element
function queueProcess(process) {
activeProcessesElem.appendChild(process);
}
// Place process into memory block
function allocate(process, memoryBlock, compaction=false) {
console.log("Loading", process.pid, "into", memoryBlock.memId);
memoryBlock.element.style.border = "3px solid green";
// Create process block element to be loaded into this memory block
process.block.style.height = (process.size/memoryBlock.size) * 100 + "%";
let memBlockElem = document.getElementById(memoryBlock.memId);
if (!compaction) {
memBlockElem.innerHTML = "";
// Display remaining memory after allocation
let remaining = document.createElement("span");
remaining.classList.add("label");
remaining.innerHTML = "Block: " + memoryBlock.memId.split("-")[1] + ": "
+ freeSpace(memoryBlock) + "kB fragmented";
// Resize or hide block label depending on size of remaining space
if (((process.size/memoryBlock.size)*100) > 85) {
remaining.style.fontSize = "0.75em";
if (((process.size/memoryBlock.size)*100) > 95) {
remaining.style.opacity = 0;
}
}
memBlockElem.append(remaining);
currentProcessWindow.push([process, memoryBlock]);
}
memBlockElem.style.justifyContent = "start";
memBlockElem.append(process.block);
memoryBlock.processes.push(process);
activeProcesses.push(process);
// Remove from queued processes window
process.element.remove();
}
function killProcess(process) {
process.element.remove(); // Remove from Active process list
process.block.remove(); // Remove from memory block
activeProcesses = activeProcesses.filter((proc) => proc.pid !== process.pid);
}
// Load process into memory block via algorithms (First fit, Best fit, Worst fit)
function loadProcess(process) {
const algorithms = document.getElementById("algorithms");
const selectedAlgo = algorithms.options[algorithms.selectedIndex].value;
const algos = {
"first-fit": firstFit,
"best-fit": bestFit,
"worst-fit": worstFit
};
algos[selectedAlgo](process);
}
function firstFit(process) {
memoryState.classList.remove("inactive");
let isAllocated = false;
process.element.style = "color: green; font-weight: 700";
// Iterate memory blocks
memoryBlocks.some((memoryBlock) => {
if (memoryBlock.processes.length > 0) { // Block is occupied
process.element.style = "color: red;";
} else {
if (process.size <= memoryBlock.size) {// process fits into memory block
allocate(process, memoryBlock);
isAllocated = true;
return true; // Exit memory block loop; load next process
}
}
memoryBlock.element.style.border = "1px solid black";
loadCurrentProcessState();
});
// END iterate memory blocks
if (!isAllocated) {
console.log(process.pid, "is waiting");
waitingProcesses.push(process);
}
}
function bestFit(process) {
if (typeof process !== "undefined") { process.element.style = "color: green; font-weight: 700"; }
let isAllocated = false;
let leastRemaining = 99999;
let bestFitBlock = memoryBlocks[0];
// Iterate memory blocks
memoryBlocks.forEach((memoryBlock) => {
if (memoryBlock.processes.length > 0) {
process.element.style = "color: red;";
if (memoryBlock.processes[0].life <= 0) {
memoryBlock.processes = [];
cleanupMemory(memoryBlock);
}
} else {
let remaining = memoryBlock.size - process.size;
if (remaining >= 0
&& remaining < leastRemaining) {
leastRemaining = remaining;
bestFitBlock = memoryBlock;
}
loadCurrentProcessState();
}
memoryBlock.element.style.border = "1px solid black";
});
// END iterate memory blocks
if (leastRemaining < 99999) {
allocate(process, bestFitBlock);
isAllocated = true;
}
if (!isAllocated) {
console.log(process.pid, "is waiting");
waitingProcesses.push(process);
}
}
function worstFit(process) {
process.element.style = "color: green; font-weight: 700";
let mostRemaining = -1;
let worstFitBlock = memoryBlocks[0];
let isAllocated = false;
// Iterate memory blocks
memoryBlocks.forEach((memoryBlock) => {
if (memoryBlock.processes.length > 0) {
process.element.style = "color: red;";
if (memoryBlock.processes[0].life <= 0) {
memoryBlock.processes = [];
cleanupMemory(memoryBlock);
}
} else {
let remaining = memoryBlock.size - process.size;
if (remaining >= 0
&& remaining > mostRemaining) {
mostRemaining = remaining;
worstFitBlock = memoryBlock;
}
loadCurrentProcessState();
}
memoryBlock.element.style.border = "1px solid black";
});
// END iterate memory blocks
if (mostRemaining > -1) {
allocate(process, worstFitBlock);
isAllocated = true;
}
if (!isAllocated) {
console.log(process.pid, "is waiting");
waitingProcesses.push(process);
}
}
function loadCurrentProcessState() {
currentProcess.innerHTML = Object.keys(activeProcesses).length === 0 && cycleCount === 0
? "<div>Click run to start</div>"
: "";
for (let entry in currentProcessWindow) {
let process = currentProcessWindow[entry][0];
let memoryBlock = currentProcessWindow[entry][1];
let procedure = document.createElement("div");
procedure.setAttribute("id", "c" + process.pid);
procedure.innerHTML = "Job: " + process.pid.split("-")[1]
+ " - Block: " + memoryBlock.memId.split("-")[1]
+ " Cycles: " + process.life;
if (process.life <= 0) {
procedure.style = "text-decoration: line-through; opacity: 0.5; color: green;";
}
currentProcess.append(procedure);
}
if (activeProcesses.length === 0 && waitingProcesses.length === 0 && cycleCount > 1) {
let state = document.createElement("div");
state.innerHTML = "<div style=\"font-weight: 700; text-align: center; color: green;\">All processes completed!</div>";
currentProcess.append(state);
}
}
function runSim() {
if (simRunning) { stopSim = true;}
else { stopSim = false; }
if (cycleCount > 0) {
console.log("Starting simulation");
simRunning = true;
const framerate = animationDelay;
const interval = setInterval(() => {
frame();
if ((processes.length === 0
&& activeProcesses.length === 0
&& waitingProcesses.length === 0)
|| stopSim) {
console.log("Stopping simulation");
clearInterval(interval);
runSimBtn.innerHTML = "<i class=\"fas fa-play\"></i> Run";
simRunning = false;
}
}, framerate);
}
if (cycleCount === 0) {
currentProcess.innerHTML = "";
// Queue processes
processes.forEach((process) => {
queueProcess(process.element);
});
}
runSimBtn.innerHTML = simRunning ? "<i class=\"fas fa-pause\"></i> Stop" : "<i class=\"fas fa-play\"></i> Run";
}
function frame() {
if (processes.length === 0
&& activeProcesses.length === 0
&& waitingProcesses.length === 0) { return; }
activeProcesses.forEach((process) => { process.life -= 1; });
// Process waiting first
if (waitingProcesses.length > 0) {
let waitingProcess = waitingProcesses.shift();
console.log("Loading waiting process:", waitingProcess);
if (isLive(waitingProcess)) {
loadProcess(waitingProcess)
}
} else { // Load process unless already active
let process = processes.shift();
console.log("Loading process:", process);
if (isLive(process)) {
loadProcess(process);
}
}
// Clean up finished processes
activeProcesses.forEach((process) => {
if (typeof(process) !== 'undefined' && process.life <= 0) {
console.log("Killing ", process);
killProcess(process);
}
});
// Clean up processes in memory
memoryBlocks.forEach((memoryBlock) => {
if (memoryBlock.processes.length <= 0 || activeProcesses.length === 0) {
console.log("cleaning", memoryBlock);
cleanupMemory(memoryBlock);
}
if (memoryBlock.processes.length > 0 && memoryBlock.processes[0].life <= 0) {
cleanupMemory(memoryBlock);
}
});
incrementCycleCount();
updateUI();
}
function updateUI() {
if (processes.length === 0) {
processList.innerHTML = "";
let placeholder = document.createElement("div");
placeholder.innerHTML = "<div>No processes...</div>";
processList.append(placeholder);
runSimBtn.disabled = true;
} else {
runSimBtn.disabled = false;
}
loadCurrentProcessState();
}
function createMemoryBlocks() {
const el = document.getElementById("total-memory-size");
const e = document.getElementById("num-of-blocks");
const totalMem = parseInt(el.options[el.selectedIndex].value);
const numOfBlocks = parseInt(e.options[e.selectedIndex].value);
for (let i = 0; i < numOfBlocks; i++) {
const memSoFar = Object.keys(memoryBlocks).map((k) => { return memoryBlocks[k].size; })
const blockSize = (i === numOfBlocks - 1) // Last block fills remaining memory
? totalMem - memSoFar.reduce((t, c) => { return t + c; })
: Math.round((totalMem/numOfBlocks) + getRandomInRange(-20, 20));
const memId = "memAddr-" + (i+1);
const blockEl = document.createElement("div");
blockEl.setAttribute("id", memId);
blockEl.className = "memory-block memory-block--unallocated";
blockEl.innerHTML = "<span class=\"label\">Block " + (i+1) + " unallocated - " + blockSize + "kB</span>";
blockEl.style.height = Math.round((blockSize/totalMem) * 100) - 1 + "%";
activeMemory.append(blockEl);
let memoryBlock = {
"memId": memId,
"size": blockSize,
"processes": [],
"element": blockEl
}
memoryBlocks.push(memoryBlock);
}
}
function createProcesses() {
reset();
let numOfProcesses = document.getElementById("number-of-processes").value;
numOfProcesses = isNaN(numOfProcesses) ? 1 : parseInt(numOfProcesses);
const processForms = document.getElementById("process-forms-container");
for (let i = 0; i < numOfProcesses; i++) {
const processForm = processForms.children[i];
const pid = "pid-" + processForm.getAttribute("id").slice(-1);
const procSize = parseInt(processForm.children[1].children[1].value);
const procCycles = parseInt(processForm.children[2].children[1].value);
// List element
const processElem = document.createElement("div");
processElem.setAttribute("id", pid);
processElem.innerHTML = "Job: " + (i+1) + " - " + procSize + "kB - " + procCycles + " cycles";
// Memory Element
const processEl = document.createElement("div");
processEl.setAttribute("id", "mem-" + pid);
processEl.className = "memory-block memory-block--process";
processEl.innerHTML = "<span class=\"label\">" + processElem.innerHTML + "</span>";
processEl.style.backgroundColor = blockColors[Math.floor(Math.random()*blockColors.length)];
// Add process to queue
addProcess(processElem);
let process = {
"pid": pid,
"size": procSize,
"life": procCycles, // Number of cycles needed to complete
"element": processElem, // Process list element in queues
"block": processEl // Process block element in active memory
}
processes.push(process);
}
closeModal();
updateUI();
}
function createRandomProcesses() {
processList.innerHTML = "";
const el = document.getElementById("total-memory-size");
const e = document.getElementById("num-of-blocks");
const totalMem = parseInt(el.options[el.selectedIndex].value);
const numOfBlocks = parseInt(e.options[e.selectedIndex].value);
const processCount = processes.length;
const numOfProcesses = parseInt(document.getElementById("number-of-processes").value);
// Load existing processes
processes.forEach((process) => {
processList.append(process.element);
});
for (let i = processCount; i < processCount + numOfProcesses; i++) {
const pid = "pid-" + (i+1);
const procSize = Math.round(getRandomInRange(50, (totalMem/numOfBlocks) - 10));
const life = Math.round(getRandomInRange(4, 10)); // Number of cycles needed to complete
// List element
const processElem = document.createElement("div");
processElem.setAttribute("id", pid);
processElem.innerHTML = "Job: " + (i+1) + " - " + procSize + "kB - " + life + " cycles";
// Memory Element
const processEl = document.createElement("div");
processEl.setAttribute("id", "mem-" + pid);
processEl.className = "memory-block memory-block--process";
processEl.innerHTML = "<span class=\"label\">" + processElem.innerHTML + "</span>";
processEl.style.backgroundColor = blockColors[Math.floor(Math.random()*blockColors.length)];
// Add process to queue
addProcess(processElem);
let process = {
"pid": pid,
"size": procSize,
"life": life, // Number of cycles needed to complete
"element": processElem, // Process list element in queues
"block": processEl // Process block element in active memory
}
processes.push(process);
}
closeModal();
updateUI();
}
function compaction() {
for (let i = 0; i < memoryBlocks.length; i++) {
const memoryBlock = memoryBlocks[i];
cleanupMemory(memoryBlock);
}
const done = [];
let pIndex = 0;
for (let i = 0; i < memoryBlocks.length; i++) {
const memoryBlock = memoryBlocks[i];
while (pIndex < activeProcesses.length) {
if (freeSpace(memoryBlock) >= activeProcesses[pIndex].size
&& !done.includes(activeProcesses[pIndex].pid)) {
allocate(activeProcesses[pIndex], memoryBlock, true);
done.push(activeProcesses[pIndex].pid);
}
pIndex += 1;
}
}
}
function coalesce() {
for (let i = 0; i < memoryBlocks.length-1; i++) {
if (isEmpty(memoryBlocks[i]) && isEmpty(memoryBlocks[i+1])) {
mergeBlocks(memoryBlocks[i], memoryBlocks[i+1]);
}
}
}
function mergeBlocks(block1, block2) {
console.log("merging ", block1.memId, block2.memId);
const el = document.getElementById("total-memory-size");
const totalMem = parseInt(el.options[el.selectedIndex].value);
block1.size = block1.size + block2.size;
console.log("adding", block1.size, block2.size, block1.size + block2.size);
block1.element.innerHTML = "<span class=\"label\">Block " + block1.memId.split("-")[1]
+" unallocated - " + block1.size + "kB</span>";
block1.element.style.height = Math.round((block1.size/totalMem) * 100) - 1 + "%";
activeMemory.removeChild(block2.element);
memoryBlocks = memoryBlocks.filter((block) => block.memId !== block2.memId);
}
function freeSpace(memoryBlock) {
if (memoryBlock.processes.length === 0) { return memoryBlock.size; }
const memUsed = memoryBlock.processes.map((p) => { return p.size; })
return memoryBlock.size - memUsed.reduce((t, c) => { return t + c; });
}
function getOwningBlock(process) {
for (let i = 0; i < memoryBlocks.length; i++) {
for (let j = 0; j < memoryBlocks[i].processes.length; j++) {
if (memoryBlocks[i].processes[j].pid === process.pid) {
return memoryBlocks[i];
}
}
}
return null;
}
function isProcessInBlock(process, block) {
for (let i = 0; i < block.processes.length; i++) {
if (process.pid === block.processes[i].pid) {
console.log(process.pid, "found in", block.memId);
return true;
}
}
return false;
}
function cleanupMemory(memoryBlock) {
memoryBlock.processes = [];
memoryBlock.element.innerHTML = "";
memoryBlock.element.style.justifyContent = "center";
memoryBlock.element.style.border = "none";
let unallocated = document.createElement("span");
unallocated.innerHTML = "<span class=\"label\">Block " + memoryBlock.memId.split("-")[1]
+ " unallocated - " + memoryBlock.size + "kB</span>";
memoryBlock.element.append(unallocated);
}
function reset() {
activeMemory.innerHTML = "";
activeProcessesElem.innerHTML = "";
cycleCountElem.innerHTML = 0;
cycleCount = 0;
processList.innerHTML = "";
currentProcess.innerHTML = "<div class=\"state-indicator\">Not running...</div>";
memoryState.innerHTML = "<div class=\"state-indicator\">Not running...</div>";
memoryBlocks = [];
processes = [];
activeProcesses = [];
waitingProcesses = [];
currentProcessWindow = [];
stopSim = false;
simRunning = false;
createMemoryBlocks();
}
function incrementCycleCount() {
cycleCount += 1;
cycleCountElem.innerHTML = cycleCount;
}
function isActive(process) {
if (typeof process === "undefined") { return false; }
for (let proc in activeProcesses) {
if (activeProcesses[proc].pid === process.pid) {
return true;
}
}
return false;
}
function isEmpty(memoryBlock) {
return memoryBlock.processes.length === 0;
}
function isLive(process) {
return (typeof process !== "undefined" && !isActive(process) && process.life > 0);
}
function getRandomInRange(min, max) {
return Math.random() * (max - min) + min;
}
function openModal() {
const modal = document.getElementById("create-processes-modal");
modal.style.display = "flex";
createProcessesForm();
}
function closeModal() {
const modal = document.getElementById("create-processes-modal");
modal.style.display = "none";
}
function validate(element) {
if (isNaN(element.value)) { element.value = element.value.slice(0, -1); }
if (element.attributes["id"].value === "number-of-processes") { createProcessesForm(); }
}
function createProcessesForm() {
const formContainer = document.getElementById("process-forms-container");
const firstChild = formContainer.children[0].cloneNode(true);
(firstChild.children.length > 2) ? firstChild.removeChild(firstChild.firstChild) : "";
formContainer.innerHTML = "";
formContainer.appendChild(firstChild);
const n = document.getElementById("number-of-processes").value;
const numberOfProcesses = isNaN(n) ? 1 : parseInt(n);
for (let i = 1; i < numberOfProcesses; i++) {
const processForm = document.getElementById("fid-1").cloneNode(true);
processForm.setAttribute("id", "fid-" + (i+1));
const jobLabel = document.createElement("div");
jobLabel.classList.add("process-label");
jobLabel.innerHTML = "Job " + (i+1);
processForm.prepend(jobLabel);
formContainer.append(processForm);
}
// First process form
const processForm = document.getElementById("fid-1");
const jobLabel = document.createElement("div");
jobLabel.classList.add("process-label");
jobLabel.innerHTML = "Job 1";
processForm.prepend(jobLabel);
}
reset();
Also see: Tab Triggers