Initial release
Signed-off-by: Marcus Noble <github@marcusnoble.co.uk>
This commit is contained in:
commit
cfa8450f9d
170
.gitignore
vendored
Normal file
170
.gitignore
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
### Git ###
|
||||
# Created by git for backups. To disable backups in Git:
|
||||
# $ git config --global mergetool.keepBackup false
|
||||
*.orig
|
||||
|
||||
# Created by git when using merge tools for conflicts
|
||||
*.BACKUP.*
|
||||
*.BASE.*
|
||||
*.LOCAL.*
|
||||
*.REMOTE.*
|
||||
*_BACKUP_*.txt
|
||||
*_BASE_*.txt
|
||||
*_LOCAL_*.txt
|
||||
*_REMOTE_*.txt
|
||||
|
||||
### Go ###
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
### Go Patch ###
|
||||
/vendor/
|
||||
/Godeps/
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# rollup.js default build output
|
||||
dist/
|
||||
|
||||
# Storybook build outputs
|
||||
.out
|
||||
.storybook-out
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# Temporary folders
|
||||
tmp/
|
||||
temp/
|
||||
|
||||
# VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
.history/
|
||||
|
||||
# MacOS
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
13
Dockerfile
Normal file
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
FROM golang:1.17-alpine AS builder
|
||||
RUN apk update && apk add --no-cache git && apk add -U --no-cache ca-certificates
|
||||
WORKDIR /app/
|
||||
ADD go.mod go.sum ./
|
||||
RUN go mod download
|
||||
ADD . .
|
||||
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" -o marcusnoble .
|
||||
|
||||
FROM scratch
|
||||
WORKDIR /app/
|
||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=builder /app/marcusnoble /app/marcusnoble
|
||||
ENTRYPOINT ["/app/marcusnoble"]
|
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
MIT License Copyright (c) 2022 - present Marcus Noble
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
61
Makefile
Normal file
61
Makefile
Normal file
@ -0,0 +1,61 @@
|
||||
.DEFAULT_GOAL := default
|
||||
|
||||
IMAGE ?= rg.fr-par.scw.cloud/averagemarcus-private/marcusnoble:latest
|
||||
|
||||
.PHONY: test # Run all tests, linting and format checks
|
||||
test: lint check-format run-tests
|
||||
|
||||
.PHONY: lint # Perform lint checks against code
|
||||
lint:
|
||||
@echo "⚠️ 'lint' unimplemented"
|
||||
|
||||
.PHONY: check-format # Checks code formatting and returns a non-zero exit code if formatting errors found
|
||||
check-format:
|
||||
@echo "⚠️ 'check-format' unimplemented"
|
||||
|
||||
.PHONY: format # Performs automatic format fixes on all code
|
||||
format:
|
||||
@echo "⚠️ 'format' unimplemented"
|
||||
|
||||
.PHONY: run-tests # Runs all tests
|
||||
run-tests:
|
||||
@echo "⚠️ 'run-tests' unimplemented"
|
||||
|
||||
.PHONY: fetch-deps # Fetch all project dependencies
|
||||
fetch-deps:
|
||||
@echo "⚠️ 'fetch-deps' unimplemented"
|
||||
|
||||
.PHONY: build # Build the project
|
||||
build: lint check-format fetch-deps
|
||||
@echo "⚠️ 'build' unimplemented"
|
||||
|
||||
.PHONY: docker-build # Build the docker image
|
||||
docker-build:
|
||||
@docker build -t $(IMAGE) .
|
||||
|
||||
.PHONY: docker-publish # Push the docker image to the remote registry
|
||||
docker-publish:
|
||||
@docker push $(IMAGE)
|
||||
|
||||
.PHONY: run # Run the application
|
||||
run: docker-build
|
||||
@docker run --rm -it -p 8080:80 -v $$(pwd)/src:/usr/share/nginx/html $(IMAGE)
|
||||
|
||||
.PHONY: ci # Perform CI specific tasks to perform on a pull request
|
||||
ci:
|
||||
@echo "⚠️ 'ci' unimplemented"
|
||||
|
||||
.PHONY: release # Release the latest version of the application
|
||||
release:
|
||||
@kubectl --context scaleway --namespace marcusnoble set image deployment marcusnoble web=rg.fr-par.scw.cloud/averagemarcus-private/marcusnoble:$(SHA)
|
||||
|
||||
.PHONY: help # Show this list of commands
|
||||
help:
|
||||
@echo "marcusnoble"
|
||||
@echo "Usage: make [target]"
|
||||
@echo ""
|
||||
@echo "target description" | expand -t20
|
||||
@echo "-----------------------------------"
|
||||
@grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20
|
||||
|
||||
default: test build
|
5
README.md
Normal file
5
README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Marcus Noble
|
||||
|
||||
Personal profile of Marcus Noble
|
||||
|
||||
Available at https://marcusnoble.com
|
116
data.yaml
Normal file
116
data.yaml
Normal file
@ -0,0 +1,116 @@
|
||||
intro: |
|
||||
I'm a <strong>platform engineer</strong> working at <a href="https://giantswarm.io">Giant Swarm</a> working on building managed Kubernetes solutions and related projects. My area of focus in recent years has been around Go, ⎈ Kubernetes, containers and DevOps but originally started out as a <em>web developer</em> and <em>JavaScript enthusiast</em>. I'm a “tinkerer” and like to dabble with 3D printing and experimenting with smart home tech.
|
||||
social:
|
||||
- url: https://marcusnoble.co.uk
|
||||
title: My articles on my Blog
|
||||
content: |
|
||||
<svg height="32" viewBox="0 0 512 512">
|
||||
<style>.st0{fill:#fff}.st1{fill:#ededed}.st4{fill:#333}.st8{fill:#f96363}.st9{fill:#fdd267}</style><path class="st0" d="M508 82.9v394.2c0 17-13.8 30.9-30.8 30.9H34.8C17.8 508 4 494.2 4 477.1V82.9h504z"/><path class="st1" d="M508 82.9v394.2c0 17-13.8 30.9-30.8 30.9h-28.6a31 31 0 0 0 30.9-30.9V82.9H508z"/><path d="M508 82.9v-48c0-17-13.8-30.8-30.8-30.8H34.9A30.7 30.7 0 0 0 4 34.9v48h504z" fill="#d3d9d9"/><path class="st1" d="M63.5 4c-17 0-30.9 13.8-30.9 30.8v48.1H4V34.8C4 17.8 17.8 4 34.8 4h28.7z"/><path d="M508 34.8v48.1h-28.6V34.8c0-17-13.8-30.8-30.9-30.8h28.7c17 0 30.8 13.8 30.8 30.8z" fill="#a8b2b4"/><path class="st4" d="M512 34.8A34.8 34.8 0 0 0 477.2 0H34.9A34.8 34.8 0 0 0 0 34.8v442.3A35 35 0 0 0 34.8 512h442.3a34.8 34.8 0 0 0 34.8-34.9l.1-442.3zm-504 0A26.9 26.9 0 0 1 34.9 8h442.3C492 8 504 20 504 34.8v44H8v-44zm496 442.3c0 14.8-12 26.9-26.8 26.9H34.8A26.9 26.9 0 0 1 8 477.1V86.9h496v390.2z"/><circle cx="50.6" cy="43.5" r="14" fill="#fc8a8a"/><circle cx="100.5" cy="43.5" r="14" fill="#fedd8e"/><circle cx="150.3" cy="43.5" r="14" fill="#7bde9e"/><path class="st8" d="M64.6 43.4a14 14 0 0 1-27.2 4.7 14 14 0 0 0 18-18c5.3 2.2 9.2 7.3 9.2 13.3z"/><path class="st9" d="M114.4 43.4a14 14 0 0 1-27.2 4.7 14 14 0 0 0 18-18c5.4 2.2 9.2 7.3 9.2 13.3z"/><path d="M164.3 43.4a14 14 0 0 1-27.2 4.7 14 14 0 0 0 17.8-18c5.5 2.2 9.4 7.3 9.4 13.3z" fill="#50d27e"/><path class="st4" d="M50.6 61.5c-9.9 0-18-8.1-18-18s8.1-18 18-18 18 8.1 18 18-8.1 18-18 18zm0-28c-5.5 0-10 4.5-10 10s4.5 10 10 10 10-4.5 10-10-4.5-10-10-10zm49.9 28c-9.9 0-18-8.1-18-18s8.1-18 18-18 18 8.1 18 18-8.1 18-18 18zm0-28c-5.5 0-10 4.5-10 10s4.5 10 10 10 10-4.5 10-10-4.5-10-10-10zm49.8 28c-9.9 0-18-8.1-18-18s8.1-18 18-18 18 8.1 18 18-8.1 18-18 18zm0-28c-5.5 0-10 4.5-10 10s4.5 10 10 10 10-4.5 10-10-4.5-10-10-10z"/><path class="st0" d="M475.4 43.4a14 14 0 0 1-14 14H229.7a14 14 0 1 1 0-28h231.7a14 14 0 0 1 14 14z"/><path class="st1" d="M475.4 43.4a14 14 0 0 1-14 14H229.7a14 14 0 0 1-14-13.3c2 1.1 4.3 1.7 6.7 1.7h231.7a14 14 0 0 0 14-14v-.6a14 14 0 0 1 7.3 12.2z"/><path class="st4" d="M461.4 61.4H229.7c-9.9 0-18-8.1-18-18s8.1-18 18-18h231.7c9.9 0 18 8.1 18 18s-8.1 18-18 18zm-231.7-28c-5.5 0-10 4.5-10 10s4.5 10 10 10h231.7c5.5 0 10-4.5 10-10s-4.5-10-10-10H229.7z"/><path d="M455.6 123.2v98.2H56.4v-98.2h399.2z" fill="#fb8a8a"/><path d="M455.6 123.2v21.7H56.4v-21.7h399.2z" fill="#fcb1b1"/><path class="st8" d="M56.4 199.7h399.2v21.6H56.4z"/><path class="st4" d="M455.6 225.3H56.4a4 4 0 0 1-4-4v-98.2a4 4 0 0 1 4-4h399.2a4 4 0 0 1 4 4v98.2a4 4 0 0 1-4 4zm-395.2-8h391.2v-90.2H60.4v90.2zm395.2 48.3H56.4c-2.2 0-4-1.8-4-4s1.8-4 4-4h399.2c2.2 0 4 1.8 4 4s-1.8 4-4 4zm0 206.1H56.4c-2.2 0-4-1.8-4-4s1.8-4 4-4h399.2c2.2 0 4 1.8 4 4s-1.8 4-4 4zm0-40.3H268.9c-2.2 0-4-1.8-4-4s1.8-4 4-4h186.7c2.2 0 4 1.8 4 4s-1.8 4-4 4zm0-41.8H268.9c-2.2 0-4-1.8-4-4s1.8-4 4-4h186.7c2.2 0 4 1.8 4 4s-1.8 4-4 4zm0-41.9H268.9c-2.2 0-4-1.8-4-4s1.8-4 4-4h186.7c2.2 0 4 1.8 4 4s-1.8 4-4 4zm0-41.9H268.9c-2.2 0-4-1.8-4-4s1.8-4 4-4h186.7c2.2 0 4 1.8 4 4s-1.8 4-4 4z"/><path fill="#fddd8d" d="M56.4 301.8h160.1v125.6H56.4z"/><path fill="#fee8b3" d="M56.4 301.8h160v26.1h-160z"/><path class="st9" d="M56.4 401.4h160v26.1h-160z"/><path class="st4" d="M216.4 431.4h-160a4 4 0 0 1-4-4V301.8a4 4 0 0 1 4-4h160.1a4 4 0 0 1 4 4v125.6a4 4 0 0 1-4.1 4zm-156-8h152.1V305.8H60.4v117.6z"/>
|
||||
</svg>
|
||||
Blog
|
||||
- url: https://marcusnoble.co.uk
|
||||
title: My articles on my Blog
|
||||
content: |
|
||||
<svg viewBox="0 0 60 60" height="32"><path d="M39 0H6.4v60h47V14.6L38.9 0zm.5 3.4L50.1 14H39.5V3.4zM8.5 58V2h29v14h14v42h-43z"/><path d="M34.5 37a1 1 0 1 0 0-2h-17a1 1 0 1 0 0 2h17zm10-7h-7a1 1 0 1 0 0 2h7a1 1 0 1 0 0-2zm-23 1c0 .6.4 1 1 1h10a1 1 0 1 0 0-2h-10a1 1 0 0 0-1 1zm-4.7-.7a1 1 0 0 0-.3.7 1 1 0 0 0 1 1c.3 0 .5-.1.7-.3.2-.2.3-.4.3-.7a1 1 0 0 0-.3-.7 1 1 0 0 0-1.4 0zm22 5a1 1 0 0 0-.3.7 1 1 0 0 0 1 1c.3 0 .5-.1.7-.3.2-.2.3-.4.3-.7a1 1 0 0 0-.3-.7 1 1 0 0 0-1.4 0zm5 0a1 1 0 0 0-.3.7 1 1 0 0 0 1 1c.3 0 .5-.1.7-.3.2-.2.3-.4.3-.7a1 1 0 0 0-.3-.7 1 1 0 0 0-1.4 0zM23 40.2c-2.2 1.1-2.9 3.3-3.2 5.5l-1.2-1c-1-.8-2.4.6-1.4 1.4l2.8 2.4c.6.5 1.7.2 1.7-.7 0-2.2.2-4.8 2.3-6 1.2-.5.2-2.2-1-1.6zm13.5 3.9c-1.5 0-3.6 2.2-4.8.2a1 1 0 0 0-1.3-.4c-1.4.9-3.3 2.1-4.8.5-.9-1-2.3.5-1.4 1.4 1.9 2 4.3 1.4 6.4.3.5.5 1 .9 1.8 1 .8.2 4-1 4.2-.8.8 1 2.5 0 1.8-1-.6-.8-1-1.1-2-1.2zM28.7 24l.6-.5-.3-.8c-.3-.6-.8-1.2-1.5-1.5l-2-1c.9-.7 1.6-1.6 2-2.9.7-.4 1.1-1.1 1.1-2v-.6c0-.7-.3-1.3-.8-1.8-.3-1.9-1.6-4-5.5-4h-.4a3 3 0 0 1-2-.4l-.5-.4c-.3-.4-.9-.6-1.3-.4a1 1 0 0 0-.7 1.2 11.2 11.2 0 0 0 .2 1.5l-.1.2-.3.6-.5 1.7c-.4.5-.7 1.1-.7 1.8v.6c0 .9.4 1.6 1 2a5.2 5.2 0 0 0 2.2 2.8L17 21.2a3 3 0 0 0-1.4 1.5l-.3.8.6.4a11 11 0 0 0 12.8 0zM18 23l2.5-1.3c.5-.3.8-.8.8-1.4V19l-.6-.2c-1-.4-1.5-1.2-1.8-2.4l-.2-.5-.5-.2a.3.3 0 0 1-.2-.3v-.6c0-.2 0-.3.2-.3l.4-.3v-.5l.5-1.6.2-.5.3-.9a5.3 5.3 0 0 0 2.7.4c3 0 3.5 1.3 3.6 2.6v.5l.6.3.1.3v.6c0 .2 0 .3-.2.3l-.5.2-.2.5c-.3 1.2-.9 2-1.8 2.4l-.6.2v1.5c0 .5.3 1 .8 1.3l2.4 1.2a9 9 0 0 1-8.5 0z"/></svg>
|
||||
C.V.
|
||||
- url: https://www.github.com/AverageMarcus
|
||||
title: AverageMarcus on GitHubBlog
|
||||
content: |
|
||||
<svg viewBox="0 0 16 16" height="32"><path d="M7.999,0.431c-4.285,0-7.76,3.474-7.76,7.761 c0,3.428,2.223,6.337,5.307,7.363c0.388,0.071,0.53-0.168,0.53-0.374c0-0.184-0.007-0.672-0.01-1.32 c-2.159,0.469-2.614-1.04-2.614-1.04c-0.353-0.896-0.862-1.135-0.862-1.135c-0.705-0.481,0.053-0.472,0.053-0.472 c0.779,0.055,1.189,0.8,1.189,0.8c0.692,1.186,1.816,0.843,2.258,0.645c0.071-0.502,0.271-0.843,0.493-1.037 C4.86,11.425,3.049,10.76,3.049,7.786c0-0.847,0.302-1.54,0.799-2.082C3.768,5.507,3.501,4.718,3.924,3.65 c0,0,0.652-0.209,2.134,0.796C6.677,4.273,7.34,4.187,8,4.184c0.659,0.003,1.323,0.089,1.943,0.261 c1.482-1.004,2.132-0.796,2.132-0.796c0.423,1.068,0.157,1.857,0.077,2.054c0.497,0.542,0.798,1.235,0.798,2.082 c0,2.981-1.814,3.637-3.543,3.829c0.279,0.24,0.527,0.713,0.527,1.437c0,1.037-0.01,1.874-0.01,2.129 c0,0.208,0.14,0.449,0.534,0.373c3.081-1.028,5.302-3.935,5.302-7.362C15.76,3.906,12.285,0.431,7.999,0.431z"></path></svg>
|
||||
GitHub
|
||||
- url: https://twitter.com/Marcus_Noble_
|
||||
title: "@Marcus_Noble_ on TwitterBlog"
|
||||
content: |
|
||||
<svg viewBox="0 0 16 16" height="32"><path d="M15.969,3.058c-0.586,0.26-1.217,0.436-1.878,0.515c0.675-0.405,1.194-1.045,1.438-1.809c-0.632,0.375-1.332,0.647-2.076,0.793c-0.596-0.636-1.446-1.033-2.387-1.033c-1.806,0-3.27,1.464-3.27,3.27 c0,0.256,0.029,0.506,0.085,0.745C5.163,5.404,2.753,4.102,1.14,2.124C0.859,2.607,0.698,3.168,0.698,3.767 c0,1.134,0.577,2.135,1.455,2.722C1.616,6.472,1.112,6.325,0.671,6.08c0,0.014,0,0.027,0,0.041c0,1.584,1.127,2.906,2.623,3.206 C3.02,9.402,2.731,9.442,2.433,9.442c-0.211,0-0.416-0.021-0.615-0.059c0.416,1.299,1.624,2.245,3.055,2.271 c-1.119,0.877-2.529,1.4-4.061,1.4c-0.264,0-0.524-0.015-0.78-0.046c1.447,0.928,3.166,1.469,5.013,1.469 c6.015,0,9.304-4.983,9.304-9.304c0-0.142-0.003-0.283-0.009-0.423C14.976,4.29,15.531,3.714,15.969,3.058z"></path></svg>
|
||||
Twitter
|
||||
- url: https://k8s.social/@Marcus
|
||||
title: "@marcus@k8s.social on MastodonBlog"
|
||||
content: |
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="80 80 360 360">
|
||||
<path d="m409 290c-5 24-43 50-85 56-86 11-137-6-137-6 3 13-4 54 70 52 31 0 58-7 58-7l2 27c-51 24-107 15-140 6-67-17-79-90-81-162v-59c0-74 49-96 49-96 50-24 180-22 222 0 0 0 49 22 49 96 0 0 1 55-7 93"></path>
|
||||
<path d="m358 202v91h-35v-88c0-18-8-27-23-27-18 0-27 11-27 33v47h-34v-47c0-22-9-33-27-33-15 0-23 9-23 27v88h-35v-91c0-18 5-60 52-60 39 0 50 37 50 37s10-37 50-37c45 0 52 42 52 60" fill="#3088d4"></path>
|
||||
</svg>
|
||||
Mastodon
|
||||
- url: https://www.linkedin.com/in/marcusnoble/
|
||||
title: Connect with me on LinkedinBlog
|
||||
content: |
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" height="32">
|
||||
<rect width="512" height="512" rx="15%"></rect>
|
||||
<circle cx="142" cy="138" r="37" fill="#0077b5"></circle>
|
||||
<path stroke="#0077b5" stroke-width="66" d="M244 194v198M142 194v198"></path>
|
||||
<path fill="#0077b5" d="M276 282c0-20 13-40 36-40 24 0 33 18 33 45v105h66V279c0-61-32-89-76-89-34 0-51 19-59 32"></path>
|
||||
</svg>
|
||||
LinkedIn
|
||||
- url: https://noti.st/averagemarcus
|
||||
title: View my previous talks on NotistBlog
|
||||
content: |
|
||||
<svg height="32" viewBox="0 -20 520 218">
|
||||
<path d="M127.7 127.6a47 47 0 0 1-36.5 18.8c-16.4 0-26.4-9.8-26.4-22.1 0-17.6 9.2-29.1 9.2-40.4 0-4.6-2.6-8-6.7-8-4.9 0-11.8 4.9-18.1 17.5A146.2 146.2 0 0 0 36.8 139c0 4.8-2 6-6.3 6-8.7 0-19.9 1.4-24.2 1.4-3.8 0-6-1.4-6-6.3 0-10.7 12-49.5 12-65 0-5-2-5.6-2-9.3 0-6.3 15.6-10.7 32.3-10.7 6.3 0 9.8 2.6 9.8 7.5 0 4.6-2.3 13-2.3 13C55.2 69.3 72.2 55 89.2 55c15.9 0 22.2 7.2 22.2 18.2 0 13.2-8 27.6-8 39.4 0 7.5 4 10.4 9.2 10.4 4.9 0 7.2-2.3 10.9-6l.7-.8a44 44 0 0 1-.4-6.4c0-28 22.2-56 61.6-56 21.3 0 36 14 36 33.8 0 32.2-20.4 59.9-55.8 59.9-18 0-31.6-7.4-37.9-20zM291.2 113c2.2-15.1 8.7-29.4 8.7-38 0-4.9-1.7-5.5-1.7-9.2 0-6.3 15.3-10.7 32-10.7 6.3 0 9.8 2.6 9.8 7.5 0 11.6-9.3 29.7-9.3 48.7 0 7.5 4.4 11.8 9.5 11.8 3.8 0 6-1.3 8.6-3.7 1-7.7 7-12.1 13-12.1 7.8 0 12.4 3.7 12.4 10.6 0 7.2 2.6 12.1 7.8 12.1 4 0 6.3-2.6 6.3-7.8 0-17-28.5-19.5-28.5-41.1 0-18.2 18.2-27.4 39.8-27.4 21 0 30.5 8 30.5 19.9 0 7.8-4 14.7-13.5 14.7-5.5 0-10.4-4.4-10.4-9.8 0-4.3 2.3-6 2.3-8.7 0-2.8-2.3-4-5.5-4-3.7 0-8.3 4-8.3 9.5 0 17 31.7 19.3 31.7 40.3 0 18.7-15 31.4-40.4 31.4-16.3 0-29.3-5.4-34.7-14.8a45.4 45.4 0 0 1-32.4 14.2c-16.8 0-26.2-8.3-28.1-19.5-9.3 9.2-24.2 19.5-38.4 19.5-20.7 0-29.7-12.3-29.7-27.6 0-18.4 9-32.8 9-47.2 0-3.8-7.8-1.5-7.8-6.7 0-2.8 1.7-8.3 4.9-8.3 15.3 0 29.4-15 36.9-27 2.8-4.7 5.1-6.4 7.7-6.4 3.2 0 4.6 2.3 4.6 4.6 0 6.3-4 18.1-4 23 0 3.8 1.2 5.8 9.8 5.8 2.3 0 4 .8 4 3.2 0 5.7-3.1 9.7-6.6 9.7-7.2 0-10.4 2.3-12.4 9.3-2.3 8.3-6 23-6 32.5 0 8.6 4.3 11.8 11.2 11.8 5.8 0 11.5-5.5 16.1-9.2l1-.9zm200.1-43.5c-7.2 0-10.3 2.3-12.4 9.3-2.3 8.3-6 23-6 32.5 0 8.6 4.3 11.8 11.2 11.8 5.8 0 11.5-5.5 16.2-9.2 2-1.7 3.4-2.9 5.1-2.9 2.3 0 3.8 1.7 3.8 3.5a10 10 0 0 1-2.3 5.7c-7.5 9.8-26.5 26.2-44.4 26.2-20.7 0-29.6-12.3-29.6-27.6 0-18.4 8.9-32.8 8.9-47.2 0-3.8-7.8-1.5-7.8-6.7 0-2.8 1.7-8.3 5-8.3 15.2 0 29.3-15 36.8-27 2.9-4.7 5.2-6.4 7.8-6.4 3.1 0 4.6 2.3 4.6 4.6 0 6.3-4 18.1-4 23 0 3.8 1 5.8 9.7 5.8 2.3 0 4 .8 4 3.2 0 5.7-3.1 9.7-6.6 9.7zM356 120.8c0 2.6 2.2 4.7 4.9 4.7 3.3 0 6.4-3.8 6.4-7.3 0-2.6-1.7-4.6-4.8-4.6-3.4 0-6.5 3.7-6.5 7.2zm-48.6-96.5c0-11.5 10.4-23.6 21.3-23.6C339.1.7 345 7.3 345 16c0 11.5-10.4 23.9-21.4 23.9-8.9 0-16-7-16-15.6zm-107.3 80.4c0-5-1.7-9.2-5.7-11-9-3.4-11.6-6.6-11.6-11.8 0-7.2 4.4-9.5 4.4-11.2 0-1.4-1-2.3-2.6-2.3-1.2 0-4 .9-8.1 4a40.6 40.6 0 0 0-14.1 32.9c0 13 7.5 21.3 18.7 21.3 11.5 0 19-11.8 19-22z" />
|
||||
</svg>
|
||||
Notist
|
||||
- url: https://youtube.com/playlist?list=PLT41C0Ggz5wa66-AU5xapbOuzkUKUPLzi
|
||||
title: My appearances on YouTubeBlog
|
||||
content: |
|
||||
<svg viewBox="0 0 490 490" height="32"><path d="M480 180v130a100 100 0 0 1-100 100H110A100 100 0 0 1 10 310V180A100 100 0 0 1 110 80h270a100 100 0 0 1 100 100z" fill="#ea4640"/><path fill="#fff" d="m320 245-120 50V195z"/><g fill="#231f20"><path d="M380 70H110A110 110 0 0 0 0 180v130a110 110 0 0 0 110 110h270a110 110 0 0 0 110-110V180A110 110 0 0 0 380 70zm90 240c0 49.6-40.4 90-90 90H110c-49.6 0-90-40.4-90-90V180c0-49.6 40.4-90 90-90h270c49.6 0 90 40.4 90 90v130z"/><path d="m323.8 235.8-120-50A10 10 0 0 0 190 195v100a10 10 0 0 0 13.8 9.2l120-50a10 10 0 0 0 0-18.4zM210 280v-70l84 35-84 35z"/></g></svg>
|
||||
YouTube
|
||||
projects:
|
||||
- url: https://github.com/AverageMarcus/kube-image-prefetch
|
||||
name: kube-image-prefetch
|
||||
description: Pre-pull all images, on all nodes, within a Kubernetes cluster
|
||||
languages:
|
||||
- color: "#00ADD8"
|
||||
name: Go
|
||||
- url: https://github.com/AverageMarcus/tweetsvg
|
||||
name: tweetsvg
|
||||
description: Generate an SVG for a given Tweet ID
|
||||
languages:
|
||||
- color: "#e34c26"
|
||||
name: HTML
|
||||
- color: "#00ADD8"
|
||||
name: Go
|
||||
- url: https://github.com/AverageMarcus/opengraph-image-gen
|
||||
name: opengraph-image-gen
|
||||
description: Dynamically generate OpenGraph social share images
|
||||
languages:
|
||||
- color: "#e34c26"
|
||||
name: HTML
|
||||
- color: "#00ADD8"
|
||||
name: Go
|
||||
- url: https://github.com/AverageMarcus/speedtest-exporter
|
||||
name: speedtest-exporter
|
||||
description: A prometheus exporter for Speedtest.net results
|
||||
languages:
|
||||
- color: "#00ADD8"
|
||||
name: Go
|
||||
- url: https://github.com/AverageMarcus/feed-fetcher
|
||||
name: feed-fetcher
|
||||
description: Returns the RSS feed associated with the given URL
|
||||
languages:
|
||||
- color: "#e34c26"
|
||||
name: HTML
|
||||
- color: "#00ADD8"
|
||||
name: Go
|
||||
events:
|
||||
- date: "2022-09-27"
|
||||
humanDate: "September 27, 2022"
|
||||
url: https://www.meetup.com/DevOps-Notts/
|
||||
eventName: DevOpsNotts
|
||||
details:
|
||||
- name: The Wonders and Woes of Webhooks
|
||||
type: Meetup Talk
|
||||
- date: "2022-09-29"
|
||||
humanDate: "September 29 - 30, 2022"
|
||||
url: https://devopsdays.org/events/2022-london/welcome/
|
||||
eventName: DevOpsDays London 2022
|
||||
details:
|
||||
- name: What DragonBall can teach us about being engineers
|
||||
type: Ignite Talk
|
||||
- date: "2022-10-03"
|
||||
humanDate: "October 3 - 4, 2022"
|
||||
url: https://kubehuddle.com/2022/
|
||||
eventName: KubeHuddle 2022
|
||||
details:
|
||||
- name: The Wonders and Woes of Webhooks
|
||||
type: Presentation
|
||||
- name: What DragonBall can teach us about being engineers
|
||||
type: Lightning Talk
|
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module marcusnoble
|
||||
|
||||
go 1.17
|
||||
|
||||
require gopkg.in/yaml.v2 v2.4.0
|
4
go.sum
Normal file
4
go.sum
Normal file
@ -0,0 +1,4 @@
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
87
main.go
Normal file
87
main.go
Normal file
@ -0,0 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed src data.yaml
|
||||
res embed.FS
|
||||
port string
|
||||
)
|
||||
|
||||
func init() {
|
||||
var ok bool
|
||||
if port, ok = os.LookupEnv("PORT"); !ok {
|
||||
port = "8080"
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
dataBytes, err := res.ReadFile("data.yaml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var data map[string]interface{}
|
||||
if err := yaml.Unmarshal(dataBytes, &data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
page := "src" + r.URL.Path
|
||||
if strings.HasSuffix(page, "/") {
|
||||
page = page + "index.html"
|
||||
}
|
||||
|
||||
if strings.HasSuffix(page, ".html") {
|
||||
tpl, err := template.ParseFS(res, page)
|
||||
if err != nil {
|
||||
log.Printf("page %s (%s) not found...", r.RequestURI, page)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
tpl.Funcs(template.FuncMap(map[string]interface{}{
|
||||
"html": func(str string) template.HTML {
|
||||
return template.HTML(str)
|
||||
},
|
||||
}))
|
||||
|
||||
if err := tpl.Execute(w, data); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
||||
// Serve up the best file format for image
|
||||
if strings.Contains(page, "headshot-transparent.png") {
|
||||
if strings.Contains(r.Header.Get("Accept"), "image/avif") {
|
||||
page = strings.Replace(page, ".png", ".avif", 1)
|
||||
} else if strings.Contains(r.Header.Get("Accept"), "image/webp") {
|
||||
page = strings.Replace(page, ".png", ".webp", 1)
|
||||
}
|
||||
}
|
||||
|
||||
body, err := res.ReadFile(page)
|
||||
if err != nil {
|
||||
log.Printf("file %s (%s) not found...", r.RequestURI, page)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Write(body)
|
||||
return
|
||||
}
|
||||
})
|
||||
// http.FileServer(http.FS(res))
|
||||
|
||||
fmt.Println("Server started at port " + port)
|
||||
log.Fatal(http.ListenAndServe(":"+port, nil))
|
||||
}
|
BIN
src/fonts/OrkneyBold.ttf
Normal file
BIN
src/fonts/OrkneyBold.ttf
Normal file
Binary file not shown.
BIN
src/fonts/OrkneyLight.ttf
Normal file
BIN
src/fonts/OrkneyLight.ttf
Normal file
Binary file not shown.
BIN
src/fonts/OrkneyRegular.ttf
Normal file
BIN
src/fonts/OrkneyRegular.ttf
Normal file
Binary file not shown.
BIN
src/headshot-transparent.avif
Normal file
BIN
src/headshot-transparent.avif
Normal file
Binary file not shown.
BIN
src/headshot-transparent.png
Executable file
BIN
src/headshot-transparent.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
BIN
src/headshot-transparent.webp
Normal file
BIN
src/headshot-transparent.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
295
src/index.html
Normal file
295
src/index.html
Normal file
@ -0,0 +1,295 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<title>Marcus Noble</title>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Orkney';
|
||||
src: url('/fonts/OrkneyRegular.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Orkney';
|
||||
src: url('/fonts/OrkneyBold.ttf') format('truetype');
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Orkney';
|
||||
src: url('/fonts/OrkneyLight.ttf') format('truetype');
|
||||
font-weight: lighter;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #11191f;
|
||||
color: #ededed;
|
||||
display: grid;
|
||||
grid-template: 100vh / 40% 60%;
|
||||
|
||||
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";
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #fd7e0b;
|
||||
}
|
||||
|
||||
header {
|
||||
height: 100vh;
|
||||
background-image: url('headshot-transparent.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: bottom right;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 3700px) {
|
||||
header {
|
||||
background-position: top right;
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 8em;
|
||||
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
main h1 {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
main p {
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
/* Social links */
|
||||
.social-links {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.social-links li {
|
||||
margin-right: .8em;
|
||||
margin-bottom: .6em;
|
||||
}
|
||||
|
||||
.social-links li a {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-end;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.social-links svg {
|
||||
fill: #fff;
|
||||
margin: 0 6px;
|
||||
}
|
||||
|
||||
/* Projects */
|
||||
|
||||
.projects {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
.projects li {
|
||||
width: 400px;
|
||||
max-width: 100%;
|
||||
border: 2px solid;
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
margin: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.projects li a {
|
||||
text-decoration: none;
|
||||
color: unset;
|
||||
}
|
||||
|
||||
.projects blockquote {
|
||||
background: none;
|
||||
margin: 4px 0;
|
||||
padding-left: 4px;
|
||||
border-left: 4px solid;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
.repo-language-color {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Events */
|
||||
.events {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
.events li {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.events time {
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.events li .details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
line-height: 1.4em;
|
||||
padding-left: 10px;
|
||||
margin-left: 2px;
|
||||
border-left: 4px solid;
|
||||
margin-top: .6em;
|
||||
}
|
||||
|
||||
.events li .details > div {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.events .tag {
|
||||
font-size: 0.7em;
|
||||
background: #ededed;
|
||||
color: #11191f;
|
||||
padding: 4px 7px;
|
||||
border-radius: 10em;
|
||||
display: inline-block;
|
||||
font-weight: lighter;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 1700px) {
|
||||
body {
|
||||
grid-template: 20vh 80vh / 100%;
|
||||
}
|
||||
|
||||
header {
|
||||
height: 100%;
|
||||
background-position: bottom center;
|
||||
background-size: contain
|
||||
}
|
||||
main {
|
||||
padding: .5em 4em;
|
||||
|
||||
overflow-y: unset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 1050px) {
|
||||
.projects li {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header></header>
|
||||
<main>
|
||||
<section id="intro">
|
||||
<h1>Hi 👋, I'm Marcus</h1>
|
||||
|
||||
<p>
|
||||
{{ .intro | html }}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="links">
|
||||
<h2>Find me around the web 🌐</h2>
|
||||
|
||||
<ul class="social-links">
|
||||
{{ range .social }}
|
||||
<li>
|
||||
<a href="{{ .url }}" rel="me" title="{{ .title }}">
|
||||
{{ .content | html }}
|
||||
</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="projects">
|
||||
<h2>My Open Source Projects 💻</h2>
|
||||
|
||||
<p>
|
||||
All my Open Source projects can be find on my <a href="https://github.com/AverageMarcus">GitHub</a> profile <small>(as well as my personal <a href="https://git.cluster.fun">Gitea</a> instance, <a href="https://gitlab.com/AverageMarcus">GitLab</a>, <a href="https://codeberg.org/AverageMarcus">Codeberg</a> and <a href="https://bitbucket.org/AverageMarcus/workspace/projects/PROJ">BitBucket</a>)</small>. Below are a selection of highlights.
|
||||
</p>
|
||||
|
||||
<ul class="projects">
|
||||
{{ range .projects }}
|
||||
<li>
|
||||
<a href="{{ .url }}">
|
||||
<strong>{{ .name }}</strong>
|
||||
<blockquote>{{ .description }}</blockquote>
|
||||
<div>
|
||||
{{ range .languages }}
|
||||
<span class="repo-language-color" style="background-color: {{ .color }}"></span> {{ .name }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="events">
|
||||
<h2>Upcoming Events 🗓</h2>
|
||||
|
||||
<ul class="events">
|
||||
{{ range .events }}
|
||||
<li>
|
||||
<time datetime="{{ .date }}">{{ .humanDate }}</time>
|
||||
<div class="details">
|
||||
<strong><a href="{{ .url }}">{{ .eventName }}</a></strong>
|
||||
{{ range .details }}
|
||||
<div>
|
||||
<span>{{ .name }}</span>
|
||||
<span class="tag">{{ .type }}</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user