Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
053d19ce6a | ||
|
|
afc05deb91 | ||
|
|
2502c2946e | ||
|
|
d865ee2d2b | ||
|
|
17b3e2d7d8 | ||
|
|
95a7dcb93b | ||
|
|
f52b3fe9e4 | ||
|
|
8c0b04db0e |
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
BUNDLE_PATH: "_vendor/bundle"
|
|
||||||
BUNDLE_DISABLE_SHARED_GEMS: "true"
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
.git
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
.git/
|
.git/
|
||||||
.gitignore
|
.agent/
|
||||||
_site
|
sample-content/
|
||||||
.sass-cache
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
_vendor
|
*.log
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
name: Build and Push Docker Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
DOCKER_HOST: unix:///var/run/docker.sock
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Log in to Gitea Registry
|
||||||
|
run: echo "${{ secrets.PUSH_TOKEN }}" | docker login git.pengzhan.dev -u "${{ github.actor }}" --password-stdin
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
run: |
|
||||||
|
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
|
||||||
|
IMAGE_NAME="git.pengzhan.dev/$REPO_LOWER"
|
||||||
|
REPO_URL="${{ github.server_url }}/${{ github.repository }}"
|
||||||
|
|
||||||
|
echo "Building image: $IMAGE_NAME with source link: $REPO_URL"
|
||||||
|
|
||||||
|
docker build \
|
||||||
|
--network host \
|
||||||
|
--label "org.opencontainers.image.source=$REPO_URL" \
|
||||||
|
-t $IMAGE_NAME:latest \
|
||||||
|
-t $IMAGE_NAME:${{ github.sha }} .
|
||||||
|
|
||||||
|
docker push $IMAGE_NAME:latest
|
||||||
|
docker push $IMAGE_NAME:${{ github.sha }}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
name: CI Quality & Security Pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security-scan:
|
||||||
|
name: Gitleaks Secret Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Run Gitleaks
|
||||||
|
uses: gitleaks/gitleaks-action@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
test-and-lint:
|
||||||
|
name: Lint & Automated Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js 22
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run Code Linter
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Run Automated Test Suites
|
||||||
|
run: npm test
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name: Docker Build & Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
tags: [ 'v*.*.*' ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
name: Build & Push Container Image
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU (Multi-platform emulation)
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry (ghcr.io)
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract Docker metadata (tags, labels)
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: ghcr.io/${{ github.repository }}
|
||||||
|
tags: |
|
||||||
|
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
|
type=sha,format=short,prefix=sha-
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
|
||||||
|
- name: Build and Push Docker Image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
@@ -1,4 +1,27 @@
|
|||||||
_site
|
# Dependencies
|
||||||
.sass-cache
|
node_modules/
|
||||||
|
|
||||||
|
# OS and Environment
|
||||||
.DS_Store
|
.DS_Store
|
||||||
_vendor
|
.env
|
||||||
|
.agent/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# SQLite Database & WAL / Journal files (runtime persistent state)
|
||||||
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
*.db-wal
|
||||||
|
*.db-shm
|
||||||
|
**/data/*.db*
|
||||||
|
|
||||||
|
# Raw WordPress XML Exports / Backups
|
||||||
|
*.WordPress.*.xml
|
||||||
|
*.wxr.xml
|
||||||
|
|
||||||
|
# Kubernetes Production Secrets
|
||||||
|
k8s/01-secret.yaml
|
||||||
|
k8s/*secret.yaml
|
||||||
|
!k8s/*.example.yaml
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
language: ruby
|
|
||||||
|
|
||||||
rvm:
|
|
||||||
- 2.5.0
|
|
||||||
|
|
||||||
script: bundle exec jekyll build
|
|
||||||
|
|
||||||
install: bundle install
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
||||||
@@ -1,11 +1,29 @@
|
|||||||
FROM ruby:2.7
|
# Multi-stage lightweight build for pengzhan.dev skeleton
|
||||||
|
FROM node:22-alpine AS dependencies
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci --omit=dev
|
||||||
|
|
||||||
WORKDIR /home/app
|
FROM node:22-alpine AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
COPY Gemfile* ./
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=3000
|
||||||
|
|
||||||
RUN bundle install
|
# Copy node_modules from dependencies stage
|
||||||
|
COPY --from=dependencies /app/node_modules ./node_modules
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
COPY . .
|
# Copy skeleton web framework code
|
||||||
|
COPY server/ ./server/
|
||||||
|
COPY views/ ./views/
|
||||||
|
COPY public/ ./public/
|
||||||
|
|
||||||
CMD [ "bundle", "exec", "jekyll", "serve" ]
|
# Persistent Volume mount point
|
||||||
|
VOLUME /app/content
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
USER node
|
||||||
|
|
||||||
|
CMD ["node", "server/index.js"]
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
source "https://rubygems.org"
|
|
||||||
|
|
||||||
gem 'github-pages'
|
|
||||||
# this gem provides regeneration support improvements on Windows
|
|
||||||
gem 'wdm', '>= 0.1.0' if Gem.win_platform?
|
|
||||||
|
|
||||||
gem "webrick"
|
|
||||||
gem "rexml", "~> 3.2"
|
|
||||||
@@ -1,281 +0,0 @@
|
|||||||
GEM
|
|
||||||
remote: https://rubygems.org/
|
|
||||||
specs:
|
|
||||||
activesupport (6.0.6.1)
|
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
||||||
i18n (>= 0.7, < 2)
|
|
||||||
minitest (~> 5.1)
|
|
||||||
tzinfo (~> 1.1)
|
|
||||||
zeitwerk (~> 2.2, >= 2.2.2)
|
|
||||||
addressable (2.8.1)
|
|
||||||
public_suffix (>= 2.0.2, < 6.0)
|
|
||||||
coffee-script (2.4.1)
|
|
||||||
coffee-script-source
|
|
||||||
execjs
|
|
||||||
coffee-script-source (1.11.1)
|
|
||||||
colorator (1.1.0)
|
|
||||||
commonmarker (0.17.13)
|
|
||||||
ruby-enum (~> 0.5)
|
|
||||||
concurrent-ruby (1.2.0)
|
|
||||||
dnsruby (1.61.3)
|
|
||||||
addressable (~> 2.5)
|
|
||||||
em-websocket (0.5.1)
|
|
||||||
eventmachine (>= 0.12.9)
|
|
||||||
http_parser.rb (~> 0.6.0)
|
|
||||||
ethon (0.15.0)
|
|
||||||
ffi (>= 1.15.0)
|
|
||||||
eventmachine (1.2.7)
|
|
||||||
eventmachine (1.2.7-x64-mingw32)
|
|
||||||
execjs (2.8.1)
|
|
||||||
faraday (1.10.2)
|
|
||||||
faraday-em_http (~> 1.0)
|
|
||||||
faraday-em_synchrony (~> 1.0)
|
|
||||||
faraday-excon (~> 1.1)
|
|
||||||
faraday-httpclient (~> 1.0)
|
|
||||||
faraday-multipart (~> 1.0)
|
|
||||||
faraday-net_http (~> 1.0)
|
|
||||||
faraday-net_http_persistent (~> 1.0)
|
|
||||||
faraday-patron (~> 1.0)
|
|
||||||
faraday-rack (~> 1.0)
|
|
||||||
faraday-retry (~> 1.0)
|
|
||||||
ruby2_keywords (>= 0.0.4)
|
|
||||||
faraday-em_http (1.0.0)
|
|
||||||
faraday-em_synchrony (1.0.0)
|
|
||||||
faraday-excon (1.1.0)
|
|
||||||
faraday-httpclient (1.0.1)
|
|
||||||
faraday-multipart (1.0.4)
|
|
||||||
multipart-post (~> 2)
|
|
||||||
faraday-net_http (1.0.1)
|
|
||||||
faraday-net_http_persistent (1.2.0)
|
|
||||||
faraday-patron (1.0.0)
|
|
||||||
faraday-rack (1.0.0)
|
|
||||||
faraday-retry (1.0.3)
|
|
||||||
ffi (1.15.5)
|
|
||||||
ffi (1.15.5-x64-mingw32)
|
|
||||||
forwardable-extended (2.6.0)
|
|
||||||
gemoji (3.0.1)
|
|
||||||
github-pages (205)
|
|
||||||
github-pages-health-check (= 1.16.1)
|
|
||||||
jekyll (= 3.8.7)
|
|
||||||
jekyll-avatar (= 0.7.0)
|
|
||||||
jekyll-coffeescript (= 1.1.1)
|
|
||||||
jekyll-commonmark-ghpages (= 0.1.6)
|
|
||||||
jekyll-default-layout (= 0.1.4)
|
|
||||||
jekyll-feed (= 0.13.0)
|
|
||||||
jekyll-gist (= 1.5.0)
|
|
||||||
jekyll-github-metadata (= 2.13.0)
|
|
||||||
jekyll-mentions (= 1.5.1)
|
|
||||||
jekyll-optional-front-matter (= 0.3.2)
|
|
||||||
jekyll-paginate (= 1.1.0)
|
|
||||||
jekyll-readme-index (= 0.3.0)
|
|
||||||
jekyll-redirect-from (= 0.15.0)
|
|
||||||
jekyll-relative-links (= 0.6.1)
|
|
||||||
jekyll-remote-theme (= 0.4.1)
|
|
||||||
jekyll-sass-converter (= 1.5.2)
|
|
||||||
jekyll-seo-tag (= 2.6.1)
|
|
||||||
jekyll-sitemap (= 1.4.0)
|
|
||||||
jekyll-swiss (= 1.0.0)
|
|
||||||
jekyll-theme-architect (= 0.1.1)
|
|
||||||
jekyll-theme-cayman (= 0.1.1)
|
|
||||||
jekyll-theme-dinky (= 0.1.1)
|
|
||||||
jekyll-theme-hacker (= 0.1.1)
|
|
||||||
jekyll-theme-leap-day (= 0.1.1)
|
|
||||||
jekyll-theme-merlot (= 0.1.1)
|
|
||||||
jekyll-theme-midnight (= 0.1.1)
|
|
||||||
jekyll-theme-minimal (= 0.1.1)
|
|
||||||
jekyll-theme-modernist (= 0.1.1)
|
|
||||||
jekyll-theme-primer (= 0.5.4)
|
|
||||||
jekyll-theme-slate (= 0.1.1)
|
|
||||||
jekyll-theme-tactile (= 0.1.1)
|
|
||||||
jekyll-theme-time-machine (= 0.1.1)
|
|
||||||
jekyll-titles-from-headings (= 0.5.3)
|
|
||||||
jemoji (= 0.11.1)
|
|
||||||
kramdown (= 1.17.0)
|
|
||||||
liquid (= 4.0.3)
|
|
||||||
mercenary (~> 0.3)
|
|
||||||
minima (= 2.5.1)
|
|
||||||
nokogiri (>= 1.10.4, < 2.0)
|
|
||||||
rouge (= 3.13.0)
|
|
||||||
terminal-table (~> 1.4)
|
|
||||||
github-pages-health-check (1.16.1)
|
|
||||||
addressable (~> 2.3)
|
|
||||||
dnsruby (~> 1.60)
|
|
||||||
octokit (~> 4.0)
|
|
||||||
public_suffix (~> 3.0)
|
|
||||||
typhoeus (~> 1.3)
|
|
||||||
html-pipeline (2.14.3)
|
|
||||||
activesupport (>= 2)
|
|
||||||
nokogiri (>= 1.4)
|
|
||||||
http_parser.rb (0.6.0)
|
|
||||||
i18n (0.9.5)
|
|
||||||
concurrent-ruby (~> 1.0)
|
|
||||||
jekyll (3.8.7)
|
|
||||||
addressable (~> 2.4)
|
|
||||||
colorator (~> 1.0)
|
|
||||||
em-websocket (~> 0.5)
|
|
||||||
i18n (~> 0.7)
|
|
||||||
jekyll-sass-converter (~> 1.0)
|
|
||||||
jekyll-watch (~> 2.0)
|
|
||||||
kramdown (~> 1.14)
|
|
||||||
liquid (~> 4.0)
|
|
||||||
mercenary (~> 0.3.3)
|
|
||||||
pathutil (~> 0.9)
|
|
||||||
rouge (>= 1.7, < 4)
|
|
||||||
safe_yaml (~> 1.0)
|
|
||||||
jekyll-avatar (0.7.0)
|
|
||||||
jekyll (>= 3.0, < 5.0)
|
|
||||||
jekyll-coffeescript (1.1.1)
|
|
||||||
coffee-script (~> 2.2)
|
|
||||||
coffee-script-source (~> 1.11.1)
|
|
||||||
jekyll-commonmark (1.3.1)
|
|
||||||
commonmarker (~> 0.14)
|
|
||||||
jekyll (>= 3.7, < 5.0)
|
|
||||||
jekyll-commonmark-ghpages (0.1.6)
|
|
||||||
commonmarker (~> 0.17.6)
|
|
||||||
jekyll-commonmark (~> 1.2)
|
|
||||||
rouge (>= 2.0, < 4.0)
|
|
||||||
jekyll-default-layout (0.1.4)
|
|
||||||
jekyll (~> 3.0)
|
|
||||||
jekyll-feed (0.13.0)
|
|
||||||
jekyll (>= 3.7, < 5.0)
|
|
||||||
jekyll-gist (1.5.0)
|
|
||||||
octokit (~> 4.2)
|
|
||||||
jekyll-github-metadata (2.13.0)
|
|
||||||
jekyll (>= 3.4, < 5.0)
|
|
||||||
octokit (~> 4.0, != 4.4.0)
|
|
||||||
jekyll-mentions (1.5.1)
|
|
||||||
html-pipeline (~> 2.3)
|
|
||||||
jekyll (>= 3.7, < 5.0)
|
|
||||||
jekyll-optional-front-matter (0.3.2)
|
|
||||||
jekyll (>= 3.0, < 5.0)
|
|
||||||
jekyll-paginate (1.1.0)
|
|
||||||
jekyll-readme-index (0.3.0)
|
|
||||||
jekyll (>= 3.0, < 5.0)
|
|
||||||
jekyll-redirect-from (0.15.0)
|
|
||||||
jekyll (>= 3.3, < 5.0)
|
|
||||||
jekyll-relative-links (0.6.1)
|
|
||||||
jekyll (>= 3.3, < 5.0)
|
|
||||||
jekyll-remote-theme (0.4.1)
|
|
||||||
addressable (~> 2.0)
|
|
||||||
jekyll (>= 3.5, < 5.0)
|
|
||||||
rubyzip (>= 1.3.0)
|
|
||||||
jekyll-sass-converter (1.5.2)
|
|
||||||
sass (~> 3.4)
|
|
||||||
jekyll-seo-tag (2.6.1)
|
|
||||||
jekyll (>= 3.3, < 5.0)
|
|
||||||
jekyll-sitemap (1.4.0)
|
|
||||||
jekyll (>= 3.7, < 5.0)
|
|
||||||
jekyll-swiss (1.0.0)
|
|
||||||
jekyll-theme-architect (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-cayman (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-dinky (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-hacker (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-leap-day (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-merlot (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-midnight (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-minimal (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-modernist (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-primer (0.5.4)
|
|
||||||
jekyll (> 3.5, < 5.0)
|
|
||||||
jekyll-github-metadata (~> 2.9)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-slate (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-tactile (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-theme-time-machine (0.1.1)
|
|
||||||
jekyll (~> 3.5)
|
|
||||||
jekyll-seo-tag (~> 2.0)
|
|
||||||
jekyll-titles-from-headings (0.5.3)
|
|
||||||
jekyll (>= 3.3, < 5.0)
|
|
||||||
jekyll-watch (2.2.1)
|
|
||||||
listen (~> 3.0)
|
|
||||||
jemoji (0.11.1)
|
|
||||||
gemoji (~> 3.0)
|
|
||||||
html-pipeline (~> 2.2)
|
|
||||||
jekyll (>= 3.0, < 5.0)
|
|
||||||
kramdown (1.17.0)
|
|
||||||
liquid (4.0.3)
|
|
||||||
listen (3.7.1)
|
|
||||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
||||||
rb-inotify (~> 0.9, >= 0.9.10)
|
|
||||||
mercenary (0.3.6)
|
|
||||||
mini_portile2 (2.8.1)
|
|
||||||
minima (2.5.1)
|
|
||||||
jekyll (>= 3.5, < 5.0)
|
|
||||||
jekyll-feed (~> 0.9)
|
|
||||||
jekyll-seo-tag (~> 2.1)
|
|
||||||
minitest (5.17.0)
|
|
||||||
multipart-post (2.1.1)
|
|
||||||
nokogiri (1.14.1)
|
|
||||||
mini_portile2 (~> 2.8.0)
|
|
||||||
racc (~> 1.4)
|
|
||||||
nokogiri (1.14.1-x64-mingw32)
|
|
||||||
racc (~> 1.4)
|
|
||||||
octokit (4.22.0)
|
|
||||||
faraday (>= 0.9)
|
|
||||||
sawyer (~> 0.8.0, >= 0.5.3)
|
|
||||||
pathutil (0.16.2)
|
|
||||||
forwardable-extended (~> 2.6)
|
|
||||||
public_suffix (3.1.1)
|
|
||||||
racc (1.6.2)
|
|
||||||
rb-fsevent (0.10.4)
|
|
||||||
rb-inotify (0.10.1)
|
|
||||||
ffi (~> 1.0)
|
|
||||||
rexml (3.2.6)
|
|
||||||
rouge (3.13.0)
|
|
||||||
ruby-enum (0.8.0)
|
|
||||||
i18n
|
|
||||||
ruby2_keywords (0.0.5)
|
|
||||||
rubyzip (2.3.2)
|
|
||||||
safe_yaml (1.0.5)
|
|
||||||
sass (3.7.4)
|
|
||||||
sass-listen (~> 4.0.0)
|
|
||||||
sass-listen (4.0.0)
|
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
|
||||||
sawyer (0.8.2)
|
|
||||||
addressable (>= 2.3.5)
|
|
||||||
faraday (> 0.8, < 2.0)
|
|
||||||
terminal-table (1.8.0)
|
|
||||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
|
||||||
thread_safe (0.3.6)
|
|
||||||
typhoeus (1.4.0)
|
|
||||||
ethon (>= 0.9.0)
|
|
||||||
tzinfo (1.2.11)
|
|
||||||
thread_safe (~> 0.1)
|
|
||||||
unicode-display_width (1.7.0)
|
|
||||||
webrick (1.8.1)
|
|
||||||
zeitwerk (2.6.6)
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
ruby
|
|
||||||
x64-mingw32
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
github-pages
|
|
||||||
rexml (~> 3.2)
|
|
||||||
webrick
|
|
||||||
|
|
||||||
BUNDLED WITH
|
|
||||||
2.1.4
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Joel Glovier
|
|
||||||
|
|
||||||
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 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.
|
|
||||||
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
.PHONY: help dev dev-persistent test lint clean docker-build docker-run k8s-status k8s-logs k8s-restart k8s-sync-content
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
all: help
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "========================================================================"
|
||||||
|
@echo " pengzhan.dev — Engineering Makefile"
|
||||||
|
@echo "========================================================================"
|
||||||
|
@echo "Available commands:"
|
||||||
|
@echo " make dev Start local server in Ephemeral Staging Mode"
|
||||||
|
@echo " (Safe by default: site.db is NEVER mutated)"
|
||||||
|
@echo " make dev-persistent Start local server in Persistent DB Mode"
|
||||||
|
@echo " (Changes to comments & logs write to site.db)"
|
||||||
|
@echo " make test Run complete automated test suite"
|
||||||
|
@echo " make lint Run comprehensive project linter (JS, EJS, CSS)"
|
||||||
|
@echo " make clean Remove temporary staging DBs and build caches"
|
||||||
|
@echo " make docker-build Build multi-stage production Docker image"
|
||||||
|
@echo " make docker-run Run production Docker container on port 3000"
|
||||||
|
@echo " make k8s-status Show pods, service, ingress, and PVC in k8s"
|
||||||
|
@echo " make k8s-logs Stream live logs from production pod"
|
||||||
|
@echo " make k8s-restart Trigger zero-downtime rolling restart"
|
||||||
|
@echo " make k8s-sync-content Sync local markdown/media into live cluster PVC"
|
||||||
|
@echo "========================================================================"
|
||||||
|
|
||||||
|
dev:
|
||||||
|
@echo "Starting dev server in Safe Ephemeral Staging Mode..."
|
||||||
|
@echo "-> Production sample-content/data/site.db is protected from writes."
|
||||||
|
APP_ENV=staging node --watch --watch-path=server --watch-path=views --watch-path=public server/index.js
|
||||||
|
|
||||||
|
dev-persistent:
|
||||||
|
@echo "Starting dev server in Persistent DB Mode..."
|
||||||
|
@echo "-> Writes will be recorded to sample-content/data/site.db."
|
||||||
|
node --watch --watch-path=server --watch-path=views --watch-path=public server/index.js
|
||||||
|
|
||||||
|
test:
|
||||||
|
@echo "Running automated test suite..."
|
||||||
|
NODE_ENV=test node test/test.js
|
||||||
|
|
||||||
|
lint:
|
||||||
|
@echo "Running project linter..."
|
||||||
|
node scripts/lint.js
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo "Cleaning temporary test and staging artifacts..."
|
||||||
|
@rm -f /tmp/site.staging-*.db /tmp/site.staging-*.db-*
|
||||||
|
@rm -f sample-content/data/*.db-journal sample-content/data/*.db-wal sample-content/data/*.db-shm
|
||||||
|
@echo "Clean complete."
|
||||||
|
|
||||||
|
docker-build:
|
||||||
|
@echo "Building Docker image pengzhan.dev:latest..."
|
||||||
|
docker build -t pengzhan.dev:latest .
|
||||||
|
|
||||||
|
docker-run:
|
||||||
|
@echo "Running Docker container on http://localhost:3000..."
|
||||||
|
docker run --rm -p 3000:3000 -v $(PWD)/sample-content:/app/content pengzhan.dev:latest
|
||||||
|
|
||||||
|
k8s-status:
|
||||||
|
@echo "Checking Kubernetes status in namespace pengzhan-dev..."
|
||||||
|
kubectl get pods,svc,ingress,pvc -n pengzhan-dev -o wide
|
||||||
|
|
||||||
|
k8s-logs:
|
||||||
|
@echo "Streaming logs from pengzhan-web deployment..."
|
||||||
|
kubectl logs -f deployment/pengzhan-web -n pengzhan-dev
|
||||||
|
|
||||||
|
k8s-restart:
|
||||||
|
@echo "Triggering zero-downtime rolling restart of pengzhan-web..."
|
||||||
|
kubectl rollout restart deployment/pengzhan-web -n pengzhan-dev
|
||||||
|
kubectl rollout status deployment/pengzhan-web -n pengzhan-dev
|
||||||
|
|
||||||
|
k8s-sync-content:
|
||||||
|
@echo "Syncing local sample-content/ to Kubernetes /app/content/..."
|
||||||
|
@POD=$$(kubectl get pod -n pengzhan-dev -l app=pengzhan-web -o jsonpath='{.items[0].metadata.name}'); \
|
||||||
|
if [ -z "$$POD" ]; then \
|
||||||
|
echo "Error: No running pengzhan-web pod found."; exit 1; \
|
||||||
|
fi; \
|
||||||
|
echo "-> Target pod: $$POD"; \
|
||||||
|
kubectl cp sample-content/. pengzhan-dev/$$POD:/app/content/; \
|
||||||
|
kubectl exec -n pengzhan-dev $$POD -- chmod -R 775 /app/content; \
|
||||||
|
echo "-> Sync complete. Hot-reload watcher will index new content."
|
||||||
@@ -1,66 +1,260 @@
|
|||||||
# Resume template
|
# pengzhan.dev — Dynamic Web Framework & Personal Site Skeleton
|
||||||
|
|
||||||
*A simple Jekyll + GitHub Pages powered resume template.*
|
A custom, ultra-lightweight dynamic web framework designed to replicate and replace WordPress for **pengzhan.dev**, optimized for containerized deployment on Kubernetes.
|
||||||
|
|
||||||

|
---
|
||||||
|
|
||||||
## Docs
|
## 1. Architectural Model: Skeleton vs. Persistent Volume
|
||||||
|
|
||||||
### Running locally
|
The architecture separates the **web runtime container (the "Skeleton")** from your **content and extensions (the "Persistent Volume")**:
|
||||||
|
|
||||||
To test locally, run the following in your terminal:
|
```plaintext
|
||||||
|
Kubernetes Pod
|
||||||
|
┌───────────────────────────────────────────────┐
|
||||||
|
│ Docker Container (The "Skeleton") │
|
||||||
|
│ - Node.js 22 + Express │
|
||||||
|
│ - SSR EJS Templates │
|
||||||
|
│ - Markdown-it + PrismJS (Okaidia) │
|
||||||
|
│ - Structured Schema Search Engine │
|
||||||
|
│ - Dynamic Plugin Loader │
|
||||||
|
│ - Hot-reload Watcher (Chokidar) │
|
||||||
|
└───────────────────────┬───────────────────────┘
|
||||||
|
│ mounts /app/content
|
||||||
|
▼
|
||||||
|
┌───────────────────────────────────────────────┐
|
||||||
|
│ Persistent Volume (Your Content & Data) │
|
||||||
|
│ - posts/ (Blog articles & bilinguals) │
|
||||||
|
│ - pages/ (Standalone timeless pages) │
|
||||||
|
│ - plugins/ (Custom executable plugins) │
|
||||||
|
│ - static/ (Fonts, PDFs, Images) │
|
||||||
|
│ - css/ (custom.css overrides) │
|
||||||
|
│ - data/ (site.db SQLite) │
|
||||||
|
│ - config.yaml (Site metadata & settings) │
|
||||||
|
└───────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
1. Clone repo locally
|
- **Zero Container Restarts**: Editing markdown files, uploading PDFs/images, adding new pages, or changing `config.yaml` immediately hot-reloads in memory via `chokidar`.
|
||||||
1. `bundle install`
|
- **Tiny Footprint**: Multi-stage Docker image weighs ~25MB (no React/Vue hydration overhead, no headless browser, no heavy DB daemon).
|
||||||
2. `bundle exec jekyll serve`
|
|
||||||
3. Open your browser to `localhost:4000`
|
|
||||||
|
|
||||||
### Running locally with Docker
|
---
|
||||||
|
|
||||||
To test locally with docker, run the following in your terminal after installing docker into your system:
|
## 2. Directory Structure on Persistent Volume (`/app/content`)
|
||||||
|
|
||||||
1. `docker image build -t resume-template .`
|
```plaintext
|
||||||
2. `docker run --rm --name resume-template -v "$PWD":/home/app --network host resume-template`
|
content/
|
||||||
|
├── config.yaml # Site title, tagline, social links, author bio
|
||||||
|
├── posts/ # Blog articles
|
||||||
|
│ ├── using-gemini-cli-and-mcp-server-to-organize-my-dropbox/
|
||||||
|
│ │ ├── index.md # Default post (English or Chinese)
|
||||||
|
│ │ ├── zh.md # Chinese translation variant
|
||||||
|
│ │ └── images/ # Post assets
|
||||||
|
│ │ └── cover.png
|
||||||
|
│ └── kubelet-source-code-deep-dive/
|
||||||
|
│ └── index.md
|
||||||
|
├── pages/ # Standalone timeless pages
|
||||||
|
│ ├── home.md # Homepage / About-me (mapped to /)
|
||||||
|
│ ├── quick-links.md # Quick links page (mapped to /quick-links)
|
||||||
|
│ └── resume.md # Custom standalone page (mapped to /resume)
|
||||||
|
├── plugins/ # Executable plugins & extensions
|
||||||
|
│ ├── google-analytics/
|
||||||
|
│ │ ├── plugin.json
|
||||||
|
│ │ └── index.js
|
||||||
|
│ └── reading-time/
|
||||||
|
│ ├── plugin.json
|
||||||
|
│ └── index.js
|
||||||
|
├── static/ # Static files served directly at root
|
||||||
|
│ ├── fonts/ # XiaoheSimplifySerif-VF, Maple Mono NF CN
|
||||||
|
│ ├── documents/ # CV.pdf, research papers
|
||||||
|
│ └── images/ # Favicon, profile avatars
|
||||||
|
├── css/
|
||||||
|
│ └── custom.css # User CSS loaded after base styles
|
||||||
|
└── data/
|
||||||
|
└── site.db # SQLite database (auto-created by server)
|
||||||
|
```
|
||||||
|
|
||||||
### Customizing
|
---
|
||||||
|
|
||||||
First you'll want to fork the repo to your own account. Then clone it locally and customize, or use the GitHub web editor to customize.
|
## 3. Posts vs. Pages
|
||||||
|
|
||||||
#### Options/configuration
|
| Feature | `posts/` | `pages/` |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| **Role** | Time-stamped, categorized blog articles. | Timeless, standalone site destinations (e.g. Home, Quick Links). |
|
||||||
|
| **Routing** | Dedicated blog router: `/<slug>` and `/<slug>/<lang>`. | Direct top-level route based on filename or permalink (`/quick-links`, `/resume`). |
|
||||||
|
| **Taxonomy** | Dynamically feeds `category`, `tags: [...]`, and author metadata. | No tags or dates required; does not pollute blog streams. |
|
||||||
|
| **Stream & RSS** | Appears in `/blogs` stream, pagination, and `/feed` (RSS 2.0). | **Excluded** from blog streams, pagination, and RSS feeds. |
|
||||||
|
| **Bilingual** | Sibling translation files (`index.md` + `zh.md` / `en.md`) with in-page switcher. | Self-contained markdown or HTML with custom layout control. |
|
||||||
|
|
||||||
Most of the basic customization will take place in the `/_config.yml` file. Here is a list of customizations available via `/_config.yml`:
|
---
|
||||||
|
|
||||||
[...write these out...]
|
## 4. 100% Dynamic Taxonomy (Tags & Categories)
|
||||||
|
|
||||||
#### Editing content
|
- **Zero Static Configuration**: Tags are **never** declared statically in `config.yaml`.
|
||||||
|
- Whenever a post specifies `tags: [k8s, cloud, "AI Era"]`, the content engine dynamically discovers, normalizes, and aggregates it with count statistics.
|
||||||
|
- The `/search` page automatically derives its default discovery pills from the top active tags and categories.
|
||||||
|
|
||||||
Most of the content configuration will take place in the `/_layouts/resume.html` file. Simply edit the markup there accordingly
|
---
|
||||||
|
|
||||||
### Publishing to GitHub Pages for free
|
## 5. Structured Schema Search Engine
|
||||||
|
|
||||||
[GitHub Pages](https://pages.github.com/) will host this for free with your GitHub account. Just make sure you're using a `gh-pages` branch, and the site will automatically be available at `yourusername.github.io/resume-template` (you can rename the repo to resume for your own use if you want it to be available at `yourusername.github.io/resume`). You can also add a CNAME if you want it to be available at a custom domain...
|
The built-in search engine supports a full query DSL combining metadata filters, exact phrases, and free-text keywords:
|
||||||
|
|
||||||
### Configuring with your own domain name
|
```text
|
||||||
|
tag:k8s "container image" category:tech cgroup
|
||||||
|
```
|
||||||
|
|
||||||
To setup your GH Pages site with a custom domain, [follow the instructions](https://help.github.com/articles/setting-up-a-custom-domain-with-github-pages/) on the GitHub Help site for that topic.
|
### Search Syntax Capabilities
|
||||||
|
|
||||||
### Themes
|
- **Schema Filters**:
|
||||||
|
- `tag:<name>` or `tags:<name>` (e.g. `tag:k8s`)
|
||||||
|
- `category:<name>` or `cat:<name>` (e.g. `category:tech`)
|
||||||
|
- `author:<name>`
|
||||||
|
- `lang:<en|zh>`
|
||||||
|
- **Exact Phrases**: Quoted strings (`"container image"`) requiring exact substring match.
|
||||||
|
- **Keywords**: Bare words searched across title, tags, excerpt, and full markdown body.
|
||||||
|
- **Ranking & Highlighting**: Returns relevance-scored results with contextual snippets wrapped in `<mark>...</mark>`.
|
||||||
|
- **Deduplication**: Bilingual versions of the same post are unified so you never get duplicate cards for the same post.
|
||||||
|
|
||||||
Right now resume-template only has one theme. More are coming :soon: though. :heart:
|
---
|
||||||
|
|
||||||
## Roadmap
|
## 6. Plugin & Extension Architecture (`plugins/`)
|
||||||
|
|
||||||
A feature roadmap is [available here](https://github.com/jglovier/resume-template/projects/1). If you features suggestions, please [open a new issue](https://github.com/jglovier/resume-template/issues/new).
|
Plugins are self-contained folders placed in `/app/content/plugins/<plugin-name>/`:
|
||||||
|
|
||||||
## Contributing
|
```javascript
|
||||||
|
// plugins/my-plugin/index.js
|
||||||
|
module.exports = {
|
||||||
|
// 1. Initialize Express middleware or routes
|
||||||
|
onInit({ app, config, pluginConfig }) {},
|
||||||
|
|
||||||
If you spot a bug, or want to improve the code, or even make the dummy content better, you can do the following:
|
// 2. Extend markdown-it renderer (e.g. custom fences, math, diagrams)
|
||||||
|
onMarkdownInit({ markdownIt, pluginConfig }) {},
|
||||||
|
|
||||||
1. [Open an issue](https://github.com/jglovier/resume-template/issues/new) describing the bug or feature idea
|
// 3. Transform or augment post metadata
|
||||||
2. Fork the project, make changes, and submit a pull request
|
onPostLoad({ post, pluginConfig }) {},
|
||||||
|
|
||||||
## License
|
// 4. Inject into HTML head or body
|
||||||
|
injectHead({ req, pageType, post }) {
|
||||||
|
return `<script src="..."></script>`;
|
||||||
|
},
|
||||||
|
|
||||||
The code and styles are licensed under the MIT license. [See project license.](LICENSE) Obviously you should not use the content of this demo repo in your own resume. :wink:
|
injectPostEnd({ post }) {
|
||||||
|
return `<div>Custom author bio or reaction buttons</div>`;
|
||||||
|
},
|
||||||
|
|
||||||
Disclaimer: Use of Lisa M. Simpson image and name used under [Fair Use](https://en.wikipedia.org/wiki/Fair_use) for educational purposes. Project license does not apply to use of this material.
|
// 5. Lifecycle event: new comment posted
|
||||||
|
async onCommentCreated({ comment, post }) {}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Bilingual Post Authoring
|
||||||
|
|
||||||
|
In `/app/content/posts/<post-slug>/`:
|
||||||
|
|
||||||
|
### Default Language (`index.md`)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
title: "Using Gemini-CLI and MCP server to organize my dropbox"
|
||||||
|
date: 2025-08-31
|
||||||
|
author: "haopengzhan"
|
||||||
|
category: "Tech"
|
||||||
|
tags: ["AI Era", "Dropbox", "Gemini", "k8s"]
|
||||||
|
excerpt: "How I automated Dropbox organization with MCP."
|
||||||
|
lang: en
|
||||||
|
---
|
||||||
|
|
||||||
|
Post content in English...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Translation Variant (`zh.md`)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
title: "使用 Gemini-CLI 与 MCP 服务整理 Dropbox"
|
||||||
|
lang: zh
|
||||||
|
---
|
||||||
|
|
||||||
|
Post content in Chinese...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Routing
|
||||||
|
|
||||||
|
- `https://pengzhan.dev/<post-slug>` → Serves default version (`index.md`).
|
||||||
|
- `https://pengzhan.dev/<post-slug>/zh` → Serves Chinese version (`zh.md`).
|
||||||
|
- Both are linked via the in-page language switcher pill (`🌐 EN | 中文`).
|
||||||
|
- Only **one** entry appears in `/blogs` and `/search`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Development & Makefile Workflows
|
||||||
|
|
||||||
|
The platform includes a native `Makefile` designed to protect your production data while developing and testing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 2. Run local development in Safe Ephemeral Staging Mode (Default)
|
||||||
|
make dev
|
||||||
|
# -> Copies site.db to a temp file in /tmp so your real database is NEVER mutated.
|
||||||
|
# -> Discards all test queries and mock comments automatically on exit.
|
||||||
|
|
||||||
|
# 3. Run development in Persistent Mode (only when you intentionally want to save changes to site.db)
|
||||||
|
make dev-persistent
|
||||||
|
|
||||||
|
# 4. Run automated test suite (in isolated temp DB)
|
||||||
|
make test
|
||||||
|
|
||||||
|
# 5. Run project linter
|
||||||
|
make lint
|
||||||
|
|
||||||
|
# 6. Clean temporary staging artifacts
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Isolation Architecture
|
||||||
|
- **Safe by Default**: Running `npm run dev` or `make dev` automatically runs with `APP_ENV=staging`.
|
||||||
|
- **Ephemeral Sandbox**: In staging or test mode (`NODE_ENV=test`), `server/services/db.js` mirrors the real SQLite database into a temporary sandbox in `os.tmpdir()`. You get 100% full application functionality, but all writes are discarded on exit, keeping `sample-content/data/site.db` 100% pristine.
|
||||||
|
|
||||||
|
### Docker Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t pengzhan-web:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Container with Mounted Persistent Volume
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
-p 3000:3000 \
|
||||||
|
-v /path/to/my-content:/app/content \
|
||||||
|
--name pengzhan-site \
|
||||||
|
pengzhan-web:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kubernetes Deployment Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pengzhan-web
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: web
|
||||||
|
image: pengzhan-web:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
volumeMounts:
|
||||||
|
- name: content
|
||||||
|
mountPath: /app/content
|
||||||
|
volumes:
|
||||||
|
- name: content
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: pengzhan-content-pvc
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="Dribbble" fill="#D1CECC" d="M13.76,14.4c0.37-0.15,0.78-0.26,1.16-0.43c-0.18-0.34-0.35-0.73-0.5-1.04
|
|
||||||
c-0.06-0.11-0.1-0.25-0.2-0.33c-2.49,0.72-5.25,1.17-8.48,1.16c-0.06,2.6,0.88,4.41,2.12,5.79C9.3,17.33,11.22,15.46,13.76,14.4z
|
|
||||||
M15.45,15.38c-2.87,1.04-5.13,2.68-6.53,5.19c0.95,0.74,2.22,1.38,3.72,1.65c1.65,0.29,3.38-0.01,4.6-0.55
|
|
||||||
c-0.37-2.12-0.97-4.14-1.65-5.92C15.57,15.62,15.57,15.46,15.45,15.38z M10.47,6.52c-2.3,1.15-3.92,2.99-4.58,5.79
|
|
||||||
c2.87-0.04,5.42-0.39,7.66-1.04C12.58,9.64,11.6,8.01,10.47,6.52z M14.01,0C6.27,0,0,6.28,0,14.01s6.27,14.01,14.01,14.01
|
|
||||||
c7.05,0,12.89-5.21,13.86-12c0.1-0.46,0.14-0.94,0.13-1.43c0.01-0.2,0.01-0.39,0.01-0.58C28.02,6.28,21.75,0,14.01,0z M21.17,20.6
|
|
||||||
c-0.77,0.85-1.69,1.53-2.78,2.07c-1.09,0.55-2.33,0.97-3.8,1.04c-3.1,0.15-5.52-1.04-7.14-2.53c-1.66-1.53-2.92-3.59-3.14-6.56
|
|
||||||
c-0.11-1.58,0.2-2.97,0.67-4.15c0.48-1.23,1.06-2.14,1.84-3.01c1.11-1.2,2.61-2.26,4.5-2.78c0.68-0.19,1.39-0.31,2.1-0.36
|
|
||||||
c3.17-0.2,5.51,1.07,7.16,2.56c1.65,1.48,2.94,3.62,3.11,6.58C23.89,16.57,22.7,18.94,21.17,20.6z M17.05,14.98
|
|
||||||
c0.64,1.86,1.23,3.76,1.59,5.9c0.46-0.26,0.86-0.61,1.24-0.99c1.14-1.15,1.99-2.63,2.33-4.55C20.79,14.91,18.79,14.7,17.05,14.98z
|
|
||||||
M15.2,10.8c1.73-0.7,3.28-1.6,4.3-3.01c-1.36-1.14-3.32-2.18-5.82-2.05c-0.6,0.03-1.05,0.08-1.59,0.2
|
|
||||||
c0.93,1.37,1.93,2.79,2.73,4.22C14.94,10.38,15.02,10.63,15.2,10.8z M15.81,12.06c0.2,0.38,0.39,0.81,0.56,1.19
|
|
||||||
c0.06,0.14,0.08,0.31,0.2,0.41c1.93-0.22,4.06-0.06,5.74,0.28c-0.06-2.27-0.82-3.85-1.87-5.14C19.24,10.23,17.65,11.27,15.81,12.06z
|
|
||||||
"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,7 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="Facebook" fill="#D1CECC" d="M14,0C6.27,0,0,6.27,0,14s6.27,14,14,14s14-6.27,14-14S21.73,0,14,0z M20.99,20.22
|
|
||||||
c0,0.43-0.35,0.77-0.77,0.77h-3.56v-5.42h1.82l0.27-2.11h-2.09v-1.35c0-0.61,0.17-1.03,1.05-1.03l1.12,0V9.2
|
|
||||||
c-0.19-0.03-0.86-0.08-1.63-0.08c-1.61,0-2.71,0.98-2.71,2.79v1.56h-1.82v2.11h1.82v5.42h-6.7c-0.43,0-0.77-0.35-0.77-0.77V7.78
|
|
||||||
c0-0.43,0.35-0.77,0.77-0.77h12.44c0.43,0,0.77,0.35,0.77,0.77V20.22z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 618 B |
@@ -1,10 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="GitHub" fill-rule="evenodd" clip-rule="evenodd" fill="#D1CECC" d="M14.01,0C6.27,0-0.01,6.28-0.01,14.02
|
|
||||||
c0,6.19,4.02,11.45,9.59,13.3c0.7,0.13,0.96-0.3,0.96-0.68c0-0.33-0.01-1.21-0.02-2.38c-3.9,0.85-4.72-1.88-4.72-1.88
|
|
||||||
c-0.64-1.62-1.56-2.05-1.56-2.05c-1.27-0.87,0.1-0.85,0.1-0.85c1.41,0.1,2.15,1.44,2.15,1.44c1.25,2.14,3.28,1.52,4.08,1.16
|
|
||||||
c0.13-0.91,0.49-1.52,0.89-1.87c-3.11-0.35-6.38-1.56-6.38-6.93c0-1.53,0.55-2.78,1.44-3.76C6.37,9.17,5.89,7.74,6.65,5.81
|
|
||||||
c0,0,1.18-0.38,3.85,1.44c1.12-0.31,2.32-0.47,3.51-0.47c1.19,0.01,2.39,0.16,3.51,0.47c2.68-1.81,3.85-1.44,3.85-1.44
|
|
||||||
c0.76,1.93,0.28,3.35,0.14,3.71c0.9,0.98,1.44,2.23,1.44,3.76c0,5.38-3.28,6.57-6.4,6.92c0.5,0.43,0.95,1.29,0.95,2.6
|
|
||||||
c0,1.87-0.02,3.39-0.02,3.84c0,0.37,0.25,0.81,0.96,0.67c5.56-1.86,9.58-7.11,9.58-13.3C28.03,6.28,21.75,0,14.01,0z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1014 B |
@@ -1,12 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="Instagram" fill="#D1CECC" d="M9.89,7.35h0.49v3.05H9.89V7.35z M7.35,8.26v2.15h0.49V7.44C7.55,7.58,7.35,7.89,7.35,8.26z
|
|
||||||
M18.22,10.3h1.36c0.51,0,0.92-0.41,0.92-0.92V8.38c0-0.51-0.41-0.92-0.92-0.92h-1.36c-0.51,0-0.92,0.41-0.92,0.92v0.99
|
|
||||||
C17.31,9.87,17.72,10.3,18.22,10.3z M8.2,7.35h0.49v3.05H8.2V7.35z M9.05,7.35h0.49v3.05H9.05V7.35z M14-0.01
|
|
||||||
C6.26-0.01-0.01,6.27-0.01,14S6.26,28.01,14,28.01S28.01,21.73,28.01,14S21.74-0.01,14-0.01z M6.63,7.93c0-0.71,0.58-1.3,1.3-1.3
|
|
||||||
h12.14c0.71,0,1.3,0.59,1.3,1.3v3.05h-4.56c-0.64-0.85-1.66-1.39-2.81-1.39s-2.16,0.55-2.81,1.39H6.63V7.93z M17.09,13.1
|
|
||||||
c0,1.7-1.39,3.09-3.09,3.09s-3.09-1.39-3.09-3.09s1.39-3.09,3.09-3.09C15.7,10.01,17.09,11.39,17.09,13.1z M21.37,20.07
|
|
||||||
c0,0.71-0.59,1.3-1.3,1.3H7.93c-0.71,0-1.3-0.59-1.3-1.3V11.5h4.24c-0.25,0.48-0.39,1.02-0.39,1.6c0,1.94,1.58,3.52,3.52,3.52
|
|
||||||
s3.52-1.58,3.52-3.52c0-0.57-0.14-1.12-0.39-1.6h4.24L21.37,20.07L21.37,20.07z M14,10.58c1.39,0,2.52,1.13,2.52,2.52
|
|
||||||
s-1.13,2.52-2.52,2.52s-2.52-1.13-2.52-2.52S12.61,10.58,14,10.58z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,9 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="LinkedIn" fill="#D1CECC" d="M18.82,15.09v3.61h-2.09v-3.37c0-0.85-0.3-1.42-1.06-1.42c-0.58,0-0.92,0.39-1.07,0.77
|
|
||||||
c-0.06,0.13-0.07,0.32-0.07,0.51v3.52h-2.09c0,0,0.03-5.71,0-6.3h2.09v0.89c0,0.01-0.01,0.01-0.01,0.02h0.01V13.3
|
|
||||||
c0.28-0.43,0.77-1.04,1.89-1.04C17.79,12.25,18.82,13.16,18.82,15.09z M9.18,18.7h2.09v-6.3H9.18V18.7z M10.24,9.36
|
|
||||||
c-0.72,0-1.19,0.47-1.19,1.09c0,0.61,0.45,1.09,1.16,1.09h0.01c0.73,0,1.18-0.48,1.18-1.09C11.39,9.84,10.95,9.36,10.24,9.36z
|
|
||||||
M28,14c0,7.73-6.27,14-14,14S0,21.73,0,14S6.27,0,14,0S28,6.27,28,14z M20.93,8.02c0-0.55-0.46-1-1.02-1H8.09
|
|
||||||
c-0.57,0-1.02,0.45-1.02,1v11.96c0,0.55,0.46,1,1.02,1h11.82c0.57,0,1.02-0.45,1.02-1V8.02z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 867 B |
@@ -1,14 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="PDF" fill="#D1CECC" d="M12.28,15.27c0.46-0.94,0.81-1.83,1.05-2.66c0.52,1.29,0.97,2.09,1.35,2.41
|
|
||||||
c0.38,0.32,0.74,0.53,1.09,0.62c-0.75,0.11-1.45,0.24-2.1,0.38c-0.65,0.14-1.35,0.38-2.1,0.71L12.28,15.27z M28,14
|
|
||||||
c0,7.73-6.27,14-14,14S0,21.73,0,14S6.27,0,14,0S28,6.27,28,14z M20.94,9.37L17.47,5.9H7.06v16.2h13.89V9.37z M19.35,17.4
|
|
||||||
c-0.39-0.02-0.86-0.11-1.42-0.27s-1.1-0.36-1.62-0.61c-0.57,0.06-1.14,0.14-1.71,0.25c-0.57,0.11-1.13,0.23-1.67,0.36
|
|
||||||
c-0.07,0.02-0.24,0.08-0.5,0.17s-0.57,0.21-0.93,0.35c-0.84,1.41-1.52,2.32-2.03,2.74c-0.51,0.42-0.92,0.6-1.22,0.55h11.54v-3.58
|
|
||||||
c-0.07,0-0.14,0.01-0.21,0.02C19.51,17.39,19.44,17.4,19.35,17.4z M10.17,16.84c0.12-0.22,0.47-0.93,1.05-2.14
|
|
||||||
c0.58-1.21,1.01-2.24,1.28-3.08c-0.2-0.72-0.33-1.42-0.39-2.09s-0.02-1.23,0.1-1.69c0.07-0.25,0.17-0.44,0.28-0.55
|
|
||||||
s0.23-0.19,0.35-0.23H8.21v10.85c0.4-0.33,0.78-0.58,1.16-0.75C9.74,16.98,10.01,16.87,10.17,16.84z M13.39,7.06
|
|
||||||
c0.27,0,0.5,0.1,0.7,0.31c0.2,0.2,0.28,0.54,0.24,1.01c0.01,0.01,0.01,0.3,0,0.87c-0.01,0.57-0.09,1.33-0.24,2.28
|
|
||||||
c0.52,1.37,1.02,2.27,1.52,2.69c0.49,0.42,0.87,0.67,1.14,0.74c0.52-0.06,0.99-0.09,1.43-0.09c0.31,0,0.61,0.04,0.88,0.13
|
|
||||||
c0.27,0.08,0.52,0.19,0.73,0.33V9.95l-2.89-2.89H13.39z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,7 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="Print" fill="#D1CECC" d="M9.5,7.5h9V9h-9V7.5z M9.5,13.5h9v7h-9V13.5z M10.5,15.51h7v-1h-7V15.51z M10.5,17.49h7v-1h-7
|
|
||||||
V17.49z M10.5,19.49h7v-1h-7V19.49z M28,14c0,7.73-6.27,14-14,14S0,21.73,0,14S6.27,0,14,0S28,6.27,28,14z M22,11c0-1.1-0.9-2-2-2
|
|
||||||
h-0.5V6.5h-11V9H8c-1.1,0-2,0.9-2,2v4c0,1.1,0.9,2,2,2h0.5v4.5h11V17H20c1.1,0,2-0.9,2-2V11z M20.02,10.45c-0.28,0-0.5,0.22-0.5,0.5
|
|
||||||
s0.22,0.5,0.5,0.5s0.5-0.22,0.5-0.5S20.29,10.45,20.02,10.45z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 643 B |
@@ -1,10 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="Twitter" fill="#D1CECC" d="M14,0C6.27,0,0,6.27,0,14s6.27,14,14,14s14-6.27,14-14S21.73,0,14,0z M20.69,10.57
|
|
||||||
c0.01,0.15,0.01,0.3,0.01,0.45c0,4.56-3.47,9.82-9.82,9.82c-1.95,0-3.76-0.57-5.29-1.55c0.27,0.03,0.54,0.05,0.82,0.05
|
|
||||||
c1.62,0,3.11-0.55,4.29-1.48c-1.51-0.03-2.79-1.03-3.23-2.4c0.21,0.04,0.43,0.06,0.65,0.06c0.31,0,0.62-0.04,0.91-0.12
|
|
||||||
c-1.58-0.32-2.77-1.71-2.77-3.39c0-0.01,0-0.03,0-0.04c0.47,0.26,1,0.41,1.56,0.43c-0.93-0.62-1.54-1.68-1.54-2.87
|
|
||||||
c0-0.63,0.17-1.23,0.47-1.74c1.7,2.09,4.25,3.46,7.12,3.61c-0.06-0.25-0.09-0.52-0.09-0.79c0-1.91,1.55-3.45,3.45-3.45
|
|
||||||
c0.99,0,1.89,0.42,2.52,1.09c0.79-0.15,1.53-0.44,2.19-0.84c-0.26,0.81-0.81,1.48-1.52,1.91c0.7-0.08,1.36-0.27,1.98-0.54
|
|
||||||
C21.95,9.47,21.37,10.08,20.69,10.57z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 934 B |
@@ -1,40 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve">
|
|
||||||
<path id="Website" fill="#D1CECC" d="M14.83,7.6c0.03,0.08,0.03,0.14,0,0.19s-0.08,0.07-0.17,0.07c-0.12,0-0.26-0.01-0.4-0.04
|
|
||||||
s-0.2-0.06-0.18-0.1c0.15-0.15,0.16-0.26,0.03-0.33c-0.13-0.07-0.27-0.11-0.42-0.11s-0.25-0.04-0.3-0.09s-0.03-0.09,0.05-0.09
|
|
||||||
s0.22,0,0.4,0.01c0.19,0.01,0.31,0.04,0.37,0.08s0.17,0.1,0.33,0.19S14.8,7.52,14.83,7.6z M15.9,13.35c-0.11-0.03-0.2-0.03-0.26,0
|
|
||||||
s-0.13,0.05-0.2,0.05c-0.08-0.01-0.25-0.09-0.5-0.24s-0.5-0.22-0.77-0.22c-0.11,0.01-0.17,0.04-0.19,0.08s-0.01,0.07,0.01,0.08
|
|
||||||
c0.02,0.01,0.12,0.03,0.29,0.05s0.4,0.11,0.67,0.26c0.28,0.15,0.48,0.21,0.61,0.19s0.22-0.06,0.28-0.1
|
|
||||||
c0.07-0.01,0.12-0.03,0.16-0.06S16.01,13.38,15.9,13.35z M13.62,6.85c0.17-0.03,0.3-0.13,0.38-0.3c0.03-0.14-0.04-0.2-0.21-0.18
|
|
||||||
s-0.29,0.07-0.37,0.13c-0.01,0.03-0.02,0.06-0.03,0.09s-0.02,0.06-0.03,0.07l-0.08,0.1c-0.03,0.03-0.03,0.05-0.02,0.06
|
|
||||||
C13.32,6.88,13.44,6.89,13.62,6.85z M16.12,7.08c-0.02-0.16-0.11-0.3-0.26-0.41s-0.32-0.19-0.5-0.22c-0.18-0.03-0.38-0.07-0.61-0.12
|
|
||||||
s-0.4-0.04-0.53,0.04c-0.21,0.18-0.25,0.31-0.12,0.39c0.07,0.03,0.2,0.05,0.38,0.06s0.44,0.15,0.76,0.41
|
|
||||||
c0.11,0.08,0.29,0.21,0.55,0.37s0.44,0.23,0.55,0.19c0.06-0.06,0.04-0.15-0.05-0.28S16.14,7.24,16.12,7.08z M28,14
|
|
||||||
c0,7.73-6.27,14-14,14S0,21.73,0,14S6.27,0,14,0S28,6.27,28,14z M21.95,14c-0.06-2.25-0.83-4.12-2.33-5.62
|
|
||||||
c-1.5-1.5-3.37-2.27-5.62-2.33c-2.25,0.06-4.12,0.83-5.62,2.33c-1.5,1.5-2.27,3.37-2.33,5.62c0.06,2.25,0.83,4.12,2.33,5.62
|
|
||||||
c1.5,1.5,3.37,2.27,5.62,2.33c0.54,0,1.06-0.05,1.57-0.14c-0.11-0.07-0.17-0.24-0.18-0.51s0.04-0.52,0.16-0.76
|
|
||||||
c0.15-0.26,0.3-0.61,0.46-1.04c0.15-0.43,0.08-0.77-0.23-1c-0.32-0.18-0.51-0.34-0.57-0.49s-0.19-0.32-0.37-0.54
|
|
||||||
s-0.28-0.36-0.28-0.44v-0.21c-0.01-0.21,0.05-0.43,0.19-0.66l0.25-0.39c0.01-0.04,0.02-0.1,0.02-0.19v-0.19
|
|
||||||
c-0.01-0.04-0.07-0.09-0.17-0.16s-0.17-0.1-0.22-0.1s-0.09,0.01-0.11,0.05s-0.07,0.06-0.13,0.06s-0.17-0.04-0.33-0.13
|
|
||||||
c-0.16-0.09-0.27-0.16-0.32-0.21s-0.1-0.11-0.14-0.19s-0.09-0.15-0.16-0.22s-0.11-0.1-0.16-0.09s-0.12,0-0.23-0.03l-1.45-0.56
|
|
||||||
c-0.26-0.11-0.43-0.23-0.5-0.37c-0.07-0.14-0.1-0.26-0.1-0.37s-0.06-0.23-0.17-0.37l-0.29-0.37c-0.08-0.12-0.14-0.24-0.17-0.34
|
|
||||||
s-0.05-0.15-0.06-0.13c-0.01,0.07,0.02,0.23,0.1,0.48s0.12,0.39,0.1,0.43c-0.03,0.01-0.07-0.02-0.12-0.11s-0.12-0.19-0.19-0.3
|
|
||||||
c-0.06-0.07-0.07-0.15-0.04-0.25c0.03-0.1-0.07-0.38-0.29-0.85c-0.22-0.47-0.26-0.85-0.11-1.15s0.24-0.57,0.3-0.82
|
|
||||||
c0.03-0.21,0.09-0.25,0.19-0.13c0.1,0.12,0.1,0.11,0.02-0.01c-0.08-0.18-0.11-0.4-0.08-0.65c0.03-0.26,0.01-0.46-0.06-0.61
|
|
||||||
c-0.11-0.1-0.3-0.08-0.58,0.05S9.12,8.14,9.1,8.16c0.03-0.12,0.18-0.28,0.46-0.46l0.87-0.58c0.26-0.17,0.49-0.22,0.69-0.17
|
|
||||||
s0.41,0.12,0.62,0.21s0.34,0.12,0.37,0.1s0.01-0.06-0.06-0.13s-0.07-0.13,0.01-0.16S12.26,6.96,12.43,7
|
|
||||||
c0.17,0.03,0.31,0.11,0.42,0.24s0.3,0.18,0.54,0.17s0.32,0.01,0.25,0.06s-0.11,0.12-0.11,0.19c0.04,0.06,0.02,0.1-0.05,0.13
|
|
||||||
s-0.2,0.1-0.36,0.21s-0.18,0.19-0.05,0.26c0.13,0.07,0.36,0.21,0.67,0.41c0.28,0.19,0.41,0.19,0.41-0.01s-0.02-0.4-0.06-0.61
|
|
||||||
c-0.01-0.14,0.05-0.19,0.2-0.14s0.22,0.07,0.24,0.08c0.17,0.11,0.27,0.15,0.32,0.11s0.13-0.04,0.26-0.01
|
|
||||||
c0.17,0.07,0.37,0.19,0.6,0.37l0.41,0.33c-0.43,0.25-0.6,0.41-0.51,0.49s0.2,0.14,0.32,0.2c0.06,0.06,0.02,0.12-0.1,0.21
|
|
||||||
s-0.2,0.12-0.23,0.12c-0.08-0.08-0.15-0.1-0.2-0.05s-0.1,0.09-0.16,0.13c-0.06,0.04-0.07,0.09-0.05,0.14s0.04,0.09,0.05,0.1
|
|
||||||
c-0.3,0.07-0.47,0.22-0.49,0.44s-0.02,0.39-0.01,0.49c0,0.08-0.07,0.18-0.21,0.3s-0.24,0.23-0.31,0.34c-0.03,0.14,0,0.29,0.08,0.47
|
|
||||||
c0.08,0.17,0.08,0.27,0,0.3c-0.08-0.01-0.22-0.12-0.41-0.32c-0.19-0.2-0.55-0.24-1.08-0.13c-0.19,0.04-0.39,0.16-0.6,0.36
|
|
||||||
s-0.23,0.49-0.06,0.88c0.21,0.32,0.43,0.38,0.68,0.19c0.25-0.19,0.43-0.3,0.56-0.31c0.1,0.08,0.12,0.2,0.06,0.35
|
|
||||||
c-0.06,0.15-0.08,0.24-0.08,0.27c0.06-0.01,0.17,0.02,0.34,0.09s0.28,0.27,0.32,0.58c0.04,0.31,0.19,0.49,0.46,0.55
|
|
||||||
s0.45,0.08,0.57,0.07s0.28-0.09,0.48-0.24s0.32-0.24,0.37-0.27s0.17-0.06,0.35-0.1s0.47,0.03,0.84,0.23s0.67,0.31,0.88,0.35
|
|
||||||
s0.38,0.11,0.5,0.2s0.18,0.2,0.18,0.33s0.05,0.23,0.14,0.3c0.15,0.04,0.39,0.07,0.72,0.07s0.57,0.1,0.72,0.28
|
|
||||||
c0.07,0.28-0.08,0.73-0.46,1.38c-0.37,0.64-0.68,1.05-0.93,1.23c-0.18,0.12-0.34,0.29-0.48,0.49s-0.3,0.38-0.49,0.55
|
|
||||||
s-0.41,0.34-0.66,0.52s-0.51,0.34-0.78,0.5c-0.21,0.15-0.36,0.32-0.46,0.51s-0.19,0.32-0.27,0.4c1.81-0.43,3.28-1.34,4.43-2.75
|
|
||||||
C21.31,17.6,21.9,15.93,21.95,14z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.3 KiB |
@@ -1,66 +0,0 @@
|
|||||||
# Site settings
|
|
||||||
title: "Pengzhan.dev"
|
|
||||||
description: "Pengzhan Hao's personal biography"
|
|
||||||
|
|
||||||
# Build settings
|
|
||||||
markdown: kramdown
|
|
||||||
sass:
|
|
||||||
sass_dir: _sass
|
|
||||||
style: compressed
|
|
||||||
|
|
||||||
# Resume settings
|
|
||||||
resume_avatar: "true"
|
|
||||||
resume_name: "Pengzhan Hao"
|
|
||||||
resume_title: "Software Engineer"
|
|
||||||
|
|
||||||
# used for the contact button in _layouts/resume.html
|
|
||||||
resume_contact_email: "[email protected]"
|
|
||||||
|
|
||||||
# the next two items are used for schema itemprops in _layouts/resume.html
|
|
||||||
#resume_contact_telephone: "555-7334"
|
|
||||||
#resume_contact_address: "742 Evergreen Terrace, Springfield"
|
|
||||||
|
|
||||||
#resume_header_contact_info: "742 Evergreen Terrace, Springfield • 555-7334 • [email protected]"
|
|
||||||
#display_header_contact_info: "false"
|
|
||||||
|
|
||||||
resume_header_intro: "<p>Software engineer on Cloud, research focus on Edge computing and Distributed systems</p>"
|
|
||||||
|
|
||||||
# use "yes" to display the email contact button,
|
|
||||||
# "no" to display an "I'm not looking for work" message,
|
|
||||||
# or remove the resume_looking_for_work option entirely
|
|
||||||
# to leave blank
|
|
||||||
resume_looking_for_work: "no"
|
|
||||||
|
|
||||||
# Decide which sections to use
|
|
||||||
# comment out to hide
|
|
||||||
resume_section_experience: true
|
|
||||||
resume_section_education: true
|
|
||||||
resume_section_publications: true
|
|
||||||
resume_section_projects: true
|
|
||||||
resume_section_skills: true
|
|
||||||
resume_section_recognition: true
|
|
||||||
resume_section_links: true
|
|
||||||
# resume_section_associations: true
|
|
||||||
# resume_section_interests: true
|
|
||||||
|
|
||||||
# Resume social links
|
|
||||||
# uncomment the options you wish to display, and add your own URL
|
|
||||||
resume_social_links:
|
|
||||||
resume_github_url: "https://github.com/CoderSherlock"
|
|
||||||
#resume_twitter_url: "http://twitter.com/jglovier"
|
|
||||||
#resume_dribbble_url: "https://dribbble.com/jag"
|
|
||||||
# resume_facebook_url: "insert Facebook URL here"
|
|
||||||
resume_linkedin_url: "https://www.linkedin.com/in/pengzhanhao/"
|
|
||||||
resume_instagram_url: "https://www.instagram.com/pengzhan.hao/"
|
|
||||||
resume_website_url: "http://pengzhan.dev"
|
|
||||||
#resume_medium_url: "https://medium.com/@jglovier"
|
|
||||||
resume_print_social_links: true
|
|
||||||
|
|
||||||
# Design settings
|
|
||||||
resume_theme: default
|
|
||||||
|
|
||||||
# Note: when editing locally, remember to restart
|
|
||||||
# your Jekyll server when you edit this file. Changes
|
|
||||||
# to _config.yml are only recognized when the server starts
|
|
||||||
|
|
||||||
exclude: ['README.md', 'LICENSE', 'Dockerfile', 'CNAME', 'Gemfile', 'Gemfile.lock', 'deploy.sh']
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Associations
|
|
||||||
# comment out the urls if you do not wish to display them
|
|
||||||
|
|
||||||
- organization: PETA
|
|
||||||
role: Volunteer
|
|
||||||
year: 2001 — 2010
|
|
||||||
url: https://www.peta.org/
|
|
||||||
summary: Organized fund drives and participated in fundraising events for the benefit of PETA's local Springfield operations.
|
|
||||||
|
|
||||||
|
|
||||||
- organization: Yale Amnesty International
|
|
||||||
role: Communications coordinator
|
|
||||||
year: 2002 — 2004
|
|
||||||
url: http://campuspress.yale.edu/amnesty/
|
|
||||||
summary: During my junion and senior years at Yale, I was actively involved in Yale Amnesty International where I helped facilitate our student organization communications through website maintenance, writing for our campus publication, and graphic design of related materials.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Degree
|
|
||||||
- degree: Doctorate of Science in Computer Science
|
|
||||||
uni: Binghamton university, the State University of New York
|
|
||||||
year: 2017 —
|
|
||||||
|
|
||||||
- degree: Master of Science in Computer Science
|
|
||||||
uni: Binghamton university, the State University of New York
|
|
||||||
year: 2015 — 2017
|
|
||||||
summary: GPA 4.0/4.0
|
|
||||||
|
|
||||||
- degree: Bachelor of Engineering in Software Engineering
|
|
||||||
uni: Beihang University
|
|
||||||
year: 2011 — 2015
|
|
||||||
summary: GPA 3.25/4.0
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# Jobs
|
|
||||||
# Google
|
|
||||||
- company: Google
|
|
||||||
position: Software Engineer
|
|
||||||
duration: Jun, 2022 —
|
|
||||||
summary: Keep GKE nodes working
|
|
||||||
|
|
||||||
# Graduate position
|
|
||||||
- company: Binghamton University, Mobile and Operating System Lab
|
|
||||||
position: Research Assistant, advised by Prof. Yifan Zhang
|
|
||||||
duration: Oct, 2016 —
|
|
||||||
summary: Edge-based distributed deep learning
|
|
||||||
<ul class="resume-item-list">
|
|
||||||
<li>Implemented a system for time-sensitive, edge-based distributed neural network training scenarios with state-of-the-art performanc</li>
|
|
||||||
<li>Applied empirical experiments to show potential opportunities in Edge-based/Mobile-based distributed neural network training.</li>
|
|
||||||
<li>Investigated heterogeneous-aware training tasks scheduling problem. </li>
|
|
||||||
</ul>
|
|
||||||
Edge computing
|
|
||||||
<ul class="resume-item-list">
|
|
||||||
<li>Envision edge computing's work-flow in end device performance(latency, traffic) improving.</li>
|
|
||||||
<li>Applied empirical experiments on different edge computing work-flow and propose/implement related solutions. </li>
|
|
||||||
<li>Design and implement an edge-based multi-tier system for decreasing bandwidth usage from endpoint mobile device. </li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
# Undergrad
|
|
||||||
- company: Advance computer application technology engineering research center
|
|
||||||
position: Research Assistant, advised by Prof. Juhua Pu
|
|
||||||
duration: Oct, 2013 — Sep, 2014
|
|
||||||
summary: Real-time routing
|
|
||||||
<ul class="resume-item-list">
|
|
||||||
<li>Studied on real-time routing problem based vehicle location data </li>
|
|
||||||
<li>Optimized current routing algorithm with predicted traffic information </li>
|
|
||||||
</ul>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# Interests
|
|
||||||
- description: Human rights and world affairs
|
|
||||||
- description: Music (baritone saxiphonist)
|
|
||||||
- description: Linguistics
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# links
|
|
||||||
- url: "https://blog.pengzhan.dev/"
|
|
||||||
description: My personal blog
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Projects
|
|
||||||
# uncomment the urls if you wish to display them, and add your own URL
|
|
||||||
- project: EDDL - Edge distributed deep learning framework
|
|
||||||
role: Leader
|
|
||||||
duration: 2018 — Present
|
|
||||||
# url: "#"
|
|
||||||
description: A lite-weight c++ written framework(based on Dlib) for distributed neural network training on embedded devices and
|
|
||||||
mobile phones. With supporting of our implemented runtime profilers, training devices can interconnect in an optimized
|
|
||||||
network topology under various network environments.
|
|
||||||
In our last publication, we showed our framework can perform distributed training for diverse neural networks on
|
|
||||||
resource-limited devices. The EDDL framework also showed well scalability in large amounts of devices.
|
|
||||||
We are currently working on network optimization on per-batch communication time and overall convergence time.
|
|
||||||
|
|
||||||
- project: Edge Courier
|
|
||||||
role: Leader
|
|
||||||
duration: 2016 — 2017
|
|
||||||
# url: "#"
|
|
||||||
description: A proxy-based protocol for incremental file synchronization and cooperative online document editing. This protocol
|
|
||||||
supports file hosting services including Google Drive, Dropbox, and OneDrive as well as document collaboration services
|
|
||||||
such as G Suite and Microsoft 365.
|
|
||||||
Edge courier can significantly decrease bandwidth consumption for collaborative editing web apps, and also showed
|
|
||||||
advancement in cloud file storage services.
|
|
||||||
|
|
||||||
- project: RTRouting assistant
|
|
||||||
role: Undergraduate-level student researcher
|
|
||||||
duration: 2013 — 2014
|
|
||||||
# url: "#"
|
|
||||||
description: A real time routing prototype which can guide vehicle to alternative routes with high-volume traffic prediction. The
|
|
||||||
predicted traffic alert is generated by a pre-trained model learned from history monitored traffics, real time event
|
|
||||||
warnings and a abnormal traffic prediction model. This project belongs to a urban computing project studied together
|
|
||||||
by Advance computer application technology engineering research center(Beihang University) and Microsoft Research
|
|
||||||
Asia(MSRA).
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# Publications
|
|
||||||
# uncomment the urls if you wish to display them, and add your own URL
|
|
||||||
- name: "EDDL: A Distributed Deep Learning System for Resource-limited Edge Computing Environment"
|
|
||||||
url: "https://blog.pengzhan.dev/static/2021-12/eddl-sec21.pdf"
|
|
||||||
description: "Pengzhan Hao, and Yifan Zhang The Sixth ACM/IEEE Symposium on Edge Computing (ACM/IEEE SEC)
|
|
||||||
San Jose, CA, USA, 2021."
|
|
||||||
|
|
||||||
- name: A Case for Web Service Bandwidth Reduction on Mobile Devices with Edge-hosted Personal Services
|
|
||||||
description: "Yongshu Bai, Pengzhan Hao, and Yifan Zhang The 37th IEEE International ConferenDDL - Edge distributed deep learning frameworkce on Computer Communications (IEEE INFOCOM)
|
|
||||||
Honolulu, HI, USA, 2018."
|
|
||||||
url: "https://blog.pengzhan.dev/static/2021-10/eta-infocom18.pdf"
|
|
||||||
|
|
||||||
- name: "EdgeCourier: An Edge-hosted Personal Service for Low-bandwidth Document Synchronization in Mobile Cloud Storage Services"
|
|
||||||
description: "Pengzhan Hao, Yongshu Bai, Xin Zhang, and Yifan Zhang
|
|
||||||
The 2nd ACM/IEEE Symposium on Edge Computing (ACM/IEEE SEC)
|
|
||||||
San Jose, CA, USA, 2017."
|
|
||||||
url: "https://blog.pengzhan.dev/static/2018-02/a7-hao.pdf"
|
|
||||||
|
|
||||||
- name: "Poster: Securing Device Inputs for Smartphones Using Hypervisor Based Approach"
|
|
||||||
description: "Xin Zhang, Yongshu Bai, Pengzhan Hao, and Yifan Zhang
|
|
||||||
The 15th ACM International Conference on Mobile Systems, Applications, and Services (ACM MobiSys)
|
|
||||||
Niagara Falls, NY, USA, 2017."
|
|
||||||
url: "https://blog.pengzhan.dev/static/2017-07/p169-zhang.pdf"
|
|
||||||
|
|
||||||
- name: "Poster: EPS - Edge-hosted Personal Services for Mobile Users"
|
|
||||||
description: "Pengzhan Hao, Yongshu Bai, Xin Zhang, and Yifan Zhang
|
|
||||||
The 15th ACM International Conference on Mobile Systems, Applications, and Services (ACM MobiSys)
|
|
||||||
Niagara Falls, NY, USA, 2017."
|
|
||||||
url: "https://blog.pengzhan.dev/static/2017-07/p163-hao.pdf"
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# Recognitions
|
|
||||||
- award: ACM/IEEE SEC student travel grant
|
|
||||||
organization: IEEE
|
|
||||||
year: 2017, 2021
|
|
||||||
|
|
||||||
- award: ACM MobiSys 2017 student travel grant
|
|
||||||
organization: ACM
|
|
||||||
year: 2017
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# Skills
|
|
||||||
# Organizational leadership
|
|
||||||
- skill: Professional skills
|
|
||||||
description: "C/C++, Python, Golang, Java, Bash, SQL, Docker, Kubernetes, Xen hypervisor, RESTful, Django, OAuth, ProtoBuf"
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
|
|
||||||
<title>{% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}</title>
|
|
||||||
|
|
||||||
<!-- Google font typography settings - defined in _config.yml -->
|
|
||||||
{% if site.resume_theme == 'default' %}
|
|
||||||
<link href='https://fonts.googleapis.com/css?family=Lora:400,700|Open+Sans:400,300,800,700' rel='stylesheet' type='text/css'>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<meta name="description" content="{% if page.excerpt %}{{ page.excerpt | strip_html | strip_newlines | truncate: 160 }}{% else %}{{ site.description }}{% endif %}">
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/main.css">
|
|
||||||
<link rel="canonical" href="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}">
|
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
|
||||||
<!-- Google tag (gtag.js) -->
|
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-MNP4QN1T9T"></script>
|
|
||||||
<script>
|
|
||||||
window.dataLayer = window.dataLayer || [];
|
|
||||||
function gtag(){dataLayer.push(arguments);}
|
|
||||||
gtag('js', new Date());
|
|
||||||
|
|
||||||
gtag('config', 'G-MNP4QN1T9T');
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<!-- and guess where these are defined? Yup, you guessed it: the _config.yml file -->
|
|
||||||
{% if site.resume_social_links %}
|
|
||||||
<ul class="icon-links">
|
|
||||||
|
|
||||||
<!-- GitHub link -->
|
|
||||||
{% if site.resume_social_links.resume_github_url %}
|
|
||||||
<li class="icon-link-item"><a href="{{ site.resume_social_links.resume_github_url }}" class="icon-link" itemprop="sameAs">{% include icons/icon-github.html %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Twitter link -->
|
|
||||||
{% if site.resume_social_links.resume_twitter_url %}
|
|
||||||
<li class="icon-link-item"><a href="{{ site.resume_social_links.resume_twitter_url }}" class="icon-link" itemprop="sameAs">{% include icons/icon-twitter.html %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Medium link -->
|
|
||||||
{% if site.resume_social_links.resume_medium_url %}
|
|
||||||
<li class="icon-link-item">
|
|
||||||
<a href="{{ site.resume_social_links.resume_medium_url }}" class="icon-link" itemprop="url">{% include icons/icon-medium.html %}</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Dribbble link -->
|
|
||||||
{% if site.resume_social_links.resume_dribbble_url %}
|
|
||||||
<li class="icon-link-item"><a href="{{ site.resume_social_links.resume_dribbble_url }}" class="icon-link" itemprop="sameAs">{% include icons/icon-dribbble.html %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Facebook link -->
|
|
||||||
{% if site.resume_social_links.resume_facebook_url %}
|
|
||||||
<li class="icon-link-item"><a href="{{ site.resume_social_links.resume_facebook_url }}" class="icon-link" itemprop="sameAs">{% include icons/icon-facebook.html %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- LinkedIn link -->
|
|
||||||
{% if site.resume_social_links.resume_linkedin_url %}
|
|
||||||
<li class="icon-link-item"><a href="{{ site.resume_social_links.resume_linkedin_url }}" class="icon-link" itemprop="sameAs">{% include icons/icon-linkedin.html %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Instagram link -->
|
|
||||||
{% if site.resume_social_links.resume_instagram_url %}
|
|
||||||
<li class="icon-link-item"><a href="{{ site.resume_social_links.resume_instagram_url }}" class="icon-link" itemprop="sameAs">{% include icons/icon-instagram.html %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Website link -->
|
|
||||||
{% if site.resume_social_links.resume_website_url %}
|
|
||||||
<li class="icon-link-item"><a href="{{ site.resume_social_links.resume_website_url }}" class="icon-link" itemprop="url">{% include icons/icon-website.html %}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="Dribbble" fill="#D1CECC" d="M13.76,14.4c0.37-0.15,0.78-0.26,1.16-0.43c-0.18-0.34-0.35-0.73-0.5-1.04
|
|
||||||
c-0.06-0.11-0.1-0.25-0.2-0.33c-2.49,0.72-5.25,1.17-8.48,1.16c-0.06,2.6,0.88,4.41,2.12,5.79C9.3,17.33,11.22,15.46,13.76,14.4z
|
|
||||||
M15.45,15.38c-2.87,1.04-5.13,2.68-6.53,5.19c0.95,0.74,2.22,1.38,3.72,1.65c1.65,0.29,3.38-0.01,4.6-0.55
|
|
||||||
c-0.37-2.12-0.97-4.14-1.65-5.92C15.57,15.62,15.57,15.46,15.45,15.38z M10.47,6.52c-2.3,1.15-3.92,2.99-4.58,5.79
|
|
||||||
c2.87-0.04,5.42-0.39,7.66-1.04C12.58,9.64,11.6,8.01,10.47,6.52z M14.01,0C6.27,0,0,6.28,0,14.01s6.27,14.01,14.01,14.01
|
|
||||||
c7.05,0,12.89-5.21,13.86-12c0.1-0.46,0.14-0.94,0.13-1.43c0.01-0.2,0.01-0.39,0.01-0.58C28.02,6.28,21.75,0,14.01,0z M21.17,20.6
|
|
||||||
c-0.77,0.85-1.69,1.53-2.78,2.07c-1.09,0.55-2.33,0.97-3.8,1.04c-3.1,0.15-5.52-1.04-7.14-2.53c-1.66-1.53-2.92-3.59-3.14-6.56
|
|
||||||
c-0.11-1.58,0.2-2.97,0.67-4.15c0.48-1.23,1.06-2.14,1.84-3.01c1.11-1.2,2.61-2.26,4.5-2.78c0.68-0.19,1.39-0.31,2.1-0.36
|
|
||||||
c3.17-0.2,5.51,1.07,7.16,2.56c1.65,1.48,2.94,3.62,3.11,6.58C23.89,16.57,22.7,18.94,21.17,20.6z M17.05,14.98
|
|
||||||
c0.64,1.86,1.23,3.76,1.59,5.9c0.46-0.26,0.86-0.61,1.24-0.99c1.14-1.15,1.99-2.63,2.33-4.55C20.79,14.91,18.79,14.7,17.05,14.98z
|
|
||||||
M15.2,10.8c1.73-0.7,3.28-1.6,4.3-3.01c-1.36-1.14-3.32-2.18-5.82-2.05c-0.6,0.03-1.05,0.08-1.59,0.2
|
|
||||||
c0.93,1.37,1.93,2.79,2.73,4.22C14.94,10.38,15.02,10.63,15.2,10.8z M15.81,12.06c0.2,0.38,0.39,0.81,0.56,1.19
|
|
||||||
c0.06,0.14,0.08,0.31,0.2,0.41c1.93-0.22,4.06-0.06,5.74,0.28c-0.06-2.27-0.82-3.85-1.87-5.14C19.24,10.23,17.65,11.27,15.81,12.06z
|
|
||||||
"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,7 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="Facebook" fill="#D1CECC" d="M14,0C6.27,0,0,6.27,0,14s6.27,14,14,14s14-6.27,14-14S21.73,0,14,0z M20.99,20.22
|
|
||||||
c0,0.43-0.35,0.77-0.77,0.77h-3.56v-5.42h1.82l0.27-2.11h-2.09v-1.35c0-0.61,0.17-1.03,1.05-1.03l1.12,0V9.2
|
|
||||||
c-0.19-0.03-0.86-0.08-1.63-0.08c-1.61,0-2.71,0.98-2.71,2.79v1.56h-1.82v2.11h1.82v5.42h-6.7c-0.43,0-0.77-0.35-0.77-0.77V7.78
|
|
||||||
c0-0.43,0.35-0.77,0.77-0.77h12.44c0.43,0,0.77,0.35,0.77,0.77V20.22z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 633 B |
@@ -1,10 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="GitHub" fill-rule="evenodd" clip-rule="evenodd" fill="#D1CECC" d="M14.01,0C6.27,0-0.01,6.28-0.01,14.02
|
|
||||||
c0,6.19,4.02,11.45,9.59,13.3c0.7,0.13,0.96-0.3,0.96-0.68c0-0.33-0.01-1.21-0.02-2.38c-3.9,0.85-4.72-1.88-4.72-1.88
|
|
||||||
c-0.64-1.62-1.56-2.05-1.56-2.05c-1.27-0.87,0.1-0.85,0.1-0.85c1.41,0.1,2.15,1.44,2.15,1.44c1.25,2.14,3.28,1.52,4.08,1.16
|
|
||||||
c0.13-0.91,0.49-1.52,0.89-1.87c-3.11-0.35-6.38-1.56-6.38-6.93c0-1.53,0.55-2.78,1.44-3.76C6.37,9.17,5.89,7.74,6.65,5.81
|
|
||||||
c0,0,1.18-0.38,3.85,1.44c1.12-0.31,2.32-0.47,3.51-0.47c1.19,0.01,2.39,0.16,3.51,0.47c2.68-1.81,3.85-1.44,3.85-1.44
|
|
||||||
c0.76,1.93,0.28,3.35,0.14,3.71c0.9,0.98,1.44,2.23,1.44,3.76c0,5.38-3.28,6.57-6.4,6.92c0.5,0.43,0.95,1.29,0.95,2.6
|
|
||||||
c0,1.87-0.02,3.39-0.02,3.84c0,0.37,0.25,0.81,0.96,0.67c5.56-1.86,9.58-7.11,9.58-13.3C28.03,6.28,21.75,0,14.01,0z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -1,12 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="Instagram" fill="#D1CECC" d="M9.89,7.35h0.49v3.05H9.89V7.35z M7.35,8.26v2.15h0.49V7.44C7.55,7.58,7.35,7.89,7.35,8.26z
|
|
||||||
M18.22,10.3h1.36c0.51,0,0.92-0.41,0.92-0.92V8.38c0-0.51-0.41-0.92-0.92-0.92h-1.36c-0.51,0-0.92,0.41-0.92,0.92v0.99
|
|
||||||
C17.31,9.87,17.72,10.3,18.22,10.3z M8.2,7.35h0.49v3.05H8.2V7.35z M9.05,7.35h0.49v3.05H9.05V7.35z M14-0.01
|
|
||||||
C6.26-0.01-0.01,6.27-0.01,14S6.26,28.01,14,28.01S28.01,21.73,28.01,14S21.74-0.01,14-0.01z M6.63,7.93c0-0.71,0.58-1.3,1.3-1.3
|
|
||||||
h12.14c0.71,0,1.3,0.59,1.3,1.3v3.05h-4.56c-0.64-0.85-1.66-1.39-2.81-1.39s-2.16,0.55-2.81,1.39H6.63V7.93z M17.09,13.1
|
|
||||||
c0,1.7-1.39,3.09-3.09,3.09s-3.09-1.39-3.09-3.09s1.39-3.09,3.09-3.09C15.7,10.01,17.09,11.39,17.09,13.1z M21.37,20.07
|
|
||||||
c0,0.71-0.59,1.3-1.3,1.3H7.93c-0.71,0-1.3-0.59-1.3-1.3V11.5h4.24c-0.25,0.48-0.39,1.02-0.39,1.6c0,1.94,1.58,3.52,3.52,3.52
|
|
||||||
s3.52-1.58,3.52-3.52c0-0.57-0.14-1.12-0.39-1.6h4.24L21.37,20.07L21.37,20.07z M14,10.58c1.39,0,2.52,1.13,2.52,2.52
|
|
||||||
s-1.13,2.52-2.52,2.52s-2.52-1.13-2.52-2.52S12.61,10.58,14,10.58z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,9 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="LinkedIn" fill="#D1CECC" d="M18.82,15.09v3.61h-2.09v-3.37c0-0.85-0.3-1.42-1.06-1.42c-0.58,0-0.92,0.39-1.07,0.77
|
|
||||||
c-0.06,0.13-0.07,0.32-0.07,0.51v3.52h-2.09c0,0,0.03-5.71,0-6.3h2.09v0.89c0,0.01-0.01,0.01-0.01,0.02h0.01V13.3
|
|
||||||
c0.28-0.43,0.77-1.04,1.89-1.04C17.79,12.25,18.82,13.16,18.82,15.09z M9.18,18.7h2.09v-6.3H9.18V18.7z M10.24,9.36
|
|
||||||
c-0.72,0-1.19,0.47-1.19,1.09c0,0.61,0.45,1.09,1.16,1.09h0.01c0.73,0,1.18-0.48,1.18-1.09C11.39,9.84,10.95,9.36,10.24,9.36z
|
|
||||||
M28,14c0,7.73-6.27,14-14,14S0,21.73,0,14S6.27,0,14,0S28,6.27,28,14z M20.93,8.02c0-0.55-0.46-1-1.02-1H8.09
|
|
||||||
c-0.57,0-1.02,0.45-1.02,1v11.96c0,0.55,0.46,1,1.02,1h11.82c0.57,0,1.02-0.45,1.02-1V8.02z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 884 B |
@@ -1,6 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="Medium" fill="#D1CECC" d="M14,0C6.3,0,0,6.3,0,14s6.3,14,14,14s14-6.3,14-14S21.7,0,14,0z M11.2,19.5H7v-0.2l1.5-1.8
|
|
||||||
c0.2-0.2,0.2-0.4,0.2-0.6v-6.2c0-0.2,0-0.3-0.2-0.5L7.2,8.7V8.4h4.1l3.1,6.9l2.8-6.9H21v0.2l-1.1,1.1c-0.1,0.1-0.1,0.2-0.1,0.3v7.9
|
|
||||||
c0,0.1,0,0.2,0.1,0.3l1.1,1.1v0.2h-5.5v-0.2l1.1-1.1c0.1-0.1,0.1-0.1,0.1-0.3v-6.4l-3.1,8h-0.4l-3.7-8v5.4c0,0.2,0,0.5,0.2,0.6
|
|
||||||
l1.5,1.8C11.2,19.3,11.2,19.5,11.2,19.5z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 627 B |
@@ -1,14 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="PDF" fill="#D1CECC" d="M12.28,15.27c0.46-0.94,0.81-1.83,1.05-2.66c0.52,1.29,0.97,2.09,1.35,2.41
|
|
||||||
c0.38,0.32,0.74,0.53,1.09,0.62c-0.75,0.11-1.45,0.24-2.1,0.38c-0.65,0.14-1.35,0.38-2.1,0.71L12.28,15.27z M28,14
|
|
||||||
c0,7.73-6.27,14-14,14S0,21.73,0,14S6.27,0,14,0S28,6.27,28,14z M20.94,9.37L17.47,5.9H7.06v16.2h13.89V9.37z M19.35,17.4
|
|
||||||
c-0.39-0.02-0.86-0.11-1.42-0.27s-1.1-0.36-1.62-0.61c-0.57,0.06-1.14,0.14-1.71,0.25c-0.57,0.11-1.13,0.23-1.67,0.36
|
|
||||||
c-0.07,0.02-0.24,0.08-0.5,0.17s-0.57,0.21-0.93,0.35c-0.84,1.41-1.52,2.32-2.03,2.74c-0.51,0.42-0.92,0.6-1.22,0.55h11.54v-3.58
|
|
||||||
c-0.07,0-0.14,0.01-0.21,0.02C19.51,17.39,19.44,17.4,19.35,17.4z M10.17,16.84c0.12-0.22,0.47-0.93,1.05-2.14
|
|
||||||
c0.58-1.21,1.01-2.24,1.28-3.08c-0.2-0.72-0.33-1.42-0.39-2.09s-0.02-1.23,0.1-1.69c0.07-0.25,0.17-0.44,0.28-0.55
|
|
||||||
s0.23-0.19,0.35-0.23H8.21v10.85c0.4-0.33,0.78-0.58,1.16-0.75C9.74,16.98,10.01,16.87,10.17,16.84z M13.39,7.06
|
|
||||||
c0.27,0,0.5,0.1,0.7,0.31c0.2,0.2,0.28,0.54,0.24,1.01c0.01,0.01,0.01,0.3,0,0.87c-0.01,0.57-0.09,1.33-0.24,2.28
|
|
||||||
c0.52,1.37,1.02,2.27,1.52,2.69c0.49,0.42,0.87,0.67,1.14,0.74c0.52-0.06,0.99-0.09,1.43-0.09c0.31,0,0.61,0.04,0.88,0.13
|
|
||||||
c0.27,0.08,0.52,0.19,0.73,0.33V9.95l-2.89-2.89H13.39z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,7 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="Print" fill="#D1CECC" d="M9.5,7.5h9V9h-9V7.5z M9.5,13.5h9v7h-9V13.5z M10.5,15.51h7v-1h-7V15.51z M10.5,17.49h7v-1h-7
|
|
||||||
V17.49z M10.5,19.49h7v-1h-7V19.49z M28,14c0,7.73-6.27,14-14,14S0,21.73,0,14S6.27,0,14,0S28,6.27,28,14z M22,11c0-1.1-0.9-2-2-2
|
|
||||||
h-0.5V6.5h-11V9H8c-1.1,0-2,0.9-2,2v4c0,1.1,0.9,2,2,2h0.5v4.5h11V17H20c1.1,0,2-0.9,2-2V11z M20.02,10.45c-0.28,0-0.5,0.22-0.5,0.5
|
|
||||||
s0.22,0.5,0.5,0.5s0.5-0.22,0.5-0.5S20.29,10.45,20.02,10.45z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 658 B |
@@ -1,10 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="Twitter" fill="#D1CECC" d="M14,0C6.27,0,0,6.27,0,14s6.27,14,14,14s14-6.27,14-14S21.73,0,14,0z M20.69,10.57
|
|
||||||
c0.01,0.15,0.01,0.3,0.01,0.45c0,4.56-3.47,9.82-9.82,9.82c-1.95,0-3.76-0.57-5.29-1.55c0.27,0.03,0.54,0.05,0.82,0.05
|
|
||||||
c1.62,0,3.11-0.55,4.29-1.48c-1.51-0.03-2.79-1.03-3.23-2.4c0.21,0.04,0.43,0.06,0.65,0.06c0.31,0,0.62-0.04,0.91-0.12
|
|
||||||
c-1.58-0.32-2.77-1.71-2.77-3.39c0-0.01,0-0.03,0-0.04c0.47,0.26,1,0.41,1.56,0.43c-0.93-0.62-1.54-1.68-1.54-2.87
|
|
||||||
c0-0.63,0.17-1.23,0.47-1.74c1.7,2.09,4.25,3.46,7.12,3.61c-0.06-0.25-0.09-0.52-0.09-0.79c0-1.91,1.55-3.45,3.45-3.45
|
|
||||||
c0.99,0,1.89,0.42,2.52,1.09c0.79-0.15,1.53-0.44,2.19-0.84c-0.26,0.81-0.81,1.48-1.52,1.91c0.7-0.08,1.36-0.27,1.98-0.54
|
|
||||||
C21.95,9.47,21.37,10.08,20.69,10.57z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 952 B |
@@ -1,40 +0,0 @@
|
|||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
||||||
viewBox="0 0 28 28" enable-background="new 0 0 28 28" xml:space="preserve" width="28">
|
|
||||||
<path id="Website" fill="#D1CECC" d="M14.83,7.6c0.03,0.08,0.03,0.14,0,0.19s-0.08,0.07-0.17,0.07c-0.12,0-0.26-0.01-0.4-0.04
|
|
||||||
s-0.2-0.06-0.18-0.1c0.15-0.15,0.16-0.26,0.03-0.33c-0.13-0.07-0.27-0.11-0.42-0.11s-0.25-0.04-0.3-0.09s-0.03-0.09,0.05-0.09
|
|
||||||
s0.22,0,0.4,0.01c0.19,0.01,0.31,0.04,0.37,0.08s0.17,0.1,0.33,0.19S14.8,7.52,14.83,7.6z M15.9,13.35c-0.11-0.03-0.2-0.03-0.26,0
|
|
||||||
s-0.13,0.05-0.2,0.05c-0.08-0.01-0.25-0.09-0.5-0.24s-0.5-0.22-0.77-0.22c-0.11,0.01-0.17,0.04-0.19,0.08s-0.01,0.07,0.01,0.08
|
|
||||||
c0.02,0.01,0.12,0.03,0.29,0.05s0.4,0.11,0.67,0.26c0.28,0.15,0.48,0.21,0.61,0.19s0.22-0.06,0.28-0.1
|
|
||||||
c0.07-0.01,0.12-0.03,0.16-0.06S16.01,13.38,15.9,13.35z M13.62,6.85c0.17-0.03,0.3-0.13,0.38-0.3c0.03-0.14-0.04-0.2-0.21-0.18
|
|
||||||
s-0.29,0.07-0.37,0.13c-0.01,0.03-0.02,0.06-0.03,0.09s-0.02,0.06-0.03,0.07l-0.08,0.1c-0.03,0.03-0.03,0.05-0.02,0.06
|
|
||||||
C13.32,6.88,13.44,6.89,13.62,6.85z M16.12,7.08c-0.02-0.16-0.11-0.3-0.26-0.41s-0.32-0.19-0.5-0.22c-0.18-0.03-0.38-0.07-0.61-0.12
|
|
||||||
s-0.4-0.04-0.53,0.04c-0.21,0.18-0.25,0.31-0.12,0.39c0.07,0.03,0.2,0.05,0.38,0.06s0.44,0.15,0.76,0.41
|
|
||||||
c0.11,0.08,0.29,0.21,0.55,0.37s0.44,0.23,0.55,0.19c0.06-0.06,0.04-0.15-0.05-0.28S16.14,7.24,16.12,7.08z M28,14
|
|
||||||
c0,7.73-6.27,14-14,14S0,21.73,0,14S6.27,0,14,0S28,6.27,28,14z M21.95,14c-0.06-2.25-0.83-4.12-2.33-5.62
|
|
||||||
c-1.5-1.5-3.37-2.27-5.62-2.33c-2.25,0.06-4.12,0.83-5.62,2.33c-1.5,1.5-2.27,3.37-2.33,5.62c0.06,2.25,0.83,4.12,2.33,5.62
|
|
||||||
c1.5,1.5,3.37,2.27,5.62,2.33c0.54,0,1.06-0.05,1.57-0.14c-0.11-0.07-0.17-0.24-0.18-0.51s0.04-0.52,0.16-0.76
|
|
||||||
c0.15-0.26,0.3-0.61,0.46-1.04c0.15-0.43,0.08-0.77-0.23-1c-0.32-0.18-0.51-0.34-0.57-0.49s-0.19-0.32-0.37-0.54
|
|
||||||
s-0.28-0.36-0.28-0.44v-0.21c-0.01-0.21,0.05-0.43,0.19-0.66l0.25-0.39c0.01-0.04,0.02-0.1,0.02-0.19v-0.19
|
|
||||||
c-0.01-0.04-0.07-0.09-0.17-0.16s-0.17-0.1-0.22-0.1s-0.09,0.01-0.11,0.05s-0.07,0.06-0.13,0.06s-0.17-0.04-0.33-0.13
|
|
||||||
c-0.16-0.09-0.27-0.16-0.32-0.21s-0.1-0.11-0.14-0.19s-0.09-0.15-0.16-0.22s-0.11-0.1-0.16-0.09s-0.12,0-0.23-0.03l-1.45-0.56
|
|
||||||
c-0.26-0.11-0.43-0.23-0.5-0.37c-0.07-0.14-0.1-0.26-0.1-0.37s-0.06-0.23-0.17-0.37l-0.29-0.37c-0.08-0.12-0.14-0.24-0.17-0.34
|
|
||||||
s-0.05-0.15-0.06-0.13c-0.01,0.07,0.02,0.23,0.1,0.48s0.12,0.39,0.1,0.43c-0.03,0.01-0.07-0.02-0.12-0.11s-0.12-0.19-0.19-0.3
|
|
||||||
c-0.06-0.07-0.07-0.15-0.04-0.25c0.03-0.1-0.07-0.38-0.29-0.85c-0.22-0.47-0.26-0.85-0.11-1.15s0.24-0.57,0.3-0.82
|
|
||||||
c0.03-0.21,0.09-0.25,0.19-0.13c0.1,0.12,0.1,0.11,0.02-0.01c-0.08-0.18-0.11-0.4-0.08-0.65c0.03-0.26,0.01-0.46-0.06-0.61
|
|
||||||
c-0.11-0.1-0.3-0.08-0.58,0.05S9.12,8.14,9.1,8.16c0.03-0.12,0.18-0.28,0.46-0.46l0.87-0.58c0.26-0.17,0.49-0.22,0.69-0.17
|
|
||||||
s0.41,0.12,0.62,0.21s0.34,0.12,0.37,0.1s0.01-0.06-0.06-0.13s-0.07-0.13,0.01-0.16S12.26,6.96,12.43,7
|
|
||||||
c0.17,0.03,0.31,0.11,0.42,0.24s0.3,0.18,0.54,0.17s0.32,0.01,0.25,0.06s-0.11,0.12-0.11,0.19c0.04,0.06,0.02,0.1-0.05,0.13
|
|
||||||
s-0.2,0.1-0.36,0.21s-0.18,0.19-0.05,0.26c0.13,0.07,0.36,0.21,0.67,0.41c0.28,0.19,0.41,0.19,0.41-0.01s-0.02-0.4-0.06-0.61
|
|
||||||
c-0.01-0.14,0.05-0.19,0.2-0.14s0.22,0.07,0.24,0.08c0.17,0.11,0.27,0.15,0.32,0.11s0.13-0.04,0.26-0.01
|
|
||||||
c0.17,0.07,0.37,0.19,0.6,0.37l0.41,0.33c-0.43,0.25-0.6,0.41-0.51,0.49s0.2,0.14,0.32,0.2c0.06,0.06,0.02,0.12-0.1,0.21
|
|
||||||
s-0.2,0.12-0.23,0.12c-0.08-0.08-0.15-0.1-0.2-0.05s-0.1,0.09-0.16,0.13c-0.06,0.04-0.07,0.09-0.05,0.14s0.04,0.09,0.05,0.1
|
|
||||||
c-0.3,0.07-0.47,0.22-0.49,0.44s-0.02,0.39-0.01,0.49c0,0.08-0.07,0.18-0.21,0.3s-0.24,0.23-0.31,0.34c-0.03,0.14,0,0.29,0.08,0.47
|
|
||||||
c0.08,0.17,0.08,0.27,0,0.3c-0.08-0.01-0.22-0.12-0.41-0.32c-0.19-0.2-0.55-0.24-1.08-0.13c-0.19,0.04-0.39,0.16-0.6,0.36
|
|
||||||
s-0.23,0.49-0.06,0.88c0.21,0.32,0.43,0.38,0.68,0.19c0.25-0.19,0.43-0.3,0.56-0.31c0.1,0.08,0.12,0.2,0.06,0.35
|
|
||||||
c-0.06,0.15-0.08,0.24-0.08,0.27c0.06-0.01,0.17,0.02,0.34,0.09s0.28,0.27,0.32,0.58c0.04,0.31,0.19,0.49,0.46,0.55
|
|
||||||
s0.45,0.08,0.57,0.07s0.28-0.09,0.48-0.24s0.32-0.24,0.37-0.27s0.17-0.06,0.35-0.1s0.47,0.03,0.84,0.23s0.67,0.31,0.88,0.35
|
|
||||||
s0.38,0.11,0.5,0.2s0.18,0.2,0.18,0.33s0.05,0.23,0.14,0.3c0.15,0.04,0.39,0.07,0.72,0.07s0.57,0.1,0.72,0.28
|
|
||||||
c0.07,0.28-0.08,0.73-0.46,1.38c-0.37,0.64-0.68,1.05-0.93,1.23c-0.18,0.12-0.34,0.29-0.48,0.49s-0.3,0.38-0.49,0.55
|
|
||||||
s-0.41,0.34-0.66,0.52s-0.51,0.34-0.78,0.5c-0.21,0.15-0.36,0.32-0.46,0.51s-0.19,0.32-0.27,0.4c1.81-0.43,3.28-1.34,4.43-2.75
|
|
||||||
C21.31,17.6,21.9,15.93,21.95,14z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 4.4 KiB |
@@ -1,41 +0,0 @@
|
|||||||
<!-- and guess where these are defined? Yup, you guessed it: the _config.yml file -->
|
|
||||||
{% if site.resume_print_social_links %}
|
|
||||||
<ul>
|
|
||||||
|
|
||||||
<!-- GitHub link -->
|
|
||||||
{% if site.resume_social_links.resume_github_url %}
|
|
||||||
<li><strong>Github</strong>: {{ site.resume_social_links.resume_github_url }}</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Twitter link -->
|
|
||||||
{% if site.resume_social_links.resume_twitter_url %}
|
|
||||||
<li><strong>Twitter</strong>: {{ site.resume_social_links.resume_twitter_url }}</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Dribbble link -->
|
|
||||||
{% if site.resume_social_links.resume_dribbble_url %}
|
|
||||||
<li><strong>Dribbble</strong>: {{ site.resume_social_links.resume_dribbble_url }}</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Facebook link -->
|
|
||||||
{% if site.resume_social_links.resume_facebook_url %}
|
|
||||||
<li><strong>Facebook</strong>: {{ site.resume_social_links.resume_facebook_url }}</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- LinkedIn link -->
|
|
||||||
{% if site.resume_social_links.resume_linkedin_url %}
|
|
||||||
<li><strong>LinkedIn</strong>: {{ site.resume_social_links.resume_linkedin_url }}</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Instagram link -->
|
|
||||||
{% if site.resume_social_links.resume_instagram_url %}
|
|
||||||
<li><strong>Instagram</strong>: {{ site.resume_social_links.resume_instagram_url }}</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Website link -->
|
|
||||||
{% if site.resume_social_links.resume_website_url %}
|
|
||||||
<li><strong>Website</strong>: {{ site.resume_social_links.resume_website_url }}</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,254 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
{% include head.html %}
|
|
||||||
|
|
||||||
<body class="theme-{% if site.resume_theme %}{{ site.resume_theme }}{% endif %}">
|
|
||||||
|
|
||||||
<div class="wrapper" itemscope itemtype="http://schema.org/Person">
|
|
||||||
<meta itemprop="telephone" content="{{ site.resume_contact_telephone }}"/>
|
|
||||||
<meta itemprop="address" content="{{ site.resume_contact_address }}"/>
|
|
||||||
|
|
||||||
<header class="page-header">
|
|
||||||
|
|
||||||
<!-- You can turn off the avatar in _config.yml by setting to false -->
|
|
||||||
{% if site.resume_avatar == 'true' %}
|
|
||||||
<img src="images/avatar.jpg" alt="my photo" class="avatar no-print" itemprop="image">
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Your name is defined in the _config.yml file -->
|
|
||||||
<h1 class="header-name" itemprop="name">{{ site.resume_name }}</h1>
|
|
||||||
|
|
||||||
<!-- To display contact info here, change `display_header_contact_info` value in _config.yml to true -->
|
|
||||||
{% if site.display_header_contact_info == 'true' %}
|
|
||||||
<div class="header-contact-info">
|
|
||||||
<p>{{ site.resume_header_contact_info }}</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="title-bar no-print">
|
|
||||||
|
|
||||||
<!-- Your title is also defined in the _config.yml file -->
|
|
||||||
<h2 class="header-title" itemprop="jobTitle">{{ site.resume_title }}</h2>
|
|
||||||
|
|
||||||
<!-- This is the markup for the icon links; moved out to an include because it's very verbose, and you shouldn't ever need to edit the markup (unless you want to re-order the icons); if you want to customize which links appear, define them in the _config.yml file -->
|
|
||||||
{% include icon-links.html %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="executive-summary" itemprop="description">
|
|
||||||
{{ site.resume_header_intro }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% if site.resume_section_experience %}
|
|
||||||
<!-- begin Experience -->
|
|
||||||
<section class="content-section">
|
|
||||||
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Experience</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% for job in site.data.experience %}
|
|
||||||
<div class="resume-item" itemscope itemprop="worksFor" itemtype="http://schema.org/Organization">
|
|
||||||
<h3 class="resume-item-title" itemprop="name">{{ job.company }}</h3>
|
|
||||||
<h4 class="resume-item-details" itemprop="description">{{ job.position }} • {{ job.duration }}</h4>
|
|
||||||
<p class="resume-item-copy">{{ job.summary }}</p>
|
|
||||||
</div><!-- end of resume-item -->
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Experience -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if site.resume_section_publications %}
|
|
||||||
<!-- begin Publications -->
|
|
||||||
<section class="content-section">
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Publications</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% for publication in site.data.publications %}
|
|
||||||
<div class="resume-item" itemscope itemtype="http://schema.org/CreativeWork">
|
|
||||||
<meta itemprop="creator" content="{{ site.resume_name }}" itemtype="http://schema.org/Person" />
|
|
||||||
<h3 class="resume-item-copy" itemprop="name">{% if publication.url %}<a href="{{ publication.url }}" itemprop="url">{{ publication.name }}</a>{% else %}{{ publication.name }}{% endif %}</h3>
|
|
||||||
<p class="resume-item-copy">{{ publication.description }}</p>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Publications -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if site.resume_section_education %}
|
|
||||||
<!-- begin Education -->
|
|
||||||
<section class="content-section">
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Education</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% for education in site.data.education %}
|
|
||||||
<div class="resume-item" itemscope itemprop="alumniOf" itemtype="http://schema.org/CollegeOrUniversity">
|
|
||||||
<h3 class="resume-item-title" itemprop="name">{{ education.uni }}</h3>
|
|
||||||
<h4 class="resume-item-details group" itemprop="description">{{ education.degree }} • {{ education.year }}</h4>
|
|
||||||
<h5 class="resume-item-details award-title" itemprop="description">{{ education.award }}</h5>
|
|
||||||
<p class="resume-item-copy" itemprop="description">
|
|
||||||
<ul class="resume-item-list">
|
|
||||||
{% for award in education.awards %}
|
|
||||||
<li>{{ award.award }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
<p class="resume-item-copy">{{ education.summary }}</p>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</section>
|
|
||||||
<!-- end Education -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% if site.resume_section_projects %}
|
|
||||||
<!-- begin Projects -->
|
|
||||||
<section class="content-section">
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Projects</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% for project in site.data.projects %}
|
|
||||||
<div class="resume-item" itemscope itemtype="http://schema.org/CreativeWork">
|
|
||||||
<meta itemprop="creator" content="{{ site.resume_name }}" itemtype="http://schema.org/Person" />
|
|
||||||
<h3 class="resume-item-title" itemprop="name">{% if project.url %}<a href="{{ project.url }}" itemprop="url">{{ project.project }}</a>{% else %}{{ project.project }}{% endif %}</h3>
|
|
||||||
<h4 class="resume-item-details" itemprop="description">{{ project.role }} • {{ project.duration }}</h4>
|
|
||||||
<p class="resume-item-copy">{{ project.description }}</p>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Projects -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if site.resume_section_skills %}
|
|
||||||
<!-- begin Skills -->
|
|
||||||
<section class="content-section">
|
|
||||||
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Skills</h2>
|
|
||||||
</header>
|
|
||||||
{% for skill in site.data.skills %}
|
|
||||||
<div class="resume-item">
|
|
||||||
<h4 class="resume-item-details">{{ skill.skill }}</h4>
|
|
||||||
<p class="resume-item-copy">{{ skill.description }}</p>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Skills -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if site.resume_section_recognition %}
|
|
||||||
<!-- begin Recognition -->
|
|
||||||
<section class="content-section">
|
|
||||||
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Recognition</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% for recognition in site.data.recognitions %}
|
|
||||||
<div class="resume-item">
|
|
||||||
<h3 class="resume-item-title" itemprop="award">{{ recognition.award }}</h3>
|
|
||||||
<h4 class="resume-item-details">{{ recognition.organization }} • {{ recognition.year }}</h4>
|
|
||||||
<p class="resume-item-copy">{{ recognition.summary }}</p>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Recognition -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if site.resume_section_associations %}
|
|
||||||
<!-- begin Associations -->
|
|
||||||
<section class="content-section">
|
|
||||||
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Associations</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% for association in site.data.associations %}
|
|
||||||
<div class="resume-item" itemscope itemprop="memberOf" itemtype="http://schema.org/Organization">
|
|
||||||
<h3 class="resume-item-title" itemprop="name">{% if association.url %}<a href="{{ association.url }}">{{ association.organization }}</a>{% else %}{{ association.organization }}{% endif %}</h3>
|
|
||||||
<h4 class="resume-item-details" itemprop="description">{{ association.role }} • {{ association.year }}</h4>
|
|
||||||
<p class="resume-item-copy">{{ association.summary }}</p>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Associations -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if site.resume_section_interests %}
|
|
||||||
<!-- begin Interests -->
|
|
||||||
<section class="content-section">
|
|
||||||
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Outside Interests</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="resume-item">
|
|
||||||
<ul class="resume-item-list">
|
|
||||||
{% for interest in site.data.interests %}
|
|
||||||
<li>{{ interest.description }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Interests -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if site.resume_section_links %}
|
|
||||||
<!-- begin Links -->
|
|
||||||
<section class="content-section">
|
|
||||||
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Additional Links</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="resume-item">
|
|
||||||
<ul class="resume-item-list">
|
|
||||||
{% for link in site.data.links %}
|
|
||||||
<li><a href={{ link.url }} itemprop="url">{{ link.description }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Links -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if site.resume_print_social_links %}
|
|
||||||
<!-- begin Print Social Links -->
|
|
||||||
<section class="content-section print-only">
|
|
||||||
|
|
||||||
<header class="section-header">
|
|
||||||
<h2>Social Links</h2>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="resume-item">
|
|
||||||
{% include print-social-links.html %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
<!-- end Print Social Links -->
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<footer class="page-footer">
|
|
||||||
<p class="footer-line">Theme credit to <a href="http://twitter.com/jglovier">@jglovier</a>. Fork me on <a href="https://github.com/jglovier/resume-template">GitHub</a>.</p>
|
|
||||||
<p class="footer-line">Pengzhan.dev - 2023</p>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
// Base styles
|
|
||||||
// ---------------------------------------/
|
|
||||||
* {
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
background: $white;
|
|
||||||
}
|
|
||||||
|
|
||||||
body{
|
|
||||||
@include serif;
|
|
||||||
color: $text_color;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper:before,
|
|
||||||
.wrapper:after { content:""; display:table; }
|
|
||||||
.wrapper:after { clear: both; }
|
|
||||||
.wrapper {
|
|
||||||
max-width: 728px;
|
|
||||||
padding: 0 24px;
|
|
||||||
margin: 0 auto;
|
|
||||||
zoom: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearfix (now called group,
|
|
||||||
// via http://css-tricks.com/snippets/css/clear-fix/)
|
|
||||||
.group:before,
|
|
||||||
.group:after { content:""; display:table; }
|
|
||||||
.group:after { clear:both; }
|
|
||||||
.group { zoom:1; /* For IE 6/7 (trigger hasLayout) */ }
|
|
||||||
|
|
||||||
::-moz-selection {
|
|
||||||
background: rgba(51,51,51,.8);
|
|
||||||
color: #fff;
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
|
||||||
::selection {
|
|
||||||
background: rgba(51,51,51,.8);
|
|
||||||
color: #fff;
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
// Layout styles
|
|
||||||
// ---------------------------------------/
|
|
||||||
|
|
||||||
// Layout from Primer (https://github.com/primer/primer/blob/master/scss/_layout.scss)
|
|
||||||
|
|
||||||
// Fixed-width, centered column for site content.
|
|
||||||
.container {
|
|
||||||
width: $container-width;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
@include clearfix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grid system
|
|
||||||
//
|
|
||||||
// Create rows with `.columns` to clear the floated columns and outdent the
|
|
||||||
// padding on `.column`s with negative margin for alignment.
|
|
||||||
|
|
||||||
.columns {
|
|
||||||
margin-right: -$grid-gutter;
|
|
||||||
margin-left: -$grid-gutter;
|
|
||||||
@include clearfix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base class for every column (requires a column width from below)
|
|
||||||
.column {
|
|
||||||
float: left;
|
|
||||||
padding-right: $grid-gutter;
|
|
||||||
padding-left: $grid-gutter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Column widths
|
|
||||||
.one-third {
|
|
||||||
width: 33.333333%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.two-thirds {
|
|
||||||
width: 66.666667%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.one-fourth {
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.one-half {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.three-fourths {
|
|
||||||
width: 75%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.one-fifth {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.four-fifths {
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Single column hack
|
|
||||||
.single-column {
|
|
||||||
padding-right: $grid-gutter;
|
|
||||||
padding-left: $grid-gutter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal width columns via table sorcery.
|
|
||||||
.table-column {
|
|
||||||
display: table-cell;
|
|
||||||
width: 1%;
|
|
||||||
padding-right: $grid-gutter;
|
|
||||||
padding-left: $grid-gutter;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
// Mixins
|
|
||||||
// ---------------------------------------/
|
|
||||||
|
|
||||||
@mixin border-radius($radius) {
|
|
||||||
-webkit-border-radius: $radius;
|
|
||||||
-moz-border-radius: $radius;
|
|
||||||
border-radius: $radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin transition($value) {
|
|
||||||
-webkit-transition: $value;
|
|
||||||
-moz-transition: $value;
|
|
||||||
transition: $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clearfix
|
|
||||||
//
|
|
||||||
// Clears floats via mixin (avoid using as a class).
|
|
||||||
|
|
||||||
@mixin clearfix {
|
|
||||||
&:before {
|
|
||||||
display: table;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
display: table;
|
|
||||||
clear: both;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// media querie tools
|
|
||||||
|
|
||||||
@mixin media_max($screen_width) {
|
|
||||||
@media (max-width: $screen_width) { @content; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin media_min($screen_width) {
|
|
||||||
@media (min-width: $screen_width) { @content; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin media_larger_than_mobile {
|
|
||||||
@media (min-width: 600px) { @content; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin media_mobile {
|
|
||||||
@media (max-width: 600px) { @content; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// type utilities
|
|
||||||
|
|
||||||
@mixin sans {
|
|
||||||
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin sans_light {
|
|
||||||
@include sans;
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin sans_regular {
|
|
||||||
@include sans;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin sans_bold {
|
|
||||||
@include sans;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin sans_extrabold {
|
|
||||||
@include sans;
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin serif {
|
|
||||||
font-family: "Lora", "Minion Pro", Palatino, Georgia, serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin serif_regular {
|
|
||||||
@include serif;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin serif_bold {
|
|
||||||
@include serif;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
// layout
|
|
||||||
|
|
||||||
@mixin section_border {
|
|
||||||
border-top: 4px solid #c7c7c7;
|
|
||||||
border-bottom: 2px solid #c7c7c7;
|
|
||||||
padding: .2rem 0 .4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin section_border_thin {
|
|
||||||
border-top: 1px solid #c7c7c7;
|
|
||||||
border-bottom: 1px solid #c7c7c7;
|
|
||||||
padding: .2rem 0 .2rem;
|
|
||||||
}
|
|
||||||
@@ -1,426 +0,0 @@
|
|||||||
// Normalize styles
|
|
||||||
// ---------------------------------------/
|
|
||||||
|
|
||||||
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Set default font family to sans-serif.
|
|
||||||
* 2. Prevent iOS and IE text size adjust after device orientation change,
|
|
||||||
* without disabling user zoom.
|
|
||||||
*/
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: sans-serif; /* 1 */
|
|
||||||
text-size-adjust: 100%; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove default margin.
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HTML5 display definitions
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
|
||||||
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
|
||||||
* and Firefox.
|
|
||||||
* Correct `block` display not defined for `main` in IE 11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
article,
|
|
||||||
aside,
|
|
||||||
details,
|
|
||||||
figcaption,
|
|
||||||
figure,
|
|
||||||
footer,
|
|
||||||
header,
|
|
||||||
hgroup,
|
|
||||||
main,
|
|
||||||
menu,
|
|
||||||
nav,
|
|
||||||
section,
|
|
||||||
summary {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct `inline-block` display not defined in IE 8/9.
|
|
||||||
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
|
||||||
*/
|
|
||||||
|
|
||||||
audio,
|
|
||||||
canvas,
|
|
||||||
progress,
|
|
||||||
video {
|
|
||||||
display: inline-block; /* 1 */
|
|
||||||
vertical-align: baseline; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent modern browsers from displaying `audio` without controls.
|
|
||||||
* Remove excess height in iOS 5 devices.
|
|
||||||
*/
|
|
||||||
|
|
||||||
audio:not([controls]) {
|
|
||||||
display: none;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address `[hidden]` styling not present in IE 8/9/10.
|
|
||||||
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[hidden],
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Links
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the gray background color from active links in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
a {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Improve readability of focused elements when they are also in an
|
|
||||||
* active/hover state.
|
|
||||||
*/
|
|
||||||
|
|
||||||
a:active,
|
|
||||||
a:hover {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Text-level semantics
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
abbr[title] {
|
|
||||||
border-bottom: 1px dotted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address styling not present in Safari and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
dfn {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address variable `h1` font-size and margin within `section` and `article`
|
|
||||||
* contexts in Firefox 4+, Safari, and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
margin: 0.67em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address styling not present in IE 8/9.
|
|
||||||
*/
|
|
||||||
|
|
||||||
mark {
|
|
||||||
background: #ff0;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address inconsistent and variable font size in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Embedded content
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove border when inside `a` element in IE 8/9/10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
img {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct overflow not hidden in IE 9/10/11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
svg:not(:root) {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grouping content
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address margin not present in IE 8/9 and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 1em 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address differences between Firefox and other browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contain overflow in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pre {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address odd `em`-unit font size rendering in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
pre,
|
|
||||||
samp {
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Forms
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
|
||||||
* styling of `select`, unless a `border` property is set.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct color not being inherited.
|
|
||||||
* Known issue: affects color of disabled elements.
|
|
||||||
* 2. Correct font properties not being inherited.
|
|
||||||
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
input,
|
|
||||||
optgroup,
|
|
||||||
select,
|
|
||||||
textarea {
|
|
||||||
color: inherit; /* 1 */
|
|
||||||
font: inherit; /* 2 */
|
|
||||||
margin: 0; /* 3 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
|
||||||
* All other form control elements do not inherit `text-transform` values.
|
|
||||||
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
|
||||||
* Correct `select` style inheritance in Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
|
||||||
* and `video` controls.
|
|
||||||
* 2. Correct inability to style clickable `input` types in iOS.
|
|
||||||
* 3. Improve usability and consistency of cursor style between image-type
|
|
||||||
* `input` and others.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
html input[type="button"], /* 1 */
|
|
||||||
input[type="reset"],
|
|
||||||
input[type="submit"] {
|
|
||||||
-webkit-appearance: button; /* 2 */
|
|
||||||
cursor: pointer; /* 3 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-set default cursor for disabled elements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button[disabled],
|
|
||||||
html input[disabled] {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove inner padding and border in Firefox 4+.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
input::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
|
||||||
* the UA stylesheet.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input {
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It's recommended that you don't attempt to style these elements.
|
|
||||||
* Firefox's implementation doesn't respect box-sizing, padding, or width.
|
|
||||||
*
|
|
||||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
|
||||||
* 2. Remove excess padding in IE 8/9/10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type="checkbox"],
|
|
||||||
input[type="radio"] {
|
|
||||||
box-sizing: border-box; /* 1 */
|
|
||||||
padding: 0; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
|
||||||
* `font-size` values of the `input`, it causes the cursor style of the
|
|
||||||
* decrement button to change from `default` to `text`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type="number"]::-webkit-inner-spin-button,
|
|
||||||
input[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
|
|
||||||
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type="search"] {
|
|
||||||
-webkit-appearance: textfield; /* 1 */
|
|
||||||
box-sizing: content-box; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
|
||||||
* Safari (but not Chrome) clips the cancel button when the search input has
|
|
||||||
* padding (and `textfield` appearance).
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type="search"]::-webkit-search-cancel-button,
|
|
||||||
input[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define consistent border, margin, and padding.
|
|
||||||
*/
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
border: 1px solid #c0c0c0;
|
|
||||||
margin: 0 2px;
|
|
||||||
padding: 0.35em 0.625em 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
|
||||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
|
||||||
*/
|
|
||||||
|
|
||||||
legend {
|
|
||||||
border: 0; /* 1 */
|
|
||||||
padding: 0; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove default vertical scrollbar in IE 8/9/10/11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't inherit the `font-weight` (applied by a rule above).
|
|
||||||
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
|
||||||
*/
|
|
||||||
|
|
||||||
optgroup {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tables
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove most spacing between table cells.
|
|
||||||
*/
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
// Resume styles
|
|
||||||
// ---------------------------------------/
|
|
||||||
|
|
||||||
// util
|
|
||||||
|
|
||||||
.section-header {
|
|
||||||
@include section_border;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
@include sans;
|
|
||||||
font-weight: 900;
|
|
||||||
font-size: 1.75rem;
|
|
||||||
letter-spacing: -.05rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// page header styles
|
|
||||||
|
|
||||||
.page-header { padding: 1.5rem 0;
|
|
||||||
|
|
||||||
.avatar {
|
|
||||||
width: 95px;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
@include border-radius(100px);
|
|
||||||
margin: 0 auto;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-name {
|
|
||||||
@include sans;
|
|
||||||
font-size: 3rem;
|
|
||||||
font-weight: 900;
|
|
||||||
text-align: center;
|
|
||||||
letter-spacing: -.15rem;
|
|
||||||
line-height: 1;
|
|
||||||
margin: 1rem 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-contact-info {
|
|
||||||
@include sans;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.header-contact-info p a {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title-bar {
|
|
||||||
@include section_border;
|
|
||||||
margin-top: 2rem;
|
|
||||||
padding: .4rem 0;
|
|
||||||
@include clearfix;
|
|
||||||
|
|
||||||
.header-title {
|
|
||||||
@include sans;
|
|
||||||
font-weight: 300;
|
|
||||||
font-size: 1.75rem;
|
|
||||||
line-height: 2rem;
|
|
||||||
letter-spacing: -.05rem;
|
|
||||||
text-align: center;
|
|
||||||
margin: 0 0 .5rem;
|
|
||||||
|
|
||||||
@include media_larger_than_mobile {
|
|
||||||
float: left;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.executive-summary {
|
|
||||||
@include media_larger_than_mobile { font-size: 1.125rem; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-links {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
position: relative;
|
|
||||||
top: 4px;
|
|
||||||
text-align: center;
|
|
||||||
border-top: 2px solid #c7c7c7;
|
|
||||||
padding-top: .4rem;
|
|
||||||
|
|
||||||
@include media_larger_than_mobile {
|
|
||||||
float: right;
|
|
||||||
border-top: none;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-link-item {
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-link { display: inline-block;
|
|
||||||
|
|
||||||
&:hover .icon path {
|
|
||||||
fill: #333;
|
|
||||||
@include transition(all .2s ease);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
height: 28px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-button {
|
|
||||||
@include border-radius(3px);
|
|
||||||
background-color: #efefef;
|
|
||||||
text-decoration: none;
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
margin: 1.5rem auto;
|
|
||||||
width: 220px;
|
|
||||||
font-size: 1.375rem;
|
|
||||||
@include sans_light;
|
|
||||||
color: #333;
|
|
||||||
line-height: 55px;
|
|
||||||
@include transition(all .2s ease);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #333;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.not-looking { width: 400px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// resume content styles
|
|
||||||
|
|
||||||
.content-section {
|
|
||||||
margin: 0 0 3rem;
|
|
||||||
|
|
||||||
.resume-item { margin-bottom: 2rem; }
|
|
||||||
|
|
||||||
.resume-item-title {
|
|
||||||
@include sans_bold;
|
|
||||||
margin: 0 0 .75rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
letter-spacing: -.05rem;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.resume-item-details {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
margin: 0 0 .75rem;
|
|
||||||
line-height: 1;
|
|
||||||
|
|
||||||
&.award-title {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.resume-item-title,
|
|
||||||
.resume-item-details,
|
|
||||||
.resume-item-copy,
|
|
||||||
.resume-item-list {
|
|
||||||
a {
|
|
||||||
color: #333;
|
|
||||||
text-decoration: none;
|
|
||||||
border-bottom: 1px solid;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-bottom: none;
|
|
||||||
color: #9c9c9c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.resume-item-copy { margin: .75rem 0 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// footer styles
|
|
||||||
|
|
||||||
.page-footer {
|
|
||||||
border-top: 4px solid #c7c7c7;
|
|
||||||
padding-top: 1.5rem;
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
|
|
||||||
.footer-line {
|
|
||||||
margin: 0;
|
|
||||||
font-size: .875rem;
|
|
||||||
color: #999;
|
|
||||||
|
|
||||||
> a {
|
|
||||||
font-weight: 700;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.print-only { display: none !important }
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
.no-print { display: none !important }
|
|
||||||
.print-only { display: block !important }
|
|
||||||
body { font-size: 12px; line-height: 1rem; }
|
|
||||||
.page-header { padding: 1rem 0 .2rem;
|
|
||||||
.header-name {
|
|
||||||
@include sans_bold;
|
|
||||||
font-size: 2rem;
|
|
||||||
margin: 0 0 .2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.section-header {
|
|
||||||
@include section_border_thin;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
h2 { font-size: 1.2rem; line-height: 1.5rem; }
|
|
||||||
}
|
|
||||||
.content-section {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
.resume-item { margin-bottom: 1rem; }
|
|
||||||
.resume-item-title {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: .7em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.resume-item-details {
|
|
||||||
font-size: 12px;
|
|
||||||
margin: 0 0 .75rem;
|
|
||||||
line-height: .7em;
|
|
||||||
font-style:italic;
|
|
||||||
|
|
||||||
&.award-title {
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Variables
|
|
||||||
// ---------------------------------------/
|
|
||||||
|
|
||||||
$container-width: 980px !default;
|
|
||||||
$grid-gutter: 10px !default;
|
|
||||||
|
|
||||||
// Colors
|
|
||||||
$white: #fff;
|
|
||||||
$black: #333;
|
|
||||||
|
|
||||||
// Styles
|
|
||||||
$text_color: $black;
|
|
||||||
|
|
||||||
// Font stack
|
|
||||||
$body-font: Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol" !default;
|
|
||||||
|
|
||||||
// The base body size
|
|
||||||
$body-font-size: 13px !default;
|
|
||||||
|
|
||||||
// Monospace font stack
|
|
||||||
$mono-font: Consolas, "Liberation Mono", Menlo, Courier, monospace !default;
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
---
|
|
||||||
|
|
||||||
// "Reset" styles and SCSS reusable components
|
|
||||||
@import "normalize";
|
|
||||||
@import "mixins";
|
|
||||||
@import "variables";
|
|
||||||
|
|
||||||
// Generic site base & layout styles
|
|
||||||
@import "base";
|
|
||||||
@import "layout";
|
|
||||||
|
|
||||||
// Layouts
|
|
||||||
@import "resume";
|
|
||||||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 551 KiB |
|
Before Width: | Height: | Size: 72 KiB |
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
layout: resume
|
|
||||||
---
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: pengzhan-dev
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: pengzhan-dev
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Template Kubernetes secret for pengzhan.dev
|
||||||
|
# Copy this file to k8s/01-secret.yaml (gitignored) and customize before applying.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: pengzhan-secrets
|
||||||
|
namespace: pengzhan-dev
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
ADMIN_SECRET: "CHANGEME_ADMIN_SECRET"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: pengzhan-content-pvc
|
||||||
|
namespace: pengzhan-dev
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: local-path
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pengzhan-web
|
||||||
|
namespace: pengzhan-dev
|
||||||
|
labels:
|
||||||
|
app: pengzhan-web
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
revisionHistoryLimit: 5
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 1
|
||||||
|
maxUnavailable: 0
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: pengzhan-web
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pengzhan-web
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 1000
|
||||||
|
fsGroupChangePolicy: "OnRootMismatch"
|
||||||
|
initContainers:
|
||||||
|
- name: init-content-perms
|
||||||
|
image: busybox:1.36
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command: ["sh", "-c"]
|
||||||
|
args:
|
||||||
|
- |
|
||||||
|
mkdir -p /app/content/data
|
||||||
|
chown -R 1000:1000 /app/content || true
|
||||||
|
chmod -R 775 /app/content || true
|
||||||
|
volumeMounts:
|
||||||
|
- name: content-data
|
||||||
|
mountPath: /app/content
|
||||||
|
containers:
|
||||||
|
- name: pengzhan-web
|
||||||
|
image: git.pengzhan.dev/haopengzhan/pengzhan.dev:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
name: http
|
||||||
|
env:
|
||||||
|
- name: NODE_ENV
|
||||||
|
value: "production"
|
||||||
|
- name: PORT
|
||||||
|
value: "3000"
|
||||||
|
- name: CONTENT_DIR
|
||||||
|
value: "/app/content"
|
||||||
|
- name: ADMIN_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: pengzhan-secrets
|
||||||
|
key: ADMIN_SECRET
|
||||||
|
volumeMounts:
|
||||||
|
- name: content-data
|
||||||
|
mountPath: /app/content
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 3000
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 30
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 3000
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 2
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
volumes:
|
||||||
|
- name: content-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: pengzhan-content-pvc
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: pengzhan-web
|
||||||
|
namespace: pengzhan-dev
|
||||||
|
labels:
|
||||||
|
app: pengzhan-web
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: pengzhan-web
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: 3000
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: pengzhan-ingress
|
||||||
|
namespace: pengzhan-dev
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
spec:
|
||||||
|
ingressClassName: traefik
|
||||||
|
rules:
|
||||||
|
- host: pengzhan.dev
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: pengzhan-web
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- pengzhan.dev
|
||||||
|
secretName: pengzhan-dev-tls
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "pengzhan-dev",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Dynamic web framework and personal site skeleton for pengzhan.dev",
|
||||||
|
"main": "server/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server/index.js",
|
||||||
|
"dev": "APP_ENV=staging node --watch --watch-path=server --watch-path=views --watch-path=public server/index.js",
|
||||||
|
"dev:persistent": "node --watch --watch-path=server --watch-path=views --watch-path=public server/index.js",
|
||||||
|
"lint": "node scripts/lint.js",
|
||||||
|
"test": "NODE_ENV=test node test/test.js"
|
||||||
|
},
|
||||||
|
"keywords": ["blog", "k8s", "ssr", "express", "markdown"],
|
||||||
|
"author": "Pengzhan Hao",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
|
"ejs": "^3.1.10",
|
||||||
|
"express": "^4.21.2",
|
||||||
|
"feed": "^4.2.2",
|
||||||
|
"gray-matter": "^4.0.3",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
|
"markdown-it-anchor": "^9.2.0",
|
||||||
|
"markdown-it-attrs": "^4.3.1",
|
||||||
|
"markdown-it-footnote": "^4.0.0",
|
||||||
|
"prismjs": "^1.29.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 272 KiB |
@@ -0,0 +1,411 @@
|
|||||||
|
:root {
|
||||||
|
--color-bg: #f9f9f9;
|
||||||
|
--color-surface: #ffffff;
|
||||||
|
--color-surface-soft: #f4f4f5;
|
||||||
|
--color-text-main: #111111;
|
||||||
|
--color-text-secondary: #4b5563;
|
||||||
|
--color-text-muted: #6b7280;
|
||||||
|
--color-border: #e5e7eb;
|
||||||
|
--color-border-hover: #d1d5db;
|
||||||
|
--color-accent: #111111;
|
||||||
|
--color-mark-bg: #fef08a;
|
||||||
|
--color-mark-text: #111111;
|
||||||
|
|
||||||
|
--font-serif: 'Cardo', 'Iowan Old Style', 'Palatino Linotype', 'Songti SC', 'STSong', Georgia, serif;
|
||||||
|
--font-mono: 'Maple Mono NF CN', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
|
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
|
||||||
|
|
||||||
|
--max-width: 1180px;
|
||||||
|
--content-width: 820px;
|
||||||
|
--header-height: 64px;
|
||||||
|
|
||||||
|
--radius-sm: 6px;
|
||||||
|
--radius-md: 12px;
|
||||||
|
--radius-lg: 20px;
|
||||||
|
--radius-full: 9999px;
|
||||||
|
|
||||||
|
--transition-fast: 0.15s ease;
|
||||||
|
--transition-normal: 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
*, *::before, *::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 16px;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
scroll-padding-top: calc(var(--header-height) + 1.5rem);
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure hash navigation (#) and footnotes never hide under sticky header */
|
||||||
|
:target,
|
||||||
|
[id],
|
||||||
|
h1[id], h2[id], h3[id], h4[id], h5[id], h6[id],
|
||||||
|
.footnote-ref,
|
||||||
|
.footnote-item,
|
||||||
|
li[id^="fn"] {
|
||||||
|
scroll-margin-top: calc(var(--header-height) + 1.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive media constraint - never wider than parent container */
|
||||||
|
img, video, iframe, embed, object {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
color: var(--color-text-main);
|
||||||
|
background-color: var(--color-bg);
|
||||||
|
line-height: 1.8;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: var(--max-width);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: var(--content-width);
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
.site-header {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: rgba(249, 249, 249, 0.95);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
height: var(--header-height);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-inner {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--color-text-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-title {
|
||||||
|
font-size: 1.55rem;
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 2rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
text-decoration: none;
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
font-size: 1.05rem;
|
||||||
|
color: var(--color-text-main);
|
||||||
|
transition: opacity var(--transition-fast);
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link:hover {
|
||||||
|
opacity: 0.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link.active {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile Hamburger Menu Toggle */
|
||||||
|
.mobile-menu-toggle {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.5rem;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 5px;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-line {
|
||||||
|
display: block;
|
||||||
|
width: 22px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: var(--color-text-main);
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: transform 0.25s ease, opacity 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-toggle.is-active .hamburger-line:nth-child(1) {
|
||||||
|
transform: translateY(7px) rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-toggle.is-active .hamburger-line:nth-child(2) {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-toggle.is-active .hamburger-line:nth-child(3) {
|
||||||
|
transform: translateY(-7px) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile Slide-Down Navigation Drawer */
|
||||||
|
.mobile-nav-drawer {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--color-bg);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 0.75rem 1.25rem 1.25rem;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-drawer.is-open {
|
||||||
|
display: block;
|
||||||
|
animation: slideDown 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideDown {
|
||||||
|
from { opacity: 0; transform: translateY(-8px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-links {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-link {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.85rem 0.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--color-text-main);
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
font-size: 1.15rem;
|
||||||
|
border-bottom: 1px solid var(--color-border-subtle, rgba(0, 0, 0, 0.05));
|
||||||
|
transition: color var(--transition-fast), padding-left var(--transition-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-link:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-link:hover, .mobile-nav-link:active {
|
||||||
|
color: var(--color-accent);
|
||||||
|
padding-left: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-link.active {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-arrow {
|
||||||
|
font-size: 1rem;
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content area */
|
||||||
|
.site-main {
|
||||||
|
flex: 1;
|
||||||
|
padding: 2.5rem 0 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
.site-footer {
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
padding: 2.5rem 0;
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-inner {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.25rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: color var(--transition-fast), transform var(--transition-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link:hover {
|
||||||
|
color: var(--color-text-main);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link svg {
|
||||||
|
width: 19px;
|
||||||
|
height: 19px;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Headings & Typography */
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
color: var(--color-text-main);
|
||||||
|
line-height: 1.35;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 { font-size: 2.2rem; }
|
||||||
|
h2 { font-size: 1.65rem; margin-top: 2rem; }
|
||||||
|
h3 { font-size: 1.35rem; margin-top: 1.5rem; }
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-accent);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-thickness: 1px;
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
transition: color var(--transition-fast);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background-color: var(--color-mark-bg);
|
||||||
|
color: var(--color-mark-text);
|
||||||
|
padding: 0.1em 0.25em;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 3px solid var(--color-border-hover);
|
||||||
|
padding: 0.5rem 0 0.5rem 1.25rem;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 0;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--color-border);
|
||||||
|
margin: 2.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
:root {
|
||||||
|
--header-height: 64px;
|
||||||
|
--content-padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 990;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide inline desktop nav and show hamburger */
|
||||||
|
.site-nav.desktop-nav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-menu-toggle {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-tagline {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.1rem;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Centered, balanced editorial mobile footer */
|
||||||
|
.site-footer {
|
||||||
|
padding: 2.5rem 1.25rem 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-inner {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
gap: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-tagline {
|
||||||
|
font-family: var(--font-serif);
|
||||||
|
font-size: 1.05rem;
|
||||||
|
color: var(--color-text-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-copyright {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links {
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 44px;
|
||||||
|
min-height: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/* Fonts definitions with graceful local fallbacks */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'XiaoheSimplifySerif-VF';
|
||||||
|
src: url('/fonts/XiaoheSimplifySerif-VF.otf') format('opentype');
|
||||||
|
font-weight: 100 900;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Maple Mono NF CN';
|
||||||
|
src: url('/fonts/MapleMono-NF-CN-Regular.ttf') format('truetype');
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Maple Mono NF CN';
|
||||||
|
src: url('/fonts/MapleMono-NF-CN-Bold.ttf') format('truetype');
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
* Okaidia PrismJS theme matching WordPress Prismatic plugin
|
||||||
|
*/
|
||||||
|
code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
color: #f8f8f2;
|
||||||
|
background: none;
|
||||||
|
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
|
||||||
|
font-family: 'Maple Mono NF CN', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 0.95em;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
word-spacing: normal;
|
||||||
|
word-break: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
line-height: 1.6;
|
||||||
|
tab-size: 2;
|
||||||
|
hyphens: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"] {
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
margin: 1.75rem 0;
|
||||||
|
overflow: auto;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #272822;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(pre) > code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
background: #272822;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code outside pre */
|
||||||
|
:not(pre) > code {
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #e83e8c;
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
font-family: 'Maple Mono NF CN', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
|
font-size: 0.88em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.comment,
|
||||||
|
.token.prolog,
|
||||||
|
.token.doctype,
|
||||||
|
.token.cdata {
|
||||||
|
color: #8292a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.punctuation {
|
||||||
|
color: #f8f8f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.namespace {
|
||||||
|
opacity: .7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.property,
|
||||||
|
.token.tag,
|
||||||
|
.token.constant,
|
||||||
|
.token.symbol,
|
||||||
|
.token.deleted {
|
||||||
|
color: #f92672;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.boolean,
|
||||||
|
.token.number {
|
||||||
|
color: #ae81ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.selector,
|
||||||
|
.token.attr-name,
|
||||||
|
.token.string,
|
||||||
|
.token.char,
|
||||||
|
.token.builtin,
|
||||||
|
.token.inserted {
|
||||||
|
color: #a6e22e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.operator,
|
||||||
|
.token.entity,
|
||||||
|
.token.url,
|
||||||
|
.language-css .token.string,
|
||||||
|
.style .token.string,
|
||||||
|
.token.variable {
|
||||||
|
color: #f8f8f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.atrule,
|
||||||
|
.token.attr-value,
|
||||||
|
.token.function,
|
||||||
|
.token.class-name {
|
||||||
|
color: #e6db74;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.keyword {
|
||||||
|
color: #66d9ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.regex,
|
||||||
|
.token.important {
|
||||||
|
color: #fd971f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.important,
|
||||||
|
.token.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 68 KiB |
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Mobile Navigation Drawer Controller
|
||||||
|
*/
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const toggleBtn = document.getElementById('mobile-menu-toggle');
|
||||||
|
const drawer = document.getElementById('mobile-nav-drawer');
|
||||||
|
|
||||||
|
if (toggleBtn && drawer) {
|
||||||
|
toggleBtn.addEventListener('click', () => {
|
||||||
|
const isOpen = drawer.classList.contains('is-open');
|
||||||
|
if (isOpen) {
|
||||||
|
drawer.classList.remove('is-open');
|
||||||
|
toggleBtn.classList.remove('is-active');
|
||||||
|
toggleBtn.setAttribute('aria-expanded', 'false');
|
||||||
|
} else {
|
||||||
|
drawer.classList.add('is-open');
|
||||||
|
toggleBtn.classList.add('is-active');
|
||||||
|
toggleBtn.setAttribute('aria-expanded', 'true');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close on navigation link click
|
||||||
|
drawer.querySelectorAll('.mobile-nav-link').forEach(link => {
|
||||||
|
link.addEventListener('click', () => {
|
||||||
|
drawer.classList.remove('is-open');
|
||||||
|
toggleBtn.classList.remove('is-active');
|
||||||
|
toggleBtn.setAttribute('aria-expanded', 'false');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close when clicking outside
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (drawer.classList.contains('is-open') && !drawer.contains(e.target) && !toggleBtn.contains(e.target)) {
|
||||||
|
drawer.classList.remove('is-open');
|
||||||
|
toggleBtn.classList.remove('is-active');
|
||||||
|
toggleBtn.setAttribute('aria-expanded', 'false');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close on Escape key
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape' && drawer.classList.contains('is-open')) {
|
||||||
|
drawer.classList.remove('is-open');
|
||||||
|
toggleBtn.classList.remove('is-active');
|
||||||
|
toggleBtn.setAttribute('aria-expanded', 'false');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const searchInput = document.getElementById('search-input');
|
||||||
|
const searchForm = document.getElementById('search-form');
|
||||||
|
const pillElements = document.querySelectorAll('.search-pill-btn');
|
||||||
|
|
||||||
|
if (searchInput && pillElements.length > 0) {
|
||||||
|
pillElements.forEach(pill => {
|
||||||
|
pill.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const query = pill.getAttribute('data-query');
|
||||||
|
if (query) {
|
||||||
|
searchInput.value = query;
|
||||||
|
if (searchForm) {
|
||||||
|
searchForm.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* Interactive Table of Contents Controller
|
||||||
|
* - Perfectly Centered Post Layout (No 70/30 split)
|
||||||
|
* - Margin-Docked Auto-Hide / Minimizable Desktop Rail (Dropbox Paper style)
|
||||||
|
* - Mobile / Tablet Floating Action Badge & Slide-Up Bottom Sheet
|
||||||
|
*/
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const sideToc = document.getElementById('side-toc');
|
||||||
|
const minimizeBtn = document.getElementById('side-toc-minimize');
|
||||||
|
const floatingBadge = document.getElementById('floating-toc-badge');
|
||||||
|
const sheet = document.getElementById('mobile-toc-sheet');
|
||||||
|
const overlay = document.getElementById('mobile-toc-overlay');
|
||||||
|
const sheetCloseBtn = document.getElementById('mobile-sheet-close');
|
||||||
|
|
||||||
|
// Check user preference for minimized TOC in localStorage
|
||||||
|
let isMinimized = false;
|
||||||
|
try {
|
||||||
|
isMinimized = localStorage.getItem('pengzhan_toc_minimized') === 'true';
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
function applyDesktopState() {
|
||||||
|
if (!sideToc) return;
|
||||||
|
if (window.innerWidth >= 1280) {
|
||||||
|
if (isMinimized) {
|
||||||
|
sideToc.classList.add('is-minimized');
|
||||||
|
if (floatingBadge) floatingBadge.classList.add('is-visible');
|
||||||
|
} else {
|
||||||
|
sideToc.classList.remove('is-minimized');
|
||||||
|
if (floatingBadge) floatingBadge.classList.remove('is-visible');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// On screens < 1280px, desktop side rail is hidden via CSS, floating badge is available
|
||||||
|
if (floatingBadge) floatingBadge.classList.add('is-visible');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minimizeBtn) {
|
||||||
|
minimizeBtn.addEventListener('click', () => {
|
||||||
|
isMinimized = true;
|
||||||
|
try { localStorage.setItem('pengzhan_toc_minimized', 'true'); } catch (_) {}
|
||||||
|
applyDesktopState();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floating badge click
|
||||||
|
if (floatingBadge) {
|
||||||
|
floatingBadge.addEventListener('click', () => {
|
||||||
|
if (window.innerWidth >= 1280) {
|
||||||
|
// Expand desktop side TOC
|
||||||
|
isMinimized = false;
|
||||||
|
try { localStorage.setItem('pengzhan_toc_minimized', 'false'); } catch (_) {}
|
||||||
|
applyDesktopState();
|
||||||
|
} else {
|
||||||
|
// Open mobile bottom sheet
|
||||||
|
openMobileSheet();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function openMobileSheet() {
|
||||||
|
if (sheet && overlay) {
|
||||||
|
sheet.classList.add('is-open');
|
||||||
|
overlay.classList.add('is-open');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMobileSheet() {
|
||||||
|
if (sheet && overlay) {
|
||||||
|
sheet.classList.remove('is-open');
|
||||||
|
overlay.classList.remove('is-open');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sheetCloseBtn) sheetCloseBtn.addEventListener('click', closeMobileSheet);
|
||||||
|
if (overlay) overlay.addEventListener('click', closeMobileSheet);
|
||||||
|
|
||||||
|
// Close mobile sheet on anchor click
|
||||||
|
if (sheet) {
|
||||||
|
sheet.querySelectorAll('.mobile-sheet-link').forEach(link => {
|
||||||
|
link.addEventListener('click', () => {
|
||||||
|
closeMobileSheet();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', applyDesktopState, { passive: true });
|
||||||
|
applyDesktopState();
|
||||||
|
|
||||||
|
// Scroll Spy for Desktop Rail and Mobile List
|
||||||
|
const sideLinks = Array.from(document.querySelectorAll('.side-toc-link'));
|
||||||
|
if (sideLinks.length === 0) return;
|
||||||
|
|
||||||
|
const headings = sideLinks
|
||||||
|
.map(link => {
|
||||||
|
const id = link.getAttribute('data-id');
|
||||||
|
const target = document.getElementById(id);
|
||||||
|
return target ? { id, target, link } : null;
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
if (headings.length === 0) return;
|
||||||
|
|
||||||
|
function updateActiveHeading() {
|
||||||
|
const scrollPos = window.scrollY + 140;
|
||||||
|
let currentActive = headings[0];
|
||||||
|
|
||||||
|
for (let i = 0; i < headings.length; i++) {
|
||||||
|
const top = headings[i].target.getBoundingClientRect().top + window.scrollY;
|
||||||
|
if (top <= scrollPos) {
|
||||||
|
currentActive = headings[i];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headings.forEach(item => {
|
||||||
|
if (item === currentActive) {
|
||||||
|
item.link.classList.add('toc-active');
|
||||||
|
} else {
|
||||||
|
item.link.classList.remove('toc-active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('scroll', updateActiveHeading, { passive: true });
|
||||||
|
updateActiveHeading();
|
||||||
|
});
|
||||||
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 42 KiB |
@@ -0,0 +1,38 @@
|
|||||||
|
site:
|
||||||
|
title: "Pengzhan"
|
||||||
|
tagline: "Was childish, Now foolish."
|
||||||
|
url: "https://pengzhan.dev"
|
||||||
|
author:
|
||||||
|
name: "Pengzhan Hao"
|
||||||
|
subtitle: "Software engineer on Cloud"
|
||||||
|
gravatar: "1f0283e19ce9680f2441b9c37211e0b890fd7ebf4b9ea5a5c413fe0379d7d3f9"
|
||||||
|
|
||||||
|
admin:
|
||||||
|
secret: "admin" # Admin dashboard password (or set via ADMIN_SECRET env var)
|
||||||
|
|
||||||
|
navigation:
|
||||||
|
- label: "Home"
|
||||||
|
path: "/"
|
||||||
|
- label: "Blogs"
|
||||||
|
path: "/blogs"
|
||||||
|
- label: "Search"
|
||||||
|
path: "/search"
|
||||||
|
- label: "Quick Links"
|
||||||
|
path: "/quick-links"
|
||||||
|
|
||||||
|
social:
|
||||||
|
- platform: github
|
||||||
|
url: "https://github.com/CoderSherlock"
|
||||||
|
- platform: instagram
|
||||||
|
url: "https://www.instagram.com/pengzhan.hao/"
|
||||||
|
- platform: linkedin
|
||||||
|
url: "https://www.linkedin.com/in/pengzhanhao/"
|
||||||
|
- platform: email
|
||||||
|
address: "[email protected]"
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
google-analytics:
|
||||||
|
enabled: true
|
||||||
|
tracking_id: "G-MNP4QN1T9T"
|
||||||
|
reading-time:
|
||||||
|
enabled: true
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/* Custom CSS overrides on Persistent Volume */
|
||||||
|
/* Any CSS written here will be loaded after base and components CSS */
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
---
|
||||||
|
title: "Pengzhan Hao"
|
||||||
|
layout: home
|
||||||
|
permalink: "/"
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="home-hero-section">
|
||||||
|
<h1 class="hero-name">Pengzhan Hao</h1>
|
||||||
|
<p class="hero-subtitle">Software engineer on Cloud</p>
|
||||||
|
|
||||||
|
<div class="hero-intro">
|
||||||
|
<p>Joined Google in 2022, working in GKE, and focusing on Node & runtime area. Most projects landed on bringing ARM-based VMs to GKE, introduced more flexibilities in node customization and pod lifecycle improvement for preemptible VMs</p>
|
||||||
|
<p>Contributed to Kubernetes open source community and became a member in 2023</p>
|
||||||
|
<p>Now working on making GKE a more productive platform for AI/ML</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="home-section">
|
||||||
|
<h2 class="section-title">Research and study life in Binghamton University</h2>
|
||||||
|
<div class="two-column-grid">
|
||||||
|
<div class="column-block">
|
||||||
|
<p>Wide interests in multiple research areas, and spend most of my time in Edge computing, distributed systems and networks, and mobile operating system research. Under supervision from Professor Yifan Zhang, I spent 7 years in these research areas and outcome publications</p>
|
||||||
|
</div>
|
||||||
|
<div class="column-block">
|
||||||
|
<p>I worked as a teaching assistant for Operating system and Distributed system courses for both graduate and undergraduate levels. Mostly, I helped lecturers finish academic goals and hosted Labs for students. Before and during my research career, I finished my Master’s level education with a full grade point average.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="home-section">
|
||||||
|
<h2 class="section-title">Publications</h2>
|
||||||
|
<div class="publications-list">
|
||||||
|
<div class="pub-item">
|
||||||
|
<a href="/documents/eddl-sec21.pdf" target="_blank" class="pub-title">EDDL: A Distributed Deep Learning System for Resource-limited Edge Computing Environment</a>
|
||||||
|
<p class="pub-meta">Pengzhan Hao, and Yifan Zhang • The Sixth ACM/IEEE Symposium on Edge Computing (ACM/IEEE SEC) • San Jose, CA, USA, 2021.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pub-item">
|
||||||
|
<a href="/documents/eta-infocom18.pdf" target="_blank" class="pub-title">A Case for Web Service Bandwidth Reduction on Mobile Devices with Edge-hosted Personal Services</a>
|
||||||
|
<p class="pub-meta">Yongshu Bai, Pengzhan Hao, and Yifan Zhang • The 37th IEEE International Conference on Computer Communications (IEEE INFOCOM) • Honolulu, HI, USA, 2018.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pub-item">
|
||||||
|
<a href="/documents/a7-hao.pdf" target="_blank" class="pub-title">EdgeCourier: An Edge-hosted Personal Service for Low-bandwidth Document Synchronization in Mobile Cloud Storage Services</a>
|
||||||
|
<p class="pub-meta">Pengzhan Hao, Yongshu Bai, Xin Zhang, and Yifan Zhang • The 2nd ACM/IEEE Symposium on Edge Computing (ACM/IEEE SEC) • San Jose, CA, USA, 2017.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pub-item">
|
||||||
|
<a href="/documents/p169-zhang.pdf" target="_blank" class="pub-title">Poster: Securing Device Inputs for Smartphones Using Hypervisor Based Approach</a>
|
||||||
|
<p class="pub-meta">Xin Zhang, Yongshu Bai, Pengzhan Hao, and Yifan Zhang • The 15th ACM International Conference on Mobile Systems, Applications, and Services (ACM MobiSys) • Niagara Falls, NY, USA, 2017.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pub-item">
|
||||||
|
<a href="/documents/p163-hao.pdf" target="_blank" class="pub-title">Poster: EPS – Edge-hosted Personal Services for Mobile Users</a>
|
||||||
|
<p class="pub-meta">Pengzhan Hao, Yongshu Bai, Xin Zhang, and Yifan Zhang • The 15th ACM International Conference on Mobile Systems, Applications, and Services (ACM MobiSys) • Niagara Falls, NY, USA, 2017.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="home-section">
|
||||||
|
<h2 class="section-title">Undergraduate life in Beihang University</h2>
|
||||||
|
<div class="two-column-grid">
|
||||||
|
<div class="column-block">
|
||||||
|
<p>From 2011 to 2015, I attended the Software Engineering program at Beihang University. Overall, I received 3.25 out of 4 when graduating. During most of the era, I was enthusiasm in participating Movie Association and Mountain Climbing Association, and also worked as student assistant for career program for the last year.</p>
|
||||||
|
</div>
|
||||||
|
<div class="column-block">
|
||||||
|
<p>Starting from my junior year, I studied and researched consecutively in two labs. Worked in Android Kernel and module localization and smart urban computing areas. In urban computing areas, led a small team to participate in a joint project together by the Advanced Computer application technology engineering research center(Beihang University) and Microsoft Research Asia(MSRA).</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="home-section">
|
||||||
|
<h2 class="section-title">Projects</h2>
|
||||||
|
<div class="projects-list">
|
||||||
|
<div class="project-item">
|
||||||
|
<h3 class="project-name">EDDL – Edge distributed deep learning framework</h3>
|
||||||
|
<p>A lite-weight c++ written framework(based on Dlib) for distributed neural network training on embedded devices and mobile phones. With supporting of our implemented runtime profilers, training devices can interconnect in an optimized network topology under various network environments. In our last publication, we showed our framework can perform distributed training for diverse neural networks on resource-limited devices. The EDDL framework also showed well scalability in large amounts of devices. We are currently working on network optimization on per-batch communication time and overall convergence time.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project-item">
|
||||||
|
<h3 class="project-name">Edge Courier</h3>
|
||||||
|
<p>A proxy-based protocol for incremental file synchronization and cooperative online document editing. This protocol supports file hosting services including Google Drive, Dropbox, and OneDrive as well as document collaboration services such as G Suite and Microsoft 365. Edge courier can significantly decrease bandwidth consumption for collaborative editing web apps, and also showed advancement in cloud file storage services.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="project-item">
|
||||||
|
<h3 class="project-name">RTRouting assistant</h3>
|
||||||
|
<p>A real time routing prototype which can guide vehicle to alternative routes with high-volume traffic prediction. The predicted traffic alert is generated by a pre-trained model learned from history monitored traffics, real time event warnings and a abnormal traffic prediction model. This project belongs to a urban computing project studied together by Advance computer application technology engineering research center(Beihang University) and Microsoft Research Asia(MSRA).</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="home-section">
|
||||||
|
<h2 class="section-title">Recognition</h2>
|
||||||
|
<div class="recognition-list">
|
||||||
|
<div class="recog-item">
|
||||||
|
<strong>ACM/IEEE SEC student travel grant</strong>
|
||||||
|
<span class="recog-meta">IEEE • 2017, 2021</span>
|
||||||
|
</div>
|
||||||
|
<div class="recog-item">
|
||||||
|
<strong>ACM MobiSys 2017 student travel grant</strong>
|
||||||
|
<span class="recog-meta">ACM • 2017</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: "Quick Links"
|
||||||
|
permalink: "/quick-links"
|
||||||
|
---
|
||||||
|
|
||||||
|
A curated collection of public resources, contact points, and references:
|
||||||
|
|
||||||
|
## Professional Profiles
|
||||||
|
|
||||||
|
- **GitHub**: [github.com/CoderSherlock](https://github.com/CoderSherlock) — open-source projects, personal tools, and experiments.
|
||||||
|
- **LinkedIn**: [linkedin.com/in/pengzhanhao](https://www.linkedin.com/in/pengzhanhao/) — professional background.
|
||||||
|
- **Instagram**: [@pengzhan.hao](https://www.instagram.com/pengzhan.hao/) — photography and outdoor life.
|
||||||
|
|
||||||
|
## Direct Contact
|
||||||
|
|
||||||
|
- **Email**: [[email protected]](mailto:[email protected])
|
||||||
|
|
||||||
|
## Documents
|
||||||
|
|
||||||
|
- **Curriculum Vitae**: [Download CV (PDF)](/documents/CV.pdf)
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
module.exports = {
|
||||||
|
injectHead({ pluginConfig, pageType }) {
|
||||||
|
const trackingId = pluginConfig.tracking_id;
|
||||||
|
if (!trackingId) return '';
|
||||||
|
|
||||||
|
// 1. Never inject analytics on administrative moderation pages
|
||||||
|
if (pageType === 'admin') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Do not inject in development, staging, or testing modes (unless explicitly enabled)
|
||||||
|
const isProd = process.env.NODE_ENV === 'production' && process.env.APP_ENV !== 'staging';
|
||||||
|
if (!isProd && !pluginConfig.enable_in_dev) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<!-- Google Analytics (GA4 via Plugin) -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=${trackingId}"></script>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
// 3. Client-side domain safeguard: only track on production pengzhan.dev domains
|
||||||
|
var host = window.location.hostname;
|
||||||
|
if (host !== 'pengzhan.dev' && !host.endsWith('.pengzhan.dev')) {
|
||||||
|
window['ga-disable-${trackingId}'] = true;
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
window.gtag = function(){};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
window.gtag = gtag;
|
||||||
|
gtag('js', new Date());
|
||||||
|
gtag('config', '${trackingId}');
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "google-analytics",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Injects Google Analytics 4 tracking script into head"
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
module.exports = {
|
||||||
|
onPostLoad({ post }) {
|
||||||
|
const wordCount = (post.rawContent || '').trim().split(/\s+/).length;
|
||||||
|
// Assume average 200 words per minute
|
||||||
|
const minutes = Math.max(1, Math.round(wordCount / 200));
|
||||||
|
post.readingTime = `${minutes} min read`;
|
||||||
|
post.wordCount = wordCount;
|
||||||
|
},
|
||||||
|
|
||||||
|
injectPostEnd({ post }) {
|
||||||
|
if (post && post.readingTime) {
|
||||||
|
return `<div style="font-family: var(--font-sans); font-size: 0.85rem; color: var(--color-text-muted); margin-top: 2rem; padding: 0.75rem 1rem; background: var(--color-surface-soft); border-radius: var(--radius-sm);">
|
||||||
|
Article statistics: ~${post.wordCount} words • ${post.readingTime}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "reading-time",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Calculates reading time and word count for articles"
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
module.exports = {
|
||||||
|
onPostLoad({ post }) {
|
||||||
|
const raw = post.rawContent || '';
|
||||||
|
const internalMatches = raw.match(/\[[^\]]+\]\((\/[^)]+)\)/g) || [];
|
||||||
|
const externalMatches = raw.match(/\[[^\]]+\]\((https?:\/\/[^)]+)\)/g) || [];
|
||||||
|
|
||||||
|
post.seoMetrics = {
|
||||||
|
internalLinkCount: internalMatches.length,
|
||||||
|
externalLinkCount: externalMatches.length,
|
||||||
|
hasMetaDescription: Boolean(post.excerpt && post.excerpt.length > 30),
|
||||||
|
titleLength: post.title.length,
|
||||||
|
isTitleOptimal: post.title.length >= 25 && post.title.length <= 70
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "seo-analyzer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Dynamic SEO auditor and content health inspector"
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 8.5 MiB |
|
After Width: | Height: | Size: 8.5 MiB |
@@ -0,0 +1,41 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600" width="100%" height="100%">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="kidBg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#fed7aa"/>
|
||||||
|
<stop offset="100%" stop-color="#fb923c"/>
|
||||||
|
</linearGradient>
|
||||||
|
<filter id="kidShadow" x="-10%" y="-10%" width="120%" height="120%">
|
||||||
|
<feDropShadow dx="0" dy="6" stdDeviation="10" flood-opacity="0.15"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<rect width="600" height="600" fill="url(#kidBg)" rx="32"/>
|
||||||
|
|
||||||
|
<!-- Creative Building Blocks / Robot Icon -->
|
||||||
|
<g transform="translate(300, 250)" filter="url(#kidShadow)">
|
||||||
|
<rect x="-90" y="-80" width="180" height="150" rx="24" fill="#ffffff"/>
|
||||||
|
<!-- Robot antenna -->
|
||||||
|
<line x1="0" y1="-80" x2="0" y2="-120" stroke="#ffffff" stroke-width="8" stroke-linecap="round"/>
|
||||||
|
<circle cx="0" cy="-125" r="14" fill="#ea580c"/>
|
||||||
|
<!-- Eyes -->
|
||||||
|
<circle cx="-40" cy="-15" r="16" fill="#0284c7"/>
|
||||||
|
<circle cx="40" cy="-15" r="16" fill="#0284c7"/>
|
||||||
|
<!-- Smile -->
|
||||||
|
<path d="M -40 30 Q 0 60 40 30" stroke="#ea580c" stroke-width="8" stroke-linecap="round" fill="none"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Educational Blocks -->
|
||||||
|
<g transform="translate(180, 420)" filter="url(#kidShadow)">
|
||||||
|
<rect x="0" y="0" width="60" height="60" rx="12" fill="#38bdf8"/>
|
||||||
|
<text x="30" y="42" text-anchor="middle" fill="#ffffff" font-family="-apple-system, sans-serif" font-size="32" font-weight="900">A</text>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(260, 400)" filter="url(#kidShadow)">
|
||||||
|
<rect x="0" y="0" width="60" height="60" rx="12" fill="#ec4899"/>
|
||||||
|
<text x="30" y="42" text-anchor="middle" fill="#ffffff" font-family="-apple-system, sans-serif" font-size="32" font-weight="900">I</text>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(340, 420)" filter="url(#kidShadow)">
|
||||||
|
<rect x="0" y="0" width="60" height="60" rx="12" fill="#10b981"/>
|
||||||
|
<text x="30" y="42" text-anchor="middle" fill="#ffffff" font-family="-apple-system, sans-serif" font-size="32" font-weight="900"><></text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<text x="300" y="530" text-anchor="middle" fill="#7c2d12" font-family="-apple-system, sans-serif" font-size="28" font-weight="800">Coding for Kids</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.3 MiB |