Compare commits

...

13 Commits

Author SHA1 Message Date
cc62d0bb95 chore: deploy to Cloudflare Pages 2025-02-09 12:11:44 +01:00
727ec58600 chore: update vuepress and plugins 2025-02-09 11:57:54 +01:00
333b7a7562 docs: update mastodon link
All checks were successful
deploy / deploy (push) Successful in 3m28s
2024-11-17 14:29:45 +01:00
baf999ea1c docs: update resume
All checks were successful
deploy / deploy (push) Successful in 5m23s
2024-10-01 23:20:02 +02:00
9a92f57986 chore: update metadata 2024-07-09 20:45:36 +02:00
c8ce7ca6da chore(package.json): remove unused packages
All checks were successful
deploy / deploy (push) Successful in 1m30s
2024-06-20 09:33:58 +02:00
d54aabd621 refactor: rework API loader and caching
All checks were successful
deploy / deploy (push) Successful in 2m24s
This commit removes dependency on rxjs.

It also implements better composables to handle data fetching from
remote APIs and caching these values more transparently.

This commit also switches from yarn to npm

It also switches to the official Umami plugin
2024-06-20 09:27:59 +02:00
24d558e0f5 test
All checks were successful
deploy / deploy (push) Successful in 2m51s
2024-02-26 07:38:38 +01:00
bc36bdec90 feat(umami): switch to dedicated Vuepress plugin
All checks were successful
deploy / deploy (push) Successful in 3m24s
2024-02-26 06:51:54 +01:00
1b54860f93 docs(find-me): Update Discord handle
Update content/en/find-me.org
Update content/find-me.org
Update content/lfn/find-me.org
2024-02-26 06:51:27 +01:00
37f9b36b2f feat,docs: add Umami to website, update privacy pages
All checks were successful
deploy / deploy (push) Successful in 2m1s
2024-01-27 18:25:44 +01:00
4b447369c2 chore: switch from Drone to Gitea Actions
All checks were successful
deploy / deploy (push) Successful in 2m8s
2024-01-27 16:55:30 +01:00
cf1147204c chore: update Vuepress, add search bar 2024-01-27 16:15:57 +01:00
32 changed files with 5573 additions and 3296 deletions

View File

