yannstatic/static/2018/08/27/Raspbian-Stretch-Lite-flightradar.html

2754 lines
246 KiB
HTML
Raw Normal View History

2024-10-31 20:18:37 +01:00
<!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>Raspbian Lite Stretch + FlightRadar24 - YannStatic</title>
<meta name="description" content="ADS-B">
<link rel="canonical" href="https://static.rnmkcy.eu/2018/08/27/Raspbian-Stretch-Lite-flightradar.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}&nbsp;{title}</a></li>'
searchResultTemplate: '<li><a href="{url}">{date}&nbsp;{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;">Raspbian Lite Stretch + FlightRadar24</h1></header></div><meta itemprop="headline" content="Raspbian Lite Stretch + FlightRadar24"><div class="article__info clearfix"><ul class="left-col menu"><li>
2024-11-08 14:10:33 +01:00
<a class="button button--secondary button--pill button--sm" style="color:#00FFFF" href="/archive.html?tag=raspberry">raspberry</a>
2024-10-31 20:18:37 +01:00
</li></ul><ul class="right-col menu"><li>
<i class="far fa-calendar-alt"></i>&nbsp;<span title="Création" style="color:#FF00FF">27&nbsp;août&nbsp;&nbsp;2018</span></li></ul></div><meta itemprop="datePublished" content="2018-08-27T00:00:00+02:00">
<meta itemprop="keywords" content="raspberry"><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">&#8679;</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><h1 id="ads-b">ADS-B</h1>
<p><em>Utiliser des solutions de streaming open-source (KSQL, Apache Kafka, un Raspberry Pi et un récepteur radio logiciel) pour cartographier le trafic aérien</em></p>
<p>Les aéronefs déterminent leur position à laide du GPS et transmettent périodiquement cette position ainsi que la chaîne didentité, laltitude, la vitesse, etc. sous forme de signaux ADS-B.</p>
<h3 id="raspbian-literaspberry-pi-3">Raspbian-Lite/Raspberry Pi 3</h3>
<p><img src="/images/raspberry-pi3.png" alt="raspberry-pi3" /></p>
<p><strong>Installer raspian-lite stretch sur raspberry…</strong>, chercher lexpression “raspbian lite stretch” dans le champ recherche du site</p>
<h3 id="matériel">Matériel</h3>
<p><img src="/images/dongle-dvb.png" alt="alt text" title="DVB-T+DAB+FM" /></p>
<ul>
<li>Dongle USB 2.0 DVB (Digital Video Broadcasting) modèle DVB-T+DAB+FM
<ul>
<li>Elle peut aussi être utilisée comme récepteur-scanner large bande, pour recevoir de 24Mhz à 1766Mhz (sans trou) en mode RTL-SDR.</li>
<li>Utilisation en SDR (software define radio) : Ce modèle est équipé du chipset RTL2832U et du tuner R820T</li>
<li>Connecteur antenne sur la clé USB : MCX Femelle</li>
</ul>
</li>
</ul>
<h3 id="introduction">Introduction</h3>
<p>Un dongle USB DVB-T peut être utilisé pour recevoir les signaux ADS-B, qui peuvent être décodés avec le logiciel approprié (<a href="http://photobyte.org/using-the-raspberry-pi-as-an-rtl-sdr-dongle-server/">Installing RTL SDR Software</a>).<br />
Installer les outils de construction du logiciel et la librairie requise.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt-get install -y git cmake pkg-config libusb-1.0-0-dev
</code></pre></div></div>
<h3 id="installation-de-rtl-sdr">Installation de rtl-sdr</h3>
<p>Le pack logiciel contient la bibliothèque chargée de communiquer avec le dongle DVB-T (Digital Video Braodcasting-Terrestrial) et un certain nombre doutils pour lutiliser comme SDR (Software Defined Radio).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr
mkdir build
cd build
cmake ../ -DINSTALL_UDEV_RULES=ON
sudo make install
sudo cp ../rtl-sdr.rules /etc/udev/rules.d/
sudo ldconfig
</code></pre></div></div>
<p>Comme nous ne voulons pas regarder la télévision le pilote DVB-T par défaut doit être supprimé dans la liste noire. Créez le fichier suivant:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/modprobe.d/rtlsdr.conf
</code></pre></div></div>
<p>Ajoutez lui les lignes suivantes :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>blacklist dvb_usb_rtl28xxu
blacklist rtl2832
blacklist rtl2830
</code></pre></div></div>
<p>Arrêter le raspberry</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo poweroff
</code></pre></div></div>
<p>Connecter le dongle DVB-T et redémarrer le raspberry<br />
Connexion ssh<br />
Vérification : aucun module chargé</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lsmod | grep dvb_usb_rtl28xxu
</code></pre></div></div>
<h3 id="installer-et-exécuter-dump1090">Installer et exécuter Dump1090</h3>
<ul>
<li><a href="https://www.framboise314.fr/un-raspberry-pi-pour-suivre-les-avions-sur-flightradar24-2/#Pygmalion_vous_explique_comment_configurer_le_Raspberry_Pi">https://www.framboise314.fr/un-raspberry-pi-pour-suivre-les-avions-sur-flightradar24-2/#Pygmalion_vous_explique_comment_configurer_le_Raspberry_Pi</a></li>
</ul>
<p>Ce logiciel est utilisé pour recevoir et décoder le signa ADS-B.<br />
Il permet également de représenter les données que vous aurez collectées sur une page web.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
# pour utiliser openstreetmap et un server externe (lighttpd ou nginx)
git clone https://github.com/mutability/dump1090
cd dump1090
make
</code></pre></div></div>
<h3 id="création-du-bash-avec-les-données-au-format-json">Création du bash avec les données au format json</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /home/pi/start_flight_radar.sh
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/sh
cd /home/pi/dump1090/
if [ -d "/run/dump1090" ]
then
echo "/run/dump1090 exists."
else
sudo mkdir -p /run/dump1090-mutability
sudo chown pi. -R /run/dump1090-mutability/ #droits pour utilisateur pi
fi
# Exécution
./dump1090 --net --ppm 0 --oversample --fix --phase-enhance --lat 47.27076 --lon -1.02527 --max-range 300 --net-http-port 0 --net-ri-port 30001 --net-ro-port 30002 --net-bi-port 30004 --net-bo-port 30005 --net-sbs-port 30003 --net-heartbeat 60 --net-ro-size 500 --net-ro-interval 1 --net-buffer 2 --net-bind-address 127.0.0.1 --stats-every 3600 --write-json /run/dump1090-mutability --write-json-every 1 --json-location-accuracy 2 --quiet&amp;
</code></pre></div></div>
<p>Rendre exécutable</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod +x /home/pi/start_flight_radar.sh
</code></pre></div></div>
<p>Test</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
./start_flight_radar.sh
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Mon Aug 27 15:01:17 2018 UTC dump1090-mutability v1.15-dev-333-gfb5942d starting up.
Using sample converter: UC8, integer/table path
Found 1 device(s):
0: Generic, RTL2832U, SN: 77771111153705700 (currently selected)
Found Rafael Micro R820T tuner
Max available gain is: 49.60 dB
Setting gain to: 49.60 dB
Gain reported by device: 49.60 dB
Allocating 15 zero-copy buffers
</code></pre></div></div>
<p>Appuyer sur entrée pour récupérer le curseur</p>
<p>Vérifier la capture des données sur le port 3003 (arrêt par <em>Ctrl C</em>)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl 127.0.0.1:30003 # localhost est résolu en ipv6 (::1)
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MSG,8,1,1,440735,1,2018/06/07,15:58:44.078,2018/06/07,15:58:44.129,,,,,,,,,,,,0
MSG,6,1,1,3B77EB,1,2018/06/07,15:58:44.085,2018/06/07,15:58:44.130,,,,,,,,1745,0,0,0,
MSG,8,1,1,440735,1,2018/06/07,15:58:44.089,2018/06/07,15:58:44.131,,,,,,,,,,,,0
MSG,4,1,1,440735,1,2018/06/07,15:58:44.190,2018/06/07,15:58:44.239,,,440,343,,,64,,,,,0
MSG,8,1,1,3C09F3,1,2018/06/07,15:58:44.282,2018/06/07,15:58:44.298,,,,,,,,,,,,0
MSG,8,1,1,3C09F3,1,2018/06/07,15:58:44.298,2018/06/07,15:58:44.348,,,,,,,,,,,,0
MSG,8,1,1,3C09F3,1,2018/06/07,15:58:44.314,2018/06/07,15:58:44.350,,,,,,,,,,,,0
MSG,7,1,1,3C09F3,1,2018/06/07,15:58:44.338,2018/06/07,15:58:44.353,,38000,,,,,,,,,,
MSG,8,1,1,3C09F3,1,2018/06/07,15:58:44.347,2018/06/07,15:58:44.402,,,,,,,,,,,,0
</code></pre></div></div>
<p>Arrêt du batch</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pkill dump1090 #Appuyer 2 fois sur entrée pour récupérer le curseur
</code></pre></div></div>
<h3 id="service-web-externe-lighttpd">service web externe lighttpd</h3>
<p>Installer <strong>lighttpd</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install lighttpd
</code></pre></div></div>
<p>Créer le dossier <strong>/usr/share/dump1090-mutability/html/</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo mkdir -p /usr/share/dump1090-mutability/html/
</code></pre></div></div>
<p>Copier les fichiers et dossiers nécessaires au fonctionnement</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo cp -r ~/dump1090/public_html/* /usr/share/dump1090-mutability/html/
</code></pre></div></div>
<p>Créer le fichier de configuration du serveur lighttpd</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/lighttpd/conf-available/89-dump1090.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Allows access to the static files that provide the dump1090 map view,
# and also to the dynamically-generated json parts that contain aircraft
# data and are periodically written by the dump1090 daemon.
url.redirect += (
"^/dump1090/$" =&gt; "/dump1090/gmap.html",
"^/dump1090$" =&gt; "/dump1090/gmap.html"
)
alias.url += (
"/dump1090/data/" =&gt; "/run/dump1090-mutability/",
"/dump1090/" =&gt; "/usr/share/dump1090-mutability/html/"
)
# The stat cache must be disabled, as receiver.json changes
# rapidly and lighttpd's stat cache often ends up with the
# wrong content length.
server.stat-cache-engine = "disable"
</code></pre></div></div>
<p>Activer le fichier de configuration <strong>/etc/lighttpd/conf-available/89-dump1090.conf</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo lighty-enable-mod dump1090 # pour l'activation ou exécuter la ligne qui suit
# sudo ln -s /etc/lighttpd/conf-available/89-dump1090.conf /etc/lighttpd/conf-enabled/
</code></pre></div></div>
<h3 id="personnaliser-dump1090">Personnaliser Dump1090</h3>
<p>Personnaliser lapparence de la couche des données dans <strong>/usr/share/dump1090-mutability/html/config.js</strong>.(remplacer le fichier existant)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /usr/share/dump1090-mutability/html/config.js
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// --------------------------------------------------------
//
// This file is to configure the configurable settings.
// Load this file before script.js file at gmap.html.
//
// --------------------------------------------------------
// -- Title Settings --------------------------------------
// Show number of aircraft and/or messages per second in the page title
PlaneCountInTitle = true;
MessageRateInTitle = false;
// -- Output Settings -------------------------------------
// Show metric values
// The Metric setting controls whether metric (m, km, km/h) or
// imperial (ft, NM, knots) units are used in the plane table
// and in the detailed plane info. If ShowOtherUnits is true,
// then the other unit will also be shown in the detailed plane
// info.
Metric = true;
ShowOtherUnits = true;
// -- Map settings ----------------------------------------
// These settings are overridden by any position information
// provided by dump1090 itself. All positions are in decimal
// degrees.
// Default center of the map.
DefaultCenterLat = 47.27076; //latitude antenne
DefaultCenterLon = -1.02527; //longitude antenne
// The google maps zoom level, 0 - 16, lower is further out
DefaultZoomLvl = 8;
// Center marker. If dump1090 provides a receiver location,
// that location is used and these settings are ignored.
SiteShow = false; // true to show a center marker
SiteLat = 47.27076; // position of the marker
SiteLon = -1.02527;
SiteName = "Radar Site"; // tooltip of the marker
// -- Marker settings -------------------------------------
// These settings control the coloring of aircraft by altitude.
// All color values are given as Hue (0-359) / Saturation (0-100) / Lightness (0-100)
ColorByAlt = {
// HSL for planes with unknown altitude:
unknown : { h: 0, s: 0, l: 40 },
// HSL for planes that are on the ground:
ground : { h: 120, s: 100, l: 30 },
air : {
// These define altitude-to-hue mappings
// at particular altitudes; the hue
// for intermediate altitudes that lie
// between the provided altitudes is linearly
// interpolated.
//
// Mappings must be provided in increasing
// order of altitude.
//
// Altitudes below the first entry use the
// hue of the first entry; altitudes above
// the last entry use the hue of the last
// entry.
h: [ { alt: 2000, val: 20 }, // orange
{ alt: 10000, val: 140 }, // light green
{ alt: 40000, val: 300 } ], // magenta
s: 85,
l: 50,
},
// Changes added to the color of the currently selected plane
selected : { h: 0, s: -10, l: +20 },
// Changes added to the color of planes that have stale position info
stale : { h: 0, s: -10, l: +30 },
// Changes added to the color of planes that have positions from mlat
mlat : { h: 0, s: -10, l: -10 }
};
// For a monochrome display try this:
// ColorByAlt = {
// unknown : { h: 0, s: 0, l: 40 },
// ground : { h: 0, s: 0, l: 30 },
// air : { h: [ { alt: 0, val: 0 } ], s: 0, l: 50 },
// selected : { h: 0, s: 0, l: +30 },
// stale : { h: 0, s: 0, l: +30 },
// mlat : { h: 0, s: 0, l: -10 }
// };
// Outline color for aircraft icons with an ADS-B position
OutlineADSBColor = '#000000';
// Outline color for aircraft icons with a mlat position
OutlineMlatColor = '#4040FF';
SiteCircles = true; // true to show circles (only shown if the center marker is shown)
// In nautical miles or km (depending settings value 'Metric')
SiteCirclesDistances = new Array(50,100,150,200);
// Show the clocks at the top of the righthand pane? You can disable the clocks if you want here
ShowClocks = true;
// Controls page title, righthand pane when nothing is selected
PageName = "DUMP1090";
// Show country flags by ICAO addresses?
ShowFlags = true;
// Path to country flags (can be a relative or absolute URL; include a trailing /)
FlagPath = "flags-tiny/";
// Set to true to enable the ChartBundle base layers (US coverage only)
ChartBundleLayers = true;
// Provide a Bing Maps API key here to enable the Bing imagery layer.
// You can obtain a free key (with usage limits) at
// https://www.bingmapsportal.com/ (you need a "basic key")
//
// Be sure to quote your key:
// BingMapsAPIKey = "your key here";
//
BingMapsAPIKey = null;
// Provide a Mapzen API key here to enable the Mapzen vector tile layer.
// You can obtain a free key at https://mapzen.com/developers/
// (you need a "vector tiles" key)
//
// Be sure to quote your key:
// MapzenAPIKey = "your key here";
//
MapzenAPIKey = null;
</code></pre></div></div>
<p>Le fichier <strong>gmap.html</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /usr/share/dump1090-mutability/html/gmap.html
</code></pre></div></div>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE HTML&gt;</span>
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
<span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">type=</span><span class="s">"text/css"</span> <span class="na">href=</span><span class="s">"style.css"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"jquery/jquery-ui-1.11.4-smoothness.css"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"jquery/jquery-3.0.0.min.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"jquery/jquery-ui-1.11.4.min.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"ol3/ol-3.17.1.css"</span> <span class="na">type=</span><span class="s">"text/css"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"ol3/ol-3.17.1.js"</span> <span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"ol3/ol3-layerswitcher.css"</span> <span class="na">type=</span><span class="s">"text/css"</span><span class="nt">/&gt;</span>
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"ol3/ol3-layerswitcher.js"</span> <span class="na">type=</span><span class="s">"text/javascript"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"config.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"markers.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"dbloader.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"registrations.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"planeObject.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"formatter.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"flags.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"layers.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"script.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"coolclock/excanvas.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"coolclock/coolclock.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"coolclock/moreskins.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;title&gt;</span>Radar Virtuel<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body</span> <span class="na">onload=</span><span class="s">"initialize()"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"loader"</span> <span class="na">class=</span><span class="s">"hidden"</span><span class="nt">&gt;</span>
<span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"spinny.gif"</span> <span class="na">id=</span><span class="s">"spinny"</span> <span class="na">alt=</span><span class="s">"Loading..."</span><span class="nt">&gt;</span>
<span class="nt">&lt;progress</span> <span class="na">id=</span><span class="s">"loader_progress"</span><span class="nt">&gt;&lt;/progress&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="c">&lt;!--
This is hideous. airframes.org insists on getting a POST with a "submit" value specified,
but if we have an input control with that name then it shadows the submit() function that
we need. So steal the submit function off a different form. Surely there is a better way?!
--&gt;</span>
<span class="nt">&lt;form</span> <span class="na">id=</span><span class="s">"horrible_hack"</span> <span class="na">class=</span><span class="s">"hidden"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/form&gt;</span>
<span class="nt">&lt;form</span> <span class="na">id=</span><span class="s">"airframes_post"</span> <span class="na">method=</span><span class="s">"POST"</span> <span class="na">action=</span><span class="s">"http://www.airframes.org/"</span> <span class="na">target=</span><span class="s">"_blank"</span> <span class="na">class=</span><span class="s">"hidden"</span><span class="nt">&gt;</span>
<span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"reg1"</span> <span class="na">value=</span><span class="s">""</span><span class="nt">&gt;</span>
<span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"selcal"</span> <span class="na">value=</span><span class="s">""</span><span class="nt">&gt;</span>
<span class="nt">&lt;input</span> <span class="na">id=</span><span class="s">"airframes_post_icao"</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"ica024"</span> <span class="na">value=</span><span class="s">""</span><span class="nt">&gt;</span>
<span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"hidden"</span> <span class="na">name=</span><span class="s">"submit"</span> <span class="na">value=</span><span class="s">"submit"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/form&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"map_container"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"map_canvas"</span><span class="nt">&gt;&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"sidebar_container"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"sidebar_canvas"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"timestamps"</span><span class="nt">&gt;</span>
<span class="nt">&lt;table</span> <span class="na">style=</span><span class="s">"width: 100%"</span><span class="nt">&gt;</span>
<span class="nt">&lt;tr&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: center"</span><span class="nt">&gt;</span> <span class="nt">&lt;canvas</span> <span class="na">id=</span><span class="s">"utcclock"</span><span class="nt">&gt;&lt;/canvas&gt;</span> <span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: center"</span><span class="nt">&gt;</span> <span class="nt">&lt;canvas</span> <span class="na">id=</span><span class="s">"receiverclock"</span><span class="nt">&gt;&lt;/canvas&gt;</span> <span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: center"</span><span class="nt">&gt;</span>Heure UTC<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: center"</span><span class="nt">&gt;</span>Dernières mises à jour<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;/table&gt;</span>
<span class="nt">&lt;/div&gt;</span> <span class="c">&lt;!-- timestamps --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"sudo_buttons"</span><span class="nt">&gt;</span>
<span class="nt">&lt;table</span> <span class="na">style=</span><span class="s">"width: 100%"</span><span class="nt">&gt;</span>
<span class="nt">&lt;tr&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"width: 150px; text-align: center;"</span> <span class="na">class=</span><span class="s">"pointer"</span><span class="nt">&gt;</span>
[ <span class="nt">&lt;span</span> <span class="na">onclick=</span><span class="s">"resetMap();"</span><span class="nt">&gt;</span>Reset Carte<span class="nt">&lt;/span&gt;</span> ]
<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;/table&gt;</span>
<span class="nt">&lt;/div&gt;</span> <span class="c">&lt;!-- sudo_buttons --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"dump1090_infoblock"</span><span class="nt">&gt;</span>
<span class="nt">&lt;table</span> <span class="na">style=</span><span class="s">"width: 100%"</span><span class="nt">&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_heading"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span>
<span class="nt">&lt;b</span> <span class="na">id=</span><span class="s">"infoblock_name"</span><span class="nt">&gt;</span>Radar Virtuel<span class="nt">&lt;/b&gt;</span>
<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>
<span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"https://github.com/mutability/dump1090"</span> <span class="na">id=</span><span class="s">"dump1090_version"</span> <span class="na">target=</span><span class="s">"_blank"</span><span class="nt">&gt;&lt;/a&gt;</span>
<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span><span class="ni">&amp;nbsp;</span><span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;</span><span class="ni">&amp;nbsp;</span><span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body dim"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span>(Aucun aéronef sélectionné)<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;</span><span class="ni">&amp;nbsp;</span><span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span><span class="ni">&amp;nbsp;</span><span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;</span><span class="ni">&amp;nbsp;</span><span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span>Aéronef (Nb total): <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"dump1090_total_ac"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;</span>Messages: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"dump1090_message_rate"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;</span>/sec<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span>(Réception correcte): <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"dump1090_total_ac_positions"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;</span>Historique: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"dump1090_total_history"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;</span> positions<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;/table&gt;</span>
<span class="nt">&lt;/div&gt;</span> <span class="c">&lt;!-- dump1090_infoblock --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"selected_infoblock"</span> <span class="na">class=</span><span class="s">"hidden"</span><span class="nt">&gt;</span>
<span class="nt">&lt;table</span> <span class="na">style=</span><span class="s">"width: 100%"</span><span class="nt">&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_heading"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td</span> <span class="na">colspan=</span><span class="s">"2"</span><span class="nt">&gt;</span>
<span class="nt">&lt;b&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_callsign"</span> <span class="na">onclick=</span><span class="s">"toggleFollowSelected();"</span> <span class="na">class=</span><span class="s">"pointer"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/b&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_follow"</span> <span class="na">onclick=</span><span class="s">"toggleFollowSelected();"</span> <span class="na">class=</span><span class="s">"pointer"</span><span class="nt">&gt;</span><span class="ni">&amp;#x21D2;</span><span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_flag"</span><span class="nt">&gt;</span>
<span class="nt">&lt;img</span> <span class="na">style=</span><span class="s">"width: 20px; height=12px"</span> <span class="na">src=</span><span class="s">"about:blank"</span> <span class="na">alt=</span><span class="s">"Flag"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"http://www.airframes.org/"</span> <span class="na">onclick=</span><span class="s">"document.getElementById('horrible_hack').submit.call(document.getElementById('airframes_post')); return false;"</span><span class="nt">&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_icao"</span><span class="nt">&gt;&lt;/span&gt;</span>
<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_registration"</span><span class="nt">&gt;&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_icaotype"</span><span class="nt">&gt;&lt;/span&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_emergency"</span><span class="nt">&gt;&lt;/span&gt;</span>
<span class="nt">&lt;a</span> <span class="na">id=</span><span class="s">"selected_flightaware_link"</span> <span class="na">href=</span><span class="s">""</span> <span class="na">target=</span><span class="s">"_blank"</span><span class="nt">&gt;</span>[FlightAware]<span class="nt">&lt;/a&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_links"</span><span class="nt">&gt;</span>
<span class="nt">&lt;a</span> <span class="na">id=</span><span class="s">"selected_fr24_link"</span> <span class="na">href=</span><span class="s">""</span> <span class="na">target=</span><span class="s">"_blank"</span><span class="nt">&gt;</span>[FR24]<span class="nt">&lt;/a&gt;</span>
<span class="c">&lt;!--
&lt;a id="selected_flightstats_link" href="" target="_blank"&gt;[FlightStats]&lt;/a&gt;
&lt;a id="selected_planefinder_link" href="" target="_blank"&gt;[PlaneFinder]&lt;/a&gt;
--&gt;</span>
<span class="nt">&lt;/span&gt;</span>
<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">id=</span><span class="s">"infoblock_country"</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td</span> <span class="na">colspan=</span><span class="s">"2"</span><span class="nt">&gt;</span>Enregistrement (pays): <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_country"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"width: 55%"</span><span class="nt">&gt;</span>Altitude: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_altitude"</span><span class="nt">&gt;&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"width: 45%"</span><span class="nt">&gt;</span>Squawk: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_squawk"</span><span class="nt">&gt;&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span>Vitesse: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_speed"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;</span>RSSI: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_rssi"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span>Direction: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_track"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;</span>Dernière vue: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_seen"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td</span> <span class="na">colspan=</span><span class="s">"2"</span><span class="nt">&gt;</span>Position: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_position"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">class=</span><span class="s">"infoblock_body"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td</span> <span class="na">colspan=</span><span class="s">"2"</span><span class="nt">&gt;</span>Distance antenne: <span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"selected_sitedist"</span><span class="nt">&gt;</span>n/a<span class="nt">&lt;/span&gt;&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;/table&gt;</span>
<span class="nt">&lt;/div&gt;</span> <span class="c">&lt;!-- selected_infoblock --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"planes_table"</span><span class="nt">&gt;</span>
<span class="nt">&lt;table</span> <span class="na">id=</span><span class="s">"tableinfo"</span> <span class="na">style=</span><span class="s">"width: 100%"</span><span class="nt">&gt;</span>
<span class="nt">&lt;thead</span> <span class="na">style=</span><span class="s">"background-color: #BBBBBB; cursor: pointer;"</span><span class="nt">&gt;</span>
<span class="nt">&lt;tr&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"icao"</span> <span class="na">onclick=</span><span class="s">"sortByICAO();"</span><span class="nt">&gt;</span>ICAO<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"flag"</span> <span class="na">onclick=</span><span class="s">"sortByCountry()"</span><span class="nt">&gt;</span><span class="c">&lt;!-- column for flag image --&gt;</span><span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"flight"</span> <span class="na">onclick=</span><span class="s">"sortByFlight();"</span><span class="nt">&gt;</span>Indicatif<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"squawk"</span> <span class="na">onclick=</span><span class="s">"sortBySquawk();"</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>Squawk<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"altitude"</span> <span class="na">onclick=</span><span class="s">"sortByAltitude();"</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>Altitude<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"speed"</span> <span class="na">onclick=</span><span class="s">"sortBySpeed();"</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>Vitesse<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"distance"</span> <span class="na">onclick=</span><span class="s">"sortByDistance();"</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>Distance<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"track"</span> <span class="na">onclick=</span><span class="s">"sortByTrack();"</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>Direction<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"msgs"</span> <span class="na">onclick=</span><span class="s">"sortByMsgs();"</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>Msgs<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">id=</span><span class="s">"seen"</span> <span class="na">onclick=</span><span class="s">"sortBySeen();"</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>Age<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;/thead&gt;</span>
<span class="nt">&lt;tbody&gt;</span>
<span class="nt">&lt;tr</span> <span class="na">id=</span><span class="s">"plane_row_template"</span> <span class="na">class=</span><span class="s">"plane_table_row hidden"</span><span class="nt">&gt;</span>
<span class="nt">&lt;td&gt;</span>ICAO<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;&lt;img</span> <span class="na">style=</span><span class="s">"width: 20px; height=12px"</span> <span class="na">src=</span><span class="s">"about:blank"</span> <span class="na">alt=</span><span class="s">"Flag"</span><span class="nt">&gt;&lt;/td&gt;</span>
<span class="nt">&lt;td&gt;</span>FLIGHT<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>SQUAWK<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>ALTITUDE<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>SPEED<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>DISTANCE<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>TRACK<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>MSGS<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;td</span> <span class="na">style=</span><span class="s">"text-align: right"</span><span class="nt">&gt;</span>SEEN<span class="nt">&lt;/td&gt;</span>
<span class="nt">&lt;/tr&gt;</span>
<span class="nt">&lt;/tbody&gt;</span>
<span class="nt">&lt;/table&gt;</span>
<span class="nt">&lt;/div&gt;</span> <span class="c">&lt;!-- planes_table --&gt;</span>
<span class="nt">&lt;/div&gt;</span> <span class="c">&lt;!-- sidebar_canvas --&gt;</span>
<span class="nt">&lt;/div&gt;</span> <span class="c">&lt;!-- sidebar_container --&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"SpecialSquawkWarning"</span> <span class="na">class=</span><span class="s">"hidden"</span><span class="nt">&gt;</span>
<span class="nt">&lt;b&gt;</span>Squawk 7x00 is reported and shown.<span class="nt">&lt;/b&gt;&lt;br&gt;</span>
This is most likely an error in receiving or decoding.<span class="nt">&lt;br&gt;</span>
Please do not call the local authorities, they already know about it if it is a valid squawk.
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"update_error"</span> <span class="na">class=</span><span class="s">"hidden"</span><span class="nt">&gt;</span>
<span class="nt">&lt;b&gt;</span>Problem fetching data from dump1090.<span class="nt">&lt;/b&gt;&lt;br&gt;</span>
<span class="nt">&lt;span</span> <span class="na">id=</span><span class="s">"update_error_detail"</span><span class="nt">&gt;&lt;/span&gt;&lt;br&gt;</span>
The displayed map data will be out of date.
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"container_splitter"</span><span class="nt">&gt;&lt;/div&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>
<h3 id="tester-le-serveur">Tester le serveur</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
./start_flight_radar.sh #Appuyer sur entrée pour récupérer le curseur
sudo service lighttpd reload
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ ok ] Reloading web server configuration: lighttpd.
</code></pre></div></div>
<p>Maintenant ouvrez une page web à ladresse de votre Raspberry Pi <a href="http://192.168.0.36/dump1090">http://192.168.0.36/dump1090</a> (remplacer 192.168.0.36 par ladresse IP de votre raspberry)<br />
Vous devriez voir une carte avec les données de tous les avions à portée.</p>
<p><img src="/images/flight-radar-home.png" alt="alt text" title="vue flight radar" /></p>
<h3 id="partager-vos-données-avec-flightradar24">Partager vos données avec FlightRadar24</h3>
<p>Pour partager vos données avec FlightRadar24, vous devez fournir un flux compatible TCP30003<br />
Installer le logiciel :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cd ~
mkdir fr24
cd fr24/
wget https://dl.dropboxusercontent.com/u/66906/fr24feed_arm-rpi_242.tgz
tar zxvf fr24feed_arm-rpi_242.tgz
</code></pre></div></div>
<p>Inscrivez vous pour obtenir une clé :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./fr24feed_arm-rpi_242 --signup
</code></pre></div></div>
<p>Remplissez le questionnaire. Vous aurez besoin des coordonnées décimales de votre récepteur. Une fois que vous aurez obtenu la clé, vous pouvez partager vos données<br />
Test de la transmission des données (remplacer <key> par votre clé)</key></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./fr24feed_arm-rpi_242 --fr24key=&lt;key&gt; --bs-ip=127.0.0.1 --bs-port=30003
</code></pre></div></div>
<p>Modifier le fichier <strong>start_flight_radar.sh</strong> pour y ajouter le partage</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /home/pi/start_flight_radar.sh
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/sh
# Dump1090
cd /home/pi/dump1090/
if [ -d "/run/dump1090" ]
then
echo "/run/dump1090 exists."
else
sudo mkdir -p /run/dump1090-mutability
sudo chown pi. -R /run/dump1090-mutability/ #droits pour utilisateur pi
fi
#
./dump1090 --net --ppm 0 --oversample --fix --phase-enhance --lat 47.27076 --lon -1.02527 --max-range 300 --net-http-port 0 --net-ri-port 30001 --net-ro-port 30002 --net-bi-port 30004 --net-bo-port 30005 --net-sbs-port 30003 --net-heartbeat 60 --net-ro-size 500 --net-ro-interval 1 --net-buffer 2 --net-bind-address 127.0.0.1 --stats-every 3600 --write-json /run/dump1090-mutability --write-json-every 1 --json-location-accuracy 2 --quiet&amp;
# Partage
cd /home/pi/fr24/
sudo pkill -f fr24feed
./fr24feed_arm-rpi_242 --fr24key=&lt;key&gt; --bs-ip=127.0.0.1 --bs-port=30003
</code></pre></div></div>
<p>Remplacer &lt;key&gt; par votre clé</p>
<h3 id="lancement-au-démarrage">Lancement au démarrage</h3>
<p>Création du service <strong>flightradar</strong></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/init.d/flightradar
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
# /etc/init.d/flightradar
### BEGIN INIT INFO
# Provides: flightradar
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Flight Radar
# Description: Flight Radar (ADS-B Receiver)
### END INIT INFO
case "$1" in
start)
echo "Starting flightradar"
/home/pi/start_flight_radar.sh &amp;
;;
stop)
echo "Stopping flightradar"
killall dump1090
;;
*)
echo "Usage: /etc/init.d/flightradar start|stop"
exit 1
;;
esac
exit 0
</code></pre></div></div>
<p>Rendre le script exécutable et configurer update-rc.d</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo chmod</span> +x /etc/init.d/flightradar
<span class="nb">sudo </span>update-rc.d flightradar defaults
</code></pre></div></div>
<p>Avant de lancer le service , on arrête les éventuels tests en cours</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pkill -f dump1090 #flightradar
sudo pkill -f fr24feed #partage
</code></pre></div></div>
<p>Démarrer le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo service flightradar start
</code></pre></div></div>
<p>Relancer le serveur</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo service lighttpd restart
</code></pre></div></div>
<p>Pour arrêter et désactiver le service</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl stop flightradar
sudo systemctl disable flightradar
</code></pre></div></div>
<p><strong>Conclusion</strong></p>
<p>le sujet vous intéresse, rejoignez le <a href="http://forums.framboise314.fr/viewtopic.php?f=36&amp;t=65&amp;p=6619#p1844">forum de framboise314</a> : Un tutoriel de <strong>Mmega</strong> vous y attend, ainsi quune intéressante discussion sur lADS-B…</p>
<h3 id="personnalisation-de-laffichage-de-dump1090">Personnalisation de laffichage de Dump1090</h3>
<p>Il est possible de personnaliser votre affichage comme indiqué plus haut.<br />
Fichier <strong>/home/pi/dump1090/public_html/config.js</strong> est modifié comme suit :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// --------------------------------------------------------</span>
<span class="c1">//</span>
<span class="c1">// Ce fichier permet de modifier l'affichage sous Dump1090.</span>
<span class="c1">// Chargez ce fichier avant script.js dans gmap.html.</span>
<span class="c1">//</span>
<span class="c1">// --------------------------------------------------------</span>
<span class="c1">// -- Valeurs de sortie -------------------------------------</span>
<span class="c1">// Affichage métrique : true pour afficher en km</span>
<span class="nx">Metric</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// true ou false</span>
<span class="c1">// -- Configuration de la carte -----------------------------</span>
<span class="c1">// Latitude et Longitude en format décimal</span>
<span class="c1">// Indique le centre de la carte qui sera affichée</span>
<span class="nx">CONST_CENTERLAT</span> <span class="o">=</span> <span class="mf">47.27076</span><span class="p">;</span>
<span class="nx">CONST_CENTERLON</span> <span class="o">=</span> <span class="o">-</span><span class="mf">1.02527</span><span class="p">;</span>
<span class="c1">// Niveau de zoom google map de 0 à 16, 0 est le plus éloigné</span>
<span class="nx">CONST_ZOOMLVL</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="c1">// -- Paramètres des marqueurs -------------------------------</span>
<span class="c1">// Couleur par défaut des marqueurs</span>
<span class="nx">MarkerColor</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">rgb(127, 127, 127)</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">SelectedColor</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">rgb(225, 225, 225)</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">StaleColor</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">rgb(190, 190, 190)</span><span class="dl">"</span><span class="p">;</span>
<span class="c1">// -- Configuration du site de réception ---------------------</span>
<span class="c1">// true affiche une cible aux coordonnées indiquées</span>
<span class="c1">// les coordonnées de l'antenne</span>
<span class="nx">SiteShow</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// true ou false</span>
<span class="c1">// Latitude et Longitude en format décimal</span>
<span class="nx">SiteLat</span> <span class="o">=</span> <span class="mf">47.27076</span><span class="p">;</span>
<span class="nx">SiteLon</span> <span class="o">=</span> <span class="o">-</span><span class="mf">1.02527</span><span class="p">;</span>
<span class="c1">// -- Dessin des cercles donnant la distance des avions ------</span>
<span class="c1">// Les cercles ne sont affichés que si SiteShow est sur true</span>
<span class="nx">SiteCircles</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// true ou false </span>
<span class="c1">// In miles nautiques ou en km (selon la valeur de 'Metric')</span>
<span class="c1">// Afficher des cercles à 50km, 100km, 150km et 200km</span>
<span class="nx">SiteCirclesDistances</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Array</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">150</span><span class="p">,</span><span class="mi">200</span><span class="p">);</span>
</code></pre></div></div>
<p><img src="/images/dump1090-cercles.png" alt="alt text" title="dump1090" /></p>
<h3 id="laffichage-sur-la-console-du-raspberry-pi">Laffichage sur la console du Raspberry Pi</h3>
<p><strong>Dump1090</strong> possède de nombreuses options accessibles par la commande</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./dump1090 --help
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-----------------------------------------------------------------------------
| dump1090 ModeS Receiver Ver : 1.10.3010.14 |
-----------------------------------------------------------------------------
--device-index &lt;index&gt; Select RTL device (default: 0)
--gain &lt;db&gt; Set gain (default: max gain. Use -10 for auto-gain)
--enable-agc Enable the Automatic Gain Control (default: off)
--freq &lt;hz&gt; Set frequency (default: 1090 Mhz)
--ifile &lt;filename&gt; Read data from file (use '-' for stdin)
--interactive Interactive mode refreshing data on screen
--interactive-rows &lt;num&gt; Max number of rows in interactive mode (default: 15)
--interactive-ttl &lt;sec&gt; Remove from list if idle for &lt;sec&gt; (default: 60)
--interactive-rtl1090 Display flight table in RTL1090 format
--raw Show only messages hex values
--net Enable networking
--modeac Enable decoding of SSR Modes 3/A &amp; 3/C
--net-beast TCP raw output in Beast binary format
--net-only Enable just networking, no RTL device or file used
--net-bind-address &lt;ip&gt; IP address to bind to (default: Any; Use 127.0.0.1 for private)
--net-http-port &lt;port&gt; HTTP server port (default: 8080)
--net-ri-port &lt;port&gt; TCP raw input listen port (default: 30001)
--net-ro-port &lt;port&gt; TCP raw output listen port (default: 30002)
--net-sbs-port &lt;port&gt; TCP BaseStation output listen port (default: 30003)
--net-bi-port &lt;port&gt; TCP Beast input listen port (default: 30004)
--net-bo-port &lt;port&gt; TCP Beast output listen port (default: 30005)
--net-ro-size &lt;size&gt; TCP raw output minimum size (default: 0)
--net-ro-rate &lt;rate&gt; TCP raw output memory flush rate (default: 0)
--net-heartbeat &lt;rate&gt; TCP heartbeat rate in seconds (default: 60 sec; 0 to disable)
--net-buffer &lt;n&gt; TCP buffer size 64Kb * (2^n) (default: n=0, 64Kb)
--lat &lt;latitude&gt; Reference/receiver latitude for surface posn (opt)
--lon &lt;longitude&gt; Reference/receiver longitude for surface posn (opt)
--fix Enable single-bits error correction using CRC
--no-fix Disable single-bits error correction using CRC
--no-crc-check Disable messages with broken CRC (discouraged)
--phase-enhance Enable phase enhancement
--aggressive More CPU for more messages (two bits fixes, ...)
--mlat display raw messages in Beast ascii mode
--stats With --ifile print stats at exit. No other output
--stats-every &lt;seconds&gt; Show and reset stats every &lt;seconds&gt; seconds
--onlyaddr Show only ICAO addresses (testing purposes)
--metric Use metric units (meters, km/h, ...)
--snip &lt;level&gt; Strip IQ file removing samples &lt; level
--debug &lt;flags&gt; Debug mode (verbose), see README for details
--quiet Disable output to stdout. Use for daemon applications
--ppm &lt;error&gt; Set receiver error in parts per million (default 0)
--help Show this help
Debug mode flags: d = Log frames decoded with errors
D = Log frames decoded with zero errors
c = Log frames with bad CRC
C = Log frames with good CRC
p = Log frames with bad preamble
n = Log network debugging info
j = Log frames to frames.js, loadable by debug.html
</code></pre></div></div>
<p>Si vous souhaitez afficher un tableau plus lisible que le défilé rapide des messages envoyé par dump1090 vers la console du Raspberry Pi, ajoutez <strong>interactive</strong> à la ligne de commande, vous pourrez lire un tableau identique à celui qui apparait sur la page web</p>
<h2 id="antennes">Antennes</h2>
<h4 id="antenne-colinéaire-coaxiale">Antenne colinéaire coaxiale</h4>
<p>Traduction partielle de larticle original <a href="http://www.balarad.net/">“Coaxial Collinear Antenna for ADS-B Receiver”</a> de <a href="balarad@balarad.net">Dusan Balara</a></p>
<p>Les composants.</p>
<ul>
<li>câble coaxial de 75 ohms utilisé pour la TV satellite ou câble coaxial de 50 ohms.</li>
<li>connecteur de type F ou SMA</li>
<li>ruban isolant</li>
<li>un tuyau en PVC avec un diamètre extérieur de 12 mm et un joint détanchéité approprié pour ce tuyau.</li>
</ul>
<p>Les outils nécessaires sont létrier, le couteau tranchant, les ciseaux, la colle pour le PVC et lohmmètre.</p>
<p>Lélément de base de lantenne colinéaire coaxiale est le câble coaxial dont la longueur est calculée à partir de la longueur donde du signal ADS-B.</p>
<p>La longueur donde du signal est</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lambda = c/f
</code></pre></div></div>
<p><strong>c</strong> est la vitesse du signal électromagnétique,dans le vide, ( c = 300 000 millions de mètres par seconde), <strong>f</strong> est la fréquence du signal ADS-B ( f = 1090 MHz),</p>
<p>la longueur donde lambda est de 275 mm.</p>
<p>La longueur L de lélément de base est la demi-longueur donde réduite par le facteur de vitesse du câble coaxial (la vitesse des ondes électromagnétiques dans le câble coaxial est inférieure). Jai utilisé le câble 75 Ohm RG-6U/32FD avec le facteur de vitesse 0.85 et 50 Ohm câble Tri-Lan 240 avec le facteur de vitesse 0.83 et jai utilisé la même longueur délément pour les deux câbles, soit :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>L=0.5*275mm*0.85=116 mm.
</code></pre></div></div>
<p><img src="/images/antenne-1.png" alt="alt text" title="L'élément de base de l'antenne" /></p>
<p>Les éléments de base sont reliés à la chaîne dans laquelle les conducteurs extérieurs et les conducteurs intérieurs sont contrebalancés entre deux éléments adjacents</p>
<p><img src="/images/antenne-2.png" alt="alt text" title="Antenne colinéaire coaxiale" /></p>
<p>De tels éléments assemblés sont encore la ligne coaxiale. Cette ligne est connectée au récepteur avec limpédance dentrée symétrique 50 Ohm. Mes expériences ont indiqué quil est bénéfique de connecter les conducteurs extérieurs et intérieurs sur lextrémité opposée avec les 75 Ohm ou 50 Ohm pour préserver le VSWR près de 1.</p>
<div class="extensions extensions--video">
<iframe src="https://www.youtube.com/embed/TkUYdCPFXXs?rel=0&amp;showinfo=0" frameborder="0" scrolling="no" allowfullscreen=""></iframe>
</div>
<h4 id="antenne-colinéaire-compacte">Antenne colinéaire compacte</h4>
<p><strong>Approche A</strong><br />
Ce colinéaire se compose simplement dun fil de cuivre de 2.5mm² avec quelques boucles situées à des emplacements spécifiques. Les dimensions des sections de lantenne sont importantes et sont illustrées dans le schéma ci-dessous.</p>
<p><img src="/images/antenne-3.png" alt="alt text" title="Dimensions du colinéaire" /></p>
<p>La longueur de la section inférieure est de 1/2 longueur donde (la section gauche dans le diagramme ci-dessus), la section centrale est 3/4 de longueur donde, et la section de fouet sur le dessus est légèrement moins de 3/4 longueur donde, apparemment pour réduire leffet de capacité.</p>
<p>Le standard ADS-B utilise la fréquences de 1090 MHz (longueur donde 275 mm), donc la 1/2 longueur donde est de 137.5 mm et la 3/4 de longueur donde est de 206 mm.<br />
Si vous avez lintention dutiliser un conduit isolant de 20 mm de diamètre pour loger votre antenne, assurez-vous que le diamètre des boucles soit environ 15 mm ou moins.<br />
Certains tests de comparaison rapide indiquent que le colinéaire avec les boucles de décalage fonctionne beaucoup mieux que le colinéaire avec les boucles centrées.</p>
<p><img src="/images/antenne-5.png" alt="alt text" title="boucles de décalage" /></p>
<p>Avec plus de gain</p>
<p><img src="/images/antenne-4.png" alt="alt text" title="colinéaire + de gain" /></p>
<p><strong>Approche B</strong><br />
Les signaux du transpondeur sont polarisés verticalement. Une antenne polarisée verticale accordée à 1090 MHz est nécessaire pour recevoir ces signaux. La solution la plus simple est un fil vertical ou un bâton métallique de 13 cm de longueur, cest la demi-longueur donde du signal de 1090 MHz. Une telle antenne est un dipôle électrique et reçoit des signaux de toutes les directions.</p>
<p>Pour améliorer la sensibilité des antennes, plusieurs dipôles électriques peuvent être combinés. Mais si elles sont placées côte à côte, alors lantenne ne serait plus une antenne omnidirectionnelle. Par conséquent, les dipôles individuels doivent être placés lun autour de lautre. Enfin, les dipôles doivent être interconnectés, mais les extrémités supérieure et inférieure de chaque dipôle oscillent avec un déphasage de 180 degrés. Pour les connecter, des boucles horizontales de 130 mm doivent être utilisées. Ils fonctionnent comme un déphaseur de 180 degrés.</p>
<p>Dipoles et boucles devraient être pliées à partir dun long morceau de fil. Son diamètre doit être suffisamment grand pour la stabilité nécessaire. Le point le plus bas de ce groupe de dipôles doit être connecté au fil central dun câble coaxial de 50 ohms.</p>
<p>Maintenant, nous avons besoin dun “faux-sol”, qui doit être connecté à lécran du câble coaxial. Un morceau rond de tôle (rayon de 13 cm) serait grand, mais certains fils radiaux peuvent être utilisés à la place. Au moins 4 fils (90 ° interspaces) doivent être utilisés (antenne-plan de masse). “Dummy-ground” et le dipôle nont pas à se toucher!</p>
<p><img src="/images/antenne6.gif" alt="alt text" title="colinéaire" /></p>
<h4 id="antenne-dipole">Antenne dipole</h4>
<p><a href="http://antirez.com/news/46">ADS-B wine cork dipole antenna</a></p>
<p><img src="/images/antenne7.jpg" alt="alt text" title="L=137mm" /></p>
<p><img src="/images/antenne8.jpg" alt="alt text" title="autre modèle" /></p>
<h2 id="liens">Liens</h2>
<ul>
<li><a href="http://sboisse.free.fr/technique/ADS-B.php">ADS-B</a></li>
<li><a href="http://www.framboise314.fr/un-raspberry-pi-pour-suivre-les-avions-sur-flightradar24-2/">raspberry pi pour suivre les avions sur flightradar24</a></li>
<li><a href="http://www.satsignal.eu/raspberry-pi/dump1090.html">dump1090</a></li>
<li><a href="http://forum.flightradar24.com/threads/8908-New-Flightradar24-feeding-software-for-Raspberry-Pie?p=66479#post66479">New Flightradar24 feeding software for Raspberry Pi</a></li>
<li><a href="http://blogwifi.fr/?p=13353">http://blogwifi.fr/?p=13353</a></li>
<li><a href="http://blogwifi.fr/?p=13343">http://blogwifi.fr/?p=13343</a></li>
<li><a href="http://pygmalion.nitri.de/flight-radar-with-raspberry-pi-and-an-sdr-dongle-637.html">http://pygmalion.nitri.de/flight-radar-with-raspberry-pi-and-an-sdr-dongle-637.html</a></li>
<li><a href="http://www.flightradar24.com">http://www.flightradar24.com</a></li>
<li><a href="https://github.com/antirez/dump1090">https://github.com/antirez/dump1090</a></li>
<li><a href="http://antirez.com/news/46">http://antirez.com/news/46</a></li>
<li><a href="http://www.capital.fr/bourse/actualites/flightradar24-ce-site-stupefiant-que-le-grand-public-a-decouvert-avec-le-crash-de-l-a320-1026205 ">http://www.capital.fr/bourse/actualites/flightradar24-ce-site-stupefiant-que-le-grand-public-a-decouvert-avec-le-crash-de-l-a320-1026205 </a></li>
<li><a href="http://www.balarad.net/">http://www.balarad.net/</a></li>
<li><a href="http://f5ann.pagesperso-orange.fr/">http://f5ann.pagesperso-orange.fr/</a></li>
<li><a href="http://www.rtl-sdr.com/homemade-ads-b-filter/">http://www.rtl-sdr.com/homemade-ads-b-filter/</a></li>
<li><a href="http://forum.flightradar24.com/archive/index.php/t-3831.html">http://forum.flightradar24.com/archive/index.php/t-3831.html</a></li>
<li><a href="http://forums.framboise314.fr/viewtopic.php?f=36&amp;t=65&amp;p=6619#p1844">http://forums.framboise314.fr/viewtopic.php?f=36&amp;t=65&amp;p=6619#p1844</a></li>
</ul>
<h2 id="wifi-raspberry-1-et-2">Wifi Raspberry 1 et 2</h2>
<p><img src="/images/WNA-1OOOM.jpg" alt="alt text" title="WNA1000M 802.11bgn [Realtek RTL8188CUS]" /></p>
<p>Utliser un dongle wifi pour se connecter au réseau local ,<code class="language-plaintext highlighter-rouge">lsusb</code> pour connaître le modèle</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Bus 001 Device 004: ID 0846:9041 NetGear, Inc. WNA1000M 802.11bgn [Realtek RTL8188CUS]
</code></pre></div></div>
<blockquote>
<p>les pilotes realtek et ralink sont installés par défaut avec raspian</p>
</blockquote>
<p>Configurer les paramètres du rréseau WIFI<br />
Ouvrir le fichier de configuration <strong>wpa-supplicant</strong> dans nano:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>country=FR
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
</code></pre></div></div>
<p>Remplacer GB par FR dans country<br />
Allez dans le bas du fichier et ajoutez ce qui suit:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>network={
ssid="YanHotSpot"
psk="testingPassword"
}
</code></pre></div></div>
<p>Si vous avez besoin de vous connecter à un réseau privé (qui ne diffuse pas son SSID) ajoutez la ligne <code class="language-plaintext highlighter-rouge">scan_ssid=1</code> à lintérieur du bloc <code class="language-plaintext highlighter-rouge">network=</code></p>
<blockquote>
<p>NOTE : il y a de nombreuses autres options qui peuvent être utilisés. Lisez la page <strong>man wpa_supplicant.conf</strong>.</p>
</blockquote>
<p>Maintenant, enregistrez le fichier en appuyant sur <em>Ctrl + X puis Y</em>, puis appuyez sur <em>Enter</em>.</p>
<p>À ce stade, <strong>wpa-supplicant</strong> remarquera normalement un changement sest produite en quelques secondes, et il va essayer de se connecter au réseau. <br />
Si ce nest pas le cas, redémarrez manuellement linterface avec <code class="language-plaintext highlighter-rouge">sudo ifdown wlan0</code> et <code class="language-plaintext highlighter-rouge">sudo ifup wlan0</code>, ou redémarrez votre Raspberry Pi avec <code class="language-plaintext highlighter-rouge">sudo reboot</code>.</p>
<p>Vous pouvez vérifier sil sest correctement connecté en utilisant <code class="language-plaintext highlighter-rouge">ifconfig wlan0</code>. <br />
Si le champ <strong>inet addr</strong> a une adresse à côté, le Pi est connecté au réseau. <br />
Sinon, vérifiez que votre mot de passe et ESSID sont corrects.</p>
<h2 id="solutions-de-streaming-kafka--ksql">Solutions de streaming Kafka &amp; KSQL</h2>
<ul>
<li><a href="https://hackaday.com/2018/06/05/cat-compels-raspberry-pi-flight-tracker/">Cat Compels Raspberry Pi Flight Tracker</a></li>
<li><a href="https://medium.com/@simon.aubury/using-ksql-apache-kafka-a-raspberry-pi-and-a-software-defined-radio-to-find-the-plane-that-wakes-14f6f9e74584">Using KSQL, Apache Kafka, a Raspberry Pi and a software defined radio to find the plane</a></li>
<li><a href="https://openflights.org/data.html">Airport and airline data</a></li>
</ul>
<p>Utiliser des solutions de streaming open source (Apache Kafka), KSQL (moteur de streaming SQL) et un Raspberry Pi pour traiter les mouvements davions en temps réel.<a href="https://github.com/saubury/plane-kafka">Plane Kafka - Plane tracking with KSQL and a Raspberry Pi</a></p>
<p><img src="/images/plane-kafka-01.png" alt="Kafka Kibana" /><br />
<a href="https://github.com/saubury/plane-kafka">https://github.com/saubury/plane-kafka</a></p>
</div>
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2018-08-27T00:00:00+02: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>
&emsp;</div>
-->
</footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2018/08/11/OVH4-KVM-vps506197-Yunohost3.0-yanfi.net.html">OVH VPS506197 Yunohost yanfi.net</a></div><div class="next"><span>SUIVANT</span><a href="/2018/08/29/Gitlab-Authentification-Double-Facteur-2FA.html">Gitlab authentification double facteur (2FA)</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}&nbsp;{title}</a>&nbsp;(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>