changing frameworks
This commit is contained in:
26
nginx/vue/src/App.vue
Normal file
26
nginx/vue/src/App.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script setup>
|
||||
import { RouterLink, RouterView } from "vue-router";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<img
|
||||
alt="Vue logo"
|
||||
class="logo"
|
||||
src="@/assets/logo.svg"
|
||||
width="125"
|
||||
height="125"
|
||||
/>
|
||||
|
||||
<div class="wrapper">
|
||||
<nav>
|
||||
<RouterLink to="/">Home</RouterLink>
|
||||
<RouterLink to="/about">About</RouterLink>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
347
nginx/vue/src/js/mobile-automata.mjs
Normal file
347
nginx/vue/src/js/mobile-automata.mjs
Normal file
@@ -0,0 +1,347 @@
|
||||
function integerDigits(n, b = 10, length = null) {
|
||||
// Get the list of digits in base b
|
||||
const digits = [];
|
||||
while (n > 0) {
|
||||
digits.push(n % b);
|
||||
n = Math.floor(n / b);
|
||||
}
|
||||
digits.reverse(); // Reverse the list to get digits in big endian order
|
||||
|
||||
// Pad with zeros if length is specified
|
||||
if (length !== null) {
|
||||
const padding = Array(Math.max(0, length - digits.length)).fill(0);
|
||||
return padding.concat(digits);
|
||||
}
|
||||
|
||||
return digits;
|
||||
}
|
||||
|
||||
function* cartesianProduct(...arrays) {
|
||||
// Generator for cartesian product
|
||||
if (arrays.length === 0) {
|
||||
yield [];
|
||||
return;
|
||||
}
|
||||
|
||||
const [first, ...rest] = arrays;
|
||||
if (rest.length === 0) {
|
||||
for (const item of first) {
|
||||
yield [item];
|
||||
}
|
||||
} else {
|
||||
for (const item of first) {
|
||||
for (const combo of cartesianProduct(...rest)) {
|
||||
yield [item, ...combo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tuplesFromList(lst, n) {
|
||||
const arrays = Array(n).fill(lst);
|
||||
return Array.from(cartesianProduct(...arrays));
|
||||
}
|
||||
|
||||
function tuplesFromMultipleLists(...lists) {
|
||||
return Array.from(cartesianProduct(...lists));
|
||||
}
|
||||
|
||||
function flattenTuples(tuples) {
|
||||
return tuples.flat();
|
||||
}
|
||||
|
||||
function partition(lst, n) {
|
||||
const result = [];
|
||||
for (let i = 0; i < lst.length; i += n) {
|
||||
result.push(lst.slice(i, i + n));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function pick(pickList, lst) {
|
||||
const trues = [];
|
||||
const falses = [];
|
||||
for (let i = 0; i < pickList.length; i++) {
|
||||
if (pickList[i]) {
|
||||
trues.push(lst[i]);
|
||||
} else {
|
||||
falses.push(lst[i]);
|
||||
}
|
||||
}
|
||||
return [trues, falses];
|
||||
}
|
||||
|
||||
function factorial(n) {
|
||||
if (n < 0) return NaN;
|
||||
if (n === 0 || n === 1) return 1;
|
||||
let result = 1;
|
||||
for (let i = 2; i <= n; i++) {
|
||||
result *= i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function unrankPermutation(r, lst) {
|
||||
const n = lst.length;
|
||||
r -= 1; // Convert r to 0-indexed
|
||||
const permutation = [];
|
||||
const availableElements = [...lst];
|
||||
|
||||
for (let i = n; i > 0; i--) {
|
||||
const fact = factorial(i - 1); // (n-1)!
|
||||
const index = Math.floor(r / fact); // Find the index of the current element
|
||||
permutation.push(availableElements.splice(index, 1)[0]); // Add the element and remove it from available
|
||||
r %= fact; // Update r to find the next element
|
||||
}
|
||||
return permutation;
|
||||
}
|
||||
|
||||
export function toMaRule(sn, dn, n, k) {
|
||||
if (n < 1 || n % 2 === 0) {
|
||||
throw new Error("n must be >= 1 and odd");
|
||||
}
|
||||
|
||||
const inputs = tuplesFromList([...Array(k).keys()], n);
|
||||
const directions = integerDigits(dn, 2, Math.pow(k, n)).map((x) =>
|
||||
Math.pow(-1, x),
|
||||
);
|
||||
const snDigits = integerDigits(sn, k, n * Math.pow(k, n));
|
||||
const outputs = partition(snDigits, n);
|
||||
|
||||
const rules = {};
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
rules[JSON.stringify(inputs[i])] = [outputs[i], directions[i]];
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
export function toReversibleMaRule(bn, pn, n, k) {
|
||||
if (n < 1 || n % 2 === 0) {
|
||||
throw new Error("n must be >= 1 and odd");
|
||||
}
|
||||
|
||||
const inputs = tuplesFromList([...Array(k).keys()], n);
|
||||
const blockers = tuplesFromList([...Array(k).keys()], n - 2);
|
||||
const blockSelect = pick(integerDigits(bn, 2, Math.pow(k, n - 2)), blockers);
|
||||
const rightBlockers = blockSelect[0];
|
||||
const leftBlockers = blockSelect[1];
|
||||
|
||||
const twoFair = tuplesFromList([...Array(k).keys()], 2);
|
||||
const leftOutputs = tuplesFromMultipleLists(leftBlockers, twoFair).map(
|
||||
(x) => [flattenTuples(x), -1],
|
||||
);
|
||||
const rightOutputs = tuplesFromMultipleLists(twoFair, rightBlockers).map(
|
||||
(x) => [flattenTuples(x), 1],
|
||||
);
|
||||
|
||||
const outputs = [...leftOutputs, ...rightOutputs];
|
||||
const rankedOutputs = unrankPermutation(pn, outputs);
|
||||
|
||||
const rules = {};
|
||||
for (let i = 0; i < inputs.length; i++) {
|
||||
rules[JSON.stringify(inputs[i])] = rankedOutputs[i];
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
export function maStep(rules, state, r) {
|
||||
/**
|
||||
* Apply one step of the mobile automaton rules
|
||||
*
|
||||
* Args:
|
||||
* rules (object): Dictionary of rules where key is input tuple and value is [output_tuple, direction]
|
||||
* state (array): [list, head] where list is current state and head is current position
|
||||
* r (number): Radius of the neighborhood (window size = 2r + 1)
|
||||
*
|
||||
* Returns:
|
||||
* array: [new_list, new_head] or [[], -1] if out of bounds
|
||||
*/
|
||||
const [currentList, head] = state;
|
||||
|
||||
// Check bounds
|
||||
if (head - r <= 0 || head + r >= currentList.length) {
|
||||
return [[], -1];
|
||||
}
|
||||
|
||||
// Get the window of elements centered at head
|
||||
const window = currentList.slice(head - r, head + r + 1);
|
||||
|
||||
// Apply rule
|
||||
const ruleKey = JSON.stringify(window);
|
||||
const [newWindow, direction] = rules[ruleKey];
|
||||
|
||||
// Create new list with replaced elements
|
||||
const newList = [...currentList];
|
||||
for (let i = 0; i < newWindow.length; i++) {
|
||||
newList[head - r + i] = newWindow[i];
|
||||
}
|
||||
|
||||
return [newList, head + direction];
|
||||
}
|
||||
|
||||
export function ma(rules, initialState, t) {
|
||||
/**
|
||||
* Perform t steps of the mobile automaton
|
||||
*
|
||||
* Args:
|
||||
* rules (object): Dictionary of rules
|
||||
* initialState (array): Initial [list, head] state
|
||||
* t (number): Number of steps to perform
|
||||
*
|
||||
* Returns:
|
||||
* array: List of states at each time step
|
||||
*/
|
||||
// Calculate radius from first rule key length
|
||||
const firstKey = Object.keys(rules)[0];
|
||||
const r = JSON.parse(firstKey).length / 2;
|
||||
|
||||
const states = [initialState];
|
||||
let currentState = initialState;
|
||||
|
||||
for (let i = 0; i < t; i++) {
|
||||
currentState = maStep(rules, currentState, r);
|
||||
states.push(currentState);
|
||||
|
||||
// Stop if we hit an invalid state
|
||||
if (currentState[0].length === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
export function cyclicMaStep(rules, state, r) {
|
||||
/**
|
||||
* Cyclic version: indexing wraps around the array.
|
||||
*/
|
||||
const [currentList, head] = state;
|
||||
const n = currentList.length;
|
||||
|
||||
// --- Cyclic window extraction ---
|
||||
const window = [];
|
||||
for (let i = -r; i <= r; i++) {
|
||||
window.push(currentList[(head + i + n) % n]);
|
||||
}
|
||||
|
||||
// Apply rule
|
||||
const ruleKey = JSON.stringify(window);
|
||||
const [newWindow, direction] = rules[ruleKey];
|
||||
|
||||
// --- Cyclic writeback ---
|
||||
const newList = [...currentList];
|
||||
for (let offset = 0; offset < newWindow.length; offset++) {
|
||||
newList[(head - r + offset + n) % n] = newWindow[offset];
|
||||
}
|
||||
|
||||
// Move head cyclically
|
||||
const newHead = (head + direction + n) % n;
|
||||
return [newList, newHead];
|
||||
}
|
||||
|
||||
export function cyclicMa(rules, initialState, t) {
|
||||
/**
|
||||
* Perform t steps of the mobile automaton
|
||||
*
|
||||
* Args:
|
||||
* rules (object): Dictionary of rules
|
||||
* initialState (array): Initial [list, head] state
|
||||
* t (number): Number of steps to perform
|
||||
*
|
||||
* Returns:
|
||||
* array: List of states at each time step
|
||||
*/
|
||||
// Calculate radius from first rule key length
|
||||
const firstKey = Object.keys(rules)[0];
|
||||
const r = JSON.parse(firstKey).length / 2;
|
||||
|
||||
const states = [initialState];
|
||||
let currentState = initialState;
|
||||
|
||||
for (let i = 0; i < t; i++) {
|
||||
currentState = cyclicMaStep(rules, currentState, r);
|
||||
states.push(currentState);
|
||||
|
||||
// Stop if we hit an invalid state
|
||||
if (currentState[0].length === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
// export function renderToCanvas(canvas, width, height) {
|
||||
// let states = Array.from({ length: height }, () =>
|
||||
// Array.from({ length: width }, () => Math.round(Math.random() + 0.4)),
|
||||
// );
|
||||
// }
|
||||
|
||||
export function renderMaToCanvas(canvas, width, height, sn = 0, dn = 0) {
|
||||
if (sn == 0) {
|
||||
const min = 1500000;
|
||||
const max = 2000000;
|
||||
sn = Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
if (dn == 0) {
|
||||
const min = 100;
|
||||
const max = 200;
|
||||
dn = Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
const r = 1;
|
||||
const n = 2 * r + 1;
|
||||
const rules = toMaRule(sn, dn, n, 2);
|
||||
let states = Array.from({ length: height }, () =>
|
||||
Array.from({ length: width }, () => Math.round(Math.random() + 0.4)),
|
||||
);
|
||||
let head = Math.floor(width / 2) % width;
|
||||
let row_num = 0;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
const img = ctx.createImageData(width, height);
|
||||
const data = img.data;
|
||||
|
||||
const colorOn = [10, 60, 130]; // dark blue (active cell)
|
||||
const colorOff = [10, 70, 110]; // darker blue (inactive cell)
|
||||
|
||||
for (let y = 0; y < height; y++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
const idx = (y * width + x) * 4;
|
||||
const color = states[y][x] ? colorOn : colorOff;
|
||||
|
||||
data[idx] = color[0]; // R
|
||||
data[idx + 1] = color[1]; // G
|
||||
data[idx + 2] = color[2]; // B
|
||||
data[idx + 3] = 255; // A
|
||||
}
|
||||
}
|
||||
|
||||
ctx.putImageData(img, 0, 0);
|
||||
|
||||
function step() {
|
||||
// calculate new state
|
||||
let [newState, newHead] = cyclicMaStep(rules, [states[row_num], head], r);
|
||||
states[row_num] = newState;
|
||||
|
||||
// write changed cells to ImageData
|
||||
for (let x = head - r; x <= head + r; x++) {
|
||||
const idx = (row_num * width + x) * 4;
|
||||
const val = newState[x] ? colorOn : colorOff;
|
||||
data[idx] = val[0]; // R
|
||||
data[idx + 1] = val[1]; // G
|
||||
data[idx + 2] = val[2]; // B
|
||||
data[idx + 3] = 255; // A
|
||||
}
|
||||
|
||||
// update canvas (only this row)
|
||||
ctx.putImageData(img, head - r, row_num, 0, 0, n, 1);
|
||||
|
||||
// advance row and head
|
||||
row_num = (row_num + 1) % height;
|
||||
head = newHead;
|
||||
|
||||
requestAnimationFrame(step);
|
||||
}
|
||||
|
||||
requestAnimationFrame(step);
|
||||
}
|
||||
11
nginx/vue/src/main.js
Normal file
11
nginx/vue/src/main.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import "./assets/main.css";
|
||||
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(router);
|
||||
|
||||
app.mount("#app");
|
||||
23
nginx/vue/src/router/index.js
Normal file
23
nginx/vue/src/router/index.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import Home from "../views/Home.vue";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
component: Home,
|
||||
},
|
||||
{
|
||||
path: "/cv",
|
||||
name: "cv",
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (About.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import("../views/CV.vue"),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export default router;
|
||||
359
nginx/vue/src/views/CV.vue
Normal file
359
nginx/vue/src/views/CV.vue
Normal file
@@ -0,0 +1,359 @@
|
||||
<template>
|
||||
<div>
|
||||
<RouterLink class="no-print" to="/">Home</RouterLink>
|
||||
|
||||
<div
|
||||
class="no-print"
|
||||
style="width: 100%; text-align: center; margin: 20px 0"
|
||||
>
|
||||
<h1>Page 1</h1>
|
||||
</div>
|
||||
|
||||
<div class="a4page">
|
||||
<div class="contact">
|
||||
<h1>Adam French</h1>
|
||||
<!-- <a href="covers.html"><img width=25 height=50 src="img/rune.png"></a> -->
|
||||
<div class="contact-details">
|
||||
<p>+447563266931</p>
|
||||
<p>adam.a.french@outlook.com</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Profile</h2>
|
||||
<p>
|
||||
Passionate about developing robust, efficient software with a
|
||||
strong focus on maintainability, scalability, and long-term
|
||||
performance. I take pride in my ability to perform under
|
||||
pressure, adapt quickly, and contribute effectively in
|
||||
collaborative, fast-paced environments.
|
||||
</p>
|
||||
<p>
|
||||
My ideal role involves designing and building scalable systems
|
||||
that balance creativity with problem-solving. I aim to cultivate
|
||||
meaningful professional connections and contribute to projects
|
||||
that deliver a clear altruistic impact.
|
||||
</p>
|
||||
|
||||
<h2>Education</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Location</th>
|
||||
<th>Date</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>The University of Leeds</td>
|
||||
<td>
|
||||
<!-- <div style="display: flex; flex-direction: column; align-items: center;"> -->
|
||||
<!-- <span>2021</span> -->
|
||||
<!-- <span>to</span> -->
|
||||
<!-- <span>2025</span> -->
|
||||
<!-- </div> -->
|
||||
2021-2025
|
||||
</td>
|
||||
<td class="row-leftalign">
|
||||
<strong
|
||||
>BSc Computer Science with Mathematics
|
||||
(International)</strong
|
||||
><br />
|
||||
<strong
|
||||
>Average:
|
||||
81.1%           (First
|
||||
Class Honours) </strong
|
||||
><br />
|
||||
<strong>Relevant Courses: </strong>
|
||||
Procedural Programming, Object Oriented Programming,
|
||||
Algorithms and Data Structures I & II, Databases,
|
||||
Computer Processors, Compiler Design and
|
||||
Construction, Formal Languages and Finite Automata,
|
||||
Probability and Statistics I, Machine Learning,
|
||||
Graph Algorithms & Complexity Theory
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>The University of Waterloo</td>
|
||||
<td>
|
||||
<!-- <div style="display: flex; flex-direction: column; align-items: center;"> -->
|
||||
<!-- <span>2023</span> -->
|
||||
<!-- <span>to</span> -->
|
||||
<!-- <span>2024</span> -->
|
||||
<!-- </div> -->
|
||||
2023-2024
|
||||
</td>
|
||||
<td class="row-leftalign">
|
||||
<strong>Average: 74.5%</strong>
|
||||
<br />
|
||||
<strong>Relevant Courses:</strong>
|
||||
Applied Cryptography, Introduction to Computer
|
||||
Graphics, Introduction to Rings and Fields with
|
||||
Applications<br /><br />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Experience</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Role</th>
|
||||
<th>Location</th>
|
||||
<th>Date</th>
|
||||
<th>Duties</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Student</td>
|
||||
<td>Wolfram Summer School</td>
|
||||
<td>2024</td>
|
||||
<td class="row-leftalign">
|
||||
Designed and completed a time-constrained research
|
||||
project exploring Mobile Automata and conditions for
|
||||
computational reversibility. Communicated findings
|
||||
through visualizations and presentations.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bartender</td>
|
||||
<td>Belgrave Music Hall</td>
|
||||
<td>2022-2025</td>
|
||||
<td class="row-leftalign">
|
||||
Delivered heartfelt customer service in various
|
||||
fast-paced, high-pressure hospitality environments.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cashier Assistant</td>
|
||||
<td>To The Rise Bakery</td>
|
||||
<td>Summer 2022</td>
|
||||
<td class="row-leftalign">
|
||||
Prepared coffee, served customers, presented goods,
|
||||
cleaned bakery equipment, and made toasties.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Waiter</td>
|
||||
<td>BFI Bar and Kitchen</td>
|
||||
<td>Summer 2020</td>
|
||||
<td class="row-leftalign">
|
||||
Managed bookings, allocated tables, handled
|
||||
complaints, ran food and drinks, and maintained BOH
|
||||
cleanliness.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="no-print"
|
||||
style="width: 100%; text-align: center; margin: 20px 0"
|
||||
>
|
||||
<h1>Page 2</h1>
|
||||
</div>
|
||||
|
||||
<div class="a4page">
|
||||
<h2>Personal Projects</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Project</th>
|
||||
<th>Skills</th>
|
||||
<th>Date</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Mobile Automata</td>
|
||||
<td>Mathematica, JS, Logic, Analysis</td>
|
||||
<td>2024</td>
|
||||
<td class="row-leftalign">
|
||||
Designed experiments and analysis tools to identify
|
||||
pattern similarities among automata. Investigated
|
||||
computational properties by defining specific
|
||||
phenomena and observing emergent behaviors through
|
||||
custom simulations.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Computer Graphics</td>
|
||||
<td>Rust, Linear Algebra, Multi-threading</td>
|
||||
<td>2023</td>
|
||||
<td class="row-leftalign">
|
||||
Developed a multi-threaded, recursive ray tracer as
|
||||
part of a University of Waterloo project. Explored
|
||||
advanced ray-surface intersection techniques,
|
||||
including experimental rendering of
|
||||
higher-dimensional geometries.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Arduino Programming & Circuits</td>
|
||||
<td>C++, Soldering, Embedded Systems</td>
|
||||
<td>2022 - 2025</td>
|
||||
<td class="row-leftalign">
|
||||
Created room decorations using salvaged components
|
||||
from discarded electronics.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memory Palace Website</td>
|
||||
<td>TS, Rust, React, Redux, SQLite</td>
|
||||
<td>2025</td>
|
||||
<td class="row-leftalign">
|
||||
Full-stack web application implementing the “memory
|
||||
palace” memorization technique. Built with a
|
||||
React/Redux frontend, Rust-based Actix backend, and
|
||||
SQLite database.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Personal Websites</td>
|
||||
<td>HTML, JS, Design, UI/UX</td>
|
||||
<td>Ongoing</td>
|
||||
<td class="row-leftalign">
|
||||
Continuously evolving my personal site and designing
|
||||
other creative websites. Experimented with Svelte,
|
||||
Vue, and React/Redux using libraries such as P5 and
|
||||
Three.js.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3D Printing</td>
|
||||
<td>FreeCAD</td>
|
||||
<td>Ongoing</td>
|
||||
<td class="row-leftalign">
|
||||
Designing and manufacturing household objects and
|
||||
repairs, including replacement window handles, desk
|
||||
organizers, and 3D scans.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
|
||||
<h2>Commitments</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Activity</th>
|
||||
<th>Date</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Learning Mandarin</td>
|
||||
<td>Ongoing</td>
|
||||
<td class="row-leftalign">
|
||||
Aiming to complete HSK 3 proficiency exam by
|
||||
December 2026
|
||||
</td>
|
||||
</tr>
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Cybersecurity Training</td> -->
|
||||
<!-- <td>Ongoing</td> -->
|
||||
<!-- <td class="row-leftalign"> -->
|
||||
<!-- Using <em>pwn.college, tryhackme.com</em> to learn pentesting techniques.</td> -->
|
||||
<!-- </tr> -->
|
||||
<tr>
|
||||
<td>Sports Activities</td>
|
||||
<td>Ongoing</td>
|
||||
<td class="row-leftalign">
|
||||
Run weekly, active gym attendee, regularly go
|
||||
hiking.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Construction and Landscaping</td>
|
||||
<td>Ongoing</td>
|
||||
<td class="row-leftalign">
|
||||
Involved in building a house in Bulgaria.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>University of Waterloo Film Club</td>
|
||||
<td>2023-2024</td>
|
||||
<td class="row-leftalign">
|
||||
Worked on student films <em>“Moon King”</em> and
|
||||
<em>“HAM”</em>, available online.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Socratica</td>
|
||||
<td>2023-2024</td>
|
||||
<td class="row-leftalign">
|
||||
Worked with like-minded individuals exploring
|
||||
innovative tech.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>University of Leeds Hockey Club</td>
|
||||
<td>2022-2023</td>
|
||||
<td class="row-leftalign">
|
||||
Played for the University of Leeds Hockey Club.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Royal Air Force Air Cadets</td>
|
||||
<td>2017-2020</td>
|
||||
<td class="row-leftalign">
|
||||
Achieved the role of Sergeant and “Best Cadet"
|
||||
award.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- <div class="interests"> -->
|
||||
<!-- <table> -->
|
||||
<!-- <tr><th>Personal qualities</th></tr> -->
|
||||
<!-- <tr><td>Intuitive</td></tr> -->
|
||||
<!-- <tr><td>Communicative</td></tr> -->
|
||||
<!-- <tr><td>Adaptable</td></tr> -->
|
||||
<!-- <tr><td>Versatile</td></tr> -->
|
||||
<!-- <tr><td>Diligent</td></tr> -->
|
||||
<!-- </table> -->
|
||||
<!-- <table> -->
|
||||
<!-- <tr><th>Interests</th></tr> -->
|
||||
<!-- <tr><td>Neuroscience</td></tr> -->
|
||||
<!-- <tr><td>Bouldering</td></tr> -->
|
||||
<!-- <tr><td>Science Fiction</td></tr> -->
|
||||
<!-- <tr><td>Mathematics</td></tr> -->
|
||||
<!-- <tr><td>Hiking</td></tr> -->
|
||||
<!-- </table> -->
|
||||
<!-- <table> -->
|
||||
<!-- <tr><th>Languages</th></tr> -->
|
||||
<!-- <tr><td>Rust</td></tr> -->
|
||||
<!-- <tr><td>HTML/JS</td></tr> -->
|
||||
<!-- <tr><td>C/C++</td></tr> -->
|
||||
<!-- <tr><td>React/Vue</td></tr> -->
|
||||
<!-- <tr><td>Python</td></tr> -->
|
||||
<!-- </table> -->
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="no-print"
|
||||
style="width: 100%; text-align: center; margin: 20px 0"
|
||||
>
|
||||
<h1>END</h1>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@import "/css/cv_styles.css";
|
||||
@media print {
|
||||
@page {
|
||||
size: A4 portrait;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
47
nginx/vue/src/views/Home.vue
Normal file
47
nginx/vue/src/views/Home.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<script setup></script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<h1>Welcome</h1>
|
||||
|
||||
<h2>whoami?</h2>
|
||||
<p>Hi im Adam</p>
|
||||
|
||||
<h2>cv</h2>
|
||||
<RouterLink to="/cv">CV</RouterLink>
|
||||
|
||||
<h2>bookmarks</h2>
|
||||
<a href="/pages/bookmarks.html">bookmarks</a>
|
||||
|
||||
<h2>Listening to:</h2>
|
||||
<div
|
||||
x-data="spotifyPlayer()"
|
||||
x-init="fetchNowPlaying(); setInterval(fetchNowPlaying, 60000)"
|
||||
class="spotify-card"
|
||||
>
|
||||
<img :src="album_image" class="album-img" alt="" />
|
||||
<div class="spotify-info">
|
||||
<div x-text="song_name || 'No song playing'"></div>
|
||||
<div x-text="artist_name"></div>
|
||||
<div
|
||||
x-text="playing ? 'Playing' : ''"
|
||||
:class="{ playing: playing }"
|
||||
></div>
|
||||
<a :href="song_url"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--<h2> </h2>
|
||||
<p>
|
||||
Sometimes there's this fire that sends shivers down my back.
|
||||
It'll come when I'm lis
|
||||
</p>
|
||||
-->
|
||||
|
||||
<!--<h2>Shrines</h1>
|
||||
<a href="/pages/shrines/evangelion.html">Evangelion</a>
|
||||
<a href="/pages/shrines/skipskipbenben.html">Skip skip ben ben</a>
|
||||
<a href="/pages/shrines/demoman.html">demoman</a>-->
|
||||
<!--<a href="pages/shrines/gto.html">GTO</a>-->
|
||||
</main>
|
||||
</template>
|
||||
Reference in New Issue
Block a user