@@ -1,178 +0,0 @@
---
kind: pipeline
type: docker
name: CD
steps:
- name: restore cache node
image: drillster/drone-volume-cache
volumes:
- name: main-website-node
path: /cache/phundrak.com/node
settings:
restore: true
mount:
- ./node_modules
- name: restore cache emacs
image: drillster/drone-volume-cache
volumes:
- name: main-website-emacs
path: /cache/phundrak.com/emacs
settings:
restore: true
mount:
- /var/emacs
- name: generate emacs
image: silex/emacs:master-alpine
commands:
- mkdir -p /var/emacs
- apk update && apk add git
- emacs --init-directory=/var/emacs --script export.el
depends_on:
- "restore cache emacs"
- name: generate node
image: node:19-alpine
commands:
- yarn install
- yarn build
depends_on:
- "restore cache node"
- "generate emacs"
- name: rebuild cache emacs
image: drillster/drone-volume-cache
volumes:
- name: conlang-emacs
path: /cache/conlang/emacs
settings:
rebuild: true
mount:
- /var/emacs
depends_on:
- "generate emacs"
- name: rebuild cache node
image: drillster/drone-volume-cache
volumes:
- name: main-website-node
path: /cache/phundrak.com/node
settings:
rebuild: true
mount:
- ./node_modules
depends_on:
- "generate node"
- name: deploy web stable
image: appleboy/drone-scp
settings:
host:
from_secret: ssh_host
target:
from_secret: ssh_target
source: content/.vuepress/dist/*
strip_components: 3
username:
from_secret: ssh_username
password:
from_secret: ssh_password
port:
from_secret: ssh_port
depends_on:
- "generate node"
when:
branch:
- main
event:
exclude:
- pull_request
- name: deploy gemini
image: appleboy/drone-scp
settings:
host:
from_secret: ssh_host
target:
from_secret: ssh_target_gemini
source: gemini/*
strip_components: 1
username:
from_secret: ssh_username
password:
from_secret: ssh_password
port:
from_secret: ssh_port
depends_on:
- "generate emacs"
when:
branch:
- main
event:
exclude:
- pull_request
- name: purge cache stable
image: jetrails/drone-cloudflare-caching
settings:
api_token:
from_secret: cloudflare_cache_api
zone_identifier:
from_secret: phundrak_com_zone_id
action: purge_files
list:
- https://beta.phundrak.com
depends_on:
- "deploy web stable"
- "deploy gemini"
when:
branch:
- main
event:
exclude:
- pull_request
- name: deploy web devel
image: appleboy/drone-scp
settings:
host:
from_secret: ssh_host
target:
from_secret: ssh_target_devel
source: content/.vuepress/dist/*
strip_components: 3
username:
from_secret: ssh_username
password:
from_secret: ssh_password
port:
from_secret: ssh_port
depends_on:
- "generate node"
when:
branch:
- devel
event:
exclude:
- pull_request
- name: purge cache devel
image: jetrails/drone-cloudflare-caching
settings:
api_token:
from_secret: cloudflare_cache_api
zone_identifier:
from_secret: phundrak_com_zone_id
action: purge_files
list:
- https://alpha.phundrak.com
depends_on:
- "deploy web devel"
when:
branch:
- devel
event:
exclude:
- pull_request

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use nix

50
.github/workflows/deploy.yaml vendored Normal file
View File

@@ -0,0 +1,50 @@
name: deploy
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
with:
node-version: 22.x
- run: npm ci
- uses: purcell/setup-emacs@master
with:
version: 29.1
- name: "Export org to md"
run: emacs -Q --script export.el
- run: npm run build
- name: "Deploy to Cloudflare Pages"
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.ACCOUNT_ID }}
projectName: phundrak-com
directory: content/.vuepress/dist/
githubToken: ${{ secrets.TOKEN }}
# - name: "Deploy on the Web"
# uses: appleboy/scp-action@v0.1.7
# with:
# host: ${{ secrets.HOST }}
# username: ${{ secrets.USERNAME }}
# key: ${{ secrets.KEY }}
# port: ${{ secrets.PORT }}
# source: content/.vuepress/dist/*
# target: ${{ secrets.DESTPATH }}
# strip_components: 3
# - name: "Deploy on Gemini"
# uses: appleboy/scp-action@v0.1.7
# with:
# host: ${{ secrets.HOST }}
# username: ${{ secrets.USERNAME }}
# key: ${{ secrets.KEY }}
# port: ${{ secrets.PORT }}
# source: gemini/*
# target: ${{ secrets.DESTPATH_GMI }}
# strip_components: 1

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ node_modules
.cache .cache
/content/.vuepress/dist/* /content/.vuepress/dist/*
*.md *.md
/.yarn/

3
.yarnrc.yml Normal file
View File

@@ -0,0 +1,3 @@
enableMessageNames: false
nodeLinker: node-modules

View File

@@ -4,9 +4,8 @@ import ListRepositories from './components/GitHub/ListRepositories.vue';
import FetchRepositories from './components/GitHub/FetchRepositories.vue'; import FetchRepositories from './components/GitHub/FetchRepositories.vue';
import GithubRepository from './components/GitHub/GithubRepository.vue'; import GithubRepository from './components/GitHub/GithubRepository.vue';
import ApiLoader from './components/ApiLoader.vue'; import ApiLoader from './components/ApiLoader.vue';
import Loader from './components/Loader.vue'; import LoaderAnimation from './components/LoaderAnimation.vue';
import Cache from './components/Cache.vue'; import FetchError from './components/FetchError.vue';
import Error from './components/Error.vue';
import Icon from './components/Icon.vue'; import Icon from './components/Icon.vue';
export default defineClientConfig({ export default defineClientConfig({
@@ -16,9 +15,8 @@ export default defineClientConfig({
app.component('FetchRepositories', FetchRepositories); app.component('FetchRepositories', FetchRepositories);
app.component('GithubRepository', GithubRepository); app.component('GithubRepository', GithubRepository);
app.component('ApiLoader', ApiLoader); app.component('ApiLoader', ApiLoader);
app.component('Loader', Loader); app.component('LoaderAnimation', LoaderAnimation);
app.component('Cache', Cache); app.component('FetchError', FetchError);
app.component('Error', Error);
app.component('Icon', Icon); app.component('Icon', Icon);
}, },
setup() {}, setup() {},

View File

@@ -1,31 +1,22 @@
<template> <template>
<Cache
:name="props.cacheName"
:callback="fetchData"
:already-known-data="alreadyKnownData"
@cached="processCachedData"
/>
<slot v-if="loading" name="loader"> <slot v-if="loading" name="loader">
<Loader /> <LoaderAnimation />
</slot> </slot>
<slot v-else-if="error" name="error"> <slot v-else-if="error" name="error">
<Error :url="props.url" /> <FetchError :url="props.url" />
</slot> </slot>
<slot v-else> </slot> <slot v-else> </slot>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Cache from './Cache.vue'; import LoaderAnimation from './LoaderAnimation.vue';
import Loader from './Loader.vue'; import FetchError from './FetchError.vue';
import Error from './Error.vue';
import { Ref, ref } from 'vue'; import { useFetchAndCache } from '../composables/fetchAndCache';
import { Observable, catchError, switchMap, throwError } from 'rxjs';
import { fromFetch } from 'rxjs/fetch';
const props = defineProps({ const props = defineProps({
url: { url: {
default: false, default: '',
required: true, required: true,
type: String, type: String,
}, },
@@ -35,31 +26,11 @@ const props = defineProps({
}, },
alreadyKnownData: Object, alreadyKnownData: Object,
}); });
const emits = defineEmits(['dataLoaded', 'dataError', 'loading']);
const error: Ref<Error> = ref(null); const emits = defineEmits(['loaded', 'error', 'loading']);
const loading: Ref<boolean> = ref(true);
const fetchData = (): Observable<any> => { const { loading, error } = useFetchAndCache(props.url, {
return fromFetch(props.url).pipe( emits: emits,
switchMap((response: Response) => response.json()), cacheName: props.cacheName,
catchError((errorResponse: Error) => { });
error.value = errorResponse;
return Error;
})
);
};
const processCachedData = (data: Observable<any>) => {
data.subscribe({
next: (response: any) => {
loading.value = false;
emits('dataLoaded', response);
},
error: (responseError: Error) => {
loading.value = false;
error.value = responseError;
},
});
};
</script> </script>

View File

@@ -1,67 +0,0 @@
<template>
<slot />
</template>
<script setup lang="ts">
import { Observable, of, tap } from 'rxjs';
const props = defineProps({
name: {
required: true,
type: String,
},
callback: {
required: true,
type: Function,
},
lifetime: {
default: 1000 * 60 * 60, // one hour
required: false,
type: Number,
},
alreadyKnownData: {
default: null,
type: Object,
},
});
const emits = defineEmits(['cached']);
const isDataOutdated = (name: string): boolean => {
const lastUpdated: number = +localStorage.getItem(name + '-timestamp');
const elapsedTime: number = Date.now() - lastUpdated;
return elapsedTime > props.lifetime;
};
const storeInCache = (
callback: Function,
data: any,
name: string,
): Observable<any> => {
let response: Observable<any> = data ? of(data) : callback();
return response.pipe(
tap((response) => {
localStorage.setItem(name, JSON.stringify(response));
localStorage.setItem(name + '-timestamp', `${Date.now()}`);
}),
);
};
if (isDataOutdated(props.name)) {
emits(
'cached',
storeInCache(props.callback, props.alreadyKnownData, props.name),
);
} else {
let data = localStorage.getItem(props.name);
try {
emits('cached', of(JSON.parse(data)));
} catch (err) {
console.error(`Could not parse data found in cache: ${err}`);
emits(
'cached',
storeInCache(props.callback, props.alreadyKnownData, props.name),
);
}
}
</script>

View File

@@ -1,11 +1,11 @@
<template> <template>
<ApiLoader :url="fetchUrl" @dataLoaded="filterRepos" cache-name="repos" /> <ApiLoader :url="fetchUrl" @loaded="filterRepos" cache-name="repos" />
<slot /> <slot />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { PropType } from 'vue'; import { PropType, ref } from 'vue';
import { GithubRepo } from '../../composables/github'; import { GithubRepo } from '../../types/github';
const props = defineProps({ const props = defineProps({
sortBy: { sortBy: {
default: 'none', default: 'none',
@@ -23,27 +23,24 @@ const props = defineProps({
type: Number, type: Number,
}, },
}); });
const emits = defineEmits(['loaded']);
const emits = defineEmits(['dataLoaded']);
const fetchUrl = `https://api.github.com/users/${props.user}/repos?per_page=100`; const fetchUrl = `https://api.github.com/users/${props.user}/repos?per_page=100`;
const repos = ref<GithubRepo[]>([]);
const filterRepos = (response: GithubRepo[]) => { const filterRepos = (response: GithubRepo[]) => {
emits( repos.value = response
'dataLoaded', .sort((a, b) => {
response if (props.sortBy === 'stars') {
.sort((a, b) => { return b.stargazers_count - a.stargazers_count;
if (props.sortBy === 'stars') { }
return b.stargazers_count - a.stargazers_count; if (props.sortBy === 'pushed_at') {
} const dateA = new Date(a.pushed_at);
if (props.sortBy === 'pushed_at') { const dateB = new Date(b.pushed_at);
const dateA = new Date(a.pushed_at); return dateB.getTime() - dateA.getTime();
const dateB = new Date(b.pushed_at); }
return dateB.getTime() - dateA.getTime(); return b.forks_count - a.forks_count;
} })
return b.forks_count - a.forks_count; .slice(0, +props.limit);
}) emits('loaded', repos.value);
.slice(0, +props.limit)
);
}; };
</script> </script>

View File

@@ -6,23 +6,23 @@
:cache-name="repoName()" :cache-name="repoName()"
:url="fetchUrl" :url="fetchUrl"
:already-known-data="props.data" :already-known-data="props.data"
@data-loaded="(repo: GithubRepo) => (repository = repo)" @loaded="(repo: GithubRepo) => (repository = repo)"
> >
<h3>{{ repository.name }}</h3> <h3>{{ repository?.name }}</h3>
<div> <div>
<p> <p>
{{ repository.description }} {{ repository?.description }}
</p> </p>
</div> </div>
<div class="flex-row flex-start gap-1rem stats"> <div class="flex-row flex-start gap-1rem stats">
<div class="stars"> <div class="stars">
<Icon name="star" /> {{ repository.stargazers_count }} <Icon name="star" /> {{ repository?.stargazers_count }}
</div> </div>
<div class="forks"> <div class="forks">
<Icon name="fork" /> {{ repository.forks_count }} <Icon name="fork" /> {{ repository?.forks_count }}
</div> </div>
<div class="link"> <div class="link">
<a :href="repository.html_url"><i class="icon phunic-link" /></a> <a :href="repository?.html_url"><i class="icon phunic-link" /></a>
</div> </div>
</div> </div>
</ApiLoader> </ApiLoader>
@@ -32,7 +32,7 @@
<script setup lang="ts"> <script setup lang="ts">
import ApiLoader from '../ApiLoader.vue'; import ApiLoader from '../ApiLoader.vue';
import { GithubRepo } from '../../composables/github'; import { GithubRepo } from '../../types/github';
import { PropType, Ref, ref } from 'vue'; import { PropType, Ref, ref } from 'vue';
const props = defineProps({ const props = defineProps({
@@ -45,7 +45,7 @@ const repoName = (): string => {
}; };
const fetchUrl = `https://api.github.com/repos/${repoName()}`; const fetchUrl = `https://api.github.com/repos/${repoName()}`;
const repository: Ref<GithubRepo> = ref(null); const repository: Ref<GithubRepo | null> = ref(null);
</script> </script>
<style lang="less"> <style lang="less">
@@ -78,5 +78,12 @@ const repository: Ref<GithubRepo> = ref(null);
gap: 0.3rem; gap: 0.3rem;
} }
} }
.link {
a {
display: flex;
align-items: center;
}
}
} }
</style> </style>

View File

@@ -5,7 +5,7 @@
:sort-by="props.sortBy" :sort-by="props.sortBy"
:user="props.user" :user="props.user"
:limit="props.limit" :limit="props.limit"
@data-loaded="(response: GithubRepo[]) => (repos = response)" @loaded="(response: GithubRepo[]) => (repos = response)"
> >
<GithubRepository <GithubRepository
:data="repo" :data="repo"
@@ -22,7 +22,7 @@ import FetchRepositories from './FetchRepositories.vue';
import GithubRepository from './GithubRepository.vue'; import GithubRepository from './GithubRepository.vue';
import { PropType, Ref, ref } from 'vue'; import { PropType, Ref, ref } from 'vue';
import { GithubRepo } from '../../composables/github'; import { GithubRepo } from '../../types/github';
const props = defineProps({ const props = defineProps({
sortBy: { sortBy: {

View File

@@ -0,0 +1,62 @@
import { Ref, computed, ref, watchEffect } from 'vue';
interface CacheOptions {
lifetime?: number;
timestampSuffix?: string;
forceUpdate?: boolean;
}
/**
* Cache data in local storage.
*
* The cache is updated if:
* - cache data does not exist
* - cached data is outdated and `data` is not null
* - or `options.forceUpdate` is true, regardless of the value of `data`
*
* Otherwise, data is retrieved from cache.
*
* @param {string} name Name of the cached value in local storage
* @param {Ref<T>} data Data to cache
* @param {CacheOptions} options Tweaks to the behaviour of the function
*/
export const useCache = <T>(
name: string,
data: Ref<T>,
options: CacheOptions,
) => {
const error = ref<string>(null);
const timestampName = name + (options?.timestampSuffix || '-timestamp');
const lifetime = options?.lifetime || 1000 * 60 * 60; // one hour in milliseconds
const lastUpdated: number = +localStorage.getItem(timestampName);
const cacheAge: number = Date.now() - lastUpdated;
const isDataOutdated = computed(() => {
return cacheAge > lifetime;
});
const shouldUpdate = computed(
() => options?.forceUpdate || (isDataOutdated.value && data.value != null),
);
const setData = () => {
console.log('Setting data in cache with name', name);
localStorage.setItem(name, JSON.stringify(data.value));
localStorage.setItem(timestampName, `${Date.now()}`);
};
const getData = () => {
console.log('Getting data from cache with name', name);
const cached = localStorage.getItem(name);
console.log('Value from storage:', cached);
try {
data.value = JSON.parse(cached);
} catch (err) {
console.error('Failed to parse cached data:', err);
data.value = null;
error.value = err;
}
};
getData();
watchEffect(() => (shouldUpdate.value ? setData() : getData()));
return { error, isDataOutdated };
};

