2549 lines
221 KiB
HTML
2549 lines
221 KiB
HTML
|
<!DOCTYPE html><html lang="fr">
|
|||
|
<head><meta charset="utf-8">
|
|||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>PC1 ArchLinux - VM Debian 10 vdb (jekyll-statique) - YannStatic</title>
|
|||
|
|
|||
|
<meta name="description" content="VM Debian 10">
|
|||
|
<link rel="canonical" href="https://static.rnmkcy.eu/2020/12/15/ArchLinux-KVM_QEMU-VM-debian10-vdb-statique.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
|
|||
|
|
|||
|
<!-- - include head/favicon.html - -->
|
|||
|
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
|
|||
|
<!-- end custom head snippets --><script>(function() {
|
|||
|
window.isArray = function(val) {
|
|||
|
return Object.prototype.toString.call(val) === '[object Array]';
|
|||
|
};
|
|||
|
window.isString = function(val) {
|
|||
|
return typeof val === 'string';
|
|||
|
};
|
|||
|
|
|||
|
window.hasEvent = function(event) {
|
|||
|
return 'on'.concat(event) in window.document;
|
|||
|
};
|
|||
|
|
|||
|
window.isOverallScroller = function(node) {
|
|||
|
return node === document.documentElement || node === document.body || node === window;
|
|||
|
};
|
|||
|
|
|||
|
window.isFormElement = function(node) {
|
|||
|
var tagName = node.tagName;
|
|||
|
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
|
|||
|
};
|
|||
|
|
|||
|
window.pageLoad = (function () {
|
|||
|
var loaded = false, cbs = [];
|
|||
|
window.addEventListener('load', function () {
|
|||
|
var i;
|
|||
|
loaded = true;
|
|||
|
if (cbs.length > 0) {
|
|||
|
for (i = 0; i < cbs.length; i++) {
|
|||
|
cbs[i]();
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
return {
|
|||
|
then: function(cb) {
|
|||
|
cb && (loaded ? cb() : (cbs.push(cb)));
|
|||
|
}
|
|||
|
};
|
|||
|
})();
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
window.throttle = function(func, wait) {
|
|||
|
var args, result, thisArg, timeoutId, lastCalled = 0;
|
|||
|
|
|||
|
function trailingCall() {
|
|||
|
lastCalled = new Date;
|
|||
|
timeoutId = null;
|
|||
|
result = func.apply(thisArg, args);
|
|||
|
}
|
|||
|
return function() {
|
|||
|
var now = new Date,
|
|||
|
remaining = wait - (now - lastCalled);
|
|||
|
|
|||
|
args = arguments;
|
|||
|
thisArg = this;
|
|||
|
|
|||
|
if (remaining <= 0) {
|
|||
|
clearTimeout(timeoutId);
|
|||
|
timeoutId = null;
|
|||
|
lastCalled = now;
|
|||
|
result = func.apply(thisArg, args);
|
|||
|
} else if (!timeoutId) {
|
|||
|
timeoutId = setTimeout(trailingCall, remaining);
|
|||
|
}
|
|||
|
return result;
|
|||
|
};
|
|||
|
};
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var Set = (function() {
|
|||
|
var add = function(item) {
|
|||
|
var i, data = this._data;
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
if (data[i] === item) {
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
this.size ++;
|
|||
|
data.push(item);
|
|||
|
return data;
|
|||
|
};
|
|||
|
|
|||
|
var Set = function(data) {
|
|||
|
this.size = 0;
|
|||
|
this._data = [];
|
|||
|
var i;
|
|||
|
if (data.length > 0) {
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
add.call(this, data[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
Set.prototype.add = add;
|
|||
|
Set.prototype.get = function(index) { return this._data[index]; };
|
|||
|
Set.prototype.has = function(item) {
|
|||
|
var i, data = this._data;
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
if (this.get(i) === item) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
};
|
|||
|
Set.prototype.is = function(map) {
|
|||
|
if (map._data.length !== this._data.length) { return false; }
|
|||
|
var i, j, flag, tData = this._data, mData = map._data;
|
|||
|
for (i = 0; i < tData.length; i++) {
|
|||
|
for (flag = false, j = 0; j < mData.length; j++) {
|
|||
|
if (tData[i] === mData[j]) {
|
|||
|
flag = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!flag) { return false; }
|
|||
|
}
|
|||
|
return true;
|
|||
|
};
|
|||
|
Set.prototype.values = function() {
|
|||
|
return this._data;
|
|||
|
};
|
|||
|
return Set;
|
|||
|
})();
|
|||
|
|
|||
|
window.Lazyload = (function(doc) {
|
|||
|
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
|
|||
|
var createNode = function(name, attrs) {
|
|||
|
var node = doc.createElement(name), attr;
|
|||
|
for (attr in attrs) {
|
|||
|
if (attrs.hasOwnProperty(attr)) {
|
|||
|
node.setAttribute(attr, attrs[attr]);
|
|||
|
}
|
|||
|
}
|
|||
|
return node;
|
|||
|
};
|
|||
|
var end = function(type, url) {
|
|||
|
var s, q, qi, cbs, i, j, cur, val, flag;
|
|||
|
if (type === 'js' || type ==='css') {
|
|||
|
s = sources[type], q = queue[type];
|
|||
|
s[url] = true;
|
|||
|
for (i = 0; i < q.length; i++) {
|
|||
|
cur = q[i];
|
|||
|
if (cur.urls.has(url)) {
|
|||
|
qi = cur, val = qi.urls.values();
|
|||
|
qi && (cbs = qi.callbacks);
|
|||
|
for (flag = true, j = 0; j < val.length; j++) {
|
|||
|
cur = val[j];
|
|||
|
if (!s[cur]) {
|
|||
|
flag = false;
|
|||
|
}
|
|||
|
}
|
|||
|
if (flag && cbs && cbs.length > 0) {
|
|||
|
for (j = 0; j < cbs.length; j++) {
|
|||
|
cbs[j].call(context);
|
|||
|
}
|
|||
|
qi.load = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
var load = function(type, urls, callback) {
|
|||
|
var s, q, qi, node, i, cur,
|
|||
|
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
|
|||
|
if (type === 'js' || type ==='css') {
|
|||
|
s = sources[type], q = queue[type];
|
|||
|
for (i = 0; i < q.length; i++) {
|
|||
|
cur = q[i];
|
|||
|
if (_urls.is(cur.urls)) {
|
|||
|
qi = cur;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
val = _urls.values();
|
|||
|
if (qi) {
|
|||
|
callback && (qi.load || qi.callbacks.push(callback));
|
|||
|
callback && (qi.load && callback());
|
|||
|
} else {
|
|||
|
q.push({
|
|||
|
urls: _urls,
|
|||
|
callbacks: callback ? [callback] : [],
|
|||
|
load: false
|
|||
|
});
|
|||
|
for (i = 0; i < val.length; i++) {
|
|||
|
node = null, url = val[i];
|
|||
|
if (s[url] === undefined) {
|
|||
|
(type === 'js' ) && (node = createNode('script', { src: url }));
|
|||
|
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
|
|||
|
if (node) {
|
|||
|
node.onload = (function(type, url) {
|
|||
|
return function() {
|
|||
|
end(type, url);
|
|||
|
};
|
|||
|
})(type, url);
|
|||
|
(doc.head || doc.body).appendChild(node);
|
|||
|
s[url] = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
return {
|
|||
|
js: function(url, callback) {
|
|||
|
load('js', url, callback);
|
|||
|
},
|
|||
|
css: function(url, callback) {
|
|||
|
load('css', url, callback);
|
|||
|
}
|
|||
|
};
|
|||
|
})(this.document);
|
|||
|
})();
|
|||
|
</script><script>
|
|||
|
(function() {
|
|||
|
var TEXT_VARIABLES = {
|
|||
|
version: '2.2.6',
|
|||
|
sources: {
|
|||
|
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
|
|||
|
jquery: '/assets/js/jquery.min.js',
|
|||
|
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
|
|||
|
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
|
|||
|
gitalk: {
|
|||
|
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
|
|||
|
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
|
|||
|
},
|
|||
|
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
|
|||
|
},
|
|||
|
site: {
|
|||
|
toc: {
|
|||
|
selectors: 'h1,h2,h3'
|
|||
|
}
|
|||
|
},
|
|||
|
paths: {
|
|||
|
search_js: '/assets/search.js'
|
|||
|
}
|
|||
|
};
|
|||
|
window.TEXT_VARIABLES = TEXT_VARIABLES;
|
|||
|
})();
|
|||
|
</script>
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<div class="root" data-is-touch="false">
|
|||
|
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
|
|||
|
|
|||
|
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
|
|||
|
<div class="header__title">
|
|||
|
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
|
|||
|
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
|
|||
|
<!-- Champ de recherche -->
|
|||
|
<div id="searchbox" class="search search--dark" style="visibility: visible">
|
|||
|
<div class="main">
|
|||
|
<div class="search__header"></div>
|
|||
|
<div class="search-bar">
|
|||
|
<div class="search-box js-search-box">
|
|||
|
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
|
|||
|
<input id="search-input" type="text" />
|
|||
|
<!-- <div class="search-box__icon-clear js-icon-clear">
|
|||
|
<a><i class="fas fa-times"></i></a>
|
|||
|
</div> -->
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- Script pointing to search-script.js -->
|
|||
|
<script>/*!
|
|||
|
* Simple-Jekyll-Search
|
|||
|
* Copyright 2015-2020, Christian Fei
|
|||
|
* Licensed under the MIT License.
|
|||
|
*/
|
|||
|
|
|||
|
(function(){
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Templater_7 = {
|
|||
|
compile: compile,
|
|||
|
setOptions: setOptions
|
|||
|
}
|
|||
|
|
|||
|
const options = {}
|
|||
|
options.pattern = /\{(.*?)\}/g
|
|||
|
options.template = ''
|
|||
|
options.middleware = function () {}
|
|||
|
|
|||
|
function setOptions (_options) {
|
|||
|
options.pattern = _options.pattern || options.pattern
|
|||
|
options.template = _options.template || options.template
|
|||
|
if (typeof _options.middleware === 'function') {
|
|||
|
options.middleware = _options.middleware
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compile (data) {
|
|||
|
return options.template.replace(options.pattern, function (match, prop) {
|
|||
|
const value = options.middleware(prop, data[prop], options.template)
|
|||
|
if (typeof value !== 'undefined') {
|
|||
|
return value
|
|||
|
}
|
|||
|
return data[prop] || match
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
function fuzzysearch (needle, haystack) {
|
|||
|
var tlen = haystack.length;
|
|||
|
var qlen = needle.length;
|
|||
|
if (qlen > tlen) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (qlen === tlen) {
|
|||
|
return needle === haystack;
|
|||
|
}
|
|||
|
outer: for (var i = 0, j = 0; i < qlen; i++) {
|
|||
|
var nch = needle.charCodeAt(i);
|
|||
|
while (j < tlen) {
|
|||
|
if (haystack.charCodeAt(j++) === nch) {
|
|||
|
continue outer;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var _$fuzzysearch_1 = fuzzysearch;
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
|
|||
|
|
|||
|
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
|
|||
|
|
|||
|
function FuzzySearchStrategy () {
|
|||
|
this.matches = function (string, crit) {
|
|||
|
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
|
|||
|
|
|||
|
function LiteralSearchStrategy () {
|
|||
|
this.matches = function (str, crit) {
|
|||
|
if (!str) return false
|
|||
|
|
|||
|
str = str.trim().toLowerCase()
|
|||
|
crit = crit.trim().toLowerCase()
|
|||
|
|
|||
|
return crit.split(' ').filter(function (word) {
|
|||
|
return str.indexOf(word) >= 0
|
|||
|
}).length === crit.split(' ').length
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Repository_4 = {
|
|||
|
put: put,
|
|||
|
clear: clear,
|
|||
|
search: search,
|
|||
|
setOptions: __setOptions_4
|
|||
|
}
|
|||
|
|
|||
|
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
|
|||
|
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
|
|||
|
|
|||
|
function NoSort () {
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
const data = []
|
|||
|
let opt = {}
|
|||
|
|
|||
|
opt.fuzzy = false
|
|||
|
opt.limit = 10
|
|||
|
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = NoSort
|
|||
|
opt.exclude = []
|
|||
|
|
|||
|
function put (data) {
|
|||
|
if (isObject(data)) {
|
|||
|
return addObject(data)
|
|||
|
}
|
|||
|
if (isArray(data)) {
|
|||
|
return addArray(data)
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
function clear () {
|
|||
|
data.length = 0
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function isObject (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
|
|||
|
}
|
|||
|
|
|||
|
function isArray (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
|
|||
|
}
|
|||
|
|
|||
|
function addObject (_data) {
|
|||
|
data.push(_data)
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function addArray (_data) {
|
|||
|
const added = []
|
|||
|
clear()
|
|||
|
for (let i = 0, len = _data.length; i < len; i++) {
|
|||
|
if (isObject(_data[i])) {
|
|||
|
added.push(addObject(_data[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
return added
|
|||
|
}
|
|||
|
|
|||
|
function search (crit) {
|
|||
|
if (!crit) {
|
|||
|
return []
|
|||
|
}
|
|||
|
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
|
|||
|
}
|
|||
|
|
|||
|
function __setOptions_4 (_opt) {
|
|||
|
opt = _opt || {}
|
|||
|
|
|||
|
opt.fuzzy = _opt.fuzzy || false
|
|||
|
opt.limit = _opt.limit || 10
|
|||
|
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = _opt.sort || NoSort
|
|||
|
opt.exclude = _opt.exclude || []
|
|||
|
}
|
|||
|
|
|||
|
function findMatches (data, crit, strategy, opt) {
|
|||
|
const matches = []
|
|||
|
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
|
|||
|
const match = findMatchesInObject(data[i], crit, strategy, opt)
|
|||
|
if (match) {
|
|||
|
matches.push(match)
|
|||
|
}
|
|||
|
}
|
|||
|
return matches
|
|||
|
}
|
|||
|
|
|||
|
function findMatchesInObject (obj, crit, strategy, opt) {
|
|||
|
for (const key in obj) {
|
|||
|
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
|
|||
|
return obj
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isExcluded (term, excludedTerms) {
|
|||
|
for (let i = 0, len = excludedTerms.length; i < len; i++) {
|
|||
|
const excludedTerm = excludedTerms[i]
|
|||
|
if (new RegExp(excludedTerm).test(term)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
/* globals ActiveXObject:false */
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$JSONLoader_2 = {
|
|||
|
load: load
|
|||
|
}
|
|||
|
|
|||
|
function load (location, callback) {
|
|||
|
const xhr = getXHR()
|
|||
|
xhr.open('GET', location, true)
|
|||
|
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
|
|||
|
xhr.send()
|
|||
|
}
|
|||
|
|
|||
|
function createStateChangeListener (xhr, callback) {
|
|||
|
return function () {
|
|||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|||
|
try {
|
|||
|
callback(null, JSON.parse(xhr.responseText))
|
|||
|
} catch (err) {
|
|||
|
callback(err, null)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getXHR () {
|
|||
|
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$OptionsValidator_3 = function OptionsValidator (params) {
|
|||
|
if (!validateParams(params)) {
|
|||
|
throw new Error('-- OptionsValidator: required options missing')
|
|||
|
}
|
|||
|
|
|||
|
if (!(this instanceof OptionsValidator)) {
|
|||
|
return new OptionsValidator(params)
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = params.required
|
|||
|
|
|||
|
this.getRequiredOptions = function () {
|
|||
|
return requiredOptions
|
|||
|
}
|
|||
|
|
|||
|
this.validate = function (parameters) {
|
|||
|
const errors = []
|
|||
|
requiredOptions.forEach(function (requiredOptionName) {
|
|||
|
if (typeof parameters[requiredOptionName] === 'undefined') {
|
|||
|
errors.push(requiredOptionName)
|
|||
|
}
|
|||
|
})
|
|||
|
return errors
|
|||
|
}
|
|||
|
|
|||
|
function validateParams (params) {
|
|||
|
if (!params) {
|
|||
|
return false
|
|||
|
}
|
|||
|
return typeof params.required !== 'undefined' && params.required instanceof Array
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$utils_9 = {
|
|||
|
merge: merge,
|
|||
|
isJSON: isJSON
|
|||
|
}
|
|||
|
|
|||
|
function merge (defaultParams, mergeParams) {
|
|||
|
const mergedOptions = {}
|
|||
|
for (const option in defaultParams) {
|
|||
|
mergedOptions[option] = defaultParams[option]
|
|||
|
if (typeof mergeParams[option] !== 'undefined') {
|
|||
|
mergedOptions[option] = mergeParams[option]
|
|||
|
}
|
|||
|
}
|
|||
|
return mergedOptions
|
|||
|
}
|
|||
|
|
|||
|
function isJSON (json) {
|
|||
|
try {
|
|||
|
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
|
|||
|
return true
|
|||
|
}
|
|||
|
return false
|
|||
|
} catch (err) {
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var _$src_8 = {};
|
|||
|
(function (window) {
|
|||
|
'use strict'
|
|||
|
|
|||
|
let options = {
|
|||
|
searchInput: null,
|
|||
|
resultsContainer: null,
|
|||
|
json: [],
|
|||
|
success: Function.prototype,
|
|||
|
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
|
|||
|
templateMiddleware: Function.prototype,
|
|||
|
sortMiddleware: function () {
|
|||
|
return 0
|
|||
|
},
|
|||
|
noResultsText: 'No results found',
|
|||
|
limit: 10,
|
|||
|
fuzzy: false,
|
|||
|
debounceTime: null,
|
|||
|
exclude: []
|
|||
|
}
|
|||
|
|
|||
|
let debounceTimerHandle
|
|||
|
const debounce = function (func, delayMillis) {
|
|||
|
if (delayMillis) {
|
|||
|
clearTimeout(debounceTimerHandle)
|
|||
|
debounceTimerHandle = setTimeout(func, delayMillis)
|
|||
|
} else {
|
|||
|
func.call()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
|
|||
|
|
|||
|
/* removed: const _$Templater_7 = require('./Templater') */;
|
|||
|
/* removed: const _$Repository_4 = require('./Repository') */;
|
|||
|
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
|
|||
|
const optionsValidator = _$OptionsValidator_3({
|
|||
|
required: requiredOptions
|
|||
|
})
|
|||
|
/* removed: const _$utils_9 = require('./utils') */;
|
|||
|
|
|||
|
window.SimpleJekyllSearch = function (_options) {
|
|||
|
const errors = optionsValidator.validate(_options)
|
|||
|
if (errors.length > 0) {
|
|||
|
throwError('You must specify the following required options: ' + requiredOptions)
|
|||
|
}
|
|||
|
|
|||
|
options = _$utils_9.merge(options, _options)
|
|||
|
|
|||
|
_$Templater_7.setOptions({
|
|||
|
template: options.searchResultTemplate,
|
|||
|
middleware: options.templateMiddleware
|
|||
|
})
|
|||
|
|
|||
|
_$Repository_4.setOptions({
|
|||
|
fuzzy: options.fuzzy,
|
|||
|
limit: options.limit,
|
|||
|
sort: options.sortMiddleware,
|
|||
|
exclude: options.exclude
|
|||
|
})
|
|||
|
|
|||
|
if (_$utils_9.isJSON(options.json)) {
|
|||
|
initWithJSON(options.json)
|
|||
|
} else {
|
|||
|
initWithURL(options.json)
|
|||
|
}
|
|||
|
|
|||
|
const rv = {
|
|||
|
search: search
|
|||
|
}
|
|||
|
|
|||
|
typeof options.success === 'function' && options.success.call(rv)
|
|||
|
return rv
|
|||
|
}
|
|||
|
|
|||
|
function initWithJSON (json) {
|
|||
|
_$Repository_4.put(json)
|
|||
|
registerInput()
|
|||
|
}
|
|||
|
|
|||
|
function initWithURL (url) {
|
|||
|
_$JSONLoader_2.load(url, function (err, json) {
|
|||
|
if (err) {
|
|||
|
throwError('failed to get JSON (' + url + ')')
|
|||
|
}
|
|||
|
initWithJSON(json)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function emptyResultsContainer () {
|
|||
|
options.resultsContainer.innerHTML = ''
|
|||
|
}
|
|||
|
|
|||
|
function appendToResultsContainer (text) {
|
|||
|
options.resultsContainer.innerHTML += text
|
|||
|
}
|
|||
|
|
|||
|
function registerInput () {
|
|||
|
options.searchInput.addEventListener('input', function (e) {
|
|||
|
if (isWhitelistedKey(e.which)) {
|
|||
|
emptyResultsContainer()
|
|||
|
debounce(function () { search(e.target.value) }, options.debounceTime)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function search (query) {
|
|||
|
if (isValidQuery(query)) {
|
|||
|
emptyResultsContainer()
|
|||
|
render(_$Repository_4.search(query), query)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function render (results, query) {
|
|||
|
const len = results.length
|
|||
|
if (len === 0) {
|
|||
|
return appendToResultsContainer(options.noResultsText)
|
|||
|
}
|
|||
|
for (let i = 0; i < len; i++) {
|
|||
|
results[i].query = query
|
|||
|
appendToResultsContainer(_$Templater_7.compile(results[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isValidQuery (query) {
|
|||
|
return query && query.length > 0
|
|||
|
}
|
|||
|
|
|||
|
function isWhitelistedKey (key) {
|
|||
|
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
|
|||
|
}
|
|||
|
|
|||
|
function throwError (message) {
|
|||
|
throw new Error('SimpleJekyllSearch --- ' + message)
|
|||
|
}
|
|||
|
})(window)
|
|||
|
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
<!-- Configuration -->
|
|||
|
<script>
|
|||
|
SimpleJekyllSearch({
|
|||
|
searchInput: document.getElementById('search-input'),
|
|||
|
resultsContainer: document.getElementById('results-container'),
|
|||
|
json: '/search.json',
|
|||
|
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date} {title}</a></li>'
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a></li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
|
|||
|
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li></ul>
|
|||
|
</nav></div>
|
|||
|
</header>
|
|||
|
|
|||
|
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
|
|||
|
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
|
|||
|
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">PC1 ArchLinux - VM Debian 10 vdb (jekyll-statique)</h1></header></div><meta itemprop="headline" content="PC1 ArchLinux - VM Debian 10 vdb (jekyll-statique)"><div class="article__info clearfix"><ul class="left-col menu"><li>
|
|||
|
<a class="button button--secondary button--pill button--sm"
|
|||
|
href="/archive.html?tag=virtuel">virtuel</a>
|
|||
|
</li></ul><ul class="right-col menu"><li>
|
|||
|
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF">15 déc. 2020</span>
|
|||
|
|
|||
|
<span title="Modification" style="color:#00FF7F"> 2 févr. 2021</span></li></ul></div><meta itemprop="datePublished" content="2021-02-02T00:00:00+01:00">
|
|||
|
<meta itemprop="keywords" content="virtuel"><div class="js-article-content">
|
|||
|
<div class="layout--article"><!-- start custom article top snippet -->
|
|||
|
<style>
|
|||
|
#myBtn {
|
|||
|
display: none;
|
|||
|
position: fixed;
|
|||
|
bottom: 10px;
|
|||
|
right: 10px;
|
|||
|
z-index: 99;
|
|||
|
font-size: 12px;
|
|||
|
font-weight: bold;
|
|||
|
border: none;
|
|||
|
outline: none;
|
|||
|
background-color: white;
|
|||
|
color: black;
|
|||
|
cursor: pointer;
|
|||
|
padding: 5px;
|
|||
|
border-radius: 4px;
|
|||
|
}
|
|||
|
|
|||
|
#myBtn:hover {
|
|||
|
background-color: #555;
|
|||
|
}
|
|||
|
</style>
|
|||
|
|
|||
|
<button onclick="topFunction()" id="myBtn" title="Haut de page">⇧</button>
|
|||
|
|
|||
|
<script>
|
|||
|
//Get the button
|
|||
|
var mybutton = document.getElementById("myBtn");
|
|||
|
|
|||
|
// When the user scrolls down 20px from the top of the document, show the button
|
|||
|
window.onscroll = function() {scrollFunction()};
|
|||
|
|
|||
|
function scrollFunction() {
|
|||
|
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
|
|||
|
mybutton.style.display = "block";
|
|||
|
} else {
|
|||
|
mybutton.style.display = "none";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// When the user clicks on the button, scroll to the top of the document
|
|||
|
function topFunction() {
|
|||
|
document.body.scrollTop = 0;
|
|||
|
document.documentElement.scrollTop = 0;
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
|
|||
|
<!-- end custom article top snippet -->
|
|||
|
<div class="article__content" itemprop="articleBody"><details>
|
|||
|
<summary><b>Afficher/cacher Sommaire</b></summary>
|
|||
|
<!-- affichage sommaire -->
|
|||
|
<div class="toc-aside js-toc-root"></div>
|
|||
|
</details><h2 id="vm-debian-10">VM Debian 10</h2>
|
|||
|
|
|||
|
<p><img src="/images/debian-buster-logo1.png" alt="Debian Buster" width="100" /></p>
|
|||
|
|
|||
|
<h3 id="créer-machine-virtuelle-debian">Créer Machine Virtuelle Debian</h3>
|
|||
|
|
|||
|
<p>En mode su</p>
|
|||
|
|
|||
|
<p>Création réseau <strong>host-bridge</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh net-define host-bridge.xml
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><network>
|
|||
|
<name>host-bridge</name>
|
|||
|
<forward mode='bridge'/>
|
|||
|
<bridge name='br0'/>
|
|||
|
</network>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Avant la création d’une machine virtuelle, le réseau doit être actif</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-start host-bridge # virsh net-autostart host-bridge
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Configurer le réseau pour un lancement au démarrage du serveur</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh net-autostart host-bridge # Network host-bridge marked as autostarted
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Liste des réseaux déclarés</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virsh net-list --all
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Nom État Démarrage automatique Persistent
|
|||
|
-------------------------------------------------------------
|
|||
|
default inactif no Oui
|
|||
|
host-bridge actif Oui Oui
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="création-vm-en-mode-console">Création VM en mode console</h3>
|
|||
|
|
|||
|
<p>Créer la machine virtuelle debian buster : <strong>debyan10</strong></p>
|
|||
|
|
|||
|
<p>Machine Virtuelle : debyan10<br />
|
|||
|
Processeurs : 2<br />
|
|||
|
Mémoire : 4096 Mo
|
|||
|
Disque dur SATA : /home/yann/virtuel/KVM/debyan10.qcow2 15Go<br />
|
|||
|
CDROM SATA : /home/yann/media/dplus/iso/debian/buster/debian-10.4.0-amd64-netinst.iso<br />
|
|||
|
NIC Réseau : Réseau virtuel ‘host-bridge’</p>
|
|||
|
|
|||
|
<p>Installation en mode console , il faut aller chercher le lien debian sur le site <a href="http://ftp.fr.debian.org/debian/dists/">http://ftp.fr.debian.org/debian/dists/</a></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>virt-install \
|
|||
|
--name debyan10 \
|
|||
|
--os-type Linux \
|
|||
|
--os-variant debian10 \
|
|||
|
--ram=4096 \
|
|||
|
--disk /home/yann/virtuel/KVM/debyan10.qcow2,device=disk,bus=virtio,size=15,format=qcow2 \
|
|||
|
--vcpus 2 \
|
|||
|
--network bridge=br0 \
|
|||
|
--location="http://ftp.fr.debian.org/debian/dists/buster/main/installer-amd64/" \
|
|||
|
--extra-args="auto console=ttyS0,115200n8 serial" \
|
|||
|
--graphics none \
|
|||
|
--console pty,target_type=serial
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Renseignements durant l’installation</p>
|
|||
|
|
|||
|
<p>Machine (hostname) : vdb<br />
|
|||
|
root : ytreu49<br />
|
|||
|
utilisateur: bust<br />
|
|||
|
Mot de passe : bust49<br />
|
|||
|
Disque entier, 1 seule partition<br />
|
|||
|
Choix : “SSH Server” et “standard system utilities”</p>
|
|||
|
|
|||
|
<p>A la fin de l’installation ,reboot</p>
|
|||
|
|
|||
|
<p><img src="/images/vdb-tty001.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Mofifier le réseau pour un adressage ip fixe : <code class="language-plaintext highlighter-rouge">nano /etc/network/interfaces</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># This file describes the network interfaces available on your system
|
|||
|
# and how to activate them. For more information, see interfaces(5).
|
|||
|
|
|||
|
source /etc/network/interfaces.d/*
|
|||
|
|
|||
|
# The loopback network interface
|
|||
|
auto lo
|
|||
|
iface lo inet loopback
|
|||
|
|
|||
|
# The primary network interface
|
|||
|
allow-hotplug enp1s0
|
|||
|
#iface enp1s0 inet dhcp
|
|||
|
iface enp1s0 inet static
|
|||
|
address 192.168.0.100
|
|||
|
netmask 255.255.255.0
|
|||
|
gateway 192.168.0.254
|
|||
|
# This is an autoconfigured IPv6 interface
|
|||
|
iface enp1s0 inet6 auto
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>On redémarre la machine virtuelle</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl reboot
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Accès root via ssh</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh root@192.168.0.100
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Réseau</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip a
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[...]
|
|||
|
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP gro
|
|||
|
up default qlen 1000
|
|||
|
link/ether 52:54:00:98:a5:d7 brd ff:ff:ff:ff:ff:ff
|
|||
|
inet 192.168.0.100/24 brd 192.168.0.255 scope global enp1s0
|
|||
|
valid_lft forever preferred_lft forever
|
|||
|
inet6 2a01:e34:eebf:df0:5054:ff:fe98:a5d7/64 scope global dynamic mngtmpaddr
|
|||
|
valid_lft 86358sec preferred_lft 86358sec
|
|||
|
inet6 fe80::5054:ff:fe98:a5d7/64 scope link
|
|||
|
valid_lft forever preferred_lft forever
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Installer sudo : <code class="language-plaintext highlighter-rouge">apt install sudo</code> <br />
|
|||
|
Les accès root utilisateur <strong>bust</strong> : <code class="language-plaintext highlighter-rouge">echo "bust ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers</code> <br />
|
|||
|
Connexion SSH avec clés , ajout clé publique dans <code class="language-plaintext highlighter-rouge">mkdir ~/.ssh , ~/.ssh/authorized_keys</code> + droits <code class="language-plaintext highlighter-rouge">chmod 600 -R ~/.ssh</code><br />
|
|||
|
Configuration <code class="language-plaintext highlighter-rouge">/etc/ssh/sshd_config</code> : <code class="language-plaintext highlighter-rouge">Port 55100</code> ,<code class="language-plaintext highlighter-rouge">PasswordAuthentication no</code> <br />
|
|||
|
Redémarrer le service : <code class="language-plaintext highlighter-rouge">sudo systemctl restart sshd</code></p>
|
|||
|
|
|||
|
<p>Test liaison SSH :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh bust@192.168.0.100 -p 55100 -i /home/yann/.ssh/kvm-vdb-ed25519
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Installer utilitaires : <code class="language-plaintext highlighter-rouge">sudo apt install rsync curl tmux jq figlet git dnsutils tree socat</code><br />
|
|||
|
Bannière <code class="language-plaintext highlighter-rouge">/etc/motd</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> __ __ __ __ _ _ _ _ __
|
|||
|
\ \ / /| \/ | __| | ___ | |__ (_) __ _ _ _ / | / \
|
|||
|
\ V / | |\/| | / _` |/ -_)| '_ \| |/ _` || ' \ | || () |
|
|||
|
_\_/__|_|__|_| \__,_|\___||_.__/|_|\__,_||_||_||_|_\__/
|
|||
|
/ |/ _ \|_ ) / | / / ( _ ) / \ / | / \ / \
|
|||
|
| |\_, / / / _ | |/ _ \/ _ \ _| () |_ | || () || () |
|
|||
|
|_| /_/ /___|(_)|_|\___/\___/(_)\__/(_)|_| \__/ \__/
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Bash <code class="language-plaintext highlighter-rouge">wget -4 https://static.xoyaz.xyz/files/ssh_rc_bash && chmod +x ssh_rc_bash && ./ssh_rc_bash</code></p>
|
|||
|
|
|||
|
<p><img src="/images/vdb01.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Pour des raisons de conformité avec archlinux, modifier ID groupe “users”</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo groupmod -g 985 users
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="partage-xoyize">Partage xoyize</h3>
|
|||
|
|
|||
|
<p>Installer <strong>autofs</strong> pour un accès aux dossiers de la machine <em>xoyize.xyz</em> 192.168.0.46</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install autofs
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Déclarer <em>xoyize</em> dans <code class="language-plaintext highlighter-rouge">/etc/hosts</code> , en ajoutant au fichier</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>192.168.0.46 xoyize
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les partages disponibles</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo showmount -e xoyize
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Export list for xoyize:
|
|||
|
/xoyipart 192.168.0.0/24
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Déclaration des répertoires parents de montages et de leur types</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/auto.master
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Oter le commentaire de la ligne suivante</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/net -hosts
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Redémarrer le service</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart autofs
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le dossier</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls /net/xoyize/xoyipart
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Créer un groupe <em>partage</em> avec id 9999</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo groupadd --gid 9999 partage
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="sshfs---partage-statique">SSHFS - Partage “statique”</h3>
|
|||
|
|
|||
|
<p><img src="/images/sshfs-logo.png" alt="sshfs" width="50" /></p>
|
|||
|
|
|||
|
<p>Le dossier “statique” est sur l’hôte PC1 (archyan)
|
|||
|
Il faut créer une liaison réseau sécurisée entre <strong>vdb ← → archyan</strong><br />
|
|||
|
On va utiliser SSHFS (<em>Secure shell file system (ou SSHFS) permet le partage d’un système de fichiers de manière sécurisée en utilisant le protocole SFTP de SSH</em>)</p>
|
|||
|
|
|||
|
<p>Installation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install sshfs
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Autorisations</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Autorisations “utilisateur”
|
|||
|
<ul>
|
|||
|
<li>Exécuter <code class="language-plaintext highlighter-rouge">sshfs</code> (ou toute autre commande de montage FUSE) avec l’option <code class="language-plaintext highlighter-rouge">-o allow_other</code></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li>Autoriser l’accès “root” des supports <strong>fuse</strong>
|
|||
|
<ul>
|
|||
|
<li>Ajouter <code class="language-plaintext highlighter-rouge">user_allow_other</code> au fichier <strong>/etc/fuse.conf</strong></li>
|
|||
|
<li>Exécuter <code class="language-plaintext highlighter-rouge">sshfs</code> (ou toute autre commande de montage FUSE) avec l’option <code class="language-plaintext highlighter-rouge">-o allow_root</code></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>PC1 : Clé publique pc1-archyan.pub ajoutée au fichier authorized_keys : <code class="language-plaintext highlighter-rouge">cat .ssh/pc1-archyan.pub >> .ssh/authorized_keys</code></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Clé privée <strong>pc1-archyan</strong> pour accéder à PC1 archyan (192.168.1.43)</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano $HOME/.ssh/pc1-archyan # copier la clé privée
|
|||
|
chmod 600 $HOME/.ssh/pc1-archyan
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Exécution manuelle</strong> pour authentifier la clé avec utilisateur “bust”</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p $HOME/statique
|
|||
|
sshfs -oIdentityFile=/home/bust/.ssh/pc1-archyan yann@192.168.0.43:/home/yann/media/statique /home/bust/statique
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The authenticity of host <span class="s1">'[192.168.1.43]:55036 ([2a04:52c0:101:82::73db]:55036)'</span> can<span class="s1">'t be established.
|
|||
|
ECDSA key fingerprint is SHA256:NuFqR5id10fVzRLsSTqJ4vBpFnNYi+APGsvPYth6PHw.
|
|||
|
Are you sure you want to continue connecting (yes/no)? yes
|
|||
|
</span></code></pre></div></div>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>NOTE: Il faut mettre l’adresse IP du serveur , si les domaines peuvent ne pas être “résolus”</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Après vérification , <code class="language-plaintext highlighter-rouge">ls $HOME/statique</code> , déconnexion <code class="language-plaintext highlighter-rouge">fusermount -u $HOME/statique</code></p>
|
|||
|
|
|||
|
<h4 id="montage-fstab">Montage fstab</h4>
|
|||
|
|
|||
|
<p>Le générateur de site statique utilise les dossiers _posts, images et files présents sur l’ordinateur hôte PC1<br />
|
|||
|
On va créer montage de chaque dossier sur la machine virtuelle debian</p>
|
|||
|
|
|||
|
<p>ajouter les lignes suivantes au fichier <code class="language-plaintext highlighter-rouge">/etc/fstab</code></p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yann@192.168.0.43:/home/yann/media/statique/_posts /home/bust/yannstatic/_posts fuse.sshfs _netdev,identityfile<span class="o">=</span>/home/bust/.ssh/pc1-archyan,allow_other,port<span class="o">=</span>22 0 0
|
|||
|
yann@192.168.0.43:/home/yann/media/statique/files /home/bust/yannstatic/files fuse.sshfs _netdev,identityfile<span class="o">=</span>/home/bust/.ssh/pc1-archyan,allow_other,port<span class="o">=</span>22 0 0
|
|||
|
yann@192.168.0.43:/home/yann/media/statique/images /home/bust/yannstatic/images fuse.sshfs _netdev,identityfile<span class="o">=</span>/home/bust/.ssh/pc1-archyan,allow_other,port<span class="o">=</span>22 0 0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Montage pour authentifier la clé avec utilisateur “root”</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mount -a
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>The authenticity of host '192.168.0.43 (192.168.0.43)' can't be established.
|
|||
|
ECDSA key fingerprint is SHA256:BxrhdNWnJS6934RvGgZs8XxGkUnlkIWu8KgU2goxnB0.
|
|||
|
Are you sure you want to continue connecting (yes/no)? yes
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérification</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ls $HOME/yannstatic/{images,files,_posts}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="sortie-du-mode-console">Sortie du mode console</h3>
|
|||
|
|
|||
|
<p>La combinaison <code class="language-plaintext highlighter-rouge">Ctrl + ]</code> ne focntionne pas<br />
|
|||
|
On recherche le PID de la console pour la supprimer</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ps aux | grep tty
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/vdb-tty002.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Correspondance avec le pid 1419 , supprimer le processus : <code class="language-plaintext highlighter-rouge">sudo kill 1419</code></p>
|
|||
|
|
|||
|
<h3 id="vm-autostart">VM autostart</h3>
|
|||
|
|
|||
|
<p><strong>Sur l’hôte PC1</strong><br />
|
|||
|
Démarrer la machine virtuelle au boot</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo virsh autostart debyan10
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><em>Domaine debyan10 marqué pour le démarrage automatique</em></p>
|
|||
|
|
|||
|
<h2 id="jekyll-générateur-site-statique">Jekyll générateur site statique</h2>
|
|||
|
|
|||
|
<p><img src="/images/jekyll-300x133.png" alt="jekyll" width="150px" /><br />
|
|||
|
<em>Générer un site statique via jekyll</em></p>
|
|||
|
|
|||
|
<p><strong>Rbenv (gestionnaire version ruby)</strong> est un outil léger de gestion des versions de Ruby qui vous permet de changer facilement de version de Ruby.</p>
|
|||
|
|
|||
|
<p>Par défaut, Rbenv ne gère pas l’installation des versions de Ruby. ruby-build est un outil qui vous aide à installer n’importe quelle version de Ruby dont vous pourriez avoir besoin. Il est disponible en tant que programme autonome et en tant que plugin pour rbenv.</p>
|
|||
|
|
|||
|
<p>Installez les dépendances nécessaires à l’outil ruby-build pour construire Ruby à partir des sources :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt update
|
|||
|
sudo apt install git curl libssl-dev libreadline-dev zlib1g-dev autoconf bison build-essential libyaml-dev libreadline-dev libncurses5-dev libffi-dev libgdbm-dev
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, lancez la commande curl suivante pour installer les scripts rbenv et ruby-build :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -sL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash -
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si l’installation est réussie, le script imprimera quelque chose comme ceci :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Running doctor script to verify installation...
|
|||
|
Checking for `rbenv' in PATH: not found
|
|||
|
You seem to have rbenv installed in `/home/dbsuser/.rbenv/bin', but that
|
|||
|
directory is not present in PATH. Please add it to PATH by configuring
|
|||
|
your `~/.bashrc', `~/.zshrc', or `~/.config/fish/config.fish'.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Avant de commencer à utiliser rbenv, nous devons ajouter $HOME/.rbenv/bin à notre PATH.</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
|
|||
|
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
|
|||
|
source ~/.bashrc
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les dernières versions stables</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rbenv install -l
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Maintenant que rbenv est installé sur notre système, nous pouvons facilement installer la dernière version stable de Ruby et la définir comme version par défaut avec :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rbenv install 2.7.2 # patientez de 3 à 8 minutes
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Downloading ruby-2.7.2.tar.bz2...
|
|||
|
-> https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.2.tar.bz2
|
|||
|
Installing ruby-2.7.2...
|
|||
|
Installed ruby-2.7.2 to /home/xoyi/.rbenv/versions/2.7.2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rbenv global 2.7.2
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifiez que Ruby a été correctement installé en imprimant le numéro de version :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ruby -v
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux]</code></p>
|
|||
|
|
|||
|
<p>Ajout du chemin bin $HOME/.rbenv/versions/2.7.2/bin/</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>echo 'export PATH="$HOME/.rbenv/versions/2.7.2/bin:$PATH"' >> ~/.bashrc
|
|||
|
source ~/.bashrc
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="yannstatic">yannstatic</h3>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd $HOME
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Cloner le dépôt</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
|
|||
|
git clone https://gitea.cinay.eu/yann/yannstatic.git yannstatic
|
|||
|
cd yannstatic
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Bundle lit le fichier <strong>Gemfile</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle install # Patientez ...
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bundle complete! 3 Gemfile dependencies, 43 gems now installed.
|
|||
|
Use `bundle info [gemname]` to see where a bundled gem is installed.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Info sur jekyll et créer un lien</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle info jekyll
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> * jekyll (4.1.1)
|
|||
|
Summary: A simple, blog aware, static site generator.
|
|||
|
Homepage: https://jekyllrb.com
|
|||
|
Path: /home/bust/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/jekyll-4.1.1
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Génération dossier ‘_site’ Manuellement</strong><br />
|
|||
|
Création du dossier <strong>_site</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>jekyll build
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Configuration file: /home/bust/yannstatic/_config.yml
|
|||
|
Source: /home/bust/yannstatic
|
|||
|
Destination: /home/bust/yannstatic/_site
|
|||
|
Incremental build: disabled. Enable with --incremental
|
|||
|
Generating...
|
|||
|
Jekyll Feed: Generating feed for posts
|
|||
|
done in 49.398 seconds.
|
|||
|
Auto-regeneration: disabled. Use --watch to enable.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">yannstatic.service</code>** - Service yannstatic, génération ‘_site’ en cas de modification**<br />
|
|||
|
Pour lancer le serveur <strong>yannstatic</strong> au démarrage, utilisation d’un <u>service systemd</u><br />
|
|||
|
<strong>ATTENTION!</strong> , remplacer <em>User=utilisateur</em> par votre nom d’utilisateur <code class="language-plaintext highlighter-rouge">echo $USER</code><br />
|
|||
|
Relever le chemin complet de jekyll : <code class="language-plaintext highlighter-rouge">which jekyll</code> → <strong>/home/bust/.rbenv/shims/jekyll</strong></p>
|
|||
|
|
|||
|
<p>Création d’un service “yannstatic” sous systemd</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/systemd/system/yannstatic.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Contenu du fichier</p>
|
|||
|
|
|||
|
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Unit]</span>
|
|||
|
<span class="py">Description</span><span class="p">=</span><span class="s">service yannstatic</span>
|
|||
|
<span class="py">After</span><span class="p">=</span><span class="s">network.target</span>
|
|||
|
|
|||
|
<span class="nn">[Service]</span>
|
|||
|
<span class="py">Type</span><span class="p">=</span><span class="s">simple</span>
|
|||
|
<span class="py">User</span><span class="p">=</span><span class="s">bust</span>
|
|||
|
<span class="py">WorkingDirectory</span><span class="p">=</span><span class="s">/home/bust/yannstatic</span>
|
|||
|
<span class="py">ExecStart</span><span class="p">=</span><span class="s">/home/bust/.rbenv/shims/bundle exec jekyll build --watch</span>
|
|||
|
<span class="py">Restart</span><span class="p">=</span><span class="s">on-abort</span>
|
|||
|
|
|||
|
|
|||
|
<span class="nn">[Install]</span>
|
|||
|
<span class="py">WantedBy</span><span class="p">=</span><span class="s">multi-user.target</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Activer et lancer le service <strong>yannstatic</strong> :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl daemon-reload
|
|||
|
sudo systemctl enable yannstatic
|
|||
|
sudo systemctl start yannstatic
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><code class="language-plaintext highlighter-rouge">synchro_site.{path,service}</code>** - En cas de modification du dossier ‘_site’, synchronisation locale → distante xoyaz.xyz**<br />
|
|||
|
<em>Avec les unités de chemin, vous pouvez surveiller les fichiers et les répertoires pour certains événements. Si un événement spécifique se produit, une unité de service est exécutée, et elle porte généralement le même nom que l’unité de chemin.</em></p>
|
|||
|
|
|||
|
<p>Nous allons surveiller le fichier <strong>sitemap.xml</strong> du dossier <em>_site/</em>. Chaque fois que le fichier est fermé après une écriture, un script spécifique démarrera.</p>
|
|||
|
|
|||
|
<p>Dans le répertoire <code class="language-plaintext highlighter-rouge">/etc/systemd/system/</code> nous créons une unité de cheminement <strong>synchro_site.path</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/systemd/system/synchro_site.path
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Unit]</span>
|
|||
|
<span class="py">Description</span><span class="p">=</span><span class="s">Surveiller le fichier pour les changements</span>
|
|||
|
|
|||
|
<span class="nn">[Path]</span>
|
|||
|
<span class="py">PathChanged</span><span class="p">=</span><span class="s">/home/bust/yannstatic/_site/sitemap.xml</span>
|
|||
|
<span class="py">Unit</span><span class="p">=</span><span class="s">synchro_site.service</span>
|
|||
|
|
|||
|
<span class="nn">[Install]</span>
|
|||
|
<span class="py">WantedBy</span><span class="p">=</span><span class="s">multi-user.target</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans la section <code class="language-plaintext highlighter-rouge">[Path]</code>, <code class="language-plaintext highlighter-rouge">PathChanged=</code> indique le chemin absolu du fichier à surveiller, tandis que <code class="language-plaintext highlighter-rouge">Unit=</code> indique l’unité de service à exécuter si le fichier change. Cette unité (<strong>synchro_site.path</strong>) doit être lancée lorsque le système est en mode multi-utilisateur.</p>
|
|||
|
|
|||
|
<p>Ensuite, nous créons l’unité de service correspondante, <strong>synchro_site.service</strong>, dans le répertoire <code class="language-plaintext highlighter-rouge">/etc/systemd/system/</code> <br />
|
|||
|
Si le fichier <strong>sitemap.xml</strong> change (c’est-à-dire qu’il est à la fois écrit et fermé), l’unité de service suivante sera appelée pour exécuter le script spécifié :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/systemd/system/synchro_site.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Unit]</span>
|
|||
|
<span class="py">Description</span><span class="p">=</span><span class="s">"/home/bust/yannstatic/_site/sitemap.xml a été modifié."</span>
|
|||
|
|
|||
|
<span class="nn">[Service]</span>
|
|||
|
<span class="py">ExecStart</span><span class="p">=</span><span class="s">/home/bust/yannstatic/synchro_site.sh</span>
|
|||
|
|
|||
|
<span class="nn">[Install]</span>
|
|||
|
<span class="py">WantedBy</span><span class="p">=</span><span class="s">multi-user.target</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le script <strong>/home/bust/yannstatic/synchro_site.sh</strong> lance une synchronisation locale distante via rsync ssh</p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
|
|||
|
|
|||
|
<span class="c"># Synchronisation locale distante du dossier _site</span>
|
|||
|
rsync <span class="nt">-avz</span> <span class="nt">--progress</span> <span class="nt">--stats</span> <span class="nt">--human-readable</span> <span class="nt">--delete</span> <span class="nt">--rsync-path</span><span class="o">=</span><span class="s2">"sudo rsync"</span> <span class="nt">-e</span> <span class="s2">"ssh -p 55036 -i /home/bust/.ssh/OVZ-STORAGE-128 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"</span> /home/bust/yannstatic/_site/<span class="k">*</span> usernl@xoyaz.xyz:/home/usernl/backup/static/ <span class="o">></span> /dev/null
|
|||
|
<span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="nt">-eq</span> 0 <span class="o">]</span><span class="p">;</span> <span class="k">then</span> <span class="se">\</span>
|
|||
|
<span class="nb">echo</span> <span class="s2">"Synchronisation dossier _site entre vdb et xoyayz -> OK"</span> | systemd-cat <span class="nt">-t</span> vdbsync <span class="nt">-p</span> info <span class="p">;</span> <span class="se">\</span>
|
|||
|
<span class="k">else</span> <span class="se">\</span>
|
|||
|
<span class="nb">echo</span> <span class="s2">"Synchronisation dossier _site entre vdb et xoyayz -> ERREUR"</span> | systemd-cat <span class="nt">-t</span> vdbsync <span class="nt">-p</span> emerg <span class="p">;</span> <span class="se">\</span>
|
|||
|
<span class="k">fi</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Activation des services</strong><br />
|
|||
|
Activer et lancer le service <strong>yannstatic</strong> :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl daemon-reload
|
|||
|
sudo systemctl enable yannstatic
|
|||
|
sudo systemctl start yannstatic
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les unités <code class="language-plaintext highlighter-rouge">synchro_site.{path,service}</code> doivent être activées</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl daemon-reload
|
|||
|
sudo systemctl enable synchro_site.{path,service}
|
|||
|
sudo systemctl start synchro_site.path
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifications</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo journalctl -f -u yannstatic.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nov. 29 14:02:31 vdb jekyll[2139]: Regenerating: 2 file(s) changed at 2020-11-29 14:02:31
|
|||
|
nov. 29 14:02:31 vdb jekyll[2139]: _posts/2020-11-27-ArchLinux-KVM_QEMU-VM-debian10-vdb-statique.md
|
|||
|
nov. 29 14:02:31 vdb jekyll[2139]: _posts/.2020-11-27-ArchLinux-KVM_QEMU-VM-debian10-vdb-statique.md.LOyEEU
|
|||
|
nov. 29 14:02:31 vdb jekyll[2139]: Jekyll Feed: Generating feed for posts
|
|||
|
nov. 29 14:02:45 vdb jekyll[2139]: ...done in 14.660143584 seconds.
|
|||
|
nov. 29 14:02:45 vdb jekyll[2139]:
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo journalctl -f -u synchro_site.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nov. 29 14:02:45 vdb systemd[1]: Started "/home/bust/yannstatic/_site/sitemap.xml a été modifié.".
|
|||
|
nov. 29 14:02:45 vdb synchro_site.sh[2635]: Warning: Permanently added '[xoyaz.xyz]:55036,[2a04:52c0:101:82::73db]:55036' (ECDSA) to the list of known hosts.
|
|||
|
nov. 29 14:02:47 vdb systemd[1]: synchro_site.service: Succeeded.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>VM - Dossiers _posts, images et files</strong> <br />
|
|||
|
On ne peut pas traiter la modification de dossier avec systemd.path dans la machine virtuelle car les dossiers sont “liés” (ln).
|
|||
|
Créer dossiers <code class="language-plaintext highlighter-rouge">/home/bust/yannstatic/{_posts,images,files}</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir -p /home/bust/yannstatic/{_posts,images,files}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="pc1---synchroniser-les-dossiers-_posts-images-et-files">PC1 - Synchroniser les dossiers _posts, images et files</h3>
|
|||
|
|
|||
|
<p>en cas de modification, il faut mettre à jour les dossiers _posts, images et files de la VM par rsync avec le script <code class="language-plaintext highlighter-rouge">/home/yann/scripts/synchro-dossiers_posts-images-files_PC1_vers_vdb</code></p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
|
|||
|
<span class="c">#!/bin/bash </span>
|
|||
|
|
|||
|
<span class="c"># COLUMNSxROWS+X+Y -> xterm -geometry 400x200+100+350</span>
|
|||
|
<span class="c"># xterm -geometry 100x30+100+350 -T yannstatic -e '/home/yann/scripts/tmux-vdb.sh'</span>
|
|||
|
<span class="c"># On supprime la session "VdbSess" si existante </span>
|
|||
|
|
|||
|
<span class="k">if</span> <span class="o">[[</span> <span class="sb">`</span>tmux list-sessions | <span class="nb">grep</span> <span class="s1">'VdbSess'</span> | <span class="nb">wc</span> <span class="nt">-l</span><span class="sb">`</span> <span class="o">!=</span> 0 <span class="o">]]</span>
|
|||
|
<span class="k">then</span>
|
|||
|
<span class="c"># On ferme la session active</span>
|
|||
|
tmux kill-session <span class="nt">-t</span> VdbSess
|
|||
|
<span class="k">fi</span>
|
|||
|
|
|||
|
|
|||
|
<span class="c"># Créer une bannière dans /etc/motd sur chaque serveur</span>
|
|||
|
<span class="c"># Nom du domaine en ascii voir lien http://patorjk.com/software/taag/#p=display&h=1&f=Small</span>
|
|||
|
<span class="nb">echo</span> <span class="s2">"fin fi"</span>
|
|||
|
<span class="c"># Créer session + terminal </span>
|
|||
|
tmux new <span class="nt">-d</span> <span class="nt">-s</span> VdbSess <span class="nt">-n</span> VdbTerm
|
|||
|
<span class="c"># Séparation horizontale en 2/3 1/3 du terminal</span>
|
|||
|
tmux split-window <span class="nt">-v</span> <span class="nt">-p</span> 33
|
|||
|
<span class="c"># | 0 |</span>
|
|||
|
<span class="c"># | 2/3 |</span>
|
|||
|
<span class="c"># | |</span>
|
|||
|
<span class="c"># |-----------|</span>
|
|||
|
<span class="c"># | 1 1/3 |</span>
|
|||
|
<span class="c"># Sélection terminal HAUT</span>
|
|||
|
tmux selectp <span class="nt">-t</span> 0
|
|||
|
<span class="c"># Séparation horizontale en 1/2 du terminal 0</span>
|
|||
|
tmux split-window <span class="nt">-v</span> <span class="nt">-p</span> 50
|
|||
|
|
|||
|
<span class="c"># Sélection terminal HAUT</span>
|
|||
|
tmux selectp <span class="nt">-t</span> 0
|
|||
|
tmux send-keys <span class="nt">-t</span> VdbSess <span class="s2">"sshm vdb exe 'sudo journalctl -f -u yannstatic.service'"</span> C-m
|
|||
|
<span class="c"># Sélection terminal MILIEU</span>
|
|||
|
tmux selectp <span class="nt">-t</span> 1
|
|||
|
<span class="c">#tmux send-keys -t VdbSess "sudo journalctl -f -u rsync_statique.service" C-m</span>
|
|||
|
tmux send-keys <span class="nt">-t</span> VdbSess <span class="s2">"sudo journalctl -f -t vdbsync --since today"</span> C-m
|
|||
|
tmux selectp <span class="nt">-t</span> 2
|
|||
|
<span class="c">#tmux send-keys -t VdbSess "sshm vdb exe 'sudo journalctl -f -u synchro_site.service'" C-m</span>
|
|||
|
tmux send-keys <span class="nt">-t</span> VdbSess <span class="s2">"sshm vdb exe 'sudo journalctl -f -t vdbsync --since today'"</span> C-m
|
|||
|
<span class="c"># Sélection terminal BAS</span>
|
|||
|
<span class="c"># Afficher la session </span>
|
|||
|
tmux a <span class="nt">-t</span> VdbSess
|
|||
|
<span class="c">#</span>
|
|||
|
<span class="c"># Tuer la session</span>
|
|||
|
<span class="c"># tmux kill-session -t VdbSess</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans la section <code class="language-plaintext highlighter-rouge">[Path]</code>, <code class="language-plaintext highlighter-rouge">PathModified=</code> indique le chemin absolu du fichier à surveiller,
|
|||
|
<code class="language-plaintext highlighter-rouge">PathModified=</code> est utilisé pour surveiller un fichier ou un répertoire et activer l’unité configurée chaque fois qu’elle change. Il activé lors de simples écritures sur le fichier/dossier surveillé.</p>
|
|||
|
|
|||
|
<p>tandis que <code class="language-plaintext highlighter-rouge">Unit=</code> indique l’unité de service à exécuter si le fichier change. Cette unité (<strong>rsync_statique.path</strong>) doit être lancée lorsque le système est en mode multi-utilisateur.</p>
|
|||
|
|
|||
|
<p>Ensuite, nous créons l’unité de service correspondante, <strong>rsync_statique.service</strong>, dans le répertoire <code class="language-plaintext highlighter-rouge">/etc/systemd/system/</code> <br />
|
|||
|
Si le dossier <strong>/home/yann/media/statique/_posts</strong> est modifié , l’unité de service <strong>rsync_statique.service</strong> sera appelé pour exécuter le script spécifié :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/systemd/system/rsync_statique.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Unit]</span>
|
|||
|
<span class="py">Description</span><span class="p">=</span><span class="s">"/home/yann/media/statique/_posts a été modifié"</span>
|
|||
|
|
|||
|
<span class="nn">[Service]</span>
|
|||
|
<span class="py">ExecStart</span><span class="p">=</span><span class="s">/home/yann/scripts/synchro-dossiers_posts-images-files_PC1_vers_vdb</span>
|
|||
|
|
|||
|
<span class="nn">[Install]</span>
|
|||
|
<span class="py">WantedBy</span><span class="p">=</span><span class="s">multi-user.target</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Les unités <code class="language-plaintext highlighter-rouge">rsync_statique.{path,service}</code> doivent être activées</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl daemon-reload
|
|||
|
sudo systemctl enable rsync_statique.{path,service}
|
|||
|
sudo systemctl start rsync_statique.path
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérification</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo journalctl -f -u rsync_statique.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-- Logs begin at Mon 2020-11-23 16:54:55 CET. --
|
|||
|
nov. 29 14:17:01 archyan synchro-dossiers_posts-images-files_PC1_vers_vdb[15264]: Warning: Permanently added '[192.168.0.100]:55100' (ECDSA) to the list of known hosts.
|
|||
|
nov. 29 14:17:01 archyan systemd[1]: rsync_statique.service: Succeeded.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="surveillance-depuis-lhôte-pc1">Surveillance depuis l’hôte (PC1)</h3>
|
|||
|
|
|||
|
<p>Créer un script <code class="language-plaintext highlighter-rouge">/home/yann/scripts/tmux-vdb.sh</code></p>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash </span>
|
|||
|
|
|||
|
<span class="c"># COLUMNSxROWS+X+Y -> xterm -geometry 400x200+100+350</span>
|
|||
|
<span class="c"># xterm -geometry 100x30+100+350 -T yannstatic -e '/home/yann/scripts/tmux-vdb.sh'</span>
|
|||
|
<span class="c"># On supprime la session "VdbSess" si existante </span>
|
|||
|
|
|||
|
<span class="k">if</span> <span class="o">[[</span> <span class="sb">`</span>tmux list-sessions | <span class="nb">grep</span> <span class="s1">'VdbSess'</span> | <span class="nb">wc</span> <span class="nt">-l</span><span class="sb">`</span> <span class="o">!=</span> 0 <span class="o">]]</span>
|
|||
|
<span class="k">then</span>
|
|||
|
<span class="c"># On ferme la session active</span>
|
|||
|
tmux kill-session <span class="nt">-t</span> VdbSess
|
|||
|
<span class="k">fi</span>
|
|||
|
|
|||
|
|
|||
|
<span class="c"># Créer une bannière dans /etc/motd sur chaque serveur</span>
|
|||
|
<span class="c"># Nom du domaine en ascii voir lien http://patorjk.com/software/taag/#p=display&h=1&f=Small</span>
|
|||
|
<span class="nb">echo</span> <span class="s2">"fin fi"</span>
|
|||
|
<span class="c"># Créer session + terminal </span>
|
|||
|
tmux new <span class="nt">-d</span> <span class="nt">-s</span> VdbSess <span class="nt">-n</span> VdbTerm
|
|||
|
<span class="c"># Séparation horizontale en 2 du terminal</span>
|
|||
|
tmux split-window <span class="nt">-v</span> <span class="nt">-p</span> 50
|
|||
|
<span class="c"># | 0 |</span>
|
|||
|
<span class="c"># | |</span>
|
|||
|
<span class="c"># |-----------|</span>
|
|||
|
<span class="c"># | 1 |</span>
|
|||
|
<span class="c"># | |</span>
|
|||
|
<span class="c"># Sélection terminal HAUT</span>
|
|||
|
tmux selectp <span class="nt">-t</span> 0
|
|||
|
<span class="c"># </span>
|
|||
|
tmux send-keys <span class="nt">-t</span> VdbSess <span class="s2">"sshm vdb exe 'sudo journalctl -f -u yannstatic.service'"</span> C-m
|
|||
|
<span class="c"># Sélection terminal BAS</span>
|
|||
|
tmux selectp <span class="nt">-t</span> 1
|
|||
|
<span class="c"># </span>
|
|||
|
tmux send-keys <span class="nt">-t</span> VdbSess <span class="s2">"sshm vdb exe 'sudo journalctl -f -u synchro_site.service'"</span> C-m
|
|||
|
|
|||
|
<span class="c"># Afficher la session </span>
|
|||
|
tmux a <span class="nt">-t</span> VdbSess
|
|||
|
<span class="c">#</span>
|
|||
|
<span class="c"># Tuer la session</span>
|
|||
|
<span class="c"># tmux kill-session -t VdbSess</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Installer <strong>xterm</strong> : <code class="language-plaintext highlighter-rouge">sudo pacman -S xterm</code><br />
|
|||
|
Créer un alias <strong>tmuxvdb</strong> pour visualiser la construction et la synchro du site statique</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano ~/.bashrc
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">alias </span><span class="nv">tmuxvdb</span><span class="o">=</span><span class="s2">"xterm -geometry 100x30+100+350 -T yannstatic -e '/home/yann/scripts/tmux-vdb.sh'"</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Voir : <code class="language-plaintext highlighter-rouge">tmuxvdb</code></p>
|
|||
|
|
|||
|
<p><img src="/images/xterm01.png" alt="" width="500" /></p>
|
|||
|
|
|||
|
<h3 id="desactivation-site-statique">DESACTIVATION site statique</h3>
|
|||
|
|
|||
|
<p>Pour rendre inactif le générateur de site statique</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl stop yannstatic
|
|||
|
sudo systemctl disable yannstatic
|
|||
|
sudo systemctl stop synchro_site.path
|
|||
|
sudo systemctl disable synchro_site.path
|
|||
|
sudo systemctl stop synchro_site.service
|
|||
|
sudo systemctl disable synchro_site.service
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h2 id="nfs-xoyipart">NFS xoyipart</h2>
|
|||
|
|
|||
|
<p>Installer client NFS</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install nfs-common
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Montage dossier <code class="language-plaintext highlighter-rouge">xoyipart</code> du serveur xoyize.xyz 192.168.0.46</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mkdir $HOME/xoyipart
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>partage NFS avec les membres d’un groupe</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo groupadd -g 9999 partage
|
|||
|
sudo usermod -a -G partage $USER
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Montage dans fichier <code class="language-plaintext highlighter-rouge">/etc/fstab</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>192.168.0.46:/xoyipart /home/bust/xoyipart nfs _netdev,nodev,noexec 0 0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Validation</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mount -a
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h2 id="construire-navidrome">Construire Navidrome</h2>
|
|||
|
|
|||
|
<p><a href="https://www.navidrome.org/docs/installation/build-from-source/">https://www.navidrome.org/docs/installation/build-from-source/</a><br />
|
|||
|
<em>Création d’un binaire navidrome issu d’une compilation en language go</em></p>
|
|||
|
|
|||
|
<p><a href="/2020/04/26/go.html">Installer Go version 15</a> <br />
|
|||
|
Vérifier les chemins ajoutés au fichier <code class="language-plaintext highlighter-rouge">~/.bashrc</code></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>export PATH=$PATH:/usr/local/go/bin
|
|||
|
export GOPATH="$HOME/go_projects"
|
|||
|
export GOBIN="$GOPATH/bin"
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour actualiser : <code class="language-plaintext highlighter-rouge">source ~/.bashrc</code> si vous avez modifié le fichier</p>
|
|||
|
|
|||
|
<p>Copier un binaire</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo cp $HOME/go_projects/bin/go-bindata /usr/local/go/bin/
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><a href="/2019/12/28/Archlinux-Debian-Node.js-Nvm-Npm-Yarn.html">Installer nodejs version 14</a><br />
|
|||
|
Dépendances :<code class="language-plaintext highlighter-rouge">sudo apt install libtag1-dev build-essential pkg-config</code> <br />
|
|||
|
Cloner le projet : <code class="language-plaintext highlighter-rouge">git clone https://github.com/deluan/navidrome</code></p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>Aller dans le dossier : <code class="language-plaintext highlighter-rouge">cd navidrome/</code></li>
|
|||
|
<li>Installer les dépendances de construction : <code class="language-plaintext highlighter-rouge">make setup</code></li>
|
|||
|
<li>pour la langue :
|
|||
|
<ol>
|
|||
|
<li>ajouter le fichier <code class="language-plaintext highlighter-rouge">ui/src/i18n/fr.json</code></li>
|
|||
|
<li>modifier provider.js <code class="language-plaintext highlighter-rouge">sed -i "s#'./en.json'#'./fr.json'#g" ui/src/i18n/provider.js</code></li>
|
|||
|
</ol>
|
|||
|
</li>
|
|||
|
<li>Construire : <code class="language-plaintext highlighter-rouge">make buildall</code></li>
|
|||
|
<li>Si OK, le fichier exécutable <code class="language-plaintext highlighter-rouge">navidrome</code> est généré</li>
|
|||
|
<li>Il est nécessaire d’installer le paquet libtag1-dev : <code class="language-plaintext highlighter-rouge">sudo apt install libtag1-dev</code></li>
|
|||
|
</ol>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2020-12-15T00:00:00+01:00"><!-- start custom article footer snippet -->
|
|||
|
|
|||
|
<!-- end custom article footer snippet -->
|
|||
|
<!--
|
|||
|
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
|
|||
|
|
|||
|
 </div>
|
|||
|
-->
|
|||
|
</footer>
|
|||
|
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2020/11/29/Linux-Systemd-cheatsheet.html">Linux - Systemd cheatsheet</a></div><div class="next"><span>SUIVANT</span><a href="/2020/12/24/Archlinux_conteneur_LXC_debian_10_(buster).html">Archlinux --> Container LXC debian buster lxcdeb (go, node, jekyll, nginx, php, mariadb)</a></div></div></div>
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
<script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
$(function() {
|
|||
|
var $this ,$scroll;
|
|||
|
var $articleContent = $('.js-article-content');
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
|
|||
|
$scroll = $(scroll);
|
|||
|
|
|||
|
$articleContent.find('.highlight').each(function() {
|
|||
|
$this = $(this);
|
|||
|
$this.attr('data-lang', $this.find('code').attr('data-lang'));
|
|||
|
});
|
|||
|
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
|
|||
|
$this = $(this);
|
|||
|
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
|
|||
|
});
|
|||
|
$articleContent.on('click', '.anchor', function() {
|
|||
|
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
|
|||
|
});
|
|||
|
});
|
|||
|
});
|
|||
|
})();
|
|||
|
</script>
|
|||
|
|
|||
|
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
|
|||
|
<!-- end custom main bottom snippet -->
|
|||
|
</div>
|
|||
|
</div></div></div></div>
|
|||
|
</div><script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $body = $('body'), $window = $(window);
|
|||
|
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
|
|||
|
var activeCount = 0;
|
|||
|
function modal(options) {
|
|||
|
var $root = this, visible, onChange, hideWhenWindowScroll = false;
|
|||
|
var scrollTop;
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
visible = _options.initialVisible === undefined ? false : show;
|
|||
|
onChange = _options.onChange;
|
|||
|
hideWhenWindowScroll = _options.hideWhenWindowScroll;
|
|||
|
}
|
|||
|
function init() {
|
|||
|
setState(visible);
|
|||
|
}
|
|||
|
function setState(isShow) {
|
|||
|
if (isShow === visible) {
|
|||
|
return;
|
|||
|
}
|
|||
|
visible = isShow;
|
|||
|
if (visible) {
|
|||
|
activeCount++;
|
|||
|
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
|
|||
|
$root.addClass('modal--show');
|
|||
|
$pageMain.scrollTop(scrollTop);
|
|||
|
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
|
|||
|
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
|
|||
|
$window.on('keyup', handleKeyup);
|
|||
|
} else {
|
|||
|
activeCount > 0 && activeCount--;
|
|||
|
$root.removeClass('modal--show');
|
|||
|
$window.scrollTop(scrollTop);
|
|||
|
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
|
|||
|
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
|
|||
|
$window.off('keyup', handleKeyup);
|
|||
|
}
|
|||
|
onChange && onChange(visible);
|
|||
|
}
|
|||
|
function show() {
|
|||
|
setState(true);
|
|||
|
}
|
|||
|
function hide() {
|
|||
|
setState(false);
|
|||
|
}
|
|||
|
function handleKeyup(e) {
|
|||
|
// Char Code: 27 ESC
|
|||
|
if (e.which === 27) {
|
|||
|
hide();
|
|||
|
}
|
|||
|
}
|
|||
|
setOptions(options);
|
|||
|
init();
|
|||
|
return {
|
|||
|
show: show,
|
|||
|
hide: hide,
|
|||
|
$el: $root
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.modal = modal;
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
|
|||
|
(function () {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
// search panel
|
|||
|
var search = (window.search || (window.search = {}));
|
|||
|
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
|
|||
|
true : window.useDefaultSearchBox ;
|
|||
|
|
|||
|
var $searchModal = $('.js-page-search-modal');
|
|||
|
var $searchToggle = $('.js-search-toggle');
|
|||
|
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
|
|||
|
var modalVisible = false;
|
|||
|
search.searchModal = searchModal;
|
|||
|
|
|||
|
var $searchBox = null;
|
|||
|
var $searchInput = null;
|
|||
|
var $searchClear = null;
|
|||
|
|
|||
|
function getModalVisible() {
|
|||
|
return modalVisible;
|
|||
|
}
|
|||
|
search.getModalVisible = getModalVisible;
|
|||
|
|
|||
|
function handleModalChange(visible) {
|
|||
|
modalVisible = visible;
|
|||
|
if (visible) {
|
|||
|
search.onShow && search.onShow();
|
|||
|
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
|
|||
|
} else {
|
|||
|
search.onShow && search.onHide();
|
|||
|
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
|
|||
|
setTimeout(function() {
|
|||
|
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
|
|||
|
search.clear && search.clear();
|
|||
|
window.pageAsideAffix && window.pageAsideAffix.refresh();
|
|||
|
}, 400);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$searchToggle.on('click', function() {
|
|||
|
modalVisible ? searchModal.hide() : searchModal.show();
|
|||
|
});
|
|||
|
// Char Code: 83 S, 191 /
|
|||
|
$(window).on('keyup', function(e) {
|
|||
|
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
|
|||
|
modalVisible || searchModal.show();
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
if (useDefaultSearchBox) {
|
|||
|
$searchBox = $('.js-search-box');
|
|||
|
$searchInput = $searchBox.children('input');
|
|||
|
$searchClear = $searchBox.children('.js-icon-clear');
|
|||
|
search.getSearchInput = function() {
|
|||
|
return $searchInput.get(0);
|
|||
|
};
|
|||
|
search.getVal = function() {
|
|||
|
return $searchInput.val();
|
|||
|
};
|
|||
|
search.setVal = function(val) {
|
|||
|
$searchInput.val(val);
|
|||
|
};
|
|||
|
|
|||
|
$searchInput.on('focus', function() {
|
|||
|
$(this).addClass('focus');
|
|||
|
});
|
|||
|
$searchInput.on('blur', function() {
|
|||
|
$(this).removeClass('focus');
|
|||
|
});
|
|||
|
$searchInput.on('input', window.throttle(function() {
|
|||
|
var val = $(this).val();
|
|||
|
if (val === '' || typeof val !== 'string') {
|
|||
|
search.clear && search.clear();
|
|||
|
} else {
|
|||
|
$searchBox.addClass('not-empty');
|
|||
|
search.onInputNotEmpty && search.onInputNotEmpty(val);
|
|||
|
}
|
|||
|
}, 400));
|
|||
|
$searchClear.on('click', function() {
|
|||
|
$searchInput.val(''); $searchBox.removeClass('not-empty');
|
|||
|
search.clear && search.clear();
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><div class="search search--dark">
|
|||
|
<div class="main">
|
|||
|
<div class="search__header">Recherche</div>
|
|||
|
<div class="search-bar">
|
|||
|
<div class="search-box js-search-box">
|
|||
|
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
|
|||
|
<input id="search-input" type="text" />
|
|||
|
<div class="search-box__icon-clear js-icon-clear">
|
|||
|
<a><i class="fas fa-times"></i></a>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
|
|||
|
Annuler</button>
|
|||
|
</div>
|
|||
|
<div id="results-container" class="search-result js-search-result"></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- Script pointing to search-script.js -->
|
|||
|
<script>/*!
|
|||
|
* Simple-Jekyll-Search
|
|||
|
* Copyright 2015-2020, Christian Fei
|
|||
|
* Licensed under the MIT License.
|
|||
|
*/
|
|||
|
|
|||
|
(function(){
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Templater_7 = {
|
|||
|
compile: compile,
|
|||
|
setOptions: setOptions
|
|||
|
}
|
|||
|
|
|||
|
const options = {}
|
|||
|
options.pattern = /\{(.*?)\}/g
|
|||
|
options.template = ''
|
|||
|
options.middleware = function () {}
|
|||
|
|
|||
|
function setOptions (_options) {
|
|||
|
options.pattern = _options.pattern || options.pattern
|
|||
|
options.template = _options.template || options.template
|
|||
|
if (typeof _options.middleware === 'function') {
|
|||
|
options.middleware = _options.middleware
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compile (data) {
|
|||
|
return options.template.replace(options.pattern, function (match, prop) {
|
|||
|
const value = options.middleware(prop, data[prop], options.template)
|
|||
|
if (typeof value !== 'undefined') {
|
|||
|
return value
|
|||
|
}
|
|||
|
return data[prop] || match
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
function fuzzysearch (needle, haystack) {
|
|||
|
var tlen = haystack.length;
|
|||
|
var qlen = needle.length;
|
|||
|
if (qlen > tlen) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (qlen === tlen) {
|
|||
|
return needle === haystack;
|
|||
|
}
|
|||
|
outer: for (var i = 0, j = 0; i < qlen; i++) {
|
|||
|
var nch = needle.charCodeAt(i);
|
|||
|
while (j < tlen) {
|
|||
|
if (haystack.charCodeAt(j++) === nch) {
|
|||
|
continue outer;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var _$fuzzysearch_1 = fuzzysearch;
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
|
|||
|
|
|||
|
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
|
|||
|
|
|||
|
function FuzzySearchStrategy () {
|
|||
|
this.matches = function (string, crit) {
|
|||
|
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
|
|||
|
|
|||
|
function LiteralSearchStrategy () {
|
|||
|
this.matches = function (str, crit) {
|
|||
|
if (!str) return false
|
|||
|
|
|||
|
str = str.trim().toLowerCase()
|
|||
|
crit = crit.trim().toLowerCase()
|
|||
|
|
|||
|
return crit.split(' ').filter(function (word) {
|
|||
|
return str.indexOf(word) >= 0
|
|||
|
}).length === crit.split(' ').length
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Repository_4 = {
|
|||
|
put: put,
|
|||
|
clear: clear,
|
|||
|
search: search,
|
|||
|
setOptions: __setOptions_4
|
|||
|
}
|
|||
|
|
|||
|
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
|
|||
|
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
|
|||
|
|
|||
|
function NoSort () {
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
const data = []
|
|||
|
let opt = {}
|
|||
|
|
|||
|
opt.fuzzy = false
|
|||
|
opt.limit = 10
|
|||
|
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = NoSort
|
|||
|
opt.exclude = []
|
|||
|
|
|||
|
function put (data) {
|
|||
|
if (isObject(data)) {
|
|||
|
return addObject(data)
|
|||
|
}
|
|||
|
if (isArray(data)) {
|
|||
|
return addArray(data)
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
function clear () {
|
|||
|
data.length = 0
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function isObject (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
|
|||
|
}
|
|||
|
|
|||
|
function isArray (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
|
|||
|
}
|
|||
|
|
|||
|
function addObject (_data) {
|
|||
|
data.push(_data)
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function addArray (_data) {
|
|||
|
const added = []
|
|||
|
clear()
|
|||
|
for (let i = 0, len = _data.length; i < len; i++) {
|
|||
|
if (isObject(_data[i])) {
|
|||
|
added.push(addObject(_data[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
return added
|
|||
|
}
|
|||
|
|
|||
|
function search (crit) {
|
|||
|
if (!crit) {
|
|||
|
return []
|
|||
|
}
|
|||
|
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
|
|||
|
}
|
|||
|
|
|||
|
function __setOptions_4 (_opt) {
|
|||
|
opt = _opt || {}
|
|||
|
|
|||
|
opt.fuzzy = _opt.fuzzy || false
|
|||
|
opt.limit = _opt.limit || 10
|
|||
|
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = _opt.sort || NoSort
|
|||
|
opt.exclude = _opt.exclude || []
|
|||
|
}
|
|||
|
|
|||
|
function findMatches (data, crit, strategy, opt) {
|
|||
|
const matches = []
|
|||
|
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
|
|||
|
const match = findMatchesInObject(data[i], crit, strategy, opt)
|
|||
|
if (match) {
|
|||
|
matches.push(match)
|
|||
|
}
|
|||
|
}
|
|||
|
return matches
|
|||
|
}
|
|||
|
|
|||
|
function findMatchesInObject (obj, crit, strategy, opt) {
|
|||
|
for (const key in obj) {
|
|||
|
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
|
|||
|
return obj
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isExcluded (term, excludedTerms) {
|
|||
|
for (let i = 0, len = excludedTerms.length; i < len; i++) {
|
|||
|
const excludedTerm = excludedTerms[i]
|
|||
|
if (new RegExp(excludedTerm).test(term)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
/* globals ActiveXObject:false */
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$JSONLoader_2 = {
|
|||
|
load: load
|
|||
|
}
|
|||
|
|
|||
|
function load (location, callback) {
|
|||
|
const xhr = getXHR()
|
|||
|
xhr.open('GET', location, true)
|
|||
|
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
|
|||
|
xhr.send()
|
|||
|
}
|
|||
|
|
|||
|
function createStateChangeListener (xhr, callback) {
|
|||
|
return function () {
|
|||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|||
|
try {
|
|||
|
callback(null, JSON.parse(xhr.responseText))
|
|||
|
} catch (err) {
|
|||
|
callback(err, null)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getXHR () {
|
|||
|
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$OptionsValidator_3 = function OptionsValidator (params) {
|
|||
|
if (!validateParams(params)) {
|
|||
|
throw new Error('-- OptionsValidator: required options missing')
|
|||
|
}
|
|||
|
|
|||
|
if (!(this instanceof OptionsValidator)) {
|
|||
|
return new OptionsValidator(params)
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = params.required
|
|||
|
|
|||
|
this.getRequiredOptions = function () {
|
|||
|
return requiredOptions
|
|||
|
}
|
|||
|
|
|||
|
this.validate = function (parameters) {
|
|||
|
const errors = []
|
|||
|
requiredOptions.forEach(function (requiredOptionName) {
|
|||
|
if (typeof parameters[requiredOptionName] === 'undefined') {
|
|||
|
errors.push(requiredOptionName)
|
|||
|
}
|
|||
|
})
|
|||
|
return errors
|
|||
|
}
|
|||
|
|
|||
|
function validateParams (params) {
|
|||
|
if (!params) {
|
|||
|
return false
|
|||
|
}
|
|||
|
return typeof params.required !== 'undefined' && params.required instanceof Array
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$utils_9 = {
|
|||
|
merge: merge,
|
|||
|
isJSON: isJSON
|
|||
|
}
|
|||
|
|
|||
|
function merge (defaultParams, mergeParams) {
|
|||
|
const mergedOptions = {}
|
|||
|
for (const option in defaultParams) {
|
|||
|
mergedOptions[option] = defaultParams[option]
|
|||
|
if (typeof mergeParams[option] !== 'undefined') {
|
|||
|
mergedOptions[option] = mergeParams[option]
|
|||
|
}
|
|||
|
}
|
|||
|
return mergedOptions
|
|||
|
}
|
|||
|
|
|||
|
function isJSON (json) {
|
|||
|
try {
|
|||
|
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
|
|||
|
return true
|
|||
|
}
|
|||
|
return false
|
|||
|
} catch (err) {
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var _$src_8 = {};
|
|||
|
(function (window) {
|
|||
|
'use strict'
|
|||
|
|
|||
|
let options = {
|
|||
|
searchInput: null,
|
|||
|
resultsContainer: null,
|
|||
|
json: [],
|
|||
|
success: Function.prototype,
|
|||
|
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
|
|||
|
templateMiddleware: Function.prototype,
|
|||
|
sortMiddleware: function () {
|
|||
|
return 0
|
|||
|
},
|
|||
|
noResultsText: 'No results found',
|
|||
|
limit: 10,
|
|||
|
fuzzy: false,
|
|||
|
debounceTime: null,
|
|||
|
exclude: []
|
|||
|
}
|
|||
|
|
|||
|
let debounceTimerHandle
|
|||
|
const debounce = function (func, delayMillis) {
|
|||
|
if (delayMillis) {
|
|||
|
clearTimeout(debounceTimerHandle)
|
|||
|
debounceTimerHandle = setTimeout(func, delayMillis)
|
|||
|
} else {
|
|||
|
func.call()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
|
|||
|
|
|||
|
/* removed: const _$Templater_7 = require('./Templater') */;
|
|||
|
/* removed: const _$Repository_4 = require('./Repository') */;
|
|||
|
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
|
|||
|
const optionsValidator = _$OptionsValidator_3({
|
|||
|
required: requiredOptions
|
|||
|
})
|
|||
|
/* removed: const _$utils_9 = require('./utils') */;
|
|||
|
|
|||
|
window.SimpleJekyllSearch = function (_options) {
|
|||
|
const errors = optionsValidator.validate(_options)
|
|||
|
if (errors.length > 0) {
|
|||
|
throwError('You must specify the following required options: ' + requiredOptions)
|
|||
|
}
|
|||
|
|
|||
|
options = _$utils_9.merge(options, _options)
|
|||
|
|
|||
|
_$Templater_7.setOptions({
|
|||
|
template: options.searchResultTemplate,
|
|||
|
middleware: options.templateMiddleware
|
|||
|
})
|
|||
|
|
|||
|
_$Repository_4.setOptions({
|
|||
|
fuzzy: options.fuzzy,
|
|||
|
limit: options.limit,
|
|||
|
sort: options.sortMiddleware,
|
|||
|
exclude: options.exclude
|
|||
|
})
|
|||
|
|
|||
|
if (_$utils_9.isJSON(options.json)) {
|
|||
|
initWithJSON(options.json)
|
|||
|
} else {
|
|||
|
initWithURL(options.json)
|
|||
|
}
|
|||
|
|
|||
|
const rv = {
|
|||
|
search: search
|
|||
|
}
|
|||
|
|
|||
|
typeof options.success === 'function' && options.success.call(rv)
|
|||
|
return rv
|
|||
|
}
|
|||
|
|
|||
|
function initWithJSON (json) {
|
|||
|
_$Repository_4.put(json)
|
|||
|
registerInput()
|
|||
|
}
|
|||
|
|
|||
|
function initWithURL (url) {
|
|||
|
_$JSONLoader_2.load(url, function (err, json) {
|
|||
|
if (err) {
|
|||
|
throwError('failed to get JSON (' + url + ')')
|
|||
|
}
|
|||
|
initWithJSON(json)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function emptyResultsContainer () {
|
|||
|
options.resultsContainer.innerHTML = ''
|
|||
|
}
|
|||
|
|
|||
|
function appendToResultsContainer (text) {
|
|||
|
options.resultsContainer.innerHTML += text
|
|||
|
}
|
|||
|
|
|||
|
function registerInput () {
|
|||
|
options.searchInput.addEventListener('input', function (e) {
|
|||
|
if (isWhitelistedKey(e.which)) {
|
|||
|
emptyResultsContainer()
|
|||
|
debounce(function () { search(e.target.value) }, options.debounceTime)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function search (query) {
|
|||
|
if (isValidQuery(query)) {
|
|||
|
emptyResultsContainer()
|
|||
|
render(_$Repository_4.search(query), query)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function render (results, query) {
|
|||
|
const len = results.length
|
|||
|
if (len === 0) {
|
|||
|
return appendToResultsContainer(options.noResultsText)
|
|||
|
}
|
|||
|
for (let i = 0; i < len; i++) {
|
|||
|
results[i].query = query
|
|||
|
appendToResultsContainer(_$Templater_7.compile(results[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isValidQuery (query) {
|
|||
|
return query && query.length > 0
|
|||
|
}
|
|||
|
|
|||
|
function isWhitelistedKey (key) {
|
|||
|
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
|
|||
|
}
|
|||
|
|
|||
|
function throwError (message) {
|
|||
|
throw new Error('SimpleJekyllSearch --- ' + message)
|
|||
|
}
|
|||
|
})(window)
|
|||
|
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
<!-- Configuration -->
|
|||
|
<script>
|
|||
|
SimpleJekyllSearch({
|
|||
|
searchInput: document.getElementById('search-input'),
|
|||
|
resultsContainer: document.getElementById('results-container'),
|
|||
|
noResultsText: '<p>Aucun résultat!</p>',
|
|||
|
json: '/search.json',
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a> (Création {create})</li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
|
|||
|
</div></div>
|
|||
|
|
|||
|
|
|||
|
<script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function scrollToAnchor(anchor, duration, callback) {
|
|||
|
var $root = this;
|
|||
|
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
|
|||
|
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
|
|||
|
callback && callback();
|
|||
|
});
|
|||
|
}
|
|||
|
$.fn.scrollToAnchor = scrollToAnchor;
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function affix(options) {
|
|||
|
var $root = this, $window = $(window), $scrollTarget, $scroll,
|
|||
|
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
|
|||
|
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
|
|||
|
hasInit = false, curState;
|
|||
|
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
|
|||
|
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
|
|||
|
_options.scroll && (scroll = _options.scroll);
|
|||
|
_options.disabled !== undefined && (disabled = _options.disabled);
|
|||
|
$scrollTarget = $(scrollTarget);
|
|||
|
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
|
|||
|
$scroll = $(scroll);
|
|||
|
}
|
|||
|
function preCalc() {
|
|||
|
top();
|
|||
|
rootHeight = $root.outerHeight();
|
|||
|
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
|
|||
|
rootLeft = $root.offset().left;
|
|||
|
}
|
|||
|
function calc(needPreCalc) {
|
|||
|
needPreCalc && preCalc();
|
|||
|
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
|
|||
|
rootBottomTop = scrollBottom - rootTop;
|
|||
|
}
|
|||
|
function top() {
|
|||
|
if (curState !== 'top') {
|
|||
|
$root.removeClass('fixed').css({
|
|||
|
left: 0,
|
|||
|
top: 0
|
|||
|
});
|
|||
|
curState = 'top';
|
|||
|
}
|
|||
|
}
|
|||
|
function fixed() {
|
|||
|
if (curState !== 'fixed') {
|
|||
|
$root.addClass('fixed').css({
|
|||
|
left: rootLeft + 'px',
|
|||
|
top: 0
|
|||
|
});
|
|||
|
curState = 'fixed';
|
|||
|
}
|
|||
|
}
|
|||
|
function bottom() {
|
|||
|
if (curState !== 'bottom') {
|
|||
|
$root.removeClass('fixed').css({
|
|||
|
left: 0,
|
|||
|
top: rootBottomTop + 'px'
|
|||
|
});
|
|||
|
curState = 'bottom';
|
|||
|
}
|
|||
|
}
|
|||
|
function setState() {
|
|||
|
var scrollTop = $scrollTarget.scrollTop();
|
|||
|
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
|
|||
|
fixed();
|
|||
|
} else if (scrollTop < rootTop) {
|
|||
|
top();
|
|||
|
} else {
|
|||
|
bottom();
|
|||
|
}
|
|||
|
}
|
|||
|
function init() {
|
|||
|
if(!hasInit) {
|
|||
|
var interval, timeout;
|
|||
|
calc(true); setState();
|
|||
|
// run calc every 100 millisecond
|
|||
|
interval = setInterval(function() {
|
|||
|
calc();
|
|||
|
}, 100);
|
|||
|
timeout = setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
}, 45000);
|
|||
|
window.pageLoad.then(function() {
|
|||
|
setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
clearTimeout(timeout);
|
|||
|
}, 3000);
|
|||
|
});
|
|||
|
$scrollTarget.on('scroll', function() {
|
|||
|
disabled || setState();
|
|||
|
});
|
|||
|
$window.on('resize', function() {
|
|||
|
disabled || (calc(true), setState());
|
|||
|
});
|
|||
|
hasInit = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
setOptions(options);
|
|||
|
if (!disabled) {
|
|||
|
init();
|
|||
|
}
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
init();
|
|||
|
}, 200));
|
|||
|
return {
|
|||
|
setOptions: setOptions,
|
|||
|
refresh: function() {
|
|||
|
calc(true, { animation: false }); setState();
|
|||
|
}
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.affix = affix;
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function toc(options) {
|
|||
|
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
|
|||
|
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
|
|||
|
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
|
|||
|
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
_options.selectors && (selectors = _options.selectors);
|
|||
|
_options.container && (container = _options.container);
|
|||
|
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
|
|||
|
_options.scroller && (scroller = _options.scroller);
|
|||
|
_options.disabled !== undefined && (disabled = _options.disabled);
|
|||
|
$headings = $(container).find(selectors).filter('[id]');
|
|||
|
$scrollTarget = $(scrollTarget);
|
|||
|
$scroller = $(scroller);
|
|||
|
}
|
|||
|
function calc() {
|
|||
|
headingsPos = [];
|
|||
|
$headings.each(function() {
|
|||
|
headingsPos.push(Math.floor($(this).position().top));
|
|||
|
});
|
|||
|
}
|
|||
|
function setState(element, disabled) {
|
|||
|
var scrollTop = $scrollTarget.scrollTop(), i;
|
|||
|
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
|
|||
|
if (element) {
|
|||
|
$activeCur = element;
|
|||
|
} else {
|
|||
|
for (i = 0; i < headingsPos.length; i++) {
|
|||
|
if (scrollTop >= headingsPos[i]) {
|
|||
|
$activeCur = $tocLi.eq(i);
|
|||
|
} else {
|
|||
|
$activeCur || ($activeCur = $tocLi.eq(i));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
$activeLast && $activeLast.removeClass('active');
|
|||
|
($activeLast = $activeCur).addClass('active');
|
|||
|
}
|
|||
|
function render() {
|
|||
|
if(!hasRendered) {
|
|||
|
$root.append($tocUl);
|
|||
|
$headings.each(function() {
|
|||
|
var $this = $(this);
|
|||
|
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
|
|||
|
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
|
|||
|
});
|
|||
|
$tocLi = $tocUl.children('li');
|
|||
|
$tocUl.on('click', 'a', function(e) {
|
|||
|
e.preventDefault();
|
|||
|
var $this = $(this);
|
|||
|
scrolling = true;
|
|||
|
setState($this.parent());
|
|||
|
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
|
|||
|
scrolling = false;
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
hasRendered = true;
|
|||
|
}
|
|||
|
function init() {
|
|||
|
var interval, timeout;
|
|||
|
if(!hasInit) {
|
|||
|
render(); calc(); setState(null, scrolling);
|
|||
|
// run calc every 100 millisecond
|
|||
|
interval = setInterval(function() {
|
|||
|
calc();
|
|||
|
}, 100);
|
|||
|
timeout = setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
}, 45000);
|
|||
|
window.pageLoad.then(function() {
|
|||
|
setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
clearTimeout(timeout);
|
|||
|
}, 3000);
|
|||
|
});
|
|||
|
$scrollTarget.on('scroll', function() {
|
|||
|
disabled || setState(null, scrolling);
|
|||
|
});
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
if (!disabled) {
|
|||
|
render(); calc(); setState(null, scrolling);
|
|||
|
}
|
|||
|
}, 100));
|
|||
|
}
|
|||
|
hasInit = true;
|
|||
|
}
|
|||
|
|
|||
|
setOptions(options);
|
|||
|
if (!disabled) {
|
|||
|
init();
|
|||
|
}
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
init();
|
|||
|
}, 200));
|
|||
|
return {
|
|||
|
setOptions: setOptions
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.toc = toc;
|
|||
|
});
|
|||
|
})();
|
|||
|
/*(function () {
|
|||
|
|
|||
|
})();*/
|
|||
|
</script><script>
|
|||
|
/* toc must before affix, since affix need to konw toc' height. */(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $window = $(window);
|
|||
|
var $articleContent = $('.js-article-content');
|
|||
|
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
|
|||
|
var toc;
|
|||
|
var tocDisabled = false;
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
|
|||
|
|
|||
|
function disabled() {
|
|||
|
return $col2.css('display') === 'none' || !hasToc;
|
|||
|
}
|
|||
|
|
|||
|
tocDisabled = disabled();
|
|||
|
|
|||
|
toc = $tocRoot.toc({
|
|||
|
selectors: TOC_SELECTOR,
|
|||
|
container: $articleContent,
|
|||
|
scrollTarget: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroller: hasSidebar ? '.js-page-main' : null,
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
tocDisabled = disabled();
|
|||
|
toc && toc.setOptions({
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
}, 100));
|
|||
|
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $window = $(window), $pageFooter = $('.js-page-footer');
|
|||
|
var $pageAside = $('.js-page-aside');
|
|||
|
var affix;
|
|||
|
var tocDisabled = false;
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
|
|||
|
affix = $pageAside.affix({
|
|||
|
offsetBottom: $pageFooter.outerHeight(),
|
|||
|
scrollTarget: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroller: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroll: hasSidebar ? $('.js-page-main').children() : null,
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
affix && affix.setOptions({
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
}, 100));
|
|||
|
|
|||
|
window.pageAsideAffix = affix;
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><!---->
|
|||
|
|
|||
|
</div>
|
|||
|
<script>(function () {
|
|||
|
var $root = document.getElementsByClassName('root')[0];
|
|||
|
if (window.hasEvent('touchstart')) {
|
|||
|
$root.dataset.isTouch = true;
|
|||
|
document.addEventListener('touchstart', function(){}, false);
|
|||
|
}
|
|||
|
})();
|
|||
|
</script>
|
|||
|
</body>
|
|||
|
</html>
|
|||
|
|