Compare commits
104 Commits
e348daa341
...
master
Author | SHA1 | Date | |
---|---|---|---|
1a9df45e55
|
|||
d5d7f74fd0
|
|||
934c4f4de3
|
|||
1ff611b3ed
|
|||
e2372b378a
|
|||
c4d3194a7f
|
|||
252f5143d1
|
|||
9a0cf62882
|
|||
c267ec35a4
|
|||
fd867c7262
|
|||
3bdc78303d
|
|||
4aafc98be9
|
|||
84bae3759d
|
|||
98ff90f460
|
|||
ab55d75296
|
|||
f69df643f7
|
|||
2e328133cc
|
|||
ac1744869d
|
|||
68e1e77843
|
|||
675f56d9c5
|
|||
7bf40c1263
|
|||
3586eeb6bf
|
|||
ee9a16865e
|
|||
a1533640cf
|
|||
d48d4dcb14
|
|||
bdd2e8c79a
|
|||
b36d394308
|
|||
a8295a7321
|
|||
a3f0a74535
|
|||
0e5cce4a52
|
|||
2007c280c8
|
|||
03aadb59fe
|
|||
0f90c7c0d0 | |||
fbf3657b77
|
|||
21f1d9216c
|
|||
0bd69bd3f3
|
|||
de146693aa
|
|||
57bd0f0fcc
|
|||
41e4d4dab0
|
|||
176a5855de
|
|||
1b2e0d7501
|
|||
db94ace86e | |||
60babf9451
|
|||
b5d6232b59
|
|||
3a123ab8ee
|
|||
652cee0e2e
|
|||
080912401b
|
|||
8acfafab45
|
|||
0e97c82aa1
|
|||
6307509542 | |||
118c8f89c0
|
|||
1a4c18cce0
|
|||
0aaf47909f
|
|||
186bdde093
|
|||
f99cd77e20
|
|||
c4dc1d26d2
|
|||
2bf4389d37 | |||
f1a7bd7dff | |||
8d1aec32f6 | |||
|
b631a8e782 | ||
|
cc792b244b | ||
0b0c028954 | |||
d01a3f227c | |||
36a58be0f1 | |||
c8f30073d9 | |||
b0e84f281d | |||
c10c858988 | |||
eeebcd3472 | |||
04e9e1fd14 | |||
fb419d0bea | |||
193625958a | |||
d7ccad274c | |||
de320346e3 | |||
1a1c1217e9 | |||
b0941cad68 | |||
f98a090095 | |||
61a40d9471 | |||
007724b8b1 | |||
15f34154f1 | |||
fe4de971a3 | |||
e44e92e156 | |||
c1df167726 | |||
ea6045be45 | |||
44c1727846 | |||
204f1d3a1b | |||
569cee1c5e | |||
0a3b59f764 | |||
88e9ee5d33 | |||
2380008894 | |||
1d093f3dfb | |||
58b92b4628 | |||
8f13ad501d | |||
ce108e696d | |||
ede7d2a77f | |||
bd66550ccc | |||
004b41a6a1 | |||
955d28ccd1 | |||
cb6c8919b4 | |||
d6a5a30d32 | |||
7485ae74b1 | |||
8c3245d36d | |||
09b375f666 | |||
7a4e1324ee | |||
2da5dd313c |
11
Dockerfile
@@ -1,9 +1,14 @@
|
||||
FROM node:12-alpine
|
||||
FROM node:16.17-alpine
|
||||
|
||||
RUN apk update && apk add python3 make gcc g++
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD package.json .
|
||||
RUN npm install
|
||||
|
||||
ADD . .
|
||||
|
||||
RUN npm install
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["npm", "start"]
|
||||
|
8
Makefile
@@ -1,6 +1,6 @@
|
||||
.DEFAULT_GOAL := default
|
||||
|
||||
IMAGE ?= docker.cloud.cluster.fun/averagemarcus/blog:latest
|
||||
IMAGE ?= rg.fr-par.scw.cloud/averagemarcus/blog:latest
|
||||
|
||||
.PHONY: test # Run all tests, linting and format checks
|
||||
test: lint check-format run-tests
|
||||
@@ -38,8 +38,8 @@ docker-publish:
|
||||
@docker push $(IMAGE)
|
||||
|
||||
.PHONY: run # Run the application
|
||||
run:
|
||||
@npm start
|
||||
run: docker-build
|
||||
@docker run --rm -it -p 8000:8000 $(IMAGE)
|
||||
|
||||
.PHONY: ci # Perform CI specific tasks to perform on a pull request
|
||||
ci:
|
||||
@@ -47,7 +47,7 @@ ci:
|
||||
|
||||
.PHONY: release # Release the latest version of the application
|
||||
release:
|
||||
@kubectl --namespace blog set image deployment blog web=docker.cluster.fun/averagemarcus/blog:$(SHA)
|
||||
@kubectl --namespace blog set image deployment blog web=rg.fr-par.scw.cloud/averagemarcus/blog:$(SHA)
|
||||
|
||||
.PHONY: help # Show this list of commands
|
||||
help:
|
||||
|
63
app.js
@@ -15,19 +15,62 @@ const define = require('metalsmith-define');
|
||||
const feed = require('metalsmith-feed');
|
||||
const sass = require('metalsmith-sass');
|
||||
const date = require('metalsmith-build-date');
|
||||
const sitemap = require('metalsmith-sitemap');
|
||||
const Handlebars = require('handlebars');
|
||||
const emoji = require('markdown-it-emoji');
|
||||
const moment = require('moment');
|
||||
const striptags = require('striptags');
|
||||
|
||||
const port = process.env.PORT || 8000;
|
||||
const oneDay = 86400000;
|
||||
|
||||
app.disable('x-powered-by');
|
||||
app.use(compress());
|
||||
app.use(express.static(__dirname + '/build'));
|
||||
|
||||
// Lets try and slow down some of those exploit crawlers
|
||||
app.use("/", require('./filterRoutes'));
|
||||
|
||||
// Redirects
|
||||
app.use("/", require('./redirects'));
|
||||
|
||||
// Handle some iOS icon 404s
|
||||
app.get("/apple-touch-icon*", function(req, res) {
|
||||
res.sendFile(__dirname + '/build/images/favico/' + req.url, () => {
|
||||
res.sendFile(__dirname + '/build/images/favico/apple-touch-icon.png');
|
||||
});
|
||||
});
|
||||
app.get("/images/favico/*.png", function(req, res) {
|
||||
res.sendFile(__dirname + '/build/images/favico/apple-touch-icon.png');
|
||||
});
|
||||
|
||||
app.get("/favicon.png", function(req, res) {
|
||||
res.sendFile(__dirname + '/build/images/favico/apple-touch-icon.png');
|
||||
});
|
||||
|
||||
app.get("/robots.txt", function(req, res) {
|
||||
res.send("User-agent: * Disallow: ");
|
||||
})
|
||||
|
||||
app.get(/(\/(feeds?|rss|atom)\/?|feed.xml|rss.xml|index.rss|feed.rss)$/, function(req, res) {
|
||||
res.redirect(301, '/feed.xml');
|
||||
});
|
||||
|
||||
app.get(/.+\/manifest.json$/, function(req, res) {
|
||||
res.redirect(301, '/manifest.json');
|
||||
});
|
||||
|
||||
app.get("/healthz", function(req, res) {
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
var md = markdown({html: true});
|
||||
md.parser.use(emoji);
|
||||
const proxy = (tokens, idx, options, env, self) => self.renderToken(tokens, idx, options);
|
||||
const defaultTableOpenRenderer = md.parser.renderer.rules.table_open || proxy;
|
||||
md.parser.renderer.rules.table_open = function(tokens, idx, options, env, self) {
|
||||
tokens[idx].attrJoin("role", "grid");
|
||||
return defaultTableOpenRenderer(tokens, idx, options, env, self)
|
||||
};
|
||||
|
||||
Handlebars.registerHelper('markdown', function(text) {
|
||||
if(!text) return;
|
||||
@@ -45,13 +88,18 @@ Handlebars.registerHelper("buildTitle", function(title, siteTitle){
|
||||
}
|
||||
return title;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper("jointags", function(tags){
|
||||
return (tags || '').split(' ').join(',');
|
||||
});
|
||||
Handlebars.registerHelper("encodetitle", function(str){
|
||||
return (str || '').replaceAll(' ', '%2B');
|
||||
});
|
||||
|
||||
Metalsmith(__dirname)
|
||||
.use(define({
|
||||
site: {
|
||||
title: 'Marcus Noble',
|
||||
description: 'Awesomeness with a side of geek',
|
||||
description: 'The blog of Marcus Noble, self-described tinkerer, platform engineer and all round average guy!',
|
||||
url: 'https://marcusnoble.co.uk'
|
||||
}
|
||||
}))
|
||||
@@ -72,11 +120,6 @@ Metalsmith(__dirname)
|
||||
},
|
||||
pages: {
|
||||
pattern: 'pages/*'
|
||||
},
|
||||
experience: {
|
||||
pattern: 'experience/*',
|
||||
sortBy: 'start',
|
||||
reverse: true
|
||||
}
|
||||
}))
|
||||
.use(inplace({
|
||||
@@ -103,6 +146,10 @@ Metalsmith(__dirname)
|
||||
collection: 'posts',
|
||||
destination: 'feed.xml'
|
||||
}))
|
||||
.use(sitemap({
|
||||
hostname: 'https://marcusnoble.co.uk',
|
||||
modifiedProperty: 'date'
|
||||
}))
|
||||
.use(pagination({
|
||||
'collections.posts': {
|
||||
perPage: 5,
|
||||
|
88
filterRoutes.js
Normal file
@@ -0,0 +1,88 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const blackHole = function (req, res) {
|
||||
res.redirect("https://crawler-test.com/redirects/infinite_redirect");
|
||||
};
|
||||
|
||||
// Specifically allow, but mark as not-found, any `/.well-known/` paths
|
||||
router.all(/^\/\.well-known\//, function(req, res) {
|
||||
res.sendStatus(404);
|
||||
});
|
||||
|
||||
// Block access to any root-level dot files
|
||||
router.all(/^\/\./, blackHole);
|
||||
// Block access to file types I don't use
|
||||
router.all(/.*\.php$/, blackHole);
|
||||
router.all(/.*\.asp$/, blackHole);
|
||||
router.all(/.*\.aspx$/, blackHole);
|
||||
router.all(/.*\.gz$/, blackHole);
|
||||
router.all(/.*\.bz2$/, blackHole);
|
||||
router.all(/.*\.tar$/, blackHole);
|
||||
router.all(/.*\.sql$/, blackHole);
|
||||
router.all(/.*\.env$/, blackHole);
|
||||
router.all(/.*\.ini$/, blackHole);
|
||||
router.all(/.*\.pem$/, blackHole);
|
||||
router.all(/.*\.key$/, blackHole);
|
||||
router.all(/.*\.crt$/, blackHole);
|
||||
router.all(/.*\.properties$/, blackHole);
|
||||
// Block access to any .git folders
|
||||
router.all(/.*\/\.git\/.*/, blackHole);
|
||||
// Block attempts to navigate up directories
|
||||
router.all(/.*\.\.\/.*/, blackHole);
|
||||
// Block access to special Mac folder
|
||||
router.all('/__MACOSX/*?', blackHole);
|
||||
// Block access to Workdpress files
|
||||
router.all('(/*)?/wp-admin/', blackHole);
|
||||
router.all('(/*)?/wp-includes/?(*)?', blackHole);
|
||||
router.all('(/*)?/wp-content/?(*)?', blackHole);
|
||||
router.all('/wordpress/', blackHole);
|
||||
router.all('/wp(2)?/', blackHole);
|
||||
// Block access to possible databases
|
||||
router.all('/database/', blackHole);
|
||||
router.all('/db/', blackHole);
|
||||
router.all('/db-backup/', blackHole);
|
||||
router.all('/db_backup/', blackHole);
|
||||
router.all('/sql-backup/', blackHole);
|
||||
router.all('/sql/', blackHole);
|
||||
router.all('/pma/', blackHole);
|
||||
router.all('/phpmyadmin/', blackHole);
|
||||
router.all('/mysqladmin/', blackHole);
|
||||
router.all('/mysql/', blackHole);
|
||||
router.all('/myadmin/', blackHole);
|
||||
// Block access to possible backups and uploads
|
||||
router.all('/backup/', blackHole);
|
||||
router.all('/uploads/', blackHole);
|
||||
router.all('/test/', blackHole);
|
||||
router.all('/temp/', blackHole);
|
||||
router.all(/.*\/dbbackup\/.*/, blackHole);
|
||||
router.all('/bak/', blackHole);
|
||||
router.all('archive.zip', blackHole);
|
||||
// Block access to possible credentials
|
||||
router.all('/env.test', blackHole);
|
||||
router.all('/admin(/.*)?', blackHole)
|
||||
router.all('/credentials(/*)?', blackHole);
|
||||
router.all(/.*credentials\.json$/, blackHole);
|
||||
router.all(/.*keys\.json$/, blackHole);
|
||||
router.all(/.*secrets\.json$/, blackHole);
|
||||
// Block system paths
|
||||
router.all('/etc/*', blackHole);
|
||||
router.all('/var/*', blackHole);
|
||||
router.all('/usr/*', blackHole);
|
||||
router.all('/user/*', blackHole);
|
||||
|
||||
// Block misc stuff
|
||||
router.all('/data/owncloud.log', blackHole);
|
||||
router.all('/autodiscover/autodiscover.xml', blackHole)
|
||||
router.all('/.well-known/autoconfig(/*)?', blackHole)
|
||||
router.all('/sites/default/files/', blackHole);
|
||||
router.all(/.*\/mail\/config-.+\.xml/, blackHole);
|
||||
router.all('/bitnami/*', blackHole)
|
||||
router.all('/aws/*', blackHole)
|
||||
|
||||
// Block methods I don't support
|
||||
router.post('*', blackHole);
|
||||
router.put('*', blackHole);
|
||||
router.delete('*', blackHole);
|
||||
|
||||
|
||||
module.exports = router
|
@@ -20,14 +20,16 @@
|
||||
"metalsmith-markdownit": "^0.3.0",
|
||||
"metalsmith-pagination": "^1.4.0",
|
||||
"metalsmith-permalinks": "^0.5.0",
|
||||
"metalsmith-sass": "^1.7.0",
|
||||
"metalsmith-sass": "^2.0.0",
|
||||
"metalsmith-sitemap": "^1.2.2",
|
||||
"moment": "^2.13.0",
|
||||
"node-sass": "^6.0.0",
|
||||
"striptags": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^1.12.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "8"
|
||||
"node": "16"
|
||||
}
|
||||
}
|
||||
|
8
redirects.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/2022-07-04-managing-kubernetes-without-loosing-your-cool(/)?', function(req, res) {
|
||||
return res.redirect("/2022-07-04-managing-kubernetes-without-losing-your-cool/")
|
||||
});
|
||||
|
||||
module.exports = router
|
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig><msapplication><tile><square70x70logo src="/images/favico/ms-icon-70x70.png"/><square150x150logo src="/images/favico/ms-icon-150x150.png"/><square310x310logo src="/images/favico/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>
|
101
src/css/_glitch.scss
Normal file
@@ -0,0 +1,101 @@
|
||||
.glitch-image:hover, .glitch:hover, a:hover {
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.glitch-image {
|
||||
animation: shift 3s ease-in-out .2s alternate 5;
|
||||
}
|
||||
|
||||
.glitch, a:hover {
|
||||
position: relative;
|
||||
text-shadow: 0.05em 0 0 var(--primary-hover), -0.03em -0.04em 0 var(--primary), 0.025em 0.04em 0 var(--primary-inverse);
|
||||
animation: glitch 2s ease alternate 5, shift 2s ease alternate 5;
|
||||
|
||||
&::before, &::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&::before {
|
||||
animation: glitch 1s infinite;
|
||||
clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
|
||||
transform: translate(-0.04em, -0.03em);
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
&::after {
|
||||
animation: glitch .5s infinite;
|
||||
clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%);
|
||||
transform: translate(0.04em, 0.03em);
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glitch {
|
||||
0% {
|
||||
text-shadow: 0.05em 0 0 var(--primary-hover), -0.03em -0.04em 0 var(--primary),
|
||||
0.025em 0.04em 0 var(--primary-inverse);
|
||||
}
|
||||
15% {
|
||||
text-shadow: 0.05em 0 0 var(--primary-hover), -0.03em -0.04em 0 var(--primary),
|
||||
0.025em 0.04em 0 var(--primary-inverse);
|
||||
}
|
||||
16% {
|
||||
text-shadow: -0.05em -0.025em 0 var(--primary-hover), 0.025em 0.035em 0 var(--primary),
|
||||
-0.05em -0.05em 0 var(--primary-inverse);
|
||||
}
|
||||
49% {
|
||||
text-shadow: -0.05em -0.025em 0 var(--primary-hover), 0.025em 0.035em 0 var(--primary),
|
||||
-0.05em -0.05em 0 var(--primary-inverse);
|
||||
}
|
||||
50% {
|
||||
text-shadow: 0.05em 0.035em 0 var(--primary-hover), 0.03em 0 0 var(--primary),
|
||||
0 -0.04em 0 var(--primary-inverse);
|
||||
}
|
||||
99% {
|
||||
text-shadow: 0.05em 0.035em 0 var(--primary-hover), 0.03em 0 0 var(--primary),
|
||||
0 -0.04em 0 var(--primary-inverse);
|
||||
}
|
||||
100% {
|
||||
text-shadow: -0.05em 0 0 var(--primary-hover), -0.025em -0.04em 0 var(--primary),
|
||||
-0.04em -0.025em 0 var(--primary-inverse);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shift {
|
||||
0%,40%, 44%, 58%, 61%, 65%,69%,73%,100% {
|
||||
transform: skewX(0deg);
|
||||
filter: invert(0%);
|
||||
fill: var(--text-color);
|
||||
}
|
||||
41% {
|
||||
transform: skewX(50deg);
|
||||
fill: var(--primary);
|
||||
}
|
||||
42% {
|
||||
transform: skewX(-20deg);
|
||||
filter: invert(40%);
|
||||
}
|
||||
59% {
|
||||
transform: skewX(50deg);
|
||||
fill: var(--primary-hover);
|
||||
}
|
||||
60% {
|
||||
transform: skewX(-40deg);
|
||||
filter: invert(10%);
|
||||
}
|
||||
63% {
|
||||
transform: skewX(10deg);
|
||||
filter: invert(30%);
|
||||
fill: var(--primary-hover);
|
||||
}
|
||||
70% {
|
||||
transform: skewX(-30deg);
|
||||
fill: var(--primary);
|
||||
}
|
||||
71% {
|
||||
transform: skewX(15deg);
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
@mixin textShadowToCropUnderline($color) {
|
||||
text-shadow:
|
||||
.01em 0 $color,
|
||||
-.01em 0 $color,
|
||||
0 .01em $color,
|
||||
0 -.01em $color,
|
||||
|
||||
.06em 0 $color,
|
||||
-.06em 0 $color,
|
||||
.09em 0 $color,
|
||||
-.09em 0 $color,
|
||||
|
||||
.12em 0 $color,
|
||||
-.12em 0 $color,
|
||||
.15em 0 $color,
|
||||
-.15em 0 $color;
|
||||
}
|
||||
|
||||
@mixin linkUnderlines($background, $color, $hoverColor) {
|
||||
color: $color;
|
||||
text-decoration: none;
|
||||
@include textShadowToCropUnderline($background);
|
||||
|
||||
background-image:
|
||||
linear-gradient($background, $background),
|
||||
linear-gradient($background, $background),
|
||||
linear-gradient($color, $color);
|
||||
background-size:
|
||||
.05em 2px,
|
||||
.05em 2px,
|
||||
2px 2px;
|
||||
background-repeat:
|
||||
no-repeat,
|
||||
no-repeat,
|
||||
repeat-x;
|
||||
background-position: 0% 1.02em, 100% 1.02em, 0% 1.04em;
|
||||
|
||||
&::selection {
|
||||
@include textShadowToCropUnderline($selectionColor);
|
||||
background-color: $selectionColor;
|
||||
}
|
||||
&::-moz-selection {
|
||||
@include textShadowToCropUnderline($selectionColor);
|
||||
background-color: $selectionColor;
|
||||
}
|
||||
&:before,
|
||||
&:after,
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
text-shadow: none;
|
||||
}
|
||||
&:visited {
|
||||
color: $color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $hoverColor;
|
||||
background-image:
|
||||
linear-gradient($background, $background),
|
||||
linear-gradient($background, $background),
|
||||
linear-gradient($hoverColor, $hoverColor);
|
||||
}
|
||||
}
|
7
src/css/_utils.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
@@ -1,250 +0,0 @@
|
||||
$link-color: #AD4E4E;
|
||||
$selectionColor: #D2D2D2;
|
||||
$background-color: #FFF;
|
||||
|
||||
@import "_underlines.scss";
|
||||
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: none;
|
||||
}
|
||||
|
||||
* {
|
||||
&::selection {
|
||||
background-color: $selectionColor;
|
||||
}
|
||||
&::-moz-selection {
|
||||
background-color: $selectionColor;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: $link-color;
|
||||
transition: color ease .3s;
|
||||
|
||||
&:hover {
|
||||
color: $link-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&+img {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header {
|
||||
font-family: 'Lucida Grande', Arial, sans-serif;
|
||||
font-size: .8em;
|
||||
|
||||
a:not(.social) {
|
||||
@include linkUnderlines($background-color, #4a4a4a, $link-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
margin: .8em 0 .8em 8px;
|
||||
|
||||
img {
|
||||
height: 1.2em;
|
||||
float: left;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000 !important;
|
||||
text-decoration: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.social {
|
||||
text-decoration: none;
|
||||
|
||||
svg {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
&:hover svg path,
|
||||
&:hover svg rect {
|
||||
fill: $link-color !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 0 auto;
|
||||
width: 95%;
|
||||
height: 1px;
|
||||
background-color: rgba(0, 0, 0, .2);
|
||||
}
|
||||
}
|
||||
|
||||
pre code {
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 15px;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
p > code {
|
||||
background-color: #3f3f3f;
|
||||
color: #dcdcdc;
|
||||
font-size: 0.9em;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 8px solid rgba(121, 130, 139, 0.52);
|
||||
margin-left: 0;
|
||||
padding-left: 1em;
|
||||
color: #79828B;
|
||||
}
|
||||
|
||||
figure {
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
iframe {
|
||||
max-width: 100%;
|
||||
border: 0;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
height: 2px;
|
||||
background: rgba(121, 130, 139, 0.52);
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
display: inline !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1020px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.post-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.post-preview {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
text-align: center;
|
||||
}
|
||||
.pagination a {
|
||||
font-size: 1.4mem;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.post {
|
||||
font-family: 'Lucida Grande', Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
line-height: 28px;
|
||||
padding: 2px 8px;
|
||||
|
||||
a {
|
||||
@include linkUnderlines($background-color, #4a4a4a, $link-color);
|
||||
}
|
||||
|
||||
.post-title {
|
||||
color: #000;
|
||||
font-size: 32px;
|
||||
line-height: 34px;
|
||||
margin: 21px 0 0;
|
||||
font-weight: 700;
|
||||
|
||||
a {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.full-post-link {
|
||||
font-style: italic;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.post-meta {
|
||||
color: #3d4145;
|
||||
font-size: 15px;
|
||||
line-height: 17px;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
margin: 20px 0 10px;
|
||||
color: #79828B;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.social-icons {
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
background: none !important;
|
||||
text-shadow: none !important;
|
||||
}
|
||||
a svg {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.share {
|
||||
background: transparent;
|
||||
border: none;
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
|
||||
&.show {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
&:hover, &:active {
|
||||
fill: $link-color;
|
||||
color: $link-color;
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 20px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
|
||||
&, tr, td, th, tbody, thead {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 5px;
|
||||
border: 1px solid #3d4145;
|
||||
}
|
||||
}
|
5
src/css/pico.min.css
vendored
Normal file
228
src/css/style.scss
Normal file
@@ -0,0 +1,228 @@
|
||||
/* Light Theme */
|
||||
[data-theme="light"],
|
||||
:root:not([data-theme="dark"]) {
|
||||
--primary: #fd7e0b;
|
||||
--primary-hover: #326ce5;
|
||||
--primary-focus: #fefefe;
|
||||
--primary-inverse: #d6efff;
|
||||
--color: #131b23;
|
||||
--text-color: #131b23;
|
||||
}
|
||||
|
||||
/* Dark Theme */
|
||||
@media only screen and (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme="light"]) {
|
||||
--primary: #fd7e0b;
|
||||
--primary-hover: #326ce5;
|
||||
--primary-focus: #131b23;
|
||||
--primary-inverse: #d6efff;
|
||||
--color: #fefefe;
|
||||
--text-color: #fefefe;
|
||||
}
|
||||
}
|
||||
[data-theme="dark"] {
|
||||
--primary: #fd7e0b;
|
||||
--primary-hover: #326ce5;
|
||||
--primary-focus: #131b23;
|
||||
--primary-inverse: #d6efff;
|
||||
--color: #fefefe;
|
||||
--text-color: #fefefe;
|
||||
}
|
||||
|
||||
:root:not([data-theme="dark"]),
|
||||
:root:not([data-theme="light"]){
|
||||
--form-element-active-border-color: var(--primary);
|
||||
--form-element-focus-color: var(--primary-focus);
|
||||
--switch-color: var(--primary-inverse);
|
||||
--switch-checked-background-color: var(--primary);
|
||||
--blockquote-border-color: var(--primary-hover);
|
||||
|
||||
--font-family: 'Orkney', system-ui, -apple-system, "Segoe UI", "Roboto", "Ubuntu",
|
||||
"Cantarell", "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
||||
"Segoe UI Symbol", "Noto Color Emoji";
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
// Links
|
||||
|
||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
|
||||
color: var(--text-color)
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
@media only screen and (prefers-color-scheme: light) {
|
||||
a.social {
|
||||
svg {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
[data-theme="light"] {
|
||||
a.social {
|
||||
svg {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
a.social {
|
||||
svg {
|
||||
margin: 4px;
|
||||
fill: #fff !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
|
||||
svg {
|
||||
animation: shift 1.5s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Layout
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 2em 0 !important;
|
||||
|
||||
& + main {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1em 0 !important;
|
||||
}
|
||||
|
||||
article {
|
||||
margin-top: 0;
|
||||
padding-top: 1.5em;
|
||||
|
||||
blockquote, dl, figure, form, ol, p, pre, table, ul {
|
||||
font-size: calc(var(--font-size) + 2px) !important;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
figure p,
|
||||
blockquote p,
|
||||
blockquote ul {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
figure a:hover {
|
||||
text-shadow: initial;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
details {
|
||||
font-size: 0.8em;
|
||||
border: 1px dashed #79828B;
|
||||
padding: 2px 8px;
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
|
||||
&::after {
|
||||
float: unset;
|
||||
display: inline-block;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
code, kbd, pre {
|
||||
color: #dcdcdc;
|
||||
background-color: #3f3f3f;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1em auto;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-top: solid 3px #57688d;
|
||||
text-align: center;
|
||||
width: 60%;
|
||||
position: relative;
|
||||
|
||||
|
||||
&::after {
|
||||
content: "✨";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: -0.7em;
|
||||
padding: 0 5px;
|
||||
font-size: 2rem;
|
||||
filter: grayscale(70%);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: ' ';
|
||||
background-color: var(--background-color);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: -1.2em;
|
||||
padding: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 23px;
|
||||
transform: translateX(-50%);
|
||||
|
||||
article & {
|
||||
background-color: var(--card-background-color) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section:last-of-type hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Custom Classes
|
||||
|
||||
.site-logo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.post-meta {
|
||||
font-size: 0.7em;
|
||||
font-family: 'OrkneyLight';
|
||||
vertical-align: text-bottom;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
&::before {
|
||||
content: "📆 ";
|
||||
filter: grayscale(70%);
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
|
||||
@import "_utils.scss";
|
||||
@import "_glitch.scss";
|
@@ -1,11 +0,0 @@
|
||||
---
|
||||
title: Elsevier
|
||||
url: https://www.elsevier.com
|
||||
role: Full Stack Software Engineer
|
||||
start: 2016-02-15
|
||||
end:
|
||||
---
|
||||
|
||||
<small>Responsibilities include</small>
|
||||
|
||||
Building an ecommerce platform with involvement at all levels of development from infrastructure to front-end design. Contributing design and development ideas to advance the project. Working on Node.js and TypeScript projects.
|
@@ -1,15 +0,0 @@
|
||||
---
|
||||
title: Science and technology Facilities Council
|
||||
url: http://www.stfc.ac.uk/
|
||||
role: Software Developer (Student Placement)
|
||||
start: 2011-07-01
|
||||
end: 2012-09-01
|
||||
---
|
||||
|
||||
<small>Responsibilities included</small>
|
||||
|
||||
Being involved at all stages of development for ASP .NET and Java web applications. Providing user supports to systems maintained by our team. Providing maintenance, updates and bug fixes to existing systems and services. Maintain and develop Oracle and Microsoft SQL servers. Communicating with users within and external to the company to resolve issues.
|
||||
|
||||
<small>Highlights</small>
|
||||
|
||||
I was awarded a Staff Recognition Award for my contribution to a project
|
@@ -1,11 +0,0 @@
|
||||
---
|
||||
title: Science and technology Facilities Council
|
||||
url: http://www.stfc.ac.uk/
|
||||
role: Software Developer
|
||||
start: 2013-06-10
|
||||
end: 2016-02-15
|
||||
---
|
||||
|
||||
<small>Responsibilities included</small>
|
||||
|
||||
Being involved at all stages of development for ASP .NET and Java web applications. Providing user supports to systems maintained by our team. Providing maintenance, updates and bug fixes to existing systems and services. Maintain and develop Oracle and Microsoft SQL servers. Communicating with users within and external to the company to resolve issues.
|
@@ -1,11 +0,0 @@
|
||||
---
|
||||
title: The University of Derby
|
||||
url: http://www.derby.ac.uk/
|
||||
role: BSc Computer Science
|
||||
start: 2009-09-01
|
||||
end: 2013-06-01
|
||||
---
|
||||
|
||||
<small>Modules included</small>
|
||||
|
||||
Software Development, Web Development, Multi-user Database Systems, Mobile Devices, Operating Systems, Systems Analysis, Language Design and Implementation, Distributed Systems, Systems Programming & Enterprise Systems
|
BIN
src/favicon.ico
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 34 KiB |
BIN
src/images/Cloud_Native_Now_-_Square.jpg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
src/images/emf-airfryer.jpg
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
src/images/emf-blacksmith.jpg
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
src/images/emf-evening-unnecessary.jpg
Normal file
After Width: | Height: | Size: 179 KiB |
BIN
src/images/emf-food.jpg
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
src/images/emf-jo.jpg
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
src/images/emf-jsoxford.jpg
Normal file
After Width: | Height: | Size: 145 KiB |
BIN
src/images/emf-laser-duck-hunt.jpg
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
src/images/emf-lasers.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
src/images/emf-terence.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
src/images/emf-tesla-coil.jpg
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
src/images/emf-van.jpg
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
src/images/favico/android-chrome-144x144.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
src/images/favico/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
src/images/favico/android-chrome-256x256.png
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
src/images/favico/android-chrome-36x36.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
src/images/favico/android-chrome-384x384.png
Normal file
After Width: | Height: | Size: 180 KiB |
BIN
src/images/favico/android-chrome-48x48.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
src/images/favico/android-chrome-512x512.png
Normal file
After Width: | Height: | Size: 307 KiB |
BIN
src/images/favico/android-chrome-72x72.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
src/images/favico/android-chrome-96x96.png
Normal file
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 86 KiB |
BIN
src/images/favico/apple-touch-icon-1024x1024.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
src/images/favico/apple-touch-icon-114x114.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
src/images/favico/apple-touch-icon-120x120.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
src/images/favico/apple-touch-icon-144x144.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
src/images/favico/apple-touch-icon-152x152.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
src/images/favico/apple-touch-icon-167x167.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
src/images/favico/apple-touch-icon-180x180.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
src/images/favico/apple-touch-icon-57x57.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
src/images/favico/apple-touch-icon-60x60.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
src/images/favico/apple-touch-icon-72x72.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
src/images/favico/apple-touch-icon-76x76.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
src/images/favico/apple-touch-icon-precomposed.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
src/images/favico/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 780 B |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
src/images/favico/favicon-48x48.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
src/images/favico/favicon-96.png
Normal file
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 22 KiB |
BIN
src/images/favico/favicon.ico
Normal file
After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 12 KiB |
BIN
src/images/favico/mstile-144x144.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
src/images/favico/mstile-150x150.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
src/images/favico/mstile-310x150.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
src/images/favico/mstile-310x310.png
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
src/images/favico/mstile-70x70.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
26
src/images/favico/safari-pinned-tab.svg
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="192.000000pt" height="192.000000pt" viewBox="0 0 192.000000 192.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.14, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,192.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M1055 1592 c-45 -10 -154 -99 -169 -137 -4 -11 -10 -45 -12 -75 -5
|
||||
-64 -7 -76 -22 -112 -11 -26 -9 -51 8 -118 5 -19 11 -47 14 -63 3 -15 11 -40
|
||||
18 -55 29 -60 4 -115 -57 -125 -11 -2 -35 -11 -52 -20 -18 -10 -33 -15 -33
|
||||
-11 0 4 -6 2 -12 -4 -7 -5 -29 -13 -48 -17 -45 -10 -121 -48 -140 -72 -41 -49
|
||||
-72 -93 -65 -93 4 0 2 -7 -5 -15 -7 -8 -9 -15 -6 -15 4 0 2 -9 -4 -20 -6 -11
|
||||
-13 -38 -15 -60 -2 -22 -9 -58 -15 -80 -6 -23 -13 -58 -16 -78 -2 -20 -7 -50
|
||||
-10 -67 -12 -57 -15 -90 -17 -223 l-2 -132 706 0 706 0 -3 58 c-4 90 -12 149
|
||||
-28 201 -8 27 -12 52 -9 55 3 3 2 13 -2 23 -5 10 -9 24 -11 30 -1 7 -9 32 -17
|
||||
55 -19 54 -41 128 -58 196 -7 28 -17 52 -21 52 -5 0 -7 4 -3 9 3 5 1 12 -5 16
|
||||
-5 3 -17 22 -26 41 -15 30 -89 94 -110 94 -4 0 -26 9 -48 20 -23 11 -50 21
|
||||
-61 23 -11 2 -33 9 -48 15 -16 7 -31 12 -34 12 -16 0 -93 45 -93 54 0 13 52
|
||||
166 73 215 9 21 12 44 7 60 -4 14 -6 64 -4 111 3 101 -8 130 -68 187 -60 57
|
||||
-123 79 -183 65z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/images/k9s.gif
Normal file
After Width: | Height: | Size: 3.8 MiB |
BIN
src/images/kosmos/AddExternalNode.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
src/images/kosmos/AddPool.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
src/images/kosmos/CivoNode.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
src/images/kosmos/CloudLabel.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
src/images/kosmos/CreateCluster.png
Normal file
After Width: | Height: | Size: 151 KiB |
BIN
src/images/kosmos/CreationInProgress.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
src/images/kosmos/KubectlARM.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
src/images/kosmos/KubectlCivo.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
src/images/kosmos/KubectlEquinix.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
src/images/kosmos/KubectlLocal.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
src/images/kosmos/KubectlMultiRegionPools.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
src/images/kosmos/Latency-1.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
src/images/kosmos/Latency-2.png
Normal file
After Width: | Height: | Size: 33 KiB |