View File

@@ -0,0 +1,72 @@
import { ref, Ref } from 'vue';
import { useCache } from './cache';
type FetchAndCacheEmitter = (
event: 'loaded' | 'error' | 'loading',
...args: any[]
) => void;
interface UseFetchAndCacheOptions {
cacheLifetime?: number;
cacheName?: string;
emits?: FetchAndCacheEmitter;
}
const dummyEmits = (
_event: 'loaded' | 'error' | 'loading',
..._args: any[]
) => {};
export const useFetchAndCache = <T, E>(
url: string,
options?: UseFetchAndCacheOptions,
) => {
const data = ref<T | null>(null) as Ref<T>;
const error = ref<E | null>(null) as Ref<E>;
const loading = ref<boolean>(true);
const cacheLifetime: number = options?.cacheLifetime || 1000 * 60 * 60; // one hour
const cacheName: string = options?.cacheName || url;
const { isDataOutdated: isCacheOutdated, error: cacheError } = useCache(
cacheName,
data,
{
lifetime: cacheLifetime,
},
);
const emits: FetchAndCacheEmitter = options?.emits || dummyEmits;
const loaded = () => {
loading.value = false;
emits('loaded', data.value);
};
const fetchData = () => {
loading.value = true;
emits('loading');
console.log('Fetching from URL', url);
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json() as Promise<T>;
})
.then((responseData) => {
data.value = responseData;
loaded();
})
.catch((e) => {
console.warn('Caught error!', e);
error.value = e;
emits('error', e);
})
.finally(() => (loading.value = false));
};
if (isCacheOutdated.value || cacheError.value != null) {
fetchData();
} else {
loaded();
}
return { data, loading, error };
};

View File

@@ -1,24 +1,56 @@
import { defineUserConfig, defaultTheme } from 'vuepress'; import { defaultTheme } from '@vuepress/theme-default';
import { removeHtmlExtensionPlugin } from 'vuepress-plugin-remove-html-extension'; import { viteBundler } from '@vuepress/bundler-vite';
import head from './head'; import { defineUserConfig } from 'vuepress';
import locales from './locales'; import { slimsearchPlugin } from '@vuepress/plugin-slimsearch';
import { umamiAnalyticsPlugin } from '@vuepress/plugin-umami-analytics';
import { head } from './head';
import { locales, searchLocaleLfn } from './locales';
import { themeLocales } from './themeLocales'; import { themeLocales } from './themeLocales';
const isProd = process.env.NODE_ENV === 'production';
export default defineUserConfig({ export default defineUserConfig({
lang: 'fr-FR', lang: 'fr-FR',
title: 'Lucien Cartier-Tilet', title: 'Lucien Cartier-Tilet',
description: 'Site web personnel de Lucien Cartier-Tilet', description: 'Site web personnel de Lucien Cartier-Tilet',
head: head, head: head,
bundler: isProd
? viteBundler({})
: viteBundler({
viteOptions: {
server: {
allowedHosts: true,
},
},
}),
markdown: { markdown: {
html: true, html: true,
linkify: true, linkify: true,
typographer: true, typographer: true,
}, },
plugins: [removeHtmlExtensionPlugin()], plugins: [
slimsearchPlugin({
indexContent: true,
indexLocaleOptions: {
'/lfn': searchLocaleLfn,
},
}),
isProd
? umamiAnalyticsPlugin({
id: '67166941-8c83-4a19-bc8c-139e44b7f7aa',
link: 'https://umami.phundrak.com/script.js',
})
: [],
],
locales: locales, locales: locales,
theme: defaultTheme({ theme: defaultTheme({
contributors: false, contributors: false,
locales: themeLocales, locales: themeLocales,
repo: 'https://labs.phundrak.com/phundrak/phundrak.com', repo: 'https://labs.phundrak.com/phundrak/phundrak.com',
themePlugins: {
copyCode: false,
prismjs: false,
},
}), }),
}); });

View File

