My Career Goals!
Let me introduce myself and my career goals
I worked in IT doing QA Automation from 2019 to 2023. I have the goal to work in IT and/or software again in some capacity.
Hello friends. I will show some little things here that are of personal interest to me; take what is useful to you for what it is, discard the rest if you like!
Here is a game I have made and worked on a little bit recently
Here I have pasted the source code for the game:
<!doctype html>
<html lang="en-US">
<head>
<title>GRAVITY MUNCHKIN</title>
<meta name="author" content="Josh Parker">
<style id="gravity-munchkin-style" title="gravity-munchkin-style">
@keyframes rotating {
0% {
transform: rotate(0turn);
}
100% {
transform: rotate(1turn);
}
}
div.my-spiky-div {
animation: rotating linear 10s infinite;
position: fixed;
}
body {
font-family:
Avenir, Montserrat, Corbel, "URW Gothic", source-sans-pro, sans-serif;
}
@keyframes heading-fade {
0% {
opacity: 100%;
transform: scaleY(0%);
letter-spacing: 0;
}
6% {
opacity: 100%;
transform: scaleY(100%);
letter-spacing: 0;
}
12% {
opacity: 80%;
transform: scaleY(100%);
letter-spacing: 0;
}
100% {
opacity: 0%;
transform: scaleY(100%);
letter-spacing: 2em;
}
}
h1 {
animation-name: heading-fade;
position: fixed;
top: 0;
left: -100%;
width: 300%;
height: fit-content;
text-wrap: nowrap;
color: white;
text-align: center;
animation-duration: 10s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
z-index: 2;
}
h2 {
position: fixed;
color: white;
z-index: 2;
width: 10%;
text-align: center;
}
.planet {
position: fixed;
aspect-ratio: 1;
border-radius: 100%;
transform: translate(-50%, -50%);
z-index: 1;
box-shadow:
0 0 4px white,
0 0 8px white,
0 0 12px white,
0 0 16px white,
0 0 20px white;
}
.starship {
height: 3%;
aspect-ratio: 1;
position: fixed;
z-index: 3;
background-image: linear-gradient(-45deg, #002fff, #9fff00);
}
.coin {
height: 3em;
width: 3em;
position: fixed;
z-index: 3;
background-color: gold;
border-radius: 100%;
transform: translate(-50%, -50%);
text-align: center;
}
.score-display {
position: fixed;
bottom: 0;
left: 0;
z-index: 2;
color: white;
}
@keyframes blast {
0% {
box-shadow:
1px 1px 1px #ffffff,
3px 3px 3px #ffff00,
5px 5px 5px #ff7f00,
7px 7px 7px #ff0000;
}
50% {
box-shadow:
3px 3px 3px #ffffff,
5px 5px 5px #ffff00,
7px 7px 7px #ff7f00,
9px 9px 9px #ff0000;
}
100% {
box-shadow:
1px 1px 1px #ffffff,
3px 3px 3px #ffff00,
5px 5px 5px #ff7f00,
7px 7px 7px #ff0000;
}
}
.starship.blasting {
animation-name: blast;
animation-duration: 250ms;
animation-iteration-count: infinite;
}
.starship.blasting.paused {
animation: none;
}
.pause-banner {
color: white;
position: fixed;
inset: 0;
text-align: center;
align-content: center;
font-size: 8em;
}
div.droplet {
background-color: hsl(260deg 60% 85% / 0.19);
position: fixed;
border-radius: 100%;
}
</style>
</head>
<body>
<div class="starship" style="transform: rotate(45deg)"></div>
<div class="coin">$$$<br>100</div>
<div class="score-display">Score: 0</div>
<script>
const styleSheetCssRules = [
...[...document.styleSheets].find(
(e) => e.title === "gravity-munchkin-style",
).cssRules,
];
const mySpikyDivStyle = styleSheetCssRules.find(
(e) => e.selectorText === "div.my-spiky-div",
).style;
const dropletStyle = styleSheetCssRules.find(
(e) => e.selectorText === "div.droplet",
).style;
const h1Style = styleSheetCssRules.find(
(e) => e.selectorText === "h1",
).style;
let seed;
const locationUrl = new URL(location);
const searchSeed = locationUrl.searchParams.get("s");
if (searchSeed) {
seed = Number.parseInt(searchSeed, 36);
}
if (!seed) {
seed = crypto.getRandomValues(new Uint32Array(1))[0];
}
// I copied this rng from here: https://github.com/michaeldzjap/rand-seed/blob/master/src/Algorithms/Mulberry32.ts
const rng = ((a) => () => {
a += 0x6d2b79f5;
let t = a;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
})(seed);
locationUrl.searchParams.set("s", seed.toString(36));
history.replaceState("", "", locationUrl);
const styleElement = (e, ...kv) => {
kv.forEach(([k, v]) => {
e.style.setProperty(k, v);
});
};
const a = (n, c) => new Array(n).fill().map(c);
const domDrop = (e) => e.parentElement.removeChild(e);
const makeDiv = (c) => () => {
const d = document.createElement("div");
d.classList.add(c);
return d;
};
const polarCoordToPercent = (theta, r) => {
const cos = Math.cos(theta);
const sin = Math.sin(theta);
return [
`${Math.round(50 + 50 * cos * r)}%`,
`${Math.round(50 + 50 * sin * r)}%`,
];
};
const spikyClipPath = (spikes, r) =>
a(spikes * 2, (_, i) =>
polarCoordToPercent(
(i * 2 * Math.PI) / (2 * spikes),
i % 2 ? 1 - r : r,
).join(" "),
).join(", ");
const pick = (a) => a[Math.floor(rng() * a.length)];
const adj = [
"Adorable",
"Baffling",
"Benthic",
"Brainy",
"Brilliant",
"Briny",
"Bustling",
"Cosmic",
"Creepy",
"Dazzling",
"Deep",
"Eerie",
"Excellent",
"Excessive",
"Extreme",
"Fetid",
"Foggy",
"Galactic",
"Gloomy",
"Grassy",
"Honorable",
"Hot",
"Infernal",
"Jocular",
"Kinetic",
"Liminal",
"Muddy",
"Nebulous",
"Occupied",
"Peaceful",
"Pleasant",
"Quantum",
"Rancid",
"Scorching",
"Shadowy",
"Spooky",
"Steamy",
"Stellar",
"Sunny",
"Timorous",
"Tumbling",
"Universal",
"Vast",
"Venomous",
"Volcanic",
"Western",
"Wretched",
"Yellow",
"Zealous",
];
const name = [
"Abyss",
"Alien",
"Alley",
"Barn",
"Bazaar",
"Bog",
"Boot",
"Brain",
"Brook",
"Castle",
"Chemist",
"College",
"Compass",
"Cottage",
"Country",
"Countryside",
"Court",
"Crab",
"Creek",
"Current",
"Deer",
"Dolphin",
"Draco",
"Druid",
"Eel",
"Egg",
"Elephant",
"Farm",
"Fissure",
"Flower",
"Forest",
"Goof",
"Guano",
"Havona",
"Hill",
"Hole",
"House",
"Immortal",
"Jacket",
"Jug",
"Keyboard",
"Kilo",
"Lobster",
"Mall",
"Meadow",
"Mesa",
"Meteor",
"Moat",
"Monster",
"Moon",
"Nation",
"Ninja",
"Ocean",
"Orbit",
"Palace",
"Path",
"Plain",
"Planet",
"Plateau",
"Pony",
"Pool",
"Port",
"Prison",
"Psycho",
"Python",
"Quagmire",
"Quasar",
"Rainbow",
"Ray",
"Resort",
"Retreat",
"Ring",
"River",
"Ruin",
"School",
"Ship",
"Shoe",
"Shuttle",
"Side",
"Sketch",
"Skunk",
"Snake",
"Splendid",
"State",
"Stream",
"Sun",
"Swamp",
"Sweater",
"Tower",
"Trail",
"Tree",
"Tub",
"Universe",
"University",
"Violin",
"Wall",
"Youth",
"Zebra",
];
const suff = [
"-city",
"bad",
"bert",
"bin",
"burg",
"burger",
"fix",
"gor",
"ings",
"ist",
"istan",
"lick",
"meade",
"mer",
"nip",
"side",
"stein",
"ton",
"town",
"ville",
];
const randName = () => `${pick(adj)} ${pick(name)}${pick(suff)}`;
const randN = () => Math.floor(rng() * rng() * 7);
const randSize = () =>
(rng() + rng()) * (1 / 2) * (5.6 * 3 - 1 / 3) + 1 / 3;
const randRGB = () =>
Math.floor(0xff - rng() * rng() * 0xbf)
.toString(16)
.padStart(2, "0")
.toLocaleUpperCase();
const randDarkRGB = () =>
Math.floor(rng() * rng() * 0x5f)
.toString(16)
.padStart(2, "0")
.toLocaleUpperCase();
const randColor = () => `#${randRGB()}${randRGB()}${randRGB()}`;
const randCoord = () => Math.floor(rng() * 94 + 3);
const systems = a(11, () => {
const starMaxSize = rng() * 6 + 2;
const starHue = rng() * 360;
return a(11, () => ({
name: randName(),
bg: `#${randDarkRGB()}${randDarkRGB()}${randDarkRGB()}`,
planets: a(randN(), () => {
const s = randSize();
return {
size: s,
color: randColor(),
top: randCoord(),
left: randCoord(),
gravity: s / 5,
};
}),
pointsOfInterest: a(Math.floor(randN() / 3), () => ({
top: randCoord(),
left: randCoord(),
title: `${pick(name)} ${pick(name)}`,
})),
spaceWeather: {
wind: rng() * 2 * Math.PI,
intensity: rng() * 3.5 + 1,
},
stars: a(Math.round(rng() * rng() * 64 + 64), () => ({
size: rng() * starMaxSize,
left: rng() * 100,
top: rng() * 100,
background: `hsl(${starHue}deg, ${rng() * 100}%, ${rng() * 50 + 50}%`,
animdur: rng() * 60,
animdir: rng() > 0.5 ? "default" : "reverse",
})),
hasCoin: true,
}));
});
let paused = false;
const pauseBanner = document.createElement("div");
pauseBanner.textContent = "PAUSED";
pauseBanner.classList.add("pause-banner");
let planetDivs = [];
let planetGravities = [];
let heading;
let poi = [];
let droplets = [];
let starDivs = [];
let starRadii = [];
let starRising = [];
let starSpeed = [];
// Spawn the coin immediately when entering a new system.
// at a random location.
// this way, if the coin isn't gettable, they can just leave the system and reenter to find it again.
// also, it should help make it easy to see whether you've already collected a system's coin
// cause if it ain't there when you enter, you got it already.
// coins don't despawn; if they fly out of a system there's a chance they'll orbit their way back in
//
const coin = document.querySelector(".coin");
const coinControl = { vx: 0.0, vy: 0.0, present: true };
let coinCenterX, coinCenterY;
let spaceWeatherDir,
spaceWeatherPop,
spaceWeatherForce,
spaceWeatherSpeed,
spaceWeatherScale,
spaceWeatherTop,
spaceWeatherLeft,
spaceWeatherDistance,
spaceWeatherVert,
spaceWeatherHorz;
const setDropletDimensions = (droplet, i) => {
const height = spaceWeatherScale * (6 - 5.75 * spaceWeatherDistance[i]);
styleElement(
droplet,
["height", `${height}px`],
["width", `${height / 20}px`],
);
};
const system = [0, 0];
const savedSystem = locationUrl.searchParams.get("c");
if (savedSystem) {
const savedSystemCoords = savedSystem.match(/\d+/gim);
system[0] = savedSystemCoords[0];
system[1] = savedSystemCoords[1];
}
const loadSystem = function loadSystem() {
if (heading) domDrop(heading);
if (coinControl.present) domDrop(coin);
coinControl.present = false;
const [x, y] = system;
styleElement(document.body, ["background-color", systems[x][y].bg]);
heading = document.createElement("h1");
heading.appendChild(new Text(systems[x][y].name));
document.body.appendChild(heading);
planetDivs.forEach(domDrop);
planetDivs = a(systems[x][y].planets.length, makeDiv("planet"));
planetDivs.forEach((planet, i) => {
const { size, color, top, left } = systems[x][y].planets[i];
styleElement(
planet,
["height", `${size}%`],
["background-color", color],
["top", `${top}%`],
["left", `${left}%`],
);
document.body.appendChild(planet);
});
planetGravities = systems[x][y].planets.map((s, i) => {
return {
centerX: planetDivs[i].offsetLeft,
centerY: planetDivs[i].offsetTop,
strength: s.gravity,
};
});
poi.forEach(domDrop);
poi = systems[x][y].pointsOfInterest.map((p) => {
const pointOfInterest = document.createElement("h2");
styleElement(
pointOfInterest,
["top", `${p.top}%`],
["left", `${p.left}%`],
);
pointOfInterest.appendChild(new Text(p.title));
document.body.appendChild(pointOfInterest);
return pointOfInterest;
});
spaceWeatherDir = systems[x][y].spaceWeather.wind;
dropletStyle.setProperty("transform", `rotate(${spaceWeatherDir}rad)`);
spaceWeatherPop = Math.round(systems[x][y].spaceWeather.intensity * 32);
spaceWeatherForce = systems[x][y].spaceWeather.intensity * 1.3;
spaceWeatherSpeed = Math.round(spaceWeatherForce);
spaceWeatherScale = Math.round(systems[x][y].spaceWeather.intensity * 4);
spaceWeatherTop = a(spaceWeatherPop, () => {
return rng() * window.innerHeight;
});
spaceWeatherLeft = a(spaceWeatherPop, () => {
return rng() * window.innerWidth;
});
spaceWeatherDistance = a(spaceWeatherPop, () => {
return rng();
});
droplets.forEach(domDrop);
droplets = a(spaceWeatherPop, makeDiv("droplet"));
droplets.forEach((droplet, i) => {
styleElement(
droplet,
["left", `${spaceWeatherLeft[i]}px`],
["top", `${spaceWeatherTop[i]}px`],
);
setDropletDimensions(droplet, i);
document.body.appendChild(droplet);
});
spaceWeatherVert = Math.cos(spaceWeatherDir);
spaceWeatherHorz = Math.sin(spaceWeatherDir);
starDivs.forEach(domDrop);
const starCount = systems[x][y].stars.length;
starDivs = a(starCount, makeDiv("my-spiky-div"));
starDivs.forEach((div, i) => {
const { size, left, top, background, animdur, animdir } =
systems[x][y].stars[i];
styleElement(
div,
["width", `${size}vh`],
["height", `${size}vh`],
["left", `${left}vw`],
["top", `${top}vh`],
["background", background],
["animation-duration", `${animdur}s`],
["animation-direction", animdir],
);
document.body.appendChild(div);
});
starRadii = a(starCount, () => 0);
starRising = a(starCount, () => true);
starSpeed = a(starCount, () => rng() * 0.02);
if (systems[x][y].hasCoin) {
document.body.appendChild(coin);
coinCenterX = rng() * (window.innerWidth / 2) + window.innerWidth / 4;
coinCenterY = rng() * (window.innerHeight / 2) + window.innerWidth / 4;
coinControl.vx = 0.0;
coinControl.vy = 0.0;
coinControl.present = true;
}
locationUrl.searchParams.set("c", `${x},${y}`);
history.replaceState("", "", locationUrl);
};
const starshipControl = { vx: 0.0, vy: 2.5 };
const starship = document.querySelector(".starship");
let starshipCenterX = 200;
let starshipCenterY = 400;
let starshipHeading = 0;
let starshipThrust = 0;
let starshipRotation = 0;
let score = 0;
const scoreDisplay = document.querySelector(".score-display");
const accelerate = () => {
planetGravities.forEach(({ centerX, centerY, strength }) => {
const xToPlanet = centerX - starshipCenterX;
const yToPlanet = centerY - starshipCenterY;
const distToPlanet = (xToPlanet ** 2 + yToPlanet ** 2) ** (1 / 2);
starshipControl.vx +=
(strength * (xToPlanet / distToPlanet ** 1.2)) / 15;
starshipControl.vy +=
(strength * (yToPlanet / distToPlanet ** 1.2)) / 15;
});
starshipControl.vx -= (spaceWeatherHorz * spaceWeatherForce) / 80;
starshipControl.vy += (spaceWeatherVert * spaceWeatherForce) / 80;
starshipHeading += starshipRotation * 3;
starshipThrustX =
Math.sin((starshipHeading * Math.PI) / 180) * starshipThrust;
starshipThrustY =
-Math.cos((starshipHeading * Math.PI) / 180) * starshipThrust;
starshipControl.vx += starshipThrustX / 12;
starshipControl.vy += starshipThrustY / 12;
starshipCenterX += starshipControl.vx;
starshipCenterY += starshipControl.vy;
if (coinControl.present) {
const coinXToShip = starshipCenterX - coinCenterX;
const coinYToShip = starshipCenterY - coinCenterY;
const distToShip = (coinXToShip ** 2 + coinYToShip ** 2) ** (1 / 2);
if (distToShip < 30) {
domDrop(coin);
coinControl.present = false;
systems[system[0]][system[1]].hasCoin = false;
score += 100;
scoreDisplay.textContent = `Score: ${score}`;
} else {
planetGravities.forEach(({ centerX, centerY, strength }) => {
const coinXToPlanet = centerX - coinCenterX;
const coinYToPlanet = centerY - coinCenterY;
const coinDistToPlanet =
(coinXToPlanet ** 2 + coinYToPlanet ** 2) ** (1 / 2);
coinControl.vx +=
(strength * (coinXToPlanet / coinDistToPlanet ** 1.2)) / 15;
coinControl.vy +=
(strength * (coinYToPlanet / coinDistToPlanet ** 1.2)) / 15;
});
coinControl.vx -= (spaceWeatherHorz * spaceWeatherForce) / 80;
coinControl.vy += (spaceWeatherVert * spaceWeatherForce) / 80;
coinCenterX += coinControl.vx;
coinCenterY += coinControl.vy;
}
}
if (starshipCenterX < 0) {
system[0]--;
system[0] += systems.length;
system[0] %= systems.length;
loadSystem();
starshipCenterX += window.innerWidth;
} else if (starshipCenterX > window.innerWidth) {
system[0]++;
system[0] %= systems.length;
loadSystem();
starshipCenterX -= window.innerWidth;
}
if (starshipCenterY < 0) {
system[1]--;
system[1] += systems[0].length;
system[1] %= systems[0].length;
loadSystem();
starshipCenterY += window.innerHeight;
} else if (starshipCenterY > window.innerHeight) {
system[1]++;
system[1] %= systems[0].length;
loadSystem();
starshipCenterY -= window.innerHeight;
}
styleElement(
starship,
["top", `${starshipCenterY}px`],
["left", `${starshipCenterX}px`],
["transform", `rotate(${45 + starshipHeading}deg)`],
);
styleElement(
coin,
["top", `${coinCenterY}px`],
["left", `${coinCenterX}px`],
);
for (let i = 0; i < spaceWeatherTop.length; i++) {
spaceWeatherTop[i] +=
spaceWeatherVert *
spaceWeatherSpeed *
(6 - 5.75 * spaceWeatherDistance[i]);
}
for (let i = 0; i < spaceWeatherTop.length; i++) {
spaceWeatherLeft[i] -=
spaceWeatherHorz *
spaceWeatherSpeed *
(6 - 5.75 * spaceWeatherDistance[i]);
}
for (let i = 0; i < spaceWeatherTop.length; i++) {
if (spaceWeatherTop[i] > window.innerHeight + 100) {
spaceWeatherTop[i] -= window.innerHeight + 200;
} else if (spaceWeatherTop[i] < -100) {
spaceWeatherTop[i] += window.innerHeight + 200;
} else if (spaceWeatherLeft[i] > window.innerWidth + 100) {
spaceWeatherLeft[i] -= window.innerWidth + 200;
} else if (spaceWeatherLeft[i] < -100) {
spaceWeatherLeft[i] += window.innerWidth + 200;
}
}
for (let i = 0; i < droplets.length; i++) {
styleElement(
droplets[i],
["top", `${spaceWeatherTop[i]}px`],
["left", `${spaceWeatherLeft[i]}px`],
);
}
starDivs.forEach((div, i) => {
if (starRadii[i] >= 1.0) {
starRising[i] = false;
} else if (starRadii[i] <= 0.0) {
starRising[i] = true;
}
if (starRising[i]) {
starRadii[i] += starSpeed[i];
} else {
starRadii[i] -= starSpeed[i];
}
styleElement(div, [
"clip-path",
`polygon(${spikyClipPath(5, starRadii[i])})`,
]);
});
if (!paused) {
requestAnimationFrame(accelerate);
}
};
document.addEventListener("keydown", ({ code }) => {
if (code === "ArrowUp" || code === "KeyW") {
starshipThrust = 1.0;
starship.classList.add("blasting");
} else if (code === "ArrowLeft" || code === "KeyA") {
starshipRotation = -2.0;
} else if (code === "ArrowRight" || code === "KeyD") {
starshipRotation = 2.0;
}
});
document.addEventListener("keyup", ({ code }) => {
if (code === "ArrowUp" || code === "KeyW") {
starshipThrust = 0.0;
starship.classList.remove("blasting");
} else if (code === "ArrowLeft" || code === "KeyA") {
starshipRotation = 0.0;
} else if (code === "ArrowRight" || code === "KeyD") {
starshipRotation = 0.0;
} else if (code === "KeyP") {
if (paused) {
paused = false;
domDrop(pauseBanner);
requestAnimationFrame(accelerate);
starship.classList.remove("paused");
mySpikyDivStyle.setProperty("animation-play-state", "running");
h1Style.setProperty("animation-play-state", "running");
} else {
paused = true;
document.body.appendChild(pauseBanner);
starship.classList.add("paused");
mySpikyDivStyle.setProperty("animation-play-state", "paused");
h1Style.setProperty("animation-play-state", "paused");
}
}
});
loadSystem();
requestAnimationFrame(accelerate);
</script>
</body>
</html>
Here are some old music files from around 2011. I think they're probably terrible. (I haven't played them back myself)
(Actually I removed most of the files because only one was asked for in the assignment requirements)
(Actually actually the assignment was accepted. Hooray! So, I have added the rest of the files back in
Here is a video clip from a terminal animation I made about a month ago.
Here I have pasted the source code for the terminal animation:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
struct line {
int start;
int len;
};
void interrupt_handler(int signo, siginfo_t *info, void *context) {
// TODO: print a number of newlines equal to the number of lines in the input
printf("\e[?25h\n");
exit(EXIT_SUCCESS);
}
void box_marquee_frame(char *buf, char *input, int frame, int line_count, struct line *line_starts, int longest_line) {
int height, i, j, offset, idx;
char *boxp, *start, *end, *middle;
height = 2 + line_count;
frame %= longest_line;
boxp = buf;
for (i = 0; i < height; i++) {
if (i == 0) {
start = " ";
end = " \n";
middle = "_";
} else if (i == 1) {
start = " /";
end = "\\ \n";
middle = NULL;
} else if (i == height - 1) {
start = " \\";
end = "/ \n";
middle = "_";
} else {
start = "| ";
end = " |\n";
middle = NULL;
}
boxp = mempcpy(boxp, start, 2);
if (middle == NULL) {
middle = " ";
for (j = 0; j < longest_line; j++) {
offset = ((frame + j) % longest_line);
idx = line_starts[i - 1].start + offset;
if (*(input + idx) == '\n' || offset >= line_starts[i - 1].len) {
boxp = mempcpy(boxp, middle, 1);
} else {
boxp = mempcpy(boxp, input + idx, 1);
}
}
} else {
for (j = 0; j < longest_line; j++) {
boxp = mempcpy(boxp, middle, 1);
}
}
boxp = mempcpy(boxp, end, 3);
}
*boxp = '\0';
}
void rainbow_frame(char *buf, char *input, int frame) {
int inputlen, chunk, lastchunk, i, j;
char *bufp;
char rainbow[6][5] = {
"\e[31m", // red
"\e[33m", // brown
"\e[32m", // green
"\e[34m", // blue
"\e[36m", // cyan
"\e[35m" // magenta
};
char reset[4] = "\e[0m";
bufp = buf;
inputlen = strlen(input);
if (inputlen < 6) {
frame %= 6;
for (i = 0; i < inputlen; i++) {
bufp = mempcpy(bufp, rainbow[((5 - i) + frame) % 6], 5);
bufp = mempcpy(bufp, input + i, 1);
}
} else {
frame %= inputlen;
for (i = 0; i < 6; i++) {
chunk = inputlen / 6;
if (i == 1) chunk += inputlen % 6;
if (frame + chunk >= inputlen) break;
frame += chunk;
}
lastchunk = inputlen - frame;
bufp = mempcpy(bufp, rainbow[i], 5);
frame = chunk - lastchunk;
bufp = mempcpy(bufp, input, frame);
for (j = 1; j < 6; j++) {
chunk = inputlen / 6;
if ((i + j) % 6 == 1) chunk += inputlen % 6;
bufp = mempcpy(bufp, rainbow[(i + j) % 6], 5);
bufp = mempcpy(bufp, input + frame, chunk);
frame += chunk;
}
bufp = mempcpy(bufp, rainbow[i], 5);
bufp = mempcpy(bufp, input + frame, lastchunk);
}
bufp = mempcpy(bufp, reset, 4);
*bufp = '\0';
}
int main(int argc, char *argv[]) {
int inputlen, frameskip, frames, seconds, lines, longest_line, i, j;
char *rainbowbuf, *boxbuf;
struct sigaction act = { 0 };
struct timespec rainbowtime = { 0, 999999999 };
long boxdraw_delay;
long boxtime = 999999999;
struct line *line_starts;
if (argc < 2) exit(EXIT_FAILURE);
inputlen = strlen(argv[1]);
if (inputlen < 1) exit(EXIT_FAILURE);
lines = 1;
for (i = 0; i < inputlen; i++) {
if (argv[1][i] == '\n') lines++;
}
line_starts = (struct line *) calloc(lines, sizeof(struct line));
line_starts[0].start = 0;
for (i = 0, j = 1; i < inputlen; i++) {
if (argv[1][i] == '\n') line_starts[j++].start = i + 1;
}
longest_line = 0;
for (i = 1; i < lines; i++) {
line_starts[i - 1].len = line_starts[i].start - line_starts[i - 1].start;
if (line_starts[i - 1].len > longest_line) {
longest_line = line_starts[i - 1].len;
}
}
if (lines == 1) {
line_starts[0].len = inputlen;
longest_line = inputlen;
} else {
line_starts[lines - 1].len = inputlen - line_starts[lines - 1].start;
if (line_starts[lines - 1].len > longest_line) {
longest_line = line_starts[lines - 1].len;
}
}
frameskip = 1 + (inputlen / 175);
frames = inputlen / frameskip;
if (inputlen < 6) frames = 6;
rainbowtime.tv_nsec /= frames;
boxtime /= 12;
seconds = 4;
if (argc > 2) seconds = atoi(argv[2]);
frames *= seconds;
boxbuf = (char *) calloc((4 + inputlen) * 5, sizeof(char));
rainbowbuf = (char *) calloc(( 4 + inputlen) * 5 + 42, sizeof(char));
printf("\e[?25l");
boxdraw_delay = 0;
j = 0;
act.sa_sigaction = &interrupt_handler;
sigaction(SIGINT, &act, NULL);
for (i = 0; i < frames; i++) {
if (boxdraw_delay <= 0) {
box_marquee_frame(boxbuf, argv[1], j, lines, line_starts, longest_line);
boxdraw_delay += boxtime;
j++;
}
rainbow_frame(rainbowbuf, boxbuf, i * frameskip);
printf("%s\n", rainbowbuf);
nanosleep(&rainbowtime, NULL);
boxdraw_delay -= rainbowtime.tv_nsec;
printf("\e[%dA", 3 + lines);
}
printf("\e[?25h");
free(boxbuf);
free(rainbowbuf);
free(line_starts);
for (i = 0; i < 3 + lines; i++) printf("\n");
exit(EXIT_SUCCESS);
}
Here is the contact form that was asked for in the assignment rubrik!
It won't actually save any data submitted; it sends it to zybooks and shows what was sent, so you can try it out! But I don't think there is any good reason to send any actual personal information over to zybooks... (maybe just try some fake information idk)