@@ -1,9 +1,11 @@
import { HeadAttrsConfig } from 'vuepress';
interface SimplifiedHeader { interface SimplifiedHeader {
tag: string; tag: string;
content: [any]; content: HeadAttrsConfig[];
} }
const simplifiedHead = [ const simplifiedHead: SimplifiedHeader[] = [
{ {
tag: 'meta', tag: 'meta',
content: [ content: [
@@ -11,6 +13,10 @@ const simplifiedHead = [
name: 'author', name: 'author',
content: 'Lucien Cartier-Tilet', content: 'Lucien Cartier-Tilet',
}, },
{
name: 'fediverse:creator',
content: '@phundrak@mastodon.phundrak.com',
},
{ {
property: 'og:image', property: 'og:image',
content: 'https://cdn.phundrak.com/img/rich_preview.png', content: 'https://cdn.phundrak.com/img/rich_preview.png',
@@ -35,6 +41,10 @@ const simplifiedHead = [
name: 'twitter:creator', name: 'twitter:creator',
content: '@phundrak', content: '@phundrak',
}, },
{
name: 'build-status',
content: `value: ${process.env.NODE_ENV}`,
},
{ name: 'msapplication-TileColor', content: '#3b4252' }, { name: 'msapplication-TileColor', content: '#3b4252' },
{ name: 'msapplication-TileImage', content: '/ms-icon-144x144.png' }, { name: 'msapplication-TileImage', content: '/ms-icon-144x144.png' },
{ name: 'theme-color', content: '#3b4252' }, { name: 'theme-color', content: '#3b4252' },
@@ -117,12 +127,16 @@ const simplifiedHead = [
}, },
]; ];
let head = []; const headBuilder = [];
simplifiedHead.forEach((tag) => { simplifiedHead.forEach((tag) => {
tag.content.forEach((element: any) => { tag.content.forEach((element) => {
head.push([tag.tag, element]); headBuilder.push([tag.tag, element]);
}); });
}); });
head.push(['a', { rel: 'me', href: 'https://emacs.ch/@phundrak' }, 'Mastodon']); headBuilder.push([
'a',
{ rel: 'me', href: 'https://mastodon.phundrak.com/@phundrak' },
'Mastodon',
]);
export default head; export const head = headBuilder;

View File

@@ -1,4 +1,6 @@
const locales = { import SlimSarchLocaleData from '@vuepress/plugin-slimsearch';
export const locales = {
'/': { '/': {
lang: 'fr-FR', lang: 'fr-FR',
title: 'Lucien Cartier-Tilet', title: 'Lucien Cartier-Tilet',
@@ -16,4 +18,19 @@ const locales = {
}, },
}; };
export default locales; export const searchLocaleLfn: SlimSarchLocaleData = {
cancel: 'Cansela',
placeholder: 'Xerca',
search: 'Xerca',
searching: 'Xercante',
defaultTitle: 'Documentos',
select: 'eleje',
navigate: 'naviga',
autocomplete: 'auto-completi',
exit: 'sorti',
queryHistory: 'Historia de xerca',
resultHistory: 'Historia de resultas',
emptyHistory: 'Historia vacua',
emptyResult: 'Resultas vacua',
loading: 'Cargante la indise de xerca...',
};

View File

@@ -7,26 +7,25 @@ I am on various websites and some social networks where you can follow
me. me.
** Social Networks ** Social Networks
- {{{icon(mastodon)}}} Mastodon :: [[https://emacs.ch/@phundrak][@phundrak@phundrak.com]] should work, - {{{icon(mastodon)}}} *Mastodon* :: [[https://mastodon.phundrak.com/@phundrak][@phundrak@mastodon.phundrak.com]]
otherwise head over to [[https://emacs.ch/@phundrak][@phundrak@emacs.ch]] - {{{icon(twitter)}}} *Twitter* :: [[https://twitter.com/phundrak][@phundrak]], though I harldy use it anymore
- {{{icon(twitter)}}} Twitter :: [[https://twitter.com/phundrak][@phundrak]], though I harldy use it anymore
and mostly reshare my Mastodon messages when I think to, and and mostly reshare my Mastodon messages when I think to, and
sometimes they get truncated sometimes they get truncated
- {{{icon(writefreely)}}} Writefreely :: - {{{icon(writefreely)}}} *Writefreely* ::
- [[https://write.phundrak.com/phundrak][@phundrak@write.phundrak.com]] : blog alternative - [[https://write.phundrak.com/phundrak][@phundrak@write.phundrak.com]] : blog alternative
- [[https://write.phundrak.com/phundraks-short-stories][@phundraks-short-stories@write.phundrak.com]] :: short stories, - [[https://write.phundrak.com/phundraks-short-stories][@phundraks-short-stories@write.phundrak.com]] :: short stories,
mainly in French for now mainly in French for now
- {{{icon(discord)}}} Discord :: =Phundrak#0001= (tell me you come from here, - {{{icon(discord)}}} *Discord* :: =@phundrak= (tell me you come from here,
otherwise theres a chance Ill consider your message as spam) otherwise theres a chance Ill consider your message as spam)
** Other Websites ** Other Websites
- {{{icon(envelope)}}} Email :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]] - {{{icon(envelope)}}} *Email* :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
- {{{icon(rss)}}} Blog :: [[https://blog.phundrak.com][blog.phundrak.com]] - {{{icon(rss)}}} *Blog* :: [[https://blog.phundrak.com][blog.phundrak.com]]
- {{{icon(gitea)}}} Gitea :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]] - {{{icon(gitea)}}} *Gitea* :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
- {{{icon(github)}}} GitHub :: [[https://github.com/Phundrak][Phundrak]] - {{{icon(github)}}} *GitHub* :: [[https://github.com/Phundrak][Phundrak]]
- {{{icon(youtube)}}} YouTube :: [[https://www.youtube.com/@phundrak][@phundrak]] - {{{icon(youtube)}}} *YouTube* :: [[https://www.youtube.com/@phundrak][@phundrak]]
- {{{icon(reddit)}}} Reddit :: [[https://www.reddit.com/user/phundrak][/u/phundrak]] - {{{icon(reddit)}}} *Reddit* :: [[https://www.reddit.com/user/phundrak][/u/phundrak]]
- {{{icon(linkedin)}}} LinkedIn :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]] - {{{icon(linkedin)}}} *LinkedIn* :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
- {{{icon(twitch)}}} Twitch :: [[https://www.twitch.tv/phundrak][phundrak]] - {{{icon(twitch)}}} *Twitch* :: [[https://www.twitch.tv/phundrak][phundrak]]
#+include: other-links #+include: other-links

View File

@@ -18,8 +18,8 @@ websites to function properly or function properly or more
efficiently. efficiently.
This website uses some functional cookies in order to remember your This website uses some functional cookies in order to remember your
preferences, such as your preferred language or its color theme. These preferences, such as your preferred language or its colour theme.
cookies are not and cannot be used to track you. These cookies are not and cannot be used to track you.
However, as this site is protected by Cloudflare, they may also host However, as this site is protected by Cloudflare, they may also host
some cookies to remember, for example, that your browser is safe or to some cookies to remember, for example, that your browser is safe or to
@@ -27,8 +27,8 @@ record traffic to the site.
*** How can I control cookies on my computer? *** How can I control cookies on my computer?
If you don't want Cloudflare to record your browsing activity on my If you don't want Cloudflare to record your browsing activity on my
website, a good adblocker should do the trick. I personally recommend website, a good ad blocker should do the trick. I personally recommend
[[https://ublockorigin.com/][uBlock Origin]], one of the most effective adblockers I know of if not [[https://ublockorigin.com/][uBlock Origin]], one of the most effective ad blockers I know of if not
the most effective one. the most effective one.
You can also manually delete cookies from your browser, but given the You can also manually delete cookies from your browser, but given the
@@ -43,7 +43,19 @@ internet, or even via emails or any web content rendered on the
screen, such as web beacons (minuscule, invisible images). It is also screen, such as web beacons (minuscule, invisible images). It is also
possible to store Flash cookies or local shared objects. possible to store Flash cookies or local shared objects.
This site does not use them at all. *** But is there any tracking at all on this website?
Well, there is, but it absolutely respects your privacy. I use my own
instance of [[https://umami.is][Umami]] which is an analytics service that is fully GDPR and
CCPA compliant. In short, when you visit a web page, some data get
sent to my service, but nothing that can identify you. If you come
back an hour later, I wont have any indication that you are the same
person.
If you still worry about your privacy, you have two options:
- Activate the Do Not Track setting of your browser (which Umami will
honour)
- Block the domain =umami.phundrak.com= in uBlock Origin (the only
ad blocker I will ever trust)
** Is there targeted advertisement on this website? ** Is there targeted advertisement on this website?
Theres no advertisement to begin with, and never will be. If you see Theres no advertisement to begin with, and never will be. If you see
@@ -55,16 +67,10 @@ is a cry for help.
** How often is this page updated? ** How often is this page updated?
It is updated from time to time to reflect any changes in how my It is updated from time to time to reflect any changes in how my
website behaves, or if I notice errors on this page (such as typos). I website behaves, or if I notice errors on this page (such as typos).
might add some user tracking, however dont worry, Matomo (the service
I would use) would only track you on this website and this website
only. Matomo respects the privacy of a websites users.
The date of the last update of this web page can be found at its very
beginning.
** I have other questions ** I have other questions
And I have the answers! Ill be more thang happy to chat with you by And I have the answers! Ill be more than happy to chat with you by
email, feel free to send me one at [[mailto:lucien@phundrak.com][lucien@phundrak.com]]. email, feel free to send me one at [[mailto:lucien@phundrak.com][lucien@phundrak.com]].
#+include: other-links #+include: other-links

View File

@@ -13,7 +13,7 @@
Startup specialized in the creation of French virtual singers using Startup specialized in the creation of French virtual singers using
vocal synthesis. Its best known product is ALYS. [[./vocal-synthesis.md][More here]]. vocal synthesis. Its best known product is ALYS. [[./vocal-synthesis.md][More here]].
- Co-founder - Co-founder, CTO
- Development of singing synthesis vocal libraries - Development of singing synthesis vocal libraries
- Linguistic research - Linguistic research
- User support - User support
@@ -30,30 +30,24 @@ Studied for a year and a half until the creation of [[./resume.md#voxwave-2014-2
** Web Programming ** Web Programming
*** Front-end *** Front-end
- Regularly using Angular, Vue, and Node.js - Professional use of Angular and TypeScript
- Good knowledge in HTML5, CSS3 (including SASS, SCSS, and LESS), and - Personal use of Vue (including Nuxt)
Javascript
- I know my way around in Python, Dart, and TypeScript
- Learning React and Next.js
*** Back-end *** Back-end
- Regularly using Rust ([[https://actix.rs/][actix-web]] and [[https://rocket.rs/][Rocket]]) and Java Spring Boot - Professional use of Java SpringBoot and SpringBatch
- Professional and personal use of PostgreSQL
- Personal use of Rust ([[https://github.com/poem-web/poem/][poem]], [[https://actix.rs/][actix-web]] and [[https://rocket.rs/][Rocket]])
- Some experience in back-end development with Django (Python) - Some experience in back-end development with Django (Python)
- Some experience communicating with a database with Djangos and - Personal use of MySQL and SQLite
[[https://diesel.rs][Diesel]]s ORM. Know my way around EmacSQL.
- Used MySQL and PostgreSQL
** System Programming ** System Programming
- Experienced in Rust, C and EmacsLisp knowledge - Frequent usage of Rust, C, EmacsLisp, and UNIX shells (bash, fish, Eshell)
- I know my way around C++, Python, and UNIX shells (bash, fish, - Occasional use of C++, Python, and CommonLisp
Eshell)
- Limited knowledge in Prolog and Scheme
** Development Tools ** Development Tools
*** IDEs and Text Editors *** IDEs and Text Editors
- Professional use of VS Code, Eclipse, and Git
- Advanced user of Emacs, including its LSP and Git integrations - Advanced user of Emacs, including its LSP and Git integrations
- Good knowledge of Git (including Magit under Emacs), VS Code, and
Eclipse
- Basic knowledge of Vim, CLion, Pycharm, and WebStorm - Basic knowledge of Vim, CLion, Pycharm, and WebStorm
*** CI/CD and Deploying to the Web *** CI/CD and Deploying to the Web
@@ -64,14 +58,14 @@ Studied for a year and a half until the creation of [[./resume.md#voxwave-2014-2
** Operating Systems ** Operating Systems
- Usage and administration of Linux (Arch Linux, Void Linux, Debian, - Usage and administration of Linux (Arch Linux, Void Linux, Debian,
Ubuntu, Alpine Linux) Ubuntu, Alpine Linux, NixOS)
- Administration of web servers and storage servers (Arch Linux, - Administration of web servers and storage servers (Arch Linux,
Debian, Raspbian, Alpine Linux) Debian, Raspbian, Alpine Linux, NixOS)
- Basic knowledge with Guix System and NixOS, and Windows XP through - Basic knowledge with Guix System and Windows XP through 10 (except
10 (except Vista) Vista)
** Office Applications ** Office Applications
- Good knowledge with org-mode (main tool), LaTeX - Good knowledge with [[https://orgmode.org/][org-mode]] (main tool), LaTeX
- I know my way around LibreOffice, Microsoft Office, OnlyOffice, and - I know my way around LibreOffice, Microsoft Office, OnlyOffice, and
WPS Office WPS Office

View File

@@ -7,26 +7,25 @@ Je suis présent sur différentes plateformes et quelques réseaux
sociaux où vous pouvez me suivre. sociaux où vous pouvez me suivre.
** Réseaux sociaux ** Réseaux sociaux
- {{{icon(mastodon)}}} *Mastodon* : [[https://emacs.ch/@phundrak][@phundrak@phundrak.com]] devrait - {{{icon(mastodon)}}} *Mastodon* :: [[https://mastodon.phundrak.com/@phundrak][@phundrak@mastodon.phundrak.com]]
fonctionner, sinon direction [[https://emacs.ch/@phundrak][@phundrak@emacs.ch]] - {{{icon(twitter)}}} *Twitter* :: [[https://twitter.com/phundrak][@phundrak]], cependant je ny suis plus très
- {{{icon(twitter)}}} *Twitter* : [[https://twitter.com/phundrak][@phundrak]], cependant je ny suis plus très
actif et jy repartage principalement mes messages Mastodon qui actif et jy repartage principalement mes messages Mastodon qui
parfois se font tronquer parfois se font tronquer
- {{{icon(writefreely)}}} *Writefreely* : - {{{icon(writefreely)}}} *Writefreely* ::
- [[https://write.phundrak.com/phundrak][*@phundrak@write.phundrak.com*]] : billets personnels - [[https://write.phundrak.com/phundrak][*@phundrak@write.phundrak.com*]] : billets personnels
- [[https://write.phundrak.com/phundraks-short-stories][*@phundraks-short-stories@write.phundrak.com*]] : histoires courtes - [[https://write.phundrak.com/phundraks-short-stories][*@phundraks-short-stories@write.phundrak.com*]] : histoires courtes
- {{{icon(discord)}}} *Discord* : =Phundrak#0001= (dites-moi que vous venez - {{{icon(discord)}}} *Discord* :: =@phundrak= (dites-moi que vous venez
dici, autrement il est possible que je considère le message comme dici, autrement il est possible que je considère le message comme
du pourriel) du pourriel)
** Autres plateformes ** Autres plateformes
- {{{icon(envelope)}}} *Courriel* : [[mailto:lucien@phundrak.com][lucien@phundrak.com]] - {{{icon(envelope)}}} *Courriel* :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
- {{{icon(rss)}}} *Blog* : [[https://blog.phundrak.com][blog.phundrak.com]] - {{{icon(rss)}}} *Blog* :: [[https://blog.phundrak.com][blog.phundrak.com]]
- {{{icon(gitea)}}} *Gitea* : [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]] - {{{icon(gitea)}}} *Gitea* :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
- {{{icon(github)}}} *GitHub* : [[https://github.com/Phundrak][Phundrak]] - {{{icon(github)}}} *GitHub* :: [[https://github.com/Phundrak][Phundrak]]
- {{{icon(youtube)}}} *YouTube* : [[https://www.youtube.com/@phundrak][@phundrak]] - {{{icon(youtube)}}} *YouTube* :: [[https://www.youtube.com/@phundrak][@phundrak]]
- {{{icon(reddit)}}} *Reddit*: [/u/phundrak](https://www.reddit.com/user/phundrak) - {{{icon(reddit)}}} *Reddit* :: [[https://www.reddit.com/user/phundrak][/u/phundrak]]
- {{{icon(linkedin)}}} *LinkedIn*: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]] - {{{icon(linkedin)}}} *LinkedIn* :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
- {{{icon(twitch)}}} *Twitch*: [[https://www.twitch.tv/phundrak][phundrak]] - {{{icon(twitch)}}} *Twitch* :: [[https://www.twitch.tv/phundrak][phundrak]]
#+include: other-links #+include: other-links

View File

@@ -5,25 +5,24 @@
On pote trova me sur multe loca ueb e redes sosial do on pote segue me. On pote trova me sur multe loca ueb e redes sosial do on pote segue me.
** Redes sosial ** Redes sosial
- {{{icon(mastodon)}}} Mastodon :: [[https://emacs.ch/@phundrak][@phundrak@phundrak.com]] ta debe funsiona, - {{{icon(mastodon)}}} *Mastodon* :: [[https://mastodon.phundrak.com/@phundrak][@phundrak@mastodon.phundrak.com]]
si no, visita [[https://emacs.ch/@phundrak][@phundrak@emacs.ch]] - {{{icon(twitter)}}} *Twitter* :: [[https://twitter.com/phundrak][@phundrak]], ma me usa lo a poca veses, la
- {{{icon(twitter)}}} Twitter :: [[https://twitter.com/phundrak][@phundrak]], ma me usa lo a poca veses, la
plu de mea tuitas es mea mesajes mastodon ce es a vesas truncada plu de mea tuitas es mea mesajes mastodon ce es a vesas truncada
- {{{icon(writefreely)}}} Writefreely :: - {{{icon(writefreely)}}} *Writefreely* ::
- [[https://write.phundrak.com/phundrak][@phundrak@write.phundrak.com]] :: revistas personal - [[https://write.phundrak.com/phundrak][@phundrak@write.phundrak.com]] :: revistas personal
- [[https://write.phundrak.com/phundraks-short-stories][@phundraks-short-stories@write.phundrak.com]] :: istorias corta (a - [[https://write.phundrak.com/phundraks-short-stories][@phundraks-short-stories@write.phundrak.com]] :: istorias corta (a
multe veses en Frans) multe veses en Frans)
- {{{icon(discord)}}} Discord :: =Phundrak#0001= (dise me ce tu veni de asi, - {{{icon(discord)}}} *Discord* :: =@phundrak= (dise me ce tu veni de asi,
si no, me pote pensa ce tua mesaje es spam) si no, me pote pensa ce tua mesaje es spam)
** Other Websites ** Other Websites
- {{{icon(envelope)}}} Eposta :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]] - {{{icon(envelope)}}} *Eposta* :: [[mailto:lucien@phundrak.com][lucien@phundrak.com]]
- {{{icon(rss)}}} Blog :: [[https://blog.phundrak.com][blog.phundrak.com]] - {{{icon(rss)}}} *Blog* :: [[https://blog.phundrak.com][blog.phundrak.com]]
- {{{icon(gitea)}}} Gitea :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]] - {{{icon(gitea)}}} *Gitea* :: [[https://labs.phundrak.com/phundrak][@phundrak@labs.phundrak.com]]
- {{{icon(github)}}} GitHub :: [[https://github.com/Phundrak][Phundrak]] - {{{icon(github)}}} *GitHub* :: [[https://github.com/Phundrak][Phundrak]]
- {{{icon(youtube)}}} YouTube :: [[https://www.youtube.com/@phundrak][@phundrak]] - {{{icon(youtube)}}} *YouTube* :: [[https://www.youtube.com/@phundrak][@phundrak]]
- {{{icon(reddit)}}} Reddit :: [[https://www.reddit.com/user/phundrak][/u/phundrak]] - {{{icon(reddit)}}} *Reddit* :: [[https://www.reddit.com/user/phundrak][/u/phundrak]]
- {{{icon(linkedin)}}} LinkedIn :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]] - {{{icon(linkedin)}}} *LinkedIn* :: [[https://www.linkedin.com/in/lucien-cartier-tilet/][Lucien Cartier-Tilet]]
- {{{icon(twitch)}}} Twitch :: [[https://www.twitch.tv/phundrak][phundrak]] - {{{icon(twitch)}}} *Twitch* :: [[https://www.twitch.tv/phundrak][phundrak]]
#+include: other-links #+include: other-links

View File

@@ -16,19 +16,15 @@ es an con tota estrema comun. Los capasi esa locas ueb a funsiona
coreta o plu eficas. coreta o plu eficas.
Esa loca ueb usa cucis con la ojeto de recorda tua prefere, como ance Esa loca ueb usa cucis con la ojeto de recorda tua prefere, como ance
la lingua o la motif ce te ia eleje. Lo ance usa cucis de mi personal la lingua o la motif ce te ia eleje.
Matomo par sabe lo ce lo usores de esa loca ueb fa asi, ma Matomo
trasa lo sola sur mea locas ueb.
An tal, esa loca ueb es protejeda par Cloudflare, esa compania ance An tal, esa loca ueb es protejeda par Cloudflare, esa compania ance
pote ospita alga cucis afin lo recorda si tu surfador es un risca par pote ospita alga cucis afin lo recorda si tu surfador es un risca par
me loca ueb o no. me loca ueb o no.
*** Como me pote controla la cucis sur mea computa? *** Como me pote controla la cucis sur mea computa?
Si te no vole ce Cloudflare o Matomo recorda cucis, un bon Si te no vole ce Cloudflare recorda cucis, un bon anti-comersial como
anti-comersial como [[https://ublockorigin.com/][uBlock Origin]] ta pote [[https://ublockorigin.com/][uBlock Origin]] ta pote te proteje (es la plu eficas ce me conose).
te proteje (es la plu eficas ce me conose). Matomo ance respecta la
demanda “no trasa me” de surfadores.
Te pote ance supresa con mano la cucis de tua surfador, ma me no pote Te pote ance supresa con mano la cucis de tua surfador, ma me no pote
te dise como, lo ave tro ce esiste. Ma te pote xerca sur DuckDuckGo, te dise como, lo ave tro ce esiste. Ma te pote xerca sur DuckDuckGo,
@@ -40,21 +36,32 @@ Lo esista otra metodos plu sutil afin de trasa usores sur la interede,
o an con epostas o cada contenida ueb, como pixeles spia (imajes o an con epostas o cada contenida ueb, como pixeles spia (imajes
estrema peti), cucis Flash o ojetos local compartida. estrema peti), cucis Flash o ojetos local compartida.
Ma esa loca ueb no usa lo. *** Ma, lo ave metodos de trasa asi?
Si, ma la lo conserva tua vida privata. Me usa mea propre varia de
[[https://umami.is][Umami]] ce es un servi de analise de datos ce respeta completa la GDPR e
la CCPA. En noncomplicada parolas, cuando te come a un paje, la
informa es enviada ce alga ia visita lo, con alga otra informas. Ma on
no pote sabe ci ia visita la loca ueb, e si te va visita lo a otra
ves, on no pote sabe ce te ia veni ja.
*** Esa loca ueb usa comersiales intendeda? Si an tal te ansiosa consernante tua vida privata, tu avec du
posibles:
- Ativi la parametre Do Not Track de tua surfador (Umami respeta lo)
- Bloci la domina ueb =umami.phundrak.com= en uBlock Origin (la sola
blocinte de comersiales ce me fida)
** Esa loca ueb usa comersiales intendeda?
Lo no ave no comersiales. Si te lo vide asi, te ave un virus sur tua Lo no ave no comersiales. Si te lo vide asi, te ave un virus sur tua
computa o surfador. Si esa comersiales vera ta veni de mea loca ueb, computa o surfador. Si esa comersiales vera ta veni de mea loca ueb,
lo es cracida. Si te pote vide en la arciveria git ce lo es me ce ia lo es cracida. Si te pote vide en la arciveria git ce lo es me ce ia
ajunta esa comersiales, o me ia dementi, o me es secuestrada e lo es ajunta esa comersiales, o me ia dementi, o me es secuestrada e lo es
un sinial de crise. un sinial de crise.
*** Ave esa pajina frecuente refrescis? ** Ave esa pajina frecuente refrescis?
Me dona esa pajina un refresci aora e alora cuando lo debe a mostra Me dona esa pajina un refresci aora e alora cuando lo debe a mostra
cambias de funsiona de mea loca ueb, o si me trova eras. Te pote trove cambias de funsiona de mea loca ueb, o si me trova eras.
la ultima refresci de esa pajina a supra.
*** Me ave otra demandas ** Me ave otra demandas
Te pote scrive me un eposta a la adirije de eposta Te pote scrive me un eposta a la adirije de eposta
[[mailto:lucien@phundrak.com][lucien@phundrak.com]]. [[mailto:lucien@phundrak.com][lucien@phundrak.com]].

View File

@@ -17,7 +17,7 @@ Compania spesialida en la developa de cantantes virtual en franses ce
usa sintese vocal. La produi la plu selebra es ALYS. Plu de informa usa sintese vocal. La produi la plu selebra es ALYS. Plu de informa
[[./vocal-synthesis.md][aci]]. [[./vocal-synthesis.md][aci]].
- Cofundor - Cofundor, dirije tecnical
- Programi de voses de sintese per la canta - Programi de voses de sintese per la canta
- Rexerca linguistica - Rexerca linguistica
- Suporta de usadores - Suporta de usadores
@@ -36,44 +36,42 @@ de [[./resume.md#voxwave-2014-2018][VoxWave]].
** Programi ueb ** Programi ueb
*** Front-end *** Front-end
- Usa fidosa de Angular, Vue e Node.JS - Usa profesal de Angular e TypeScript
- Bon conose de HTML5, CSS3 (incluinte SASS, SCSS e LESS) e Javascript - Usa personal de Vue (inclui Nuxt)
- Conoses de Python, Dart e Typescript
- Aprende React e Next.js
*** Backend *** Backend
- Usa fidosa de Rust ([[https://actix.rs/][actix-web]] e [[https://rocket.rs/][Rocket]]) e Java Spring Boot - Usa profesional de Java SpringBoot e SpringBatch
- Usa profesional e personal de PostgreSQL
- Usa personal de Rust ([[https://github.com/poem-web/poem/][poem]], [[https://actix.rs/][actix-web]] e [[https://rocket.rs/][Rocket]])
- Esperia en programi de backend con Django (Python) - Esperia en programi de backend con Django (Python)
- Esperia en comunica con banco de datos con [[https://diesel.rs][Diesel]] (Rust) e Django, - Usa personal de PostgreSQL e SQLite
conose alga EmacSQL
- Usa de PostgreSQL e MySQL
** Programi sistem ** Programi sistem
- Esperia con Rust, C e EmacsLisp - Usa personal e frecuente de Rust, C, shelles UNIX (bash, fish,
- Conoses de C++, Python, CommonLisp e shelles UNIX (bash, fish, eshell) Eshell) e EmacsLisp
- Conoses limitada de Prolog e Scheme Usa personal nonfrecuente de C++, Python e CommonLisp
** Utiles de developa ** Utiles de developa
*** IDEs e editadores *** IDEs e editadores
- Usa profesional de VS Code, Eclipse e Git
- Conoses esperta de Emacs, inclui con la incluis de LSP e Git - Conoses esperta de Emacs, inclui con la incluis de LSP e Git
- Bon conoses de Git (inclui sua interfas Magit per Emacs), VS Code e
Eclipse
- Conoses fundal de Vim, CLion, PyCharm e WebStorm - Conoses fundal de Vim, CLion, PyCharm e WebStorm
** CI/CD e desplia ueb *** CI/CD e desplia ueb
- Esperia con la servadores ueb Nginx e Caddyserver - Esperia con la servadores ueb Nginx e Caddyserver
- Bon conoses de Docker, Drone.io e GitHub Actions per despia ueb - Bon conoses de Docker e Docker Compose, Drone.io e GitHub Actions
per despia ueb
** Sistemes de opera ** Sistemes de opera
- Usa et manejablia de Linux (ArchLinux, VoidLinux, Debian, Ubuntu, - Usa et manejablia de Linux (ArchLinux, VoidLinux, Debian, Ubuntu,
AlpineLinux) AlpineLinux, NixOS)
- Manjablia de servidores ueb e servidores de conserva (ArchLinux, - Manjablia de servidores ueb e servidores de conserva (ArchLinux,
Debian, Ubuntu, AlpineLinux) Debian, Ubuntu, AlpineLinux, NixOS)
- Conosas fundal de Guix System, NixOS e Windows (de XP a 10, con - Conosas fundal de Guix System e Windows (de XP a 10, con eseta de
eseta de Vista) Vista)
** Program de ofisia ** Program de ofisia
- Bon conosas con org-mode (Emacs) e LaTeX - Bon conosas con [[https://orgmode.org/][org-mode]] (Emacs) e LaTeX
- Conosas con LibreOffice, Microsoft Office, WPS Office e OnlyOffice - Conosas con LibreOffice, Microsoft Office, WPS Office e OnlyOffice
** Audio ** Audio

View File

@@ -5,7 +5,7 @@
** Où est hébergé le site? ** Où est hébergé le site?
Ce site est hébergé sur mon serveur personnel, situé dans la ville de Ce site est hébergé sur mon serveur personnel, situé dans la ville de
Bron en France, comme la majorité de mes sites. Deux autres sites, Bron en France, comme la majorité de mes sites. Deux autres sites,
=labs.phundrak.com= et =mail.phundrak.com=, sont hébergé sur dautres =labs.phundrak.com= et =mail.phundrak.com=, sont hébergés sur dautres
serveurs loués à Scaleway et à OVH France respectivement, et les serveurs loués à Scaleway et à OVH France respectivement, et les
serveurs se situent également en France. serveurs se situent également en France.
@@ -23,7 +23,7 @@ Ces cookies ne sont pas et ne peuvent pas être utilisés pour vous
traquer. traquer.
Cependant, ce site étant protégé par Cloudflare, ce dernier pourra Cependant, ce site étant protégé par Cloudflare, ce dernier pourra
également héberger quelques cookies afin par exemple de se souvenir pareillement héberger quelques cookies afin par exemple de se souvenir
que votre navigateur ne présente pas de risque ou bien pour que votre navigateur ne présente pas de risque ou bien pour
enregistrer le trafic sur le site. enregistrer le trafic sur le site.
@@ -33,7 +33,7 @@ activités, un bon anti-pub devrait faire laffaire. Je recommande
personnellement [[https://ublockorigin.com/][uBlock Origin]], lun des bloqueurs de pub les plus personnellement [[https://ublockorigin.com/][uBlock Origin]], lun des bloqueurs de pub les plus
efficaces que je connaisse. efficaces que je connaisse.
Vous pouvez également supprimer manuellement les cookies de votre Vous pouvez par ailleurs supprimer manuellement les cookies de votre
navigateur, mais étant donné le nombre de navigateurs existants, il navigateur, mais étant donné le nombre de navigateurs existants, il
sera sans doute plus rapide pour vous de chercher sur DuckDuckGo, sera sans doute plus rapide pour vous de chercher sur DuckDuckGo,
Qwant ou Startpage comment faire pour votre navigateur actuel (si vous Qwant ou Startpage comment faire pour votre navigateur actuel (si vous
@@ -44,15 +44,29 @@ voudrez éviter Google).
Il existe dautres méthodes plus subtiles qui permettent de traquer Il existe dautres méthodes plus subtiles qui permettent de traquer
quelquun sur internet, ou même via des mails ou tout contenu web quelquun sur internet, ou même via des mails ou tout contenu web
rendu à lécran, comme pixels espions (des images extrêmement rendu à lécran, comme pixels espions (des images extrêmement
petites). Il est également possible de stocker des cookies Flash ou petites). Il est de plus possible de stocker des cookies Flash ou des
des objets locaux partagés. objets locaux partagés.
Ce site nen utilise absolument pas. *** Mais, est-ce quil y a du tracking sur ce site?
Oui, mais en préservant intégralement votre vie privée. Jutilise ma
propre instance de [[https://umami.is][Umami]] qui est un service danalyse de données qui
respecte entièrement le RGPD et le [[https://www.oag.ca.gov/privacy/ccpa][CCPA]]. Pour résumer, lorsque vous
passez sur une nouvelle page du site, linformation est envoyée quune
visite sest produite, avec quelques informations supplémentaires,
mais rien qui permet didentifier qui que ce soit. Si vous revenez
dans une heure, je ne saurai pas que vous êtes la même personne.
Si vous vous inquiétez tout de même de votre vie privée, deux options
soffrent à vous:
- Activez loption Do Not Track de votre navigateur (Umami respecte ce
paramètre)
- Bloquez le domaine =umami.phundrak.com= dans uBlock Origin (le seul
bloqueur de pubs auquel je fais confiance)
** Est-ce quil y a de la pub ciblée sur ce site? ** Est-ce quil y a de la pub ciblée sur ce site?
Il ny a tout simplement aucune pub sur ce site. Si vous en voyez, Il ny a tout simplement aucune pub sur ce site. Si vous en voyez,
vous avez sans doute un virus installé sur votre ordinateur. Si ça vous avez sans doute un virus installé sur votre ordinateur. Si ça
vient en effet de mon site web, cela veut dire quil a été hacké. Si vient en effet de mon site web, cela veut dire quil a été piraté. Si
vous voyez sur son dépôt de code que cest bien moi qui ai rajouté ces vous voyez sur son dépôt de code que cest bien moi qui ai rajouté ces
pubs, cela veut dire que jai perdu tout mon sens moral, ou bien que pubs, cela veut dire que jai perdu tout mon sens moral, ou bien que
jai été kidnappé et il sagit dun appel au secours. jai été kidnappé et il sagit dun appel au secours.
@@ -60,11 +74,7 @@ jai été kidnappé et il sagit dun appel au secours.
** Est-ce que cette page est souvent mise à jour? ** Est-ce que cette page est souvent mise à jour?
Je peux la mettre à jour de temps en temps afin de refléter des Je peux la mettre à jour de temps en temps afin de refléter des
changements de fonctionnement du site, ou si je remarque une erreur changements de fonctionnement du site, ou si je remarque une erreur
sur la page. Il se peut aussi que jajoute un jour un tracking des sur la page.
utilisateurs sur mon site via Matomo, un service de tracking
respectant la vie privée des utilisateurs et qui est tout à fait
bloquable. La date de la dernière mise à jour de cette page peut être
trouvée à son tout début.
** Jai dautres questions ** Jai dautres questions
Et je serai heureux dy répondre par mail. Vous pouvez me contacter Et je serai heureux dy répondre par mail. Vous pouvez me contacter

View File

@@ -20,7 +20,7 @@ Startup spécialisée dans le développement de chanteurs virtuels
francophones utilisant de la synthèse vocale. Le produit le plus connu francophones utilisant de la synthèse vocale. Le produit le plus connu
est la chanteuse virtuelle ALYS. Plus dinformations [[./vocal-synthesis.md][ici]]. est la chanteuse virtuelle ALYS. Plus dinformations [[./vocal-synthesis.md][ici]].
- Co-fondateur - Co-fondateur, directeur technique
- Programmation de voix de synthèse pour le chant - Programmation de voix de synthèse pour le chant
- Recherches linguistiques - Recherches linguistiques
- Support utilisateur - Support utilisateur
@@ -38,32 +38,25 @@ LLCE. Études interrompues suite à la création de [[./resume.md#voxwave-2014-2
** Programmation Web ** Programmation Web
*** Frontend *** Frontend
- Utilisation régulière de Angular, Vue et Node.js - Expérience professionnelle avec Angular et TypeScript
- Bonnes connaissances en HTML5, CSS3 (y compris SASS, SCSS et LESS) - Expérience personnelle avec Vue (y compris Nuxt)
et JavaScript
- Connaissances en Python, Dart et TypeScript
- Apprentissage de React et Next.js
*** Backend *** Backend
- Utilisation régulière de Rust ([[https://actix.rs/][actix-web]] et [[https://rocket.rs/][Rocket]]) et Java Spring - Utilisation professionnelle de Java SpringBoot et SpringBatch
Boot - Utilisation professionnelle et personnelle de PostgreSQL
- De lexpérience en développement backend avec Django (Python) - Utilisation personnelle de Rust ([[https://github.com/poem-web/poem/][poem]], [[https://actix.rs/][actix-web]] et [[https://rocket.rs/][Rocket]])
- De lexpérience en communication avec des bases de données via - Connaissances en développement backend avec Django (Python)
Django et [[https://diesel.rs][Diesel]]. Connaissances de base avec EmacSQL. - Utilisation personnelle de MySQL et SQLite
- Utilisation de MySQL et PostgreSQL.
** Programmation Système ** Programmation Système
- De lexpérience avec Rust, C et EmacsLisp - Utilisation personnelle fréquente de Rust, C, shells UNIX (bash, fish, Eshell) et EmacsLisp
- Connaissances en C++, Python, CommonLisp et les shells UNIX - Utilisation personnelle occasionnelle de C++, Python et CommonLisp
(bash, fish, Eshell)
- Connaissances limitées en Prolog et Scheme
** Outils de développement ** Outils de développement
*** IDEs et éditeurs de texte *** IDEs et éditeurs de texte
- Utilisateur avancé dEmacs, y compris avec ses intégrations pour LSP - Utilisation professionnelle de VS Code, Eclipse et Git
et Git - Utilisateur avancé personnelle dEmacs, y compris avec ses
- Bonnes connaissances de Git (y compris avec son interface Magit pour intégrations pour LSP et Git
Emacs), VS Code et Eclipse
- Connaissances basiques de Vim, CLion, PyCharm et WebStorm - Connaissances basiques de Vim, CLion, PyCharm et WebStorm
*** CI/CD et déploiement sur le web *** CI/CD et déploiement sur le web
@@ -73,14 +66,14 @@ LLCE. Études interrompues suite à la création de [[./resume.md#voxwave-2014-2
** Systèmes dexploitation ** Systèmes dexploitation
- Utilisation et administration de Linux (ArchLinux, VoidLinux, - Utilisation et administration de Linux (ArchLinux, VoidLinux,
Debian, Ubuntu, AlpineLinux) Debian, Ubuntu, AlpineLinux, NixOS)
- Administration de serveurs web et serveurs de stockage (ArchLinux, - Administration de serveurs web et serveurs de stockage (ArchLinux,
Debian, Ubuntu, AlpineLinux) Debian, Ubuntu, AlpineLinux, NixOS)
- Connaissances élémentaires de Guix System, NixOS et Windows de XP à - Connaissances élémentaires de Guix System et Windows de XP à 10
10 (excepté Vista) (excepté Vista)
** Bureautique ** Bureautique
- Bonnes connaissances avec orgmode et LaTeX - Bonnes connaissances avec [[https://orgmode.org/][org mode]] et LaTeX
- Connaissances avec Libre Office, Microsoft Office, WPS Office et OnlyOffice - Connaissances avec Libre Office, Microsoft Office, WPS Office et OnlyOffice
** Audio ** Audio

5090
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,28 +3,24 @@
"version": "0.1.0", "version": "0.1.0",
"description": "Static website of Phundrak", "description": "Static website of Phundrak",
"main": "index.js", "main": "index.js",
"repository": "https://labs.phundrak.com/phundrak/vuepress-www", "repository": "https://labs.phundrak.com/phundrak/phundrak.com",
"author": "Lucien Cartier-Tilet <lucien@phundrak.com>", "author": "Lucien Cartier-Tilet <lucien@phundrak.com>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"cz-conventional-changelog": "^3.3.0", "@vuepress/bundler-vite": "2.0.0-rc.19",
"git-cliff": "^1.1.2", "@vuepress/plugin-slimsearch": "^2.0.0-rc.74",
"vuepress": "2.0.0-beta.61" "@vuepress/plugin-umami-analytics": "^2.0.0-rc.74",
"@vuepress/theme-default": "^2.0.0-rc.36",
"sass-embedded": "^1.83.4",
"vuepress": "2.0.0-rc.19"
},
"dependencies": {
"less": "^4.2.0",
"nord": "^0.2.1"
}, },
"scripts": { "scripts": {
"dev": "vuepress dev content", "dev": "vuepress dev content",
"build": "vuepress build content" "build": "vuepress build content"
},
"dependencies": {
"less": "^4.1.3",
"nord": "^0.2.1",
"rxjs": "^7.8.1",
"vuepress-plugin-remove-html-extension": "^0.1.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
} }
} }

6
shell.nix Normal file
View File

@@ -0,0 +1,6 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs; [
nodejs_22
];
}

2800
yarn.lock

File diff suppressed because it is too large Load Diff