Commit 583a8e81a1c9
Changed files (164)
www
vincent.demeester.fr
.fancyindex
about
assets
css
images
2012
2016
2019
01
emacs
tekton
www-inspirations
legacy
posts
2012-05-07-reinit-and-jekyll
2012-05-08-gitolite-quick-and-dirty-mirror
2012-05-13-jekyll-foreman-guard-bundler
2012-07-21-news
2012-07-23-maven-release-gitflow
2012-12-16-gollum-comme-wiki-personnel
2013-09-08-maven-tmpfs
2013-10-12-podcasts
2014-03-24-redesign-et-rรฉsolutions
2014-10-27-docker-1.3-ecosystem
2015-05-01-orgmode-et-jekyll
2015-05-09-migration-to-hugo
2015-06-01-docker-1.6-ecosystem
2015-07-31-config-managment-intro
2016-09-18-firefox-places-and-bookmarks
2017-01-01-go-testing-functionnal-builders
2017-04-22-golang-testing-golden-file
2018-07-28-gotest-tools-intro
2018-08-16-gotest-tools-assertions
2018-09-01-gotest-tools-skip
2018-09-06-gotest-tools-golden
2018-09-14-gotest-tools-fs
2018-09-18-gotest-tools-icmd
2018-12-16-link
2019-01-10-link
2019-01-20-2018-year-review
2019-01-26-nix-run-alias
2019-01-27-link
2019-02-15-link
2019-02-25-link
2019-03-12-link
2019-03-23-gotest-tools-poll
2019-03-24-link
2019-03-26-link
2019-03-27-link
2019-03-28-link
2019-03-31-link
2019-04-18-link
2019-04-19-link
2019-04-23-link
2019-05-11-link
2019-06-28-link
posts
templates
www/vincent.demeester.fr/.fancyindex/addNginxFancyIndexForm.js
@@ -0,0 +1,33 @@
+// addNginxFancyIndexForm.js
+// Add a small form to filter through the output of Nginx FancyIndex page
+// ยฉ 2017, Lilian Besson (Naereen) and contributors,
+// open-sourced under the MIT License, https://lbesson.mit-license.org/
+// hosted on GitHub, https://GitHub.com/Naereen/Nginx-Fancyindex-Theme
+var form = document.createElement('form');
+var input = document.createElement('input');
+
+input.name = 'filter';
+input.id = 'search';
+input.placeholder = 'Type to search...';
+
+form.appendChild(input);
+
+document.querySelector('h1').after(form);
+
+var listItems = [].slice.call(document.querySelectorAll('#list tbody tr'));
+
+input.addEventListener('keyup', function () {
+ var i,
+ // Word sequence _matching_ to input. All, except last, words must be _complete_.
+ e = "(^|.*[^\\pL])" + this.value.trim().split(/\s+/).join("([^\\pL]|[^\\pL].*[^\\pL])") + ".*$",
+ n = RegExp(e, "i");
+ listItems.forEach(function(item) {
+ item.removeAttribute('hidden');
+ });
+ listItems.filter(function(item) {
+ i = item.querySelector('td').textContent.replace(/\s+/g, " ");
+ return !n.test(i);
+ }).forEach(function(item) {
+ item.hidden = true;
+ });
+});
www/vincent.demeester.fr/.fancyindex/header.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="x-ua-compatible" content="IE=edge">
+ <title>Directory</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="stylesheet" href="https://vincent.demeester.fr/css/new.css">
+ <script type="text/javascript" src="/.fancyindex/jquery.min.js"></script>
+ </head>
+ <body>
+ <header id="top" class="status">
+ <nav>
+ <img src="https://vincent.demeester.fr/images/favicon.ico" id="sitelogo"/> <a href='https://vincent.demeester.fr/'>home</a> /
+ <a href='https://vincent.demeester.fr/posts/'>posts</a> (<a href='https://vincent.demeester.fr/index.xml'>rss</a>) /
+ <a href='https://vincent.demeester.fr/articles/'>articles</a> /
+ <a href='https://vincent.demeester.fr/configurations/'>configurations</a> /
+ <a href='https://dl.sbr.pm/'>files</a> /
+ <a href='https://vincent.demeester.fr/about/'>about</a></li>
+ </nav>
+ </header>
+ <main id="content">
+ <header id="raw_include_HEADER_md">
+ </header>
+<h1>Directory:
www/vincent.demeester.fr/.fancyindex/HEADER.md
@@ -0,0 +1,4 @@
+# Test of a HEADER.md file
+## Test of a HEADER.md file
+### Test of a HEADER.md file
+#### Test of a HEADER.md file
www/vincent.demeester.fr/.fancyindex/jquery.min.js
@@ -0,0 +1,5 @@
+/*! jQuery v2.1.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+/* Used on Lilian Besson's web pages ~ 2011-2014 */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m=a.document,n="2.1.0",o=function(a,b){return new o.fn.init(a,b)},p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};o.fn=o.prototype={jquery:n,constructor:o,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=o.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return o.each(this,a,b)},map:function(a){return this.pushStack(o.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},o.extend=o.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||o.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(o.isPlainObject(d)||(e=o.isArray(d)))?(e?(e=!1,f=c&&o.isArray(c)?c:[]):f=c&&o.isPlainObject(c)?c:{},g[b]=o.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},o.extend({expando:"jQuery"+(n+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===o.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isPlainObject:function(a){if("object"!==o.type(a)||a.nodeType||o.isWindow(a))return!1;try{if(a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(b){return!1}return!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=o.trim(a),a&&(1===a.indexOf("use strict")?(b=m.createElement("script"),b.text=a,m.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":k.call(a)},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?o.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),o.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||o.guid++,f):void 0},now:Date.now,support:l}),o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=o.type(a);return"function"===c||o.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);o.find=t,o.expr=t.selectors,o.expr[":"]=o.expr.pseudos,o.unique=t.uniqueSort,o.text=t.getText,o.isXMLDoc=t.isXML,o.contains=t.contains;var u=o.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(o.isFunction(b))return o.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return o.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return o.filter(b,a,c);b=o.filter(b,a)}return o.grep(a,function(a){return g.call(b,a)>=0!==c})}o.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?o.find.matchesSelector(d,a)?[d]:[]:o.find.matches(a,o.grep(b,function(a){return 1===a.nodeType}))},o.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(o(a).filter(function(){for(b=0;c>b;b++)if(o.contains(e[b],this))return!0}));for(b=0;c>b;b++)o.find(a,e[b],d);return d=this.pushStack(c>1?o.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?o(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=o.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof o?b[0]:b,o.merge(this,o.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:m,!0)),v.test(c[1])&&o.isPlainObject(b))for(c in b)o.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=m.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=m,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):o.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(o):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),o.makeArray(a,this))};A.prototype=o.fn,y=o(m);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};o.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&o(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),o.fn.extend({has:function(a){var b=o(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(o.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?o(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&o.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?o.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(o(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(o.unique(o.merge(this.get(),o(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}o.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return o.dir(a,"parentNode")},parentsUntil:function(a,b,c){return o.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return o.dir(a,"nextSibling")},prevAll:function(a){return o.dir(a,"previousSibling")},nextUntil:function(a,b,c){return o.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return o.dir(a,"previousSibling",c)},siblings:function(a){return o.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return o.sibling(a.firstChild)},contents:function(a){return a.contentDocument||o.merge([],a.childNodes)}},function(a,b){o.fn[a]=function(c,d){var e=o.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=o.filter(d,e)),this.length>1&&(C[a]||o.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return o.each(a.match(E)||[],function(a,c){b[c]=!0}),b}o.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):o.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){o.each(b,function(b,c){var d=o.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&o.each(arguments,function(a,b){var c;while((c=o.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?o.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},o.extend({Deferred:function(a){var b=[["resolve","done",o.Callbacks("once memory"),"resolved"],["reject","fail",o.Callbacks("once memory"),"rejected"],["notify","progress",o.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return o.Deferred(function(c){o.each(b,function(b,f){var g=o.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&o.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?o.extend(a,d):d}},e={};return d.pipe=d.then,o.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&o.isFunction(a.promise)?e:0,g=1===f?a:o.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&o.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;o.fn.ready=function(a){return o.ready.promise().done(a),this},o.extend({isReady:!1,readyWait:1,holdReady:function(a){a?o.readyWait++:o.ready(!0)},ready:function(a){(a===!0?--o.readyWait:o.isReady)||(o.isReady=!0,a!==!0&&--o.readyWait>0||(H.resolveWith(m,[o]),o.fn.trigger&&o(m).trigger("ready").off("ready")))}});function I(){m.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),o.ready()}o.ready.promise=function(b){return H||(H=o.Deferred(),"complete"===m.readyState?setTimeout(o.ready):(m.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},o.ready.promise();var J=o.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===o.type(c)){e=!0;for(h in c)o.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,o.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(o(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};o.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=o.expando+Math.random()}K.uid=1,K.accepts=o.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,o.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(o.isEmptyObject(f))o.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,o.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{o.isArray(b)?d=b.concat(b.map(o.camelCase)):(e=o.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!o.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?o.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}o.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),o.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;
+while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=o.camelCase(d.slice(5)),P(f,d,e[d]));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=o.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),o.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||o.isArray(c)?d=L.access(a,b,o.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=o.queue(a,b),d=c.length,e=c.shift(),f=o._queueHooks(a,b),g=function(){o.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:o.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),o.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?o.queue(this[0],a):void 0===b?this:this.each(function(){var c=o.queue(this,a,b);o._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&o.dequeue(this,a)})},dequeue:function(a){return this.each(function(){o.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=o.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===o.css(a,"display")||!o.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=m.createDocumentFragment(),b=a.appendChild(m.createElement("div"));b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";l.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return m.activeElement}catch(a){}}o.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=o.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof o!==U&&o.event.triggered!==b.type?o.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n&&(l=o.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=o.event.special[n]||{},k=o.extend({type:n,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&o.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(n,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),o.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n){l=o.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||o.removeEvent(a,n,r.handle),delete i[n])}else for(n in i)o.event.remove(a,n+b[j],c,d,!0);o.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,p=[d||m],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||m,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+o.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[o.expando]?b:new o.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:o.makeArray(c,[b]),n=o.event.special[q]||{},e||!n.trigger||n.trigger.apply(d,c)!==!1)){if(!e&&!n.noBubble&&!o.isWindow(d)){for(i=n.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||m)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:n.bindType||q,l=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),l&&l.apply(g,c),l=k&&g[k],l&&l.apply&&o.acceptData(g)&&(b.result=l.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||n._default&&n._default.apply(p.pop(),c)!==!1||!o.acceptData(d)||k&&o.isFunction(d[q])&&!o.isWindow(d)&&(h=d[k],h&&(d[k]=null),o.event.triggered=q,d[q](),o.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=o.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=o.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=o.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((o.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?o(e,this).index(i)>=0:o.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||m,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[o.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new o.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=m),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&o.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return o.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=o.extend(new o.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?o.event.trigger(e,null,b):o.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},o.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},o.Event=function(a,b){return this instanceof o.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.getPreventDefault&&a.getPreventDefault()?Z:$):this.type=a,b&&o.extend(this,b),this.timeStamp=a&&a.timeStamp||o.now(),void(this[o.expando]=!0)):new o.Event(a,b)},o.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z,this.stopPropagation()}},o.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){o.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!o.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.focusinBubbles||o.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){o.event.simulate(b,a.target,o.event.fix(a),!0)};o.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),o.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return o().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=o.guid++)),this.each(function(){o.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,o(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){o.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){o.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?o.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return o.nodeName(a,"table")&&o.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)o.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=o.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&o.nodeName(a,b)?o.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}o.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=o.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||o.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,n=a.length;n>m;m++)if(e=a[m],e||0===e)if("object"===o.type(e))o.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;o.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===o.inArray(e,d))&&(i=o.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f,g,h=o.event.special,i=0;void 0!==(c=a[i]);i++){if(o.acceptData(c)&&(f=c[L.expando],f&&(b=L.cache[f]))){if(d=Object.keys(b.events||{}),d.length)for(g=0;void 0!==(e=d[g]);g++)h[e]?o.event.remove(c,e):o.removeEvent(c,e,b.handle);L.cache[f]&&delete L.cache[f]}delete M.cache[c[M.expando]]}}}),o.fn.extend({text:function(a){return J(this,function(a){return void 0===a?o.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?o.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||o.cleanData(ob(c)),c.parentNode&&(b&&o.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(o.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return o.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(o.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,o.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,n=k-1,p=a[0],q=o.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(c=o.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=o.map(ob(c,"script"),kb),g=f.length;k>j;j++)h=c,j!==n&&(h=o.clone(h,!0,!0),g&&o.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,o.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&o.contains(i,h)&&(h.src?o._evalUrl&&o._evalUrl(h.src):o.globalEval(h.textContent.replace(hb,"")))}return this}}),o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){o.fn[a]=function(a){for(var c,d=[],e=o(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),o(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d=o(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:o.css(d[0],"display");return d.detach(),e}function tb(a){var b=m,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||o("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||o.contains(a.ownerDocument,a)||(g=o.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",e=m.documentElement,f=m.createElement("div"),g=m.createElement("div");g.style.backgroundClip="content-box",g.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===g.style.backgroundClip,f.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",f.appendChild(g);function h(){g.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",e.appendChild(f);var d=a.getComputedStyle(g,null);b="1%"!==d.top,c="4px"===d.width,e.removeChild(f)}a.getComputedStyle&&o.extend(l,{pixelPosition:function(){return h(),b},boxSizingReliable:function(){return null==c&&h(),c},reliableMarginRight:function(){var b,c=g.appendChild(m.createElement("div"));return c.style.cssText=g.style.cssText=d,c.style.marginRight=c.style.width="0",g.style.width="1px",e.appendChild(f),b=!parseFloat(a.getComputedStyle(c,null).marginRight),e.removeChild(f),g.innerHTML="",b}})}(),o.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:0,fontWeight:400},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=o.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=o.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=o.css(a,"border"+R[f]+"Width",!0,e))):(g+=o.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=o.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===o.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):f[g]||(e=S(d),(c&&"none"!==c||!e)&&L.set(d,"olddisplay",e?c:o.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}o.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=o.camelCase(b),i=a.style;return b=o.cssProps[h]||(o.cssProps[h]=Fb(i,h)),g=o.cssHooks[b]||o.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(o.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||o.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]="",i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=o.camelCase(b);return b=o.cssProps[h]||(o.cssProps[h]=Fb(a.style,h)),g=o.cssHooks[b]||o.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||o.isNumeric(f)?f||0:e):e}}),o.each(["height","width"],function(a,b){o.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&zb.test(o.css(a,"display"))?o.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===o.css(a,"boxSizing",!1,e),e):0)}}}),o.cssHooks.marginRight=yb(l.reliableMarginRight,function(a,b){return b?o.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),o.each({margin:"",padding:"",border:"Width"},function(a,b){o.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(o.cssHooks[a+b].set=Gb)}),o.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(o.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=o.css(a,b[g],!1,d);return f}return void 0!==c?o.style(a,b,c):o.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?o(this).show():o(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}o.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(o.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?o.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=o.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){o.fx.step[a.prop]?o.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[o.cssProps[a.prop]]||o.cssHooks[a.prop])?o.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},o.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},o.fx=Kb.prototype.init,o.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(o.cssNumber[a]?"":"px"),g=(o.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(o.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,o.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=o.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k=this,l={},m=a.style,n=a.nodeType&&S(a),p=L.get(a,"fxshow");c.queue||(h=o._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,k.always(function(){k.always(function(){h.unqueued--,o.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],j=o.css(a,"display"),"none"===j&&(j=tb(a.nodeName)),"inline"===j&&"none"===o.css(a,"float")&&(m.display="inline-block")),c.overflow&&(m.overflow="hidden",k.always(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(n?"hide":"show")){if("show"!==e||!p||void 0===p[d])continue;n=!0}l[d]=p&&p[d]||o.style(a,d)}if(!o.isEmptyObject(l)){p?"hidden"in p&&(n=p.hidden):p=L.access(a,"fxshow",{}),f&&(p.hidden=!n),n?o(a).show():k.done(function(){o(a).hide()}),k.done(function(){var b;L.remove(a,"fxshow");for(b in l)o.style(a,b,l[b])});for(d in l)g=Ub(n?p[d]:0,d,k),d in p||(p[d]=g.start,n&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=o.camelCase(c),e=b[d],f=a[c],o.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=o.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=o.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:o.extend({},b),opts:o.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=o.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return o.map(k,Ub,j),o.isFunction(j.opts.start)&&j.opts.start.call(a,j),o.fx.timer(o.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}o.Animation=o.extend(Xb,{tweener:function(a,b){o.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),o.speed=function(a,b,c){var d=a&&"object"==typeof a?o.extend({},a):{complete:c||!c&&b||o.isFunction(a)&&a,duration:a,easing:c&&b||b&&!o.isFunction(b)&&b};return d.duration=o.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in o.fx.speeds?o.fx.speeds[d.duration]:o.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){o.isFunction(d.old)&&d.old.call(this),d.queue&&o.dequeue(this,d.queue)},d},o.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=o.isEmptyObject(a),f=o.speed(b,c,d),g=function(){var b=Xb(this,o.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=o.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&o.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=o.timers,g=d?d.length:0;for(c.finish=!0,o.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),o.each(["toggle","show","hide"],function(a,b){var c=o.fn[b];o.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),o.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){o.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),o.timers=[],o.fx.tick=function(){var a,b=0,c=o.timers;for(Lb=o.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||o.fx.stop(),Lb=void 0},o.fx.timer=function(a){o.timers.push(a),a()?o.fx.start():o.timers.pop()},o.fx.interval=13,o.fx.start=function(){Mb||(Mb=setInterval(o.fx.tick,o.fx.interval))},o.fx.stop=function(){clearInterval(Mb),Mb=null},o.fx.speeds={slow:600,fast:200,_default:400},o.fn.delay=function(a,b){return a=o.fx?o.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=m.createElement("input"),b=m.createElement("select"),c=b.appendChild(m.createElement("option"));a.type="checkbox",l.checkOn=""!==a.value,l.optSelected=c.selected,b.disabled=!0,l.optDisabled=!c.disabled,a=m.createElement("input"),a.value="t",a.type="radio",l.radioValue="t"===a.value}();var Yb,Zb,$b=o.expr.attrHandle;o.fn.extend({attr:function(a,b){return J(this,o.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){o.removeAttr(this,a)})}}),o.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?o.prop(a,b,c):(1===f&&o.isXMLDoc(a)||(b=b.toLowerCase(),d=o.attrHooks[b]||(o.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=o.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void o.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=o.propFix[c]||c,o.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&o.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?o.removeAttr(a,c):a.setAttribute(c,c),c}},o.each(o.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||o.find.attr;$b[b]=function(a,b,d){var e,f;
+return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;o.fn.extend({prop:function(a,b){return J(this,o.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[o.propFix[a]||a]})}}),o.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!o.isXMLDoc(a),f&&(b=o.propFix[b]||b,e=o.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),l.optSelected||(o.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),o.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){o.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;o.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=o.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?o.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(o.isFunction(a)?function(c){o(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=o(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;o.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=o.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,o(this).val()):a,null==e?e="":"number"==typeof e?e+="":o.isArray(e)&&(e=o.map(e,function(a){return null==a?"":a+""})),b=o.valHooks[this.type]||o.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=o.valHooks[e.type]||o.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),o.extend({valHooks:{select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&o.nodeName(c.parentNode,"optgroup"))){if(b=o(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=o.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=o.inArray(o(d).val(),f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),o.each(["radio","checkbox"],function(){o.valHooks[this]={set:function(a,b){return o.isArray(b)?a.checked=o.inArray(o(a).val(),b)>=0:void 0}},l.checkOn||(o.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),o.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){o.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),o.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=o.now(),dc=/\?/;o.parseJSON=function(a){return JSON.parse(a+"")},o.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&o.error("Invalid XML: "+a),b};var ec,fc,gc=/#.*$/,hc=/([?&])_=[^&]*/,ic=/^(.*?):[ \t]*([^\r\n]*)$/gm,jc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kc=/^(?:GET|HEAD)$/,lc=/^\/\//,mc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,nc={},oc={},pc="*/".concat("*");try{fc=location.href}catch(qc){fc=m.createElement("a"),fc.href="",fc=fc.href}ec=mc.exec(fc.toLowerCase())||[];function rc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(o.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function sc(a,b,c,d){var e={},f=a===oc;function g(h){var i;return e[h]=!0,o.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function tc(a,b){var c,d,e=o.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&o.extend(!0,a,d),a}function uc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function vc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}o.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:fc,type:"GET",isLocal:jc.test(ec[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":pc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":o.parseJSON,"text xml":o.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?tc(tc(a,o.ajaxSettings),b):tc(o.ajaxSettings,a)},ajaxPrefilter:rc(nc),ajaxTransport:rc(oc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=o.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?o(l):o.event,n=o.Deferred(),p=o.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=ic.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(n.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||fc)+"").replace(gc,"").replace(lc,ec[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=o.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=mc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===ec[1]&&h[2]===ec[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(ec[3]||("http:"===ec[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=o.param(k.data,k.traditional)),sc(nc,k,b,v),2===t)return v;i=k.global,i&&0===o.active++&&o.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!kc.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=hc.test(d)?d.replace(hc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(o.lastModified[d]&&v.setRequestHeader("If-Modified-Since",o.lastModified[d]),o.etag[d]&&v.setRequestHeader("If-None-Match",o.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+pc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=sc(oc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=uc(k,v,f)),u=vc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(o.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(o.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?n.resolveWith(l,[r,x,v]):n.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--o.active||o.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return o.get(a,b,c,"json")},getScript:function(a,b){return o.get(a,void 0,b,"script")}}),o.each(["get","post"],function(a,b){o[b]=function(a,c,d,e){return o.isFunction(c)&&(e=e||d,d=c,c=void 0),o.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),o.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){o.fn[b]=function(a){return this.on(b,a)}}),o._evalUrl=function(a){return o.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},o.fn.extend({wrapAll:function(a){var b;return o.isFunction(a)?this.each(function(b){o(this).wrapAll(a.call(this,b))}):(this[0]&&(b=o(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(o.isFunction(a)?function(b){o(this).wrapInner(a.call(this,b))}:function(){var b=o(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=o.isFunction(a);return this.each(function(c){o(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){o.nodeName(this,"body")||o(this).replaceWith(this.childNodes)}).end()}}),o.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},o.expr.filters.visible=function(a){return!o.expr.filters.hidden(a)};var wc=/%20/g,xc=/\[\]$/,yc=/\r?\n/g,zc=/^(?:submit|button|image|reset|file)$/i,Ac=/^(?:input|select|textarea|keygen)/i;function Bc(a,b,c,d){var e;if(o.isArray(b))o.each(b,function(b,e){c||xc.test(a)?d(a,e):Bc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==o.type(b))d(a,b);else for(e in b)Bc(a+"["+e+"]",b[e],c,d)}o.param=function(a,b){var c,d=[],e=function(a,b){b=o.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=o.ajaxSettings&&o.ajaxSettings.traditional),o.isArray(a)||a.jquery&&!o.isPlainObject(a))o.each(a,function(){e(this.name,this.value)});else for(c in a)Bc(c,a[c],b,e);return d.join("&").replace(wc,"+")},o.fn.extend({serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=o.prop(this,"elements");return a?o.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!o(this).is(":disabled")&&Ac.test(this.nodeName)&&!zc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=o(this).val();return null==c?null:o.isArray(c)?o.map(c,function(a){return{name:b.name,value:a.replace(yc,"\r\n")}}):{name:b.name,value:c.replace(yc,"\r\n")}}).get()}}),o.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Cc=0,Dc={},Ec={0:200,1223:204},Fc=o.ajaxSettings.xhr();a.ActiveXObject&&o(a).on("unload",function(){for(var a in Dc)Dc[a]()}),l.cors=!!Fc&&"withCredentials"in Fc,l.ajax=Fc=!!Fc,o.ajaxTransport(function(a){var b;return l.cors||Fc&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Cc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Dc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Ec[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Dc[g]=b("abort"),f.send(a.hasContent&&a.data||null)},abort:function(){b&&b()}}:void 0}),o.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return o.globalEval(a),a}}}),o.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),o.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=o("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),m.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Gc=[],Hc=/(=)\?(?=&|$)|\?\?/;o.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Gc.pop()||o.expando+"_"+cc++;return this[a]=!0,a}}),o.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Hc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Hc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=o.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Hc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||o.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Gc.push(e)),g&&o.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),o.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||m;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=o.buildFragment([a],b,e),e&&e.length&&o(e).remove(),o.merge([],d.childNodes))};var Ic=o.fn.load;o.fn.load=function(a,b,c){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h),a=a.slice(0,h)),o.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&o.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?o("<div>").append(o.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},o.expr.filters.animated=function(a){return o.grep(o.timers,function(b){return a===b.elem}).length};var Jc=a.document.documentElement;function Kc(a){return o.isWindow(a)?a:9===a.nodeType&&a.defaultView}o.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=o.css(a,"position"),l=o(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=o.css(a,"top"),i=o.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),o.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},o.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){o.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,o.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Kc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===o.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),o.nodeName(a[0],"html")||(d=a.offset()),d.top+=o.css(a[0],"borderTopWidth",!0),d.left+=o.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-o.css(c,"marginTop",!0),left:b.left-d.left-o.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Jc;while(a&&!o.nodeName(a,"html")&&"static"===o.css(a,"position"))a=a.offsetParent;return a||Jc})}}),o.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;o.fn[b]=function(e){return J(this,function(b,e,f){var g=Kc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),o.each(["top","left"],function(a,b){o.cssHooks[b]=yb(l.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?o(a).position()[b]+"px":c):void 0})}),o.each({Height:"height",Width:"width"},function(a,b){o.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){o.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return o.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?o.css(b,c,g):o.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),o.fn.size=function(){return this.length},o.fn.andSelf=o.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return o});var Lc=a.jQuery,Mc=a.$;return o.noConflict=function(b){return a.$===o&&(a.$=Mc),b&&a.jQuery===o&&(a.jQuery=Lc),o},typeof b===U&&(a.jQuery=a.$=o),o});
www/vincent.demeester.fr/.fancyindex/new.css
@@ -0,0 +1,605 @@
+:root {
+ ---font-sans: 'Ubuntu Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ ---font-mono: 'Ubuntu Mono', Consolas, monaco, 'Liberation Mono', 'Courier New', Courier, monospace;
+ ---tx-1: #000000;
+ ---tx-2: #1A1A1A;
+ ---tx-3: #666666;
+ ---tx-4: #999999;
+ ---bg-1: #FFFFFF;
+ ---bg-2: #F6F8FA;
+ ---bg-3: #E5E7EB;
+ ---lk-1: #0070F3;
+ ---lk-2: #0366D6;
+ ---lk-tx: #FFFFFF;
+ ---ac-1: #79FFE1;
+ ---ac-tx: #0C4047;
+
+ --content-box-padding: 0.5rem;
+ --aside-width: 12.5rem;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ ---tx-1: #ffffff;
+ ---tx-2: #eeeeee;
+ ---tx-3: #cccccc;
+ ---tx-4: #aaaaaa;
+ ---bg-1: #000000;
+ ---bg-2: #111111;
+ ---bg-3: #222222;
+ ---lk-1: #3291FF;
+ ---lk-2: #0070F3;
+ ---lk-tx: #FFFFFF;
+ ---ac-1: #7928CA;
+ ---ac-tx: #FFFFFF;
+ }
+}
+
+* {
+ /* Reset margins and padding */
+ margin: 0;
+ padding: 0;
+}
+
+address,
+area,
+article,
+aside,
+audio,
+blockquote,
+datalist,
+details,
+dl,
+fieldset,
+figure,
+form,
+input,
+iframe,
+img,
+meter,
+nav,
+ol,
+optgroup,
+option,
+output,
+p,
+pre,
+progress,
+ruby,
+section,
+table,
+textarea,
+ul,
+video {
+ /* Margins for most elements */
+ margin-bottom: 1rem;
+}
+
+html,input,select,button {
+ /* Set body font family and some finicky elements */
+ font-family: var(---font-sans);
+}
+
+body {
+ /* Center body in page */
+ margin: 0 auto;
+ max-width: 70rem;
+ padding: 2rem;
+ border-radius: 6px;
+ overflow-x: hidden;
+ word-break: break-word;
+ overflow-wrap: break-word;
+ background: var(---bg-1);
+
+ /* Main body text */
+ color: var(---tx-2);
+ font-size: 1.03rem;
+ line-height: 1.5;
+}
+
+::selection {
+ /* Set background color for selected text */
+ background: var(---ac-1);
+ color: var(---ac-tx);
+}
+
+h1,h2,h3,h4,h5,h6 {
+ line-height: 1;
+ color: var(---tx-1);
+ padding-top: .875rem;
+}
+
+h1,
+h2,
+h3 {
+ color: var(---tx-1);
+ padding-bottom: 2px;
+ margin-bottom: 8px;
+ border-bottom: 1px solid var(---bg-2);
+}
+
+h4,
+h5,
+h6 {
+ margin-bottom: .3rem;
+}
+
+h1 {
+ font-size: 2.25rem;
+}
+
+h2 {
+ font-size: 1.85rem;
+}
+
+h3 {
+ font-size: 1.55rem;
+}
+
+h4 {
+ font-size: 1.25rem;
+}
+
+h5 {
+ font-size: 1rem;
+}
+
+h6 {
+ font-size: .875rem;
+}
+
+a {
+ color: var(---lk-1);
+}
+
+a:hover {
+ color: var(---lk-2);
+}
+
+abbr:hover {
+ /* Set the '?' cursor while hovering an abbreviation */
+ cursor: help;
+}
+
+blockquote {
+ padding: 1.5rem;
+ background: var(---bg-2);
+ border-left: 5px solid var(---bg-3);
+}
+
+abbr {
+ cursor: help;
+}
+
+blockquote *:last-child {
+ padding-bottom: 0;
+ margin-bottom: 0;
+}
+
+header {
+ background: var(---bg-2);
+ border-bottom: 1px solid var(---bg-3);
+ padding: 1rem 1.5rem;
+
+ /* This sets the right and left margins to cancel out the body's margins. It's width is still the same, but the background stretches across the page's width. */
+
+ margin: -2rem calc(0px - (50vw - 50%)) 2rem;
+
+ /* Shorthand for:
+
+ margin-top: -2rem;
+ margin-bottom: 2rem;
+
+ margin-left: calc(0px - (50vw - 50%));
+ margin-right: calc(0px - (50vw - 50%)); */
+
+ padding-left: calc(50vw - 50%);
+ padding-right: calc(50vw - 50%);
+}
+
+header img#sitelogo {
+ margin-bottom: 0;
+ margin-right: 1em;
+}
+
+header h1,
+header h2,
+header h3 {
+ padding-bottom: 0;
+ border-bottom: 0;
+}
+
+header > *:first-child {
+ margin-top: 0;
+ padding-top: 0;
+}
+
+header > *:last-child {
+ margin-bottom: 0;
+}
+
+main header {
+ background: var(---bg-3);
+}
+
+a button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+ font-size: 1rem;
+ display: inline-block;
+ padding: 6px 12px;
+ text-align: center;
+ text-decoration: none;
+ white-space: nowrap;
+ background: var(---lk-1);
+ color: var(---lk-tx);
+ border: 0;
+ border-radius: 4px;
+ box-sizing: border-box;
+ cursor: pointer;
+ color: var(---lk-tx);
+}
+
+a button[disabled],
+button[disabled],
+input[type="submit"][disabled],
+input[type="reset"][disabled],
+input[type="button"][disabled] {
+ cursor: default;
+ opacity: .5;
+
+ /* Set the [X] cursor while hovering a disabled link */
+ cursor: not-allowed;
+}
+
+.button:focus,
+.button:hover,
+button:focus,
+button:hover,
+input[type="submit"]:focus,
+input[type="submit"]:hover,
+input[type="reset"]:focus,
+input[type="reset"]:hover,
+input[type="button"]:focus,
+input[type="button"]:hover {
+ background: var(---lk-2);
+}
+
+code,
+pre,
+kbd,
+samp {
+ /* Set the font family for monospaced elements */
+ font-family: var(---font-mono);
+}
+
+code,
+samp,
+kbd,
+pre {
+ /* The main preformatted style. This is changed slightly across different cases. */
+ background: var(---bg-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+ padding: 3px 6px;
+}
+
+kbd {
+ /* Makes the kbd element look like a keyboard key */
+ border-bottom: 3px solid var(---bg-3);
+}
+
+pre {
+ padding: 1rem 1.4rem;
+ max-width: 100%;
+ overflow: auto;
+}
+
+pre.src {
+ position: relative;
+}
+pre.src:before {
+ /*display: none;*/
+ position: absolute;
+ background-color: var(---bg-3);
+ /*color: #f3f4f4;*/
+ top: 0;
+ right: 0;
+ padding: 0.2rem 0.5rem;
+}
+
+pre code {
+ /* When <code> is in a <pre>, reset it's formatting to blend in */
+ background: inherit;
+ font-size: inherit;
+ color: inherit;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+code pre {
+ /* When <pre> is in a <code>, reset it's formatting to blend in */
+ display: inline;
+ background: inherit;
+ font-size: inherit;
+ color: inherit;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+details {
+ /* Make the <details> look more "clickable" */
+ padding: .6rem 1rem;
+ background: var(---bg-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+}
+
+summary {
+ /* Makes the <summary> look more like a "clickable" link with the pointer cursor */
+ cursor: pointer;
+ font-weight: bold;
+}
+
+details[open] {
+ /* Adjust the <details> padding while open */
+ padding-bottom: .75rem;
+}
+
+details[open] summary {
+ /* Adjust the <details> padding while open */
+ margin-bottom: 6px;
+}
+
+details[open]>*:last-child {
+ /* Resets the bottom margin of the last element in the <details> while <details> is opened. This prevents double margins/paddings. */
+ margin-bottom: 0;
+}
+
+dt {
+ font-weight: bold;
+}
+
+dd::before {
+ /* Add an arrow to data table definitions */
+ content: 'โ ';
+}
+
+hr {
+ /* Reset the border of the <hr> separator, then set a better line */
+ border: 0;
+ border-bottom: 1px solid var(---bg-3);
+ margin: 1rem auto;
+}
+
+fieldset {
+ margin-top: 1rem;
+ padding: 2rem;
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+}
+
+legend {
+ padding: auto .5rem;
+}
+
+table {
+ /* border-collapse sets the table's elements to share borders, rather than floating as separate "boxes". */
+ border-collapse: collapse;
+ width: 100%
+}
+
+td,
+th {
+ border: 1px solid var(---bg-3);
+ text-align: left;
+ padding: .5rem;
+}
+
+th {
+ background: var(---bg-2);
+}
+
+tr:nth-child(even) {
+ /* Set every other cell slightly darker. Improves readability. */
+ background: var(---bg-2);
+}
+
+table caption {
+ font-weight: bold;
+ margin-bottom: .5rem;
+}
+
+textarea {
+ /* Don't let the <textarea> extend off the screen naturally or when dragged by the user */
+ max-width: 100%;
+}
+
+ol,
+ul {
+ /* Replace the browser default padding */
+ padding-left: 2rem;
+}
+
+li {
+ margin-top: .4rem;
+}
+
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+ margin-bottom: 0;
+}
+
+mark {
+ padding: 3px 6px;
+ background: var(---ac-1);
+ color: var(---ac-tx);
+}
+
+textarea,
+select,
+input {
+ padding: 6px 12px;
+ margin-bottom: .5rem;
+ background: var(---bg-2);
+ color: var(---tx-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+ box-shadow: none;
+ box-sizing: border-box;
+}
+
+img {
+ max-width: 100%;
+}
+
+aside {
+ --aside-offset: 1rem;
+ --aside-offset-lineheight: 1.5rem;
+ background-color: var(---bg-2);
+ padding: calc(var(--content-box-padding) * 0.5) calc(var(--content-box-padding) * 2);
+ padding-top: 1em;
+ margin-bottom: 0em;
+ float: right;
+ width: var(--aside-width);
+ font-size: 0.9rem;
+ line-height: 1.25rem;
+ border: 1px solid var(--bg-3);
+}
+
+figure figcaption {
+ text-align: center;
+ color: var(---tx-2);
+ font-style: italic;
+ margin: 0 2rem;
+}
+
+footer {
+ text-align: center;
+ color: var(---tx-4);
+}
+
+footer a {
+ color: var(---tx-3);
+}
+
+section img {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+section img.shadow {
+ box-shadow: 0 28px 50px rgba(0,0,0,0.16);
+}
+
+div.drawer:before {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 4.4rem;
+ width: 1px;
+ background-color: #555;
+}
+
+div.drawer {
+ display: flex;
+ padding: 0;
+ margin: 1rem;
+ padding-top: 1rem;
+ position: relative;
+ color: #555;
+}
+
+div.drawer h6 {
+ box-sizing: border-box;
+ font-style: italic;
+ flex: 0 0 5rem;
+ margin:0;
+ padding:0;
+ align-self: center;
+ text-align: right;
+ padding-right: 1.2rem;
+}
+
+div.drawer.info:before {
+ background-color: #00529B;
+}
+div.drawer.info {
+ color: #00529B;
+}
+
+div.drawer.note:before {
+ background-color: #9F6000;
+}
+div.drawer.note {
+ color: #9F6000;
+}
+div.drawer.tip:before {
+ background-color: #4F8A10;
+}
+div.drawer.tip {
+ color: #4F8A10;
+}
+div.drawer.warning:before {
+ background-color: #D8000C;
+}
+div.drawer.warning {
+ color: #D8000C;
+}
+div.drawer.results:before {
+ background-color: black;
+}
+div.drawer.results {
+ font-family:monospace,monospace;
+ font-family: var(---font-mono);
+ color: black;
+ width: 100% !important;
+}
+div.drawer.results p {
+ display: block;
+ unicode-bidi: embed;
+ white-space: pre;
+ margin-top: 0;
+}
+div.drawer.results pre {
+ background-color: inherit;
+ border: 0;
+}
+div.drawer.results pre.src:before {
+ background-color: #eee;
+ color: #555;
+}
+
+.tag {
+ font-family:var(---font-mono);
+ font-size: 1rem;
+}
+.tag span {
+ padding:.3em;
+ float:right;
+ margin-right:.5em;
+ border:1px solid #bbb;
+ border-radius:3px;
+ background-clip:padding-box;
+ color:#333;
+ background-color:#eee;
+ line-height:1rem;
+}
+
+.todo {
+ font-family: monospace; color: red;
+}
+.done {
+ font-family: monospace; color: green;
+}
+.priority { font-family: monospace; color: orange; }
+.timestamp { color: #bebebe; }
+.timestamp-kwd { color: #5f9ea0; }
www/vincent.demeester.fr/.fancyindex/showdown.min.js
@@ -0,0 +1,3 @@
+/*! showdown v 1.8.6 - 22-12-2017 */
+(function(){function g(g){"use strict";var A={omitExtraWLInCodeBlocks:{defaultValue:!1,describe:"Omit the default extra whiteline added to code blocks",type:"boolean"},noHeaderId:{defaultValue:!1,describe:"Turn on/off generated header id",type:"boolean"},prefixHeaderId:{defaultValue:!1,describe:"Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic 'section-' prefix",type:"string"},rawPrefixHeaderId:{defaultValue:!1,describe:'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',type:"boolean"},ghCompatibleHeaderId:{defaultValue:!1,describe:"Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)",type:"boolean"},rawHeaderId:{defaultValue:!1,describe:"Remove only spaces, ' and \" from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids",type:"boolean"},headerLevelStart:{defaultValue:!1,describe:"The header blocks level start",type:"integer"},parseImgDimensions:{defaultValue:!1,describe:"Turn on/off image dimension parsing",type:"boolean"},simplifiedAutoLink:{defaultValue:!1,describe:"Turn on/off GFM autolink style",type:"boolean"},excludeTrailingPunctuationFromURLs:{defaultValue:!1,describe:"Excludes trailing punctuation from links generated with autoLinking",type:"boolean"},literalMidWordUnderscores:{defaultValue:!1,describe:"Parse midword underscores as literal underscores",type:"boolean"},literalMidWordAsterisks:{defaultValue:!1,describe:"Parse midword asterisks as literal asterisks",type:"boolean"},strikethrough:{defaultValue:!1,describe:"Turn on/off strikethrough support",type:"boolean"},tables:{defaultValue:!1,describe:"Turn on/off tables support",type:"boolean"},tablesHeaderId:{defaultValue:!1,describe:"Add an id to table headers",type:"boolean"},ghCodeBlocks:{defaultValue:!0,describe:"Turn on/off GFM fenced code blocks support",type:"boolean"},tasklists:{defaultValue:!1,describe:"Turn on/off GFM tasklist support",type:"boolean"},smoothLivePreview:{defaultValue:!1,describe:"Prevents weird effects in live previews due to incomplete input",type:"boolean"},smartIndentationFix:{defaultValue:!1,description:"Tries to smartly fix indentation in es6 strings",type:"boolean"},disableForced4SpacesIndentedSublists:{defaultValue:!1,description:"Disables the requirement of indenting nested sublists by 4 spaces",type:"boolean"},simpleLineBreaks:{defaultValue:!1,description:"Parses simple line breaks as <br> (GFM Style)",type:"boolean"},requireSpaceBeforeHeadingText:{defaultValue:!1,description:"Makes adding a space between `#` and the header text mandatory (GFM Style)",type:"boolean"},ghMentions:{defaultValue:!1,description:"Enables github @mentions",type:"boolean"},ghMentionsLink:{defaultValue:"https://github.com/{u}",description:"Changes the link generated by @mentions. Only applies if ghMentions option is enabled.",type:"string"},encodeEmails:{defaultValue:!0,description:"Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities",type:"boolean"},openLinksInNewWindow:{defaultValue:!1,description:"Open all links in new windows",type:"boolean"},backslashEscapesHTMLTags:{defaultValue:!1,description:"Support for HTML Tag escaping. ex: <div>foo</div>",type:"boolean"},emoji:{defaultValue:!1,description:"Enable emoji support. Ex: `this is a :smile: emoji`",type:"boolean"},underline:{defaultValue:!1,description:"Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `<em>` and `<strong>`",type:"boolean"},completeHTMLDocument:{defaultValue:!1,description:"Outputs a complete html document, including `<html>`, `<head>` and `<body>` tags",type:"boolean"},metadata:{defaultValue:!1,description:"Enable support for document metadata (defined at the top of the document between `ยซยซยซ` and `ยปยปยป` or between `---` and `---`).",type:"boolean"},splitAdjacentBlockquotes:{defaultValue:!1,description:"Split adjacent blockquote blocks",type:"boolean"}};if(!1===g)return JSON.parse(JSON.stringify(A));var C={};for(var I in A)A.hasOwnProperty(I)&&(C[I]=A[I].defaultValue);return C}function A(g,A){"use strict";var C=A?"Error in "+A+" extension->":"Error in unnamed extension",e={valid:!0,error:""};I.helper.isArray(g)||(g=[g]);for(var r=0;r<g.length;++r){var t=C+" sub-extension "+r+": ",a=g[r];if("object"!=typeof a)return e.valid=!1,e.error=t+"must be an object, but "+typeof a+" given",e;if(!I.helper.isString(a.type))return e.valid=!1,e.error=t+'property "type" must be a string, but '+typeof a.type+" given",e;var n=a.type=a.type.toLowerCase();if("language"===n&&(n=a.type="lang"),"html"===n&&(n=a.type="output"),"lang"!==n&&"output"!==n&&"listener"!==n)return e.valid=!1,e.error=t+"type "+n+' is not recognized. Valid values: "lang/language", "output/html" or "listener"',e;if("listener"===n){if(I.helper.isUndefined(a.listeners))return e.valid=!1,e.error=t+'. Extensions of type "listener" must have a property called "listeners"',e}else if(I.helper.isUndefined(a.filter)&&I.helper.isUndefined(a.regex))return e.valid=!1,e.error=t+n+' extensions must define either a "regex" property or a "filter" method',e;if(a.listeners){if("object"!=typeof a.listeners)return e.valid=!1,e.error=t+'"listeners" property must be an object but '+typeof a.listeners+" given",e;for(var o in a.listeners)if(a.listeners.hasOwnProperty(o)&&"function"!=typeof a.listeners[o])return e.valid=!1,e.error=t+'"listeners" property must be an hash of [event name]: [callback]. listeners.'+o+" must be a function but "+typeof a.listeners[o]+" given",e}if(a.filter){if("function"!=typeof a.filter)return e.valid=!1,e.error=t+'"filter" must be a function, but '+typeof a.filter+" given",e}else if(a.regex){if(I.helper.isString(a.regex)&&(a.regex=new RegExp(a.regex,"g")),!(a.regex instanceof RegExp))return e.valid=!1,e.error=t+'"regex" property must either be a string or a RegExp object, but '+typeof a.regex+" given",e;if(I.helper.isUndefined(a.replace))return e.valid=!1,e.error=t+'"regex" extensions must implement a replace string or function',e}}return e}function C(g,A){"use strict";return"ยจE"+A.charCodeAt(0)+"E"}var I={},e={},r={},t=g(!0),a="vanilla",n={github:{omitExtraWLInCodeBlocks:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,disableForced4SpacesIndentedSublists:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghCompatibleHeaderId:!0,ghMentions:!0,backslashEscapesHTMLTags:!0,emoji:!0,splitAdjacentBlockquotes:!0},original:{noHeaderId:!0,ghCodeBlocks:!1},ghost:{omitExtraWLInCodeBlocks:!0,parseImgDimensions:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,smoothLivePreview:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghMentions:!1,encodeEmails:!0},vanilla:g(!0),allOn:function(){"use strict";var A=g(!0),C={};for(var I in A)A.hasOwnProperty(I)&&(C[I]=!0);return C}()};I.helper={},I.extensions={},I.setOption=function(g,A){"use strict";return t[g]=A,this},I.getOption=function(g){"use strict";return t[g]},I.getOptions=function(){"use strict";return t},I.resetOptions=function(){"use strict";t=g(!0)},I.setFlavor=function(g){"use strict";if(!n.hasOwnProperty(g))throw Error(g+" flavor was not found");I.resetOptions();var A=n[g];a=g;for(var C in A)A.hasOwnProperty(C)&&(t[C]=A[C])},I.getFlavor=function(){"use strict";return a},I.getFlavorOptions=function(g){"use strict";if(n.hasOwnProperty(g))return n[g]},I.getDefaultOptions=function(A){"use strict";return g(A)},I.subParser=function(g,A){"use strict";if(I.helper.isString(g)){if(void 0===A){if(e.hasOwnProperty(g))return e[g];throw Error("SubParser named "+g+" not registered!")}e[g]=A}},I.extension=function(g,C){"use strict";if(!I.helper.isString(g))throw Error("Extension 'name' must be a string");if(g=I.helper.stdExtName(g),I.helper.isUndefined(C)){if(!r.hasOwnProperty(g))throw Error("Extension named "+g+" is not registered!");return r[g]}"function"==typeof C&&(C=C()),I.helper.isArray(C)||(C=[C]);var e=A(C,g);if(!e.valid)throw Error(e.error);r[g]=C},I.getAllExtensions=function(){"use strict";return r},I.removeExtension=function(g){"use strict";delete r[g]},I.resetExtensions=function(){"use strict";r={}},I.validateExtension=function(g){"use strict";var C=A(g,null);return!!C.valid||(console.warn(C.error),!1)},I.hasOwnProperty("helper")||(I.helper={}),I.helper.isString=function(g){"use strict";return"string"==typeof g||g instanceof String},I.helper.isFunction=function(g){"use strict";return g&&"[object Function]"==={}.toString.call(g)},I.helper.isArray=function(g){"use strict";return Array.isArray(g)},I.helper.isUndefined=function(g){"use strict";return void 0===g},I.helper.forEach=function(g,A){"use strict";if(I.helper.isUndefined(g))throw new Error("obj param is required");if(I.helper.isUndefined(A))throw new Error("callback param is required");if(!I.helper.isFunction(A))throw new Error("callback param must be a function/closure");if("function"==typeof g.forEach)g.forEach(A);else if(I.helper.isArray(g))for(var C=0;C<g.length;C++)A(g[C],C,g);else{if("object"!=typeof g)throw new Error("obj does not seem to be an array or an iterable object");for(var e in g)g.hasOwnProperty(e)&&A(g[e],e,g)}},I.helper.stdExtName=function(g){"use strict";return g.replace(/[_?*+\/\\.^-]/g,"").replace(/\s/g,"").toLowerCase()},I.helper.escapeCharactersCallback=C,I.helper.escapeCharacters=function(g,A,I){"use strict";var e="(["+A.replace(/([\[\]\\])/g,"\\$1")+"])";I&&(e="\\\\"+e);var r=new RegExp(e,"g");return g=g.replace(r,C)};var o=function(g,A,C,I){"use strict";var e,r,t,a,n,o=I||"",s=o.indexOf("g")>-1,i=new RegExp(A+"|"+C,"g"+o.replace(/g/g,"")),l=new RegExp(A,o.replace(/g/g,"")),c=[];do{for(e=0;t=i.exec(g);)if(l.test(t[0]))e++||(a=(r=i.lastIndex)-t[0].length);else if(e&&!--e){n=t.index+t[0].length;var u={left:{start:a,end:r},match:{start:r,end:t.index},right:{start:t.index,end:n},wholeMatch:{start:a,end:n}};if(c.push(u),!s)return c}}while(e&&(i.lastIndex=r));return c};I.helper.matchRecursiveRegExp=function(g,A,C,I){"use strict";for(var e=o(g,A,C,I),r=[],t=0;t<e.length;++t)r.push([g.slice(e[t].wholeMatch.start,e[t].wholeMatch.end),g.slice(e[t].match.start,e[t].match.end),g.slice(e[t].left.start,e[t].left.end),g.slice(e[t].right.start,e[t].right.end)]);return r},I.helper.replaceRecursiveRegExp=function(g,A,C,e,r){"use strict";if(!I.helper.isFunction(A)){var t=A;A=function(){return t}}var a=o(g,C,e,r),n=g,s=a.length;if(s>0){var i=[];0!==a[0].wholeMatch.start&&i.push(g.slice(0,a[0].wholeMatch.start));for(var l=0;l<s;++l)i.push(A(g.slice(a[l].wholeMatch.start,a[l].wholeMatch.end),g.slice(a[l].match.start,a[l].match.end),g.slice(a[l].left.start,a[l].left.end),g.slice(a[l].right.start,a[l].right.end))),l<s-1&&i.push(g.slice(a[l].wholeMatch.end,a[l+1].wholeMatch.start));a[s-1].wholeMatch.end<g.length&&i.push(g.slice(a[s-1].wholeMatch.end)),n=i.join("")}return n},I.helper.regexIndexOf=function(g,A,C){"use strict";if(!I.helper.isString(g))throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";if(A instanceof RegExp==!1)throw"InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp";var e=g.substring(C||0).search(A);return e>=0?e+(C||0):e},I.helper.splitAtIndex=function(g,A){"use strict";if(!I.helper.isString(g))throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";return[g.substring(0,A),g.substring(A)]},I.helper.encodeEmailAddress=function(g){"use strict";var A=[function(g){return"&#"+g.charCodeAt(0)+";"},function(g){return"&#x"+g.charCodeAt(0).toString(16)+";"},function(g){return g}];return g=g.replace(/./g,function(g){if("@"===g)g=A[Math.floor(2*Math.random())](g);else{var C=Math.random();g=C>.9?A[2](g):C>.45?A[1](g):A[0](g)}return g})},"undefined"==typeof console&&(console={warn:function(g){"use strict";alert(g)},log:function(g){"use strict";alert(g)},error:function(g){"use strict";throw g}}),I.helper.regexes={asteriskDashAndColon:/([*_:~])/g},I.helper.emojis={"+1":"๐","-1":"๐",100:"๐ฏ",1234:"๐ข","1st_place_medal":"๐ฅ","2nd_place_medal":"๐ฅ","3rd_place_medal":"๐ฅ","8ball":"๐ฑ",a:"๐
ฐ๏ธ",ab:"๐",abc:"๐ค",abcd:"๐ก",accept:"๐",aerial_tramway:"๐ก",airplane:"โ๏ธ",alarm_clock:"โฐ",alembic:"โ๏ธ",alien:"๐ฝ",ambulance:"๐",amphora:"๐บ",anchor:"โ๏ธ",angel:"๐ผ",anger:"๐ข",angry:"๐ ",anguished:"๐ง",ant:"๐",apple:"๐",aquarius:"โ๏ธ",aries:"โ๏ธ",arrow_backward:"โ๏ธ",arrow_double_down:"โฌ",arrow_double_up:"โซ",arrow_down:"โฌ๏ธ",arrow_down_small:"๐ฝ",arrow_forward:"โถ๏ธ",arrow_heading_down:"โคต๏ธ",arrow_heading_up:"โคด๏ธ",arrow_left:"โฌ
๏ธ",arrow_lower_left:"โ๏ธ",arrow_lower_right:"โ๏ธ",arrow_right:"โก๏ธ",arrow_right_hook:"โช๏ธ",arrow_up:"โฌ๏ธ",arrow_up_down:"โ๏ธ",arrow_up_small:"๐ผ",arrow_upper_left:"โ๏ธ",arrow_upper_right:"โ๏ธ",arrows_clockwise:"๐",arrows_counterclockwise:"๐",art:"๐จ",articulated_lorry:"๐",artificial_satellite:"๐ฐ",astonished:"๐ฒ",athletic_shoe:"๐",atm:"๐ง",atom_symbol:"โ๏ธ",avocado:"๐ฅ",b:"๐
ฑ๏ธ",baby:"๐ถ",baby_bottle:"๐ผ",baby_chick:"๐ค",baby_symbol:"๐ผ",back:"๐",bacon:"๐ฅ",badminton:"๐ธ",baggage_claim:"๐",baguette_bread:"๐ฅ",balance_scale:"โ๏ธ",balloon:"๐",ballot_box:"๐ณ",ballot_box_with_check:"โ๏ธ",bamboo:"๐",banana:"๐",bangbang:"โผ๏ธ",bank:"๐ฆ",bar_chart:"๐",barber:"๐",baseball:"โพ๏ธ",basketball:"๐",basketball_man:"โน๏ธ",basketball_woman:"โน๏ธ‍โ๏ธ",bat:"๐ฆ",bath:"๐",bathtub:"๐",battery:"๐",beach_umbrella:"๐",bear:"๐ป",bed:"๐",bee:"๐",beer:"๐บ",beers:"๐ป",beetle:"๐",beginner:"๐ฐ",bell:"๐",bellhop_bell:"๐",bento:"๐ฑ",biking_man:"๐ด",bike:"๐ฒ",biking_woman:"๐ด‍โ๏ธ",bikini:"๐",biohazard:"โฃ๏ธ",bird:"๐ฆ",birthday:"๐",black_circle:"โซ๏ธ",black_flag:"๐ด",black_heart:"๐ค",black_joker:"๐",black_large_square:"โฌ๏ธ",black_medium_small_square:"โพ๏ธ",black_medium_square:"โผ๏ธ",black_nib:"โ๏ธ",black_small_square:"โช๏ธ",black_square_button:"๐ฒ",blonde_man:"๐ฑ",blonde_woman:"๐ฑ‍โ๏ธ",blossom:"๐ผ",blowfish:"๐ก",blue_book:"๐",blue_car:"๐",blue_heart:"๐",blush:"๐",boar:"๐",boat:"โต๏ธ",bomb:"๐ฃ",book:"๐",bookmark:"๐",bookmark_tabs:"๐",books:"๐",boom:"๐ฅ",boot:"๐ข",bouquet:"๐",bowing_man:"๐",bow_and_arrow:"๐น",bowing_woman:"๐‍โ๏ธ",bowling:"๐ณ",boxing_glove:"๐ฅ",boy:"๐ฆ",bread:"๐",bride_with_veil:"๐ฐ",bridge_at_night:"๐",briefcase:"๐ผ",broken_heart:"๐",bug:"๐",building_construction:"๐",bulb:"๐ก",bullettrain_front:"๐
",bullettrain_side:"๐",burrito:"๐ฏ",bus:"๐",business_suit_levitating:"๐ด",busstop:"๐",bust_in_silhouette:"๐ค",busts_in_silhouette:"๐ฅ",butterfly:"๐ฆ",cactus:"๐ต",cake:"๐ฐ",calendar:"๐",call_me_hand:"๐ค",calling:"๐ฒ",camel:"๐ซ",camera:"๐ท",camera_flash:"๐ธ",camping:"๐",cancer:"โ๏ธ",candle:"๐ฏ",candy:"๐ฌ",canoe:"๐ถ",capital_abcd:"๐ ",capricorn:"โ๏ธ",car:"๐",card_file_box:"๐",card_index:"๐",card_index_dividers:"๐",carousel_horse:"๐ ",carrot:"๐ฅ",cat:"๐ฑ",cat2:"๐",cd:"๐ฟ",chains:"โ",champagne:"๐พ",chart:"๐น",chart_with_downwards_trend:"๐",chart_with_upwards_trend:"๐",checkered_flag:"๐",cheese:"๐ง",cherries:"๐",cherry_blossom:"๐ธ",chestnut:"๐ฐ",chicken:"๐",children_crossing:"๐ธ",chipmunk:"๐ฟ",chocolate_bar:"๐ซ",christmas_tree:"๐",church:"โช๏ธ",cinema:"๐ฆ",circus_tent:"๐ช",city_sunrise:"๐",city_sunset:"๐",cityscape:"๐",cl:"๐",clamp:"๐",clap:"๐",clapper:"๐ฌ",classical_building:"๐",clinking_glasses:"๐ฅ",clipboard:"๐",clock1:"๐",clock10:"๐",clock1030:"๐ฅ",clock11:"๐",clock1130:"๐ฆ",clock12:"๐",clock1230:"๐ง",clock130:"๐",clock2:"๐",clock230:"๐",clock3:"๐",clock330:"๐",clock4:"๐",clock430:"๐",clock5:"๐",clock530:"๐ ",clock6:"๐",clock630:"๐ก",clock7:"๐",clock730:"๐ข",clock8:"๐",clock830:"๐ฃ",clock9:"๐",clock930:"๐ค",closed_book:"๐",closed_lock_with_key:"๐",closed_umbrella:"๐",cloud:"โ๏ธ",cloud_with_lightning:"๐ฉ",cloud_with_lightning_and_rain:"โ",cloud_with_rain:"๐ง",cloud_with_snow:"๐จ",clown_face:"๐คก",clubs:"โฃ๏ธ",cocktail:"๐ธ",coffee:"โ๏ธ",coffin:"โฐ๏ธ",cold_sweat:"๐ฐ",comet:"โ๏ธ",computer:"๐ป",computer_mouse:"๐ฑ",confetti_ball:"๐",confounded:"๐",confused:"๐",congratulations:"ใ๏ธ",construction:"๐ง",construction_worker_man:"๐ท",construction_worker_woman:"๐ท‍โ๏ธ",control_knobs:"๐",convenience_store:"๐ช",cookie:"๐ช",cool:"๐",policeman:"๐ฎ",copyright:"ยฉ๏ธ",corn:"๐ฝ",couch_and_lamp:"๐",couple:"๐ซ",couple_with_heart_woman_man:"๐",couple_with_heart_man_man:"๐จ‍โค๏ธ‍๐จ",couple_with_heart_woman_woman:"๐ฉ‍โค๏ธ‍๐ฉ",couplekiss_man_man:"๐จ‍โค๏ธ‍๐‍๐จ",couplekiss_man_woman:"๐",couplekiss_woman_woman:"๐ฉ‍โค๏ธ‍๐‍๐ฉ",cow:"๐ฎ",cow2:"๐",cowboy_hat_face:"๐ค ",crab:"๐ฆ",crayon:"๐",credit_card:"๐ณ",crescent_moon:"๐",cricket:"๐",crocodile:"๐",croissant:"๐ฅ",crossed_fingers:"๐ค",crossed_flags:"๐",crossed_swords:"โ๏ธ",crown:"๐",cry:"๐ข",crying_cat_face:"๐ฟ",crystal_ball:"๐ฎ",cucumber:"๐ฅ",cupid:"๐",curly_loop:"โฐ",currency_exchange:"๐ฑ",curry:"๐",custard:"๐ฎ",customs:"๐",cyclone:"๐",dagger:"๐ก",dancer:"๐",dancing_women:"๐ฏ",dancing_men:"๐ฏ‍โ๏ธ",dango:"๐ก",dark_sunglasses:"๐ถ",dart:"๐ฏ",dash:"๐จ",date:"๐
",deciduous_tree:"๐ณ",deer:"๐ฆ",department_store:"๐ฌ",derelict_house:"๐",desert:"๐",desert_island:"๐",desktop_computer:"๐ฅ",male_detective:"๐ต๏ธ",diamond_shape_with_a_dot_inside:"๐ ",diamonds:"โฆ๏ธ",disappointed:"๐",disappointed_relieved:"๐ฅ",dizzy:"๐ซ",dizzy_face:"๐ต",do_not_litter:"๐ฏ",dog:"๐ถ",dog2:"๐",dollar:"๐ต",dolls:"๐",dolphin:"๐ฌ",door:"๐ช",doughnut:"๐ฉ",dove:"๐",dragon:"๐",dragon_face:"๐ฒ",dress:"๐",dromedary_camel:"๐ช",drooling_face:"๐คค",droplet:"๐ง",drum:"๐ฅ",duck:"๐ฆ",dvd:"๐","e-mail":"๐ง",eagle:"๐ฆ
",ear:"๐",ear_of_rice:"๐พ",earth_africa:"๐",earth_americas:"๐",earth_asia:"๐",egg:"๐ฅ",eggplant:"๐",eight_pointed_black_star:"โด๏ธ",eight_spoked_asterisk:"โณ๏ธ",electric_plug:"๐",elephant:"๐",email:"โ๏ธ",end:"๐",envelope_with_arrow:"๐ฉ",euro:"๐ถ",european_castle:"๐ฐ",european_post_office:"๐ค",evergreen_tree:"๐ฒ",exclamation:"โ๏ธ",expressionless:"๐",eye:"๐",eye_speech_bubble:"๐‍๐จ",eyeglasses:"๐",eyes:"๐",face_with_head_bandage:"๐ค",face_with_thermometer:"๐ค",fist_oncoming:"๐",factory:"๐ญ",fallen_leaf:"๐",family_man_woman_boy:"๐ช",family_man_boy:"๐จ‍๐ฆ",family_man_boy_boy:"๐จ‍๐ฆ‍๐ฆ",family_man_girl:"๐จ‍๐ง",family_man_girl_boy:"๐จ‍๐ง‍๐ฆ",family_man_girl_girl:"๐จ‍๐ง‍๐ง",family_man_man_boy:"๐จ‍๐จ‍๐ฆ",family_man_man_boy_boy:"๐จ‍๐จ‍๐ฆ‍๐ฆ",family_man_man_girl:"๐จ‍๐จ‍๐ง",family_man_man_girl_boy:"๐จ‍๐จ‍๐ง‍๐ฆ",family_man_man_girl_girl:"๐จ‍๐จ‍๐ง‍๐ง",family_man_woman_boy_boy:"๐จ‍๐ฉ‍๐ฆ‍๐ฆ",family_man_woman_girl:"๐จ‍๐ฉ‍๐ง",family_man_woman_girl_boy:"๐จ‍๐ฉ‍๐ง‍๐ฆ",family_man_woman_girl_girl:"๐จ‍๐ฉ‍๐ง‍๐ง",family_woman_boy:"๐ฉ‍๐ฆ",family_woman_boy_boy:"๐ฉ‍๐ฆ‍๐ฆ",family_woman_girl:"๐ฉ‍๐ง",family_woman_girl_boy:"๐ฉ‍๐ง‍๐ฆ",family_woman_girl_girl:"๐ฉ‍๐ง‍๐ง",family_woman_woman_boy:"๐ฉ‍๐ฉ‍๐ฆ",family_woman_woman_boy_boy:"๐ฉ‍๐ฉ‍๐ฆ‍๐ฆ",family_woman_woman_girl:"๐ฉ‍๐ฉ‍๐ง",family_woman_woman_girl_boy:"๐ฉ‍๐ฉ‍๐ง‍๐ฆ",family_woman_woman_girl_girl:"๐ฉ‍๐ฉ‍๐ง‍๐ง",fast_forward:"โฉ",fax:"๐ ",fearful:"๐จ",feet:"๐พ",female_detective:"๐ต๏ธ‍โ๏ธ",ferris_wheel:"๐ก",ferry:"โด",field_hockey:"๐",file_cabinet:"๐",file_folder:"๐",film_projector:"๐ฝ",film_strip:"๐",fire:"๐ฅ",fire_engine:"๐",fireworks:"๐",first_quarter_moon:"๐",first_quarter_moon_with_face:"๐",fish:"๐",fish_cake:"๐ฅ",fishing_pole_and_fish:"๐ฃ",fist_raised:"โ",fist_left:"๐ค",fist_right:"๐ค",flags:"๐",flashlight:"๐ฆ",fleur_de_lis:"โ๏ธ",flight_arrival:"๐ฌ",flight_departure:"๐ซ",floppy_disk:"๐พ",flower_playing_cards:"๐ด",flushed:"๐ณ",fog:"๐ซ",foggy:"๐",football:"๐",footprints:"๐ฃ",fork_and_knife:"๐ด",fountain:"โฒ๏ธ",fountain_pen:"๐",four_leaf_clover:"๐",fox_face:"๐ฆ",framed_picture:"๐ผ",free:"๐",fried_egg:"๐ณ",fried_shrimp:"๐ค",fries:"๐",frog:"๐ธ",frowning:"๐ฆ",frowning_face:"โน๏ธ",frowning_man:"๐‍โ๏ธ",frowning_woman:"๐",middle_finger:"๐",fuelpump:"โฝ๏ธ",full_moon:"๐",full_moon_with_face:"๐",funeral_urn:"โฑ๏ธ",game_die:"๐ฒ",gear:"โ๏ธ",gem:"๐",gemini:"โ๏ธ",ghost:"๐ป",gift:"๐",gift_heart:"๐",girl:"๐ง",globe_with_meridians:"๐",goal_net:"๐ฅ
",goat:"๐",golf:"โณ๏ธ",golfing_man:"๐๏ธ",golfing_woman:"๐๏ธ‍โ๏ธ",gorilla:"๐ฆ",grapes:"๐",green_apple:"๐",green_book:"๐",green_heart:"๐",green_salad:"๐ฅ",grey_exclamation:"โ",grey_question:"โ",grimacing:"๐ฌ",grin:"๐",grinning:"๐",guardsman:"๐",guardswoman:"๐‍โ๏ธ",guitar:"๐ธ",gun:"๐ซ",haircut_woman:"๐",haircut_man:"๐‍โ๏ธ",hamburger:"๐",hammer:"๐จ",hammer_and_pick:"โ",hammer_and_wrench:"๐ ",hamster:"๐น",hand:"โ",handbag:"๐",handshake:"๐ค",hankey:"๐ฉ",hatched_chick:"๐ฅ",hatching_chick:"๐ฃ",headphones:"๐ง",hear_no_evil:"๐",heart:"โค๏ธ",heart_decoration:"๐",heart_eyes:"๐",heart_eyes_cat:"๐ป",heartbeat:"๐",heartpulse:"๐",hearts:"โฅ๏ธ",heavy_check_mark:"โ๏ธ",heavy_division_sign:"โ",heavy_dollar_sign:"๐ฒ",heavy_heart_exclamation:"โฃ๏ธ",heavy_minus_sign:"โ",heavy_multiplication_x:"โ๏ธ",heavy_plus_sign:"โ",helicopter:"๐",herb:"๐ฟ",hibiscus:"๐บ",high_brightness:"๐",high_heel:"๐ ",hocho:"๐ช",hole:"๐ณ",honey_pot:"๐ฏ",horse:"๐ด",horse_racing:"๐",hospital:"๐ฅ",hot_pepper:"๐ถ",hotdog:"๐ญ",hotel:"๐จ",hotsprings:"โจ๏ธ",hourglass:"โ๏ธ",hourglass_flowing_sand:"โณ",house:"๐ ",house_with_garden:"๐ก",houses:"๐",hugs:"๐ค",hushed:"๐ฏ",ice_cream:"๐จ",ice_hockey:"๐",ice_skate:"โธ",icecream:"๐ฆ",id:"๐",ideograph_advantage:"๐",imp:"๐ฟ",inbox_tray:"๐ฅ",incoming_envelope:"๐จ",tipping_hand_woman:"๐",information_source:"โน๏ธ",innocent:"๐",interrobang:"โ๏ธ",iphone:"๐ฑ",izakaya_lantern:"๐ฎ",jack_o_lantern:"๐",japan:"๐พ",japanese_castle:"๐ฏ",japanese_goblin:"๐บ",japanese_ogre:"๐น",jeans:"๐",joy:"๐",joy_cat:"๐น",joystick:"๐น",kaaba:"๐",key:"๐",keyboard:"โจ๏ธ",keycap_ten:"๐",kick_scooter:"๐ด",kimono:"๐",kiss:"๐",kissing:"๐",kissing_cat:"๐ฝ",kissing_closed_eyes:"๐",kissing_heart:"๐",kissing_smiling_eyes:"๐",kiwi_fruit:"๐ฅ",koala:"๐จ",koko:"๐",label:"๐ท",large_blue_circle:"๐ต",large_blue_diamond:"๐ท",large_orange_diamond:"๐ถ",last_quarter_moon:"๐",last_quarter_moon_with_face:"๐",latin_cross:"โ๏ธ",laughing:"๐",leaves:"๐",ledger:"๐",left_luggage:"๐
",left_right_arrow:"โ๏ธ",leftwards_arrow_with_hook:"โฉ๏ธ",lemon:"๐",leo:"โ๏ธ",leopard:"๐",level_slider:"๐",libra:"โ๏ธ",light_rail:"๐",link:"๐",lion:"๐ฆ",lips:"๐",lipstick:"๐",lizard:"๐ฆ",lock:"๐",lock_with_ink_pen:"๐",lollipop:"๐ญ",loop:"โฟ",loud_sound:"๐",loudspeaker:"๐ข",love_hotel:"๐ฉ",love_letter:"๐",low_brightness:"๐
",lying_face:"๐คฅ",m:"โ๏ธ",mag:"๐",mag_right:"๐",mahjong:"๐๏ธ",mailbox:"๐ซ",mailbox_closed:"๐ช",mailbox_with_mail:"๐ฌ",mailbox_with_no_mail:"๐ญ",man:"๐จ",man_artist:"๐จ‍๐จ",man_astronaut:"๐จ‍๐",man_cartwheeling:"๐คธ‍โ๏ธ",man_cook:"๐จ‍๐ณ",man_dancing:"๐บ",man_facepalming:"๐คฆ‍โ๏ธ",man_factory_worker:"๐จ‍๐ญ",man_farmer:"๐จ‍๐พ",man_firefighter:"๐จ‍๐",man_health_worker:"๐จ‍โ๏ธ",man_in_tuxedo:"๐คต",man_judge:"๐จ‍โ๏ธ",man_juggling:"๐คน‍โ๏ธ",man_mechanic:"๐จ‍๐ง",man_office_worker:"๐จ‍๐ผ",man_pilot:"๐จ‍โ๏ธ",man_playing_handball:"๐คพ‍โ๏ธ",man_playing_water_polo:"๐คฝ‍โ๏ธ",man_scientist:"๐จ‍๐ฌ",man_shrugging:"๐คท‍โ๏ธ",man_singer:"๐จ‍๐ค",man_student:"๐จ‍๐",man_teacher:"๐จ‍๐ซ",man_technologist:"๐จ‍๐ป",man_with_gua_pi_mao:"๐ฒ",man_with_turban:"๐ณ",tangerine:"๐",mans_shoe:"๐",mantelpiece_clock:"๐ฐ",maple_leaf:"๐",martial_arts_uniform:"๐ฅ",mask:"๐ท",massage_woman:"๐",massage_man:"๐‍โ๏ธ",meat_on_bone:"๐",medal_military:"๐",medal_sports:"๐
",mega:"๐ฃ",melon:"๐",memo:"๐",men_wrestling:"๐คผ‍โ๏ธ",menorah:"๐",mens:"๐น",metal:"๐ค",metro:"๐",microphone:"๐ค",microscope:"๐ฌ",milk_glass:"๐ฅ",milky_way:"๐",minibus:"๐",minidisc:"๐ฝ",mobile_phone_off:"๐ด",money_mouth_face:"๐ค",money_with_wings:"๐ธ",moneybag:"๐ฐ",monkey:"๐",monkey_face:"๐ต",monorail:"๐",moon:"๐",mortar_board:"๐",mosque:"๐",motor_boat:"๐ฅ",motor_scooter:"๐ต",motorcycle:"๐",motorway:"๐ฃ",mount_fuji:"๐ป",mountain:"โฐ",mountain_biking_man:"๐ต",mountain_biking_woman:"๐ต‍โ๏ธ",mountain_cableway:"๐ ",mountain_railway:"๐",mountain_snow:"๐",mouse:"๐ญ",mouse2:"๐",movie_camera:"๐ฅ",moyai:"๐ฟ",mrs_claus:"๐คถ",muscle:"๐ช",mushroom:"๐",musical_keyboard:"๐น",musical_note:"๐ต",musical_score:"๐ผ",mute:"๐",nail_care:"๐
",name_badge:"๐",national_park:"๐",nauseated_face:"๐คข",necktie:"๐",negative_squared_cross_mark:"โ",nerd_face:"๐ค",neutral_face:"๐",new:"๐",new_moon:"๐",new_moon_with_face:"๐",newspaper:"๐ฐ",newspaper_roll:"๐",next_track_button:"โญ",ng:"๐",no_good_man:"๐
‍โ๏ธ",no_good_woman:"๐
",night_with_stars:"๐",no_bell:"๐",no_bicycles:"๐ณ",no_entry:"โ๏ธ",no_entry_sign:"๐ซ",no_mobile_phones:"๐ต",no_mouth:"๐ถ",no_pedestrians:"๐ท",no_smoking:"๐ญ","non-potable_water":"๐ฑ",nose:"๐",notebook:"๐",notebook_with_decorative_cover:"๐",notes:"๐ถ",nut_and_bolt:"๐ฉ",o:"โญ๏ธ",o2:"๐
พ๏ธ",ocean:"๐",octopus:"๐",oden:"๐ข",office:"๐ข",oil_drum:"๐ข",ok:"๐",ok_hand:"๐",ok_man:"๐‍โ๏ธ",ok_woman:"๐",old_key:"๐",older_man:"๐ด",older_woman:"๐ต",om:"๐",on:"๐",oncoming_automobile:"๐",oncoming_bus:"๐",oncoming_police_car:"๐",oncoming_taxi:"๐",open_file_folder:"๐",open_hands:"๐",open_mouth:"๐ฎ",open_umbrella:"โ๏ธ",ophiuchus:"โ",orange_book:"๐",orthodox_cross:"โฆ๏ธ",outbox_tray:"๐ค",owl:"๐ฆ",ox:"๐",package:"๐ฆ",page_facing_up:"๐",page_with_curl:"๐",pager:"๐",paintbrush:"๐",palm_tree:"๐ด",pancakes:"๐ฅ",panda_face:"๐ผ",paperclip:"๐",paperclips:"๐",parasol_on_ground:"โฑ",parking:"๐
ฟ๏ธ",part_alternation_mark:"ใฝ๏ธ",partly_sunny:"โ
๏ธ",passenger_ship:"๐ณ",passport_control:"๐",pause_button:"โธ",peace_symbol:"โฎ๏ธ",peach:"๐",peanuts:"๐ฅ",pear:"๐",pen:"๐",pencil2:"โ๏ธ",penguin:"๐ง",pensive:"๐",performing_arts:"๐ญ",persevere:"๐ฃ",person_fencing:"๐คบ",pouting_woman:"๐",phone:"โ๏ธ",pick:"โ",pig:"๐ท",pig2:"๐",pig_nose:"๐ฝ",pill:"๐",pineapple:"๐",ping_pong:"๐",pisces:"โ๏ธ",pizza:"๐",place_of_worship:"๐",plate_with_cutlery:"๐ฝ",play_or_pause_button:"โฏ",point_down:"๐",point_left:"๐",point_right:"๐",point_up:"โ๏ธ",point_up_2:"๐",police_car:"๐",policewoman:"๐ฎ‍โ๏ธ",poodle:"๐ฉ",popcorn:"๐ฟ",post_office:"๐ฃ",postal_horn:"๐ฏ",postbox:"๐ฎ",potable_water:"๐ฐ",potato:"๐ฅ",pouch:"๐",poultry_leg:"๐",pound:"๐ท",rage:"๐ก",pouting_cat:"๐พ",pouting_man:"๐‍โ๏ธ",pray:"๐",prayer_beads:"๐ฟ",pregnant_woman:"๐คฐ",previous_track_button:"โฎ",prince:"๐คด",princess:"๐ธ",printer:"๐จ",purple_heart:"๐",purse:"๐",pushpin:"๐",put_litter_in_its_place:"๐ฎ",question:"โ",rabbit:"๐ฐ",rabbit2:"๐",racehorse:"๐",racing_car:"๐",radio:"๐ป",radio_button:"๐",radioactive:"โข๏ธ",railway_car:"๐",railway_track:"๐ค",rainbow:"๐",rainbow_flag:"๐ณ๏ธ‍๐",raised_back_of_hand:"๐ค",raised_hand_with_fingers_splayed:"๐",raised_hands:"๐",raising_hand_woman:"๐",raising_hand_man:"๐‍โ๏ธ",ram:"๐",ramen:"๐",rat:"๐",record_button:"โบ",recycle:"โป๏ธ",red_circle:"๐ด",registered:"ยฎ๏ธ",relaxed:"โบ๏ธ",relieved:"๐",reminder_ribbon:"๐",repeat:"๐",repeat_one:"๐",rescue_worker_helmet:"โ",restroom:"๐ป",revolving_hearts:"๐",rewind:"โช",rhinoceros:"๐ฆ",ribbon:"๐",rice:"๐",rice_ball:"๐",rice_cracker:"๐",rice_scene:"๐",right_anger_bubble:"๐ฏ",ring:"๐",robot:"๐ค",rocket:"๐",rofl:"๐คฃ",roll_eyes:"๐",roller_coaster:"๐ข",rooster:"๐",rose:"๐น",rosette:"๐ต",rotating_light:"๐จ",round_pushpin:"๐",rowing_man:"๐ฃ",rowing_woman:"๐ฃ‍โ๏ธ",rugby_football:"๐",running_man:"๐",running_shirt_with_sash:"๐ฝ",running_woman:"๐‍โ๏ธ",sa:"๐๏ธ",sagittarius:"โ๏ธ",sake:"๐ถ",sandal:"๐ก",santa:"๐
",satellite:"๐ก",saxophone:"๐ท",school:"๐ซ",school_satchel:"๐",scissors:"โ๏ธ",scorpion:"๐ฆ",scorpius:"โ๏ธ",scream:"๐ฑ",scream_cat:"๐",scroll:"๐",seat:"๐บ",secret:"ใ๏ธ",see_no_evil:"๐",seedling:"๐ฑ",selfie:"๐คณ",shallow_pan_of_food:"๐ฅ",shamrock:"โ๏ธ",shark:"๐ฆ",shaved_ice:"๐ง",sheep:"๐",shell:"๐",shield:"๐ก",shinto_shrine:"โฉ",ship:"๐ข",shirt:"๐",shopping:"๐",shopping_cart:"๐",shower:"๐ฟ",shrimp:"๐ฆ",signal_strength:"๐ถ",six_pointed_star:"๐ฏ",ski:"๐ฟ",skier:"โท",skull:"๐",skull_and_crossbones:"โ ๏ธ",sleeping:"๐ด",sleeping_bed:"๐",sleepy:"๐ช",slightly_frowning_face:"๐",slightly_smiling_face:"๐",slot_machine:"๐ฐ",small_airplane:"๐ฉ",small_blue_diamond:"๐น",small_orange_diamond:"๐ธ",small_red_triangle:"๐บ",small_red_triangle_down:"๐ป",smile:"๐",smile_cat:"๐ธ",smiley:"๐",smiley_cat:"๐บ",smiling_imp:"๐",smirk:"๐",smirk_cat:"๐ผ",smoking:"๐ฌ",snail:"๐",snake:"๐",sneezing_face:"๐คง",snowboarder:"๐",snowflake:"โ๏ธ",snowman:"โ๏ธ",snowman_with_snow:"โ๏ธ",sob:"๐ญ",soccer:"โฝ๏ธ",soon:"๐",sos:"๐",sound:"๐",space_invader:"๐พ",spades:"โ ๏ธ",spaghetti:"๐",sparkle:"โ๏ธ",sparkler:"๐",sparkles:"โจ",sparkling_heart:"๐",speak_no_evil:"๐",speaker:"๐",speaking_head:"๐ฃ",speech_balloon:"๐ฌ",speedboat:"๐ค",spider:"๐ท",spider_web:"๐ธ",spiral_calendar:"๐",spiral_notepad:"๐",spoon:"๐ฅ",squid:"๐ฆ",stadium:"๐",star:"โญ๏ธ",star2:"๐",star_and_crescent:"โช๏ธ",star_of_david:"โก๏ธ",stars:"๐ ",station:"๐",statue_of_liberty:"๐ฝ",steam_locomotive:"๐",stew:"๐ฒ",stop_button:"โน",stop_sign:"๐",stopwatch:"โฑ",straight_ruler:"๐",strawberry:"๐",stuck_out_tongue:"๐",stuck_out_tongue_closed_eyes:"๐",stuck_out_tongue_winking_eye:"๐",studio_microphone:"๐",stuffed_flatbread:"๐ฅ",sun_behind_large_cloud:"๐ฅ",sun_behind_rain_cloud:"๐ฆ",sun_behind_small_cloud:"๐ค",sun_with_face:"๐",sunflower:"๐ป",sunglasses:"๐",sunny:"โ๏ธ",sunrise:"๐
",sunrise_over_mountains:"๐",surfing_man:"๐",surfing_woman:"๐‍โ๏ธ",sushi:"๐ฃ",suspension_railway:"๐",sweat:"๐",sweat_drops:"๐ฆ",sweat_smile:"๐
",sweet_potato:"๐ ",swimming_man:"๐",swimming_woman:"๐‍โ๏ธ",symbols:"๐ฃ",synagogue:"๐",syringe:"๐",taco:"๐ฎ",tada:"๐",tanabata_tree:"๐",taurus:"โ๏ธ",taxi:"๐",tea:"๐ต",telephone_receiver:"๐",telescope:"๐ญ",tennis:"๐พ",tent:"โบ๏ธ",thermometer:"๐ก",thinking:"๐ค",thought_balloon:"๐ญ",ticket:"๐ซ",tickets:"๐",tiger:"๐ฏ",tiger2:"๐
",timer_clock:"โฒ",tipping_hand_man:"๐‍โ๏ธ",tired_face:"๐ซ",tm:"โข๏ธ",toilet:"๐ฝ",tokyo_tower:"๐ผ",tomato:"๐
",tongue:"๐
",top:"๐",tophat:"๐ฉ",tornado:"๐ช",trackball:"๐ฒ",tractor:"๐",traffic_light:"๐ฅ",train:"๐",train2:"๐",tram:"๐",triangular_flag_on_post:"๐ฉ",triangular_ruler:"๐",trident:"๐ฑ",triumph:"๐ค",trolleybus:"๐",trophy:"๐",tropical_drink:"๐น",tropical_fish:"๐ ",truck:"๐",trumpet:"๐บ",tulip:"๐ท",tumbler_glass:"๐ฅ",turkey:"๐ฆ",turtle:"๐ข",tv:"๐บ",twisted_rightwards_arrows:"๐",two_hearts:"๐",two_men_holding_hands:"๐ฌ",two_women_holding_hands:"๐ญ",u5272:"๐น",u5408:"๐ด",u55b6:"๐บ",u6307:"๐ฏ๏ธ",u6708:"๐ท๏ธ",u6709:"๐ถ",u6e80:"๐ต",u7121:"๐๏ธ",u7533:"๐ธ",u7981:"๐ฒ",u7a7a:"๐ณ",umbrella:"โ๏ธ",unamused:"๐",underage:"๐",unicorn:"๐ฆ",unlock:"๐",up:"๐",upside_down_face:"๐",v:"โ๏ธ",vertical_traffic_light:"๐ฆ",vhs:"๐ผ",vibration_mode:"๐ณ",video_camera:"๐น",video_game:"๐ฎ",violin:"๐ป",virgo:"โ๏ธ",volcano:"๐",volleyball:"๐",vs:"๐",vulcan_salute:"๐",walking_man:"๐ถ",walking_woman:"๐ถ‍โ๏ธ",waning_crescent_moon:"๐",waning_gibbous_moon:"๐",warning:"โ ๏ธ",wastebasket:"๐",watch:"โ๏ธ",water_buffalo:"๐",watermelon:"๐",wave:"๐",wavy_dash:"ใฐ๏ธ",waxing_crescent_moon:"๐",wc:"๐พ",weary:"๐ฉ",wedding:"๐",weight_lifting_man:"๐๏ธ",weight_lifting_woman:"๐๏ธ‍โ๏ธ",whale:"๐ณ",whale2:"๐",wheel_of_dharma:"โธ๏ธ",wheelchair:"โฟ๏ธ",white_check_mark:"โ
",white_circle:"โช๏ธ",white_flag:"๐ณ๏ธ",white_flower:"๐ฎ",white_large_square:"โฌ๏ธ",white_medium_small_square:"โฝ๏ธ",white_medium_square:"โป๏ธ",white_small_square:"โซ๏ธ",white_square_button:"๐ณ",wilted_flower:"๐ฅ",wind_chime:"๐",wind_face:"๐ฌ",wine_glass:"๐ท",wink:"๐",wolf:"๐บ",woman:"๐ฉ",woman_artist:"๐ฉ‍๐จ",woman_astronaut:"๐ฉ‍๐",woman_cartwheeling:"๐คธ‍โ๏ธ",woman_cook:"๐ฉ‍๐ณ",woman_facepalming:"๐คฆ‍โ๏ธ",woman_factory_worker:"๐ฉ‍๐ญ",woman_farmer:"๐ฉ‍๐พ",woman_firefighter:"๐ฉ‍๐",woman_health_worker:"๐ฉ‍โ๏ธ",woman_judge:"๐ฉ‍โ๏ธ",woman_juggling:"๐คน‍โ๏ธ",woman_mechanic:"๐ฉ‍๐ง",woman_office_worker:"๐ฉ‍๐ผ",woman_pilot:"๐ฉ‍โ๏ธ",woman_playing_handball:"๐คพ‍โ๏ธ",woman_playing_water_polo:"๐คฝ‍โ๏ธ",woman_scientist:"๐ฉ‍๐ฌ",woman_shrugging:"๐คท‍โ๏ธ",woman_singer:"๐ฉ‍๐ค",woman_student:"๐ฉ‍๐",woman_teacher:"๐ฉ‍๐ซ",woman_technologist:"๐ฉ‍๐ป",woman_with_turban:"๐ณ‍โ๏ธ",womans_clothes:"๐",womans_hat:"๐",women_wrestling:"๐คผ‍โ๏ธ",womens:"๐บ",world_map:"๐บ",worried:"๐",wrench:"๐ง",writing_hand:"โ๏ธ",x:"โ",yellow_heart:"๐",yen:"๐ด",yin_yang:"โฏ๏ธ",yum:"๐",zap:"โก๏ธ",zipper_mouth_face:"๐ค",zzz:"๐ค",octocat:'<img width="20" height="20" align="absmiddle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAOwUlEQVR42uVbCVyO6RbPmn0sw9gZS0aZO4y5GTEUE2ObxjZjrbHEJVy3sWS5pkaWxjLEkCVDSbSgFLdESaWSLIVUSIi4kvb9f895vi/zbbR+yZ339/tbnu99n/ec/3Oe85xznufV0CjDBaAdwZqwnzCJ0FXjHV70/i8J5oQDhCFV8cJdq1atwqxZs+Ds7Iz4+HhqwgXCLELNKlK6G2Ej4e6lS5ewZcsWzJgxA+fOnWNZFqvzxT1v3boF/qcsBg0ahP3796OwsJAFWKYuIqjfPoS9cXFxWL58Obp06SInh5aWFr//jjoJWLlu3TolAorRuXNn7Ny5k4W4Spgj81xrgj5hLmED4RDhlNRygglBhADCSakpWxFMCHoETUJTwrYHDx7A1NT0je9nPHz4kN/fXl0EeI0aNeqtAjB69+4NPz8/FsSdlXvy5An8/f1hZ2cHCwsLGBsbY/To0cJy9PT0MGDAAAwePBhGRkbClNesWYODBw8iODgYOTk53M/d9evXo27duiW++8iRI3z/ZHURENOjR48ShSjGuHHjhHJ16tQp9TOKaNWqlZKpvw1MHluQOpSvk5eXh5YtW5ZbmarAvHnzmIBd6iCgXnZ2Npo1a1atCWAfwY5SHQTUKCoqQocOHao1AebmHBJgi7p8QBDP6epMwKFDvMDAWF0ELLS1ta3WBNy9e5cJMFIXAdvt7e2rNQHDhw9nAv5D+KKylV9y8+bNCi1pVYWZM2cyCfaVTcDdsqzH7xpBQRxcwqyylLdi5/K+KM/Q0dFhAqIri4Bn1T0AUgVpdmhYUeVHnD59+r1TnjF27Fgm4HhFCThoYmLyXhLQoEGD4mRKsyIE3OrZs+d7SQCDCyZcNSqv8k1evXoFTU3NUr+wzUcfYqRBf8yb/C2WzfoBFoTF08fBdMIITDD8CsP1+kL30x7Q6dYZH7drjfZ0f4fWLdG1Q1t81qMLBvTRwejB/TBl1BDMnzQGS2dMxKo5k7Fs9iSY/jAaBvR8Pc26pZaH02quLZSXgO6xsbGlelGnli1wZKcVMqN8gKcRwItrf+K/VB95doXaLwOJIVSzOU/+2Re5kV7IuuyJrIhTyLt6mmztLBBPNZLHoUAy9fE8UvJ8ikxfj8PwJPQErJeYlkquTZs2MQFLykuANgc/Jb2kn3Z3ZMaQUrmxwO1zyAo7gfRAJ6RfOIyMEFdkXj5F8BTK5lzxQv610yi8QcFatI8gQoCIK7x+hojwRnaE5H4JTiEj9Pjr/rJDqcZyn9b4ovu45LYbdWvXeqtsXMHiSlZ5CegRExPz1hd83PYj5POo0QinXyLFg48hnZTOiQ1Dzr1IZEaeQRoJn0HKZIR7lA2kfHrQUerXHTlx4ZL+rnjjFRGRGeYB5MUj2GnbW+XbuJFrp1heXgI6JCYmvvUFN1x3Aek3SWkapRAXMeJFGS8ge2Xfuog0toaykED3Mpk8+shOk+sv68Y50V9WuKewBKt5094o39atW/mRf5WXgIYZGRlo3Lixys4nj6A6Z1YMcqRCpwU4ouDlUyHk/QA/hNttR25Wlvh/ZthJUsil9ATQ/axkYbqEzDgfL0Ts/x35+aLyTES7IY36Q6w/+Q4/tP6wuUoZ9+7dy7ebVmQZjO/atavKzn32rAdeXkd6KCkXdAxZ13yFcLFnvPD73zrDVrsdTs6eggKSuSjjORHkUGoC0i86Iyc6QPQX7eqMnTodYNuzHU4vnosiaitMSUSavwMy6d3IvEUrzViVMrq5uXEX4ytCgL++vr5Sx7Vr1cIDX0dKkQJfj37Rs3jw1sBxkwlwGD4Ax3+ciN1faCHW76xQRFgAOcjSEMBkIe0x8nLzcez7kTg8Rh/uxuOxR/cTJISFSfq7eATpZCk8CAfXLVFJwIULXHnHoIoQYLtw4UKljps2aogXQcQuef/XAiMDKY+S4DhyEFwpDnCj9f+Afl8EbbWRTANaAdihlYoAMn8aZzyNuYODX/eD29TvRH/7v+qN8H27JdOAyWQfQQ74xPafVRLAPox9WUlK6hIGEgx4f00Kg2JcvHhRqeP6FIwknXemyen/2gLIIeC/CYk49M0AuE4xgtu0sThg8AUCN62TEuBdRgJo2Y+Kxh9D/k59SQiwH9QHobt3SAk4KSGA4oWjm1YqyVi8U6Soj4yOrHM/jTAyKVby/PnzIoNi8L+L4eXlpXoFcLcTgc1rAlISkJeXDxeK2A6P1hdTwI6mQPTJE+WbAlnJyE7PhNO3Q3BkrKGYWtxfHMkkmQLO0ilwA7+vXqAkn66urtBLUZ9iHfm30NBQaPAf165dA0d9vP2UlJSEp0+f4vHjx3j06JH4e+rUqUovcNmyGkiNEkLwklXsBG+ecMUOnfbYod1emG5uboFKJ8jPFVD0l0dBUHqoPDHpQeQEb0qc4FUHe3KAbYUT9JgzDbwOFL5MfN0fXkXhJ5PxSvLt2LFD1Ah5u4z1YJ14l4qnBe8v3rhxAzz4PAVG8nLHivIP0dHRiIiIQGRkpEgmrl69ClW1QBMjQ7LDW8hmU+RRI69ckJIkhL7jfRJBm62R+TJVYq6h0jhBRslsivqenT2MF/7OyI70VmkFhWnPJaS6OyPkt43IycqR9EfWlH7JDQUUTuNhCHR7Ke9YcRp/5coVoQPrcvnyZURFRYmBZlLS0kR8MVLD29sbnp6e8PHxQUBAgCgn8YO8E3z79m3BGKeVc+bMkXuBZt06SA12F/F5Go0gR4C8HBalPZMPXKL8lQKhPAqF+f97KXFyNx6HQsoPsshJ/kmAp2TKkJLISpXvjyxNhMYcDVLOEO+lPDi8B5mamipkZx1YF9YpJCRErAy+vr5CZ9ZdWABhDGEYYTBhAOFz3g4nfMJelNCbkNCpUye5F034mvxIPi1/FM+zQCw0k5B9O0iEr5kRXkqhMJOVf9NXIHjtT7hmaymSoBzKETimkAuFpaF1dkwI9RcmIYaXv3BJXoGCuyIgk5WpefPmKCgoYK46SmX/RKoL69Sfl0WuFEl1HlmWJXE5z6WmTZvKJxxmxkIQ3AuU5APk6NICj4hRT6eITTEEzqWk55HHPjz3cxJhNF5cxeNT9kj2cRDTQjEkzpDtjyyCic5l5fEA7uSHFEefR5pPsahrb2B9QkICFHeJ51HunkdLIg0VLY0BFKdLwllVHp4dHyvst3QuEiiju21vA/+VZkiluIKt4I3RIfWXQ4QgKUxkni47LJWUP3PmjHo2RxVI+CebmKJP6EiFDVurxUgmExe5PHlnPAkn8w4QqW62NCVmYopozid5H0CI9RKE21ggJeAYEeMnfitOnRn5XCfgeJ+VTosWQU8MOc6ZE0cqnUm4fv165SrPBVHCfMI4TowUfmOfsIcdJh92kBWmUcP6GDt8EDZbzIffH5tx3/ewSFjw5LKk0MEFEkZenDBjgew7Yiog5brkt+QrknvJmhIp4Apw/A1bVpjhG/0v5d7Vrl07bNu2TelUSqUoz8uI3Z49OEtBAy+TdP1CqKtwHzvQUxxgTJs2TeX5gdq1a0ObSmCjh+jB+NuvRamL1+3ls77HCip1rTSdJP5eNnMizKndjMLoH42G4bthX+FzHS3UVVEC69evH3799VeKMXJZrlWKclUGAZ5jxoxB02ZNsNlxH74aagBHZyex986HlVTczyGmI58h4CjL2toa48ePFxsUPEotWrQoc0GT0/C2bduiY8eO4ISMcxLeoOFYhS6qm2EpoZG65jmbv+dPSyRZlt5QfVjvtX19AOFNL+aDFNI4m0eFc9Ho5ORkaGtrl5kAVp6DMOk88efEjLe++ZhclZwHTJHEHbs4YOCmLj2645fdvwnTK42zoXtaEHwNDQ3LXdZm5yad3/2r+gQmDsRnIF5KAldX6zdsgG/GG8F44Vzcu3eP2y1K6GPr2rVrK1zbnz59Or/LoaoJCPZ4kCZsjw9GECL79OmDj9q2wb+320C3/5fgPQO6Vrzh+fpcDqxXr16lbHBwgkZXm6okYJr0ECMrX5vraiJ1lArEjrEnzWuOqemiYj9spGd2ee478XkiPsJakmJ83qA05/8qXNurJFLiunXrhpo1a6LxB02wyHIFZpovgOHwYfjZ0hK2lH5u2rwZ5suWYv5ycyUlmjRpgl69eimlrFy3kwuoyOvXr19frm3RokVMwPZ3TYC57E6xVq+e6KzVDSaL/oEp82Zh8IhhWLjGAp/p9oX5ujVKBNjY2MDV1VWuzd3dXaTesm2biUQuZ8u28elSPmKr8a4vdog8GnJpcT1N1KHUuBbt0jSgWuGbzJh3mVhh2TYHBwdxjFa2jVcZnvPVlQBOLXdZWlqW2ZFxNYYVlm07fPgwAgMD5dr4OD5HeHLFFxM+O42DGtXhIkFaMQlcUjIzM0P37t1Ro0YNpZPjPJcVK7SOjo5ybU5OTqIAo0gAh97VlgAZIj4l8Pn4WFaO64ocuXG6zJtDbMqySnC7IgF8uptLVrJtq1evFuWqak+A4j4i4TNpltiJ8LPiNFFFwNGjRyWFyfedAFUny/joekkEuLi4KK0CfykCeFnkiu1flgBeFtl3/D8SsMbKykpOifv37ysRcPz4cVHKUiSA8wwNdR9/VTMBSh9Y8S4Nf2qnSICiBbDzVCRg9uzZTMC+94kAv6FDh8opwRsVHPjItnl4eEDxHNLKlStFXV+2javQ/M1SpZe+1KA4L4G7WDG57fSm/OUbXiqG0ewAFYOeYcN4fwZhvLkp2y4tftrxcltdlf/w+fPn4qNGxTCYU2m6nrRu3VqunT/EoiuZvw6TTZHpyuNNmEaNGsndP3fu3OJAq1N1JOAHDmyKheVtNP4OkE2crULRAW7fvl20EyyLy24a8p+/7WISFixYIMLt4t82bNhQYjXqXREgPq3j74mlX3AmSL8E1eOPIBXnuVT5OsVZpuLnOMeOHeN7vifwiYhYzhC5IpwlOXj1QXWdBmy/XWU/X+UqMZfKBw4cKAobHPlJlZe9h6tOu+7cuSN2dg0MDMSSyZUpmXvaSD+crq/xvl0k9BTCRa7qEPq+5T4t6ffF52WVV+f1P6zyLG30bsU4AAAAAElFTkSuQmCC">',showdown:'<img width="20" height="20" align="absmiddle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAECtaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzA2NyA3OS4xNTc3NDcsIDIwMTUvMDMvMzAtMjM6NDA6NDIgICAgICAgICI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTUtMDEtMTVUMjE6MDE6MTlaPC94bXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxNy0xMC0yNFQxMzozMTozMCswMTowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPHhtcDpNb2RpZnlEYXRlPjIwMTctMTAtMjRUMTM6MzE6MzArMDE6MDA8L3htcDpNb2RpZnlEYXRlPgogICAgICAgICA8cGhvdG9zaG9wOkNvbG9yTW9kZT4zPC9waG90b3Nob3A6Q29sb3JNb2RlPgogICAgICAgICA8cGhvdG9zaG9wOklDQ1Byb2ZpbGU+c1JHQiBJRUM2MTk2Ni0yLjE8L3Bob3Rvc2hvcDpJQ0NQcm9maWxlPgogICAgICAgICA8cGhvdG9zaG9wOlRleHRMYXllcnM+CiAgICAgICAgICAgIDxyZGY6QmFnPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHBob3Rvc2hvcDpMYXllck5hbWU+UyAtPC9waG90b3Nob3A6TGF5ZXJOYW1lPgogICAgICAgICAgICAgICAgICA8cGhvdG9zaG9wOkxheWVyVGV4dD5TIC08L3Bob3Rvc2hvcDpMYXllclRleHQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgIDwvcGhvdG9zaG9wOlRleHRMYXllcnM+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6N2NkMzQxNzctOWYyZi0yNDRiLWEyYjQtMzU1MzJkY2Y1MWJiPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6M2E1YzgxYmYtYjhiNy0xMWU3LTk0NDktYTQ2MzdlZjJkNjMzPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkhpc3Rvcnk+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jcmVhdGVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTUtMDEtMTVUMjE6MDE6MTlaPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6ODZjNjBkMGQtOGY0Yy01ZTRlLWEwMjQtODI4ZWQyNTIwZDc3PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE3LTEwLTI0VDEzOjMxOjMwKzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoV2luZG93cyk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jb252ZXJ0ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnBhcmFtZXRlcnM+ZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZzwvc3RFdnQ6cGFyYW1ldGVycz4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmRlcml2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnBhcmFtZXRlcnM+Y29udmVydGVkIGZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmc8L3N0RXZ0OnBhcmFtZXRlcnM+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOjdjZDM0MTc3LTlmMmYtMjQ0Yi1hMmI0LTM1NTMyZGNmNTFiYjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNy0xMC0yNFQxMzozMTozMCswMTowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICAgICA8c3RFdnQ6Y2hhbmdlZD4vPC9zdEV2dDpjaGFuZ2VkPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICA8L3htcE1NOkhpc3Rvcnk+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0YW5jZUlEPnhtcC5paWQ6ODZjNjBkMGQtOGY0Yy01ZTRlLWEwMjQtODI4ZWQyNTIwZDc3PC9zdFJlZjppbnN0YW5jZUlEPgogICAgICAgICAgICA8c3RSZWY6ZG9jdW1lbnRJRD54bXAuZGlkOjYwQzVBRTY1RjY5Q0U0MTE5NDVBODU1RTNCQ0E3RUVCPC9zdFJlZjpkb2N1bWVudElEPgogICAgICAgICAgICA8c3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3N0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPC94bXBNTTpEZXJpdmVkRnJvbT4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+NzIwMDAwLzEwMDAwPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WVJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+MTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NjQ8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+NjQ8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/Pse7bzcAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAA1JJREFUeNrsm1+OmlAUhz+aeS9dwZggJn1AnRUMO6jpBgZXULuC2hWUWUGZBTSxKyiuoA4mfUBMnB04K5g+9DihRBHlyh/lJLwIXLgf99xzzu9etZeXFy7Z3nDh1gBoAFy4XeVtQNO0zNcapmUDfUBPnFoBfhQGq6IBaHmjwD4Ahmk5wAD4kKG5J8CNwsAFaHe6DvA9cc0wCgOv8gDka3vA9RHNPgo0D7hNnJtGYWBXxgV2dH4MfMnRRA+Y1WIO2NJ5F/ikoKm3tYsChmkNFHW+fmHQMC1dfHaXPQP3wM1yMdc2B/AOGALTWobBmI1Shu0UGCwX83XyRBQGawHntTtdG5gUNfxVu4CTNqNv6/wWGL7kCc+1AmCYVisl3I2ydD4GYZUCs7IjoLXrxHIx9w9tLAqDCfBwDrXAY457x+cAoCfuwRGjYFUnAGk+PsjR7s8Dn1VeLWCYVlpDw+VivjVHSHt+u9PVJbzGzZXQWTkAkz0V31fATUaEsjVJlQBs4FeGcteLgzgbAALBA+4y3voAeJL8nA0AHfClnM1qm1HhnYUidCSE+KzvSSJUTwAxCOMcpfETMFYpfRUKIAbCFhC3OTJJJwqDWS0BxED0JZ4Pjix1P2+E0loCSMBwyK4S/xc1ojBwag8gMU84cvTKGgmlAYhngu1O9xAXuVE5J1QCQCz3bwHuHvdQui5QKQAxEO6eEKpsFCgTRSXkvdoxSlBMCxhJJbgrrbZRtHCiShN0pRB6PeQ3ckBw2K0oKXMBVYJIP+Nvh9qulFivGoBt1lLQxowT2ykBXCfnhZIglgYACWmqXQv+baioBYCeiCQHm+QEg1O7RhF7hO4OhSAhcJKSFU7qBGADwZeqMMuXn6TUBw8qlaMrirNb4LdhWlP+SWD+cjFfxTpuS2GUpik+o3jFSEkqbJiWn0P0OMSGqlWiOu0TvD+FRHZKAE+oW+cfRmEwqlsesJJEJs8y91QqP+9UL6lqEtz2gpuNEY5sm9sIHln2DRa2aFKGJtiXkZEMiWtgVvRKUSUFkSKt2S7fAGgAXLYpmQQXf36MUChTZdUa2u8/rkvPA6Tz30r4eH3ybcBS5gJ6SaNXb+aABkA1AMxKenclBZLW/He4cYEGwEXb3wEASelexk6LIIIAAAAASUVORK5CYII=">'},I.Converter=function(g){"use strict";function C(g,C){if(C=C||null,I.helper.isString(g)){if(g=I.helper.stdExtName(g),C=g,I.extensions[g])return console.warn("DEPRECATION WARNING: "+g+" is an old extension that uses a deprecated loading method.Please inform the developer that the extension should be updated!"),void function(g,C){"function"==typeof g&&(g=g(new I.Converter));I.helper.isArray(g)||(g=[g]);var e=A(g,C);if(!e.valid)throw Error(e.error);for(var r=0;r<g.length;++r)switch(g[r].type){case"lang":s.push(g[r]);break;case"output":i.push(g[r]);break;default:throw Error("Extension loader error: Type unrecognized!!!")}}(I.extensions[g],g);if(I.helper.isUndefined(r[g]))throw Error('Extension "'+g+'" could not be loaded. It was either not found or is not a valid extension.');g=r[g]}"function"==typeof g&&(g=g()),I.helper.isArray(g)||(g=[g]);var t=A(g,C);if(!t.valid)throw Error(t.error);for(var a=0;a<g.length;++a){switch(g[a].type){case"lang":s.push(g[a]);break;case"output":i.push(g[a])}if(g[a].hasOwnProperty("listeners"))for(var n in g[a].listeners)g[a].listeners.hasOwnProperty(n)&&e(n,g[a].listeners[n])}}function e(g,A){if(!I.helper.isString(g))throw Error("Invalid argument in converter.listen() method: name must be a string, but "+typeof g+" given");if("function"!=typeof A)throw Error("Invalid argument in converter.listen() method: callback must be a function, but "+typeof A+" given");l.hasOwnProperty(g)||(l[g]=[]),l[g].push(A)}var o={},s=[],i=[],l={},c=a,u={parsed:{},raw:"",format:""};!function(){g=g||{};for(var A in t)t.hasOwnProperty(A)&&(o[A]=t[A]);if("object"!=typeof g)throw Error("Converter expects the passed parameter to be an object, but "+typeof g+" was passed instead.");for(var e in g)g.hasOwnProperty(e)&&(o[e]=g[e]);o.extensions&&I.helper.forEach(o.extensions,C)}(),this._dispatch=function(g,A,C,I){if(l.hasOwnProperty(g))for(var e=0;e<l[g].length;++e){var r=l[g][e](g,A,this,C,I);r&&void 0!==r&&(A=r)}return A},this.listen=function(g,A){return e(g,A),this},this.makeHtml=function(g){if(!g)return g;var A={gHtmlBlocks:[],gHtmlMdBlocks:[],gHtmlSpans:[],gUrls:{},gTitles:{},gDimensions:{},gListLevel:0,hashLinkCounts:{},langExtensions:s,outputModifiers:i,converter:this,ghCodeBlocks:[],metadata:{parsed:{},raw:"",format:""}};return g=g.replace(/ยจ/g,"ยจT"),g=g.replace(/\$/g,"ยจD"),g=g.replace(/\r\n/g,"\n"),g=g.replace(/\r/g,"\n"),g=g.replace(/\u00A0/g," "),o.smartIndentationFix&&(g=function(g){var A=g.match(/^\s*/)[0].length,C=new RegExp("^\\s{0,"+A+"}","gm");return g.replace(C,"")}(g)),g="\n\n"+g+"\n\n",g=I.subParser("detab")(g,o,A),g=g.replace(/^[ \t]+$/gm,""),I.helper.forEach(s,function(C){g=I.subParser("runExtension")(C,g,o,A)}),g=I.subParser("metadata")(g,o,A),g=I.subParser("hashPreCodeTags")(g,o,A),g=I.subParser("githubCodeBlocks")(g,o,A),g=I.subParser("hashHTMLBlocks")(g,o,A),g=I.subParser("hashCodeTags")(g,o,A),g=I.subParser("stripLinkDefinitions")(g,o,A),g=I.subParser("blockGamut")(g,o,A),g=I.subParser("unhashHTMLSpans")(g,o,A),g=I.subParser("unescapeSpecialChars")(g,o,A),g=g.replace(/ยจD/g,"$$"),g=g.replace(/ยจT/g,"ยจ"),g=I.subParser("completeHTMLDocument")(g,o,A),I.helper.forEach(i,function(C){g=I.subParser("runExtension")(C,g,o,A)}),u=A.metadata,g},this.setOption=function(g,A){o[g]=A},this.getOption=function(g){return o[g]},this.getOptions=function(){return o},this.addExtension=function(g,A){C(g,A=A||null)},this.useExtension=function(g){C(g)},this.setFlavor=function(g){if(!n.hasOwnProperty(g))throw Error(g+" flavor was not found");var A=n[g];c=g;for(var C in A)A.hasOwnProperty(C)&&(o[C]=A[C])},this.getFlavor=function(){return c},this.removeExtension=function(g){I.helper.isArray(g)||(g=[g]);for(var A=0;A<g.length;++A){for(var C=g[A],e=0;e<s.length;++e)s[e]===C&&s[e].splice(e,1);for(;0<i.length;++e)i[0]===C&&i[0].splice(e,1)}},this.getAllExtensions=function(){return{language:s,output:i}},this.getMetadata=function(g){return g?u.raw:u.parsed},this.getMetadataFormat=function(){return u.format},this._setMetadataPair=function(g,A){u.parsed[g]=A},this._setMetadataFormat=function(g){u.format=g},this._setMetadataRaw=function(g){u.raw=g}},I.subParser("anchors",function(g,A,C){"use strict";var e=function(g,e,r,t,a,n,o){if(I.helper.isUndefined(o)&&(o=""),r=r.toLowerCase(),g.search(/\(<?\s*>? ?(['"].*['"])?\)$/m)>-1)t="";else if(!t){if(r||(r=e.toLowerCase().replace(/ ?\n/g," ")),t="#"+r,I.helper.isUndefined(C.gUrls[r]))return g;t=C.gUrls[r],I.helper.isUndefined(C.gTitles[r])||(o=C.gTitles[r])}var s='<a href="'+(t=t.replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback))+'"';return""!==o&&null!==o&&(s+=' title="'+(o=(o=o.replace(/"/g,""")).replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback))+'"'),A.openLinksInNewWindow&&!/^#/.test(t)&&(s+=' target="ยจE95Eblank"'),s+=">"+e+"</a>"};return g=(g=C.converter._dispatch("anchors.before",g,A,C)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g,e),g=g.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,e),g=g.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,e),g=g.replace(/\[([^\[\]]+)]()()()()()/g,e),A.ghMentions&&(g=g.replace(/(^|\s)(\\)?(@([a-z\d\-]+))(?=[.!?;,[\]()]|\s|$)/gim,function(g,C,e,r,t){if("\\"===e)return C+r;if(!I.helper.isString(A.ghMentionsLink))throw new Error("ghMentionsLink option must be a string");var a=A.ghMentionsLink.replace(/\{u}/g,t),n="";return A.openLinksInNewWindow&&(n=' target="ยจE95Eblank"'),C+'<a href="'+a+'"'+n+">"+r+"</a>"})),g=C.converter._dispatch("anchors.after",g,A,C)});var s=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,i=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,l=/()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,c=/(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gim,u=/<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,d=function(g){"use strict";return function(A,C,e,r,t,a,n){var o=e=e.replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback),s="",i="",l=C||"",c=n||"";return/^www\./i.test(e)&&(e=e.replace(/^www\./i,"http://www.")),g.excludeTrailingPunctuationFromURLs&&a&&(s=a),g.openLinksInNewWindow&&(i=' target="ยจE95Eblank"'),l+'<a href="'+e+'"'+i+">"+o+"</a>"+s+c}},p=function(g,A){"use strict";return function(C,e,r){var t="mailto:";return e=e||"",r=I.subParser("unescapeSpecialChars")(r,g,A),g.encodeEmails?(t=I.helper.encodeEmailAddress(t+r),r=I.helper.encodeEmailAddress(r)):t+=r,e+'<a href="'+t+'">'+r+"</a>"}};I.subParser("autoLinks",function(g,A,C){"use strict";return g=C.converter._dispatch("autoLinks.before",g,A,C),g=g.replace(l,d(A)),g=g.replace(u,p(A,C)),g=C.converter._dispatch("autoLinks.after",g,A,C)}),I.subParser("simplifiedAutoLinks",function(g,A,C){"use strict";return A.simplifiedAutoLink?(g=C.converter._dispatch("simplifiedAutoLinks.before",g,A,C),g=A.excludeTrailingPunctuationFromURLs?g.replace(i,d(A)):g.replace(s,d(A)),g=g.replace(c,p(A,C)),g=C.converter._dispatch("simplifiedAutoLinks.after",g,A,C)):g}),I.subParser("blockGamut",function(g,A,C){"use strict";return g=C.converter._dispatch("blockGamut.before",g,A,C),g=I.subParser("blockQuotes")(g,A,C),g=I.subParser("headers")(g,A,C),g=I.subParser("horizontalRule")(g,A,C),g=I.subParser("lists")(g,A,C),g=I.subParser("codeBlocks")(g,A,C),g=I.subParser("tables")(g,A,C),g=I.subParser("hashHTMLBlocks")(g,A,C),g=I.subParser("paragraphs")(g,A,C),g=C.converter._dispatch("blockGamut.after",g,A,C)}),I.subParser("blockQuotes",function(g,A,C){"use strict";g=C.converter._dispatch("blockQuotes.before",g,A,C),g+="\n\n";var e=/(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm;return A.splitAdjacentBlockquotes&&(e=/^ {0,3}>[\s\S]*?(?:\n\n)/gm),g=g.replace(e,function(g){return g=g.replace(/^[ \t]*>[ \t]?/gm,""),g=g.replace(/ยจ0/g,""),g=g.replace(/^[ \t]+$/gm,""),g=I.subParser("githubCodeBlocks")(g,A,C),g=I.subParser("blockGamut")(g,A,C),g=g.replace(/(^|\n)/g,"$1 "),g=g.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm,function(g,A){var C=A;return C=C.replace(/^ /gm,"ยจ0"),C=C.replace(/ยจ0/g,"")}),I.subParser("hashBlock")("<blockquote>\n"+g+"\n</blockquote>",A,C)}),g=C.converter._dispatch("blockQuotes.after",g,A,C)}),I.subParser("codeBlocks",function(g,A,C){"use strict";g=C.converter._dispatch("codeBlocks.before",g,A,C);return g=(g+="ยจ0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=ยจ0))/g,function(g,e,r){var t=e,a=r,n="\n";return t=I.subParser("outdent")(t,A,C),t=I.subParser("encodeCode")(t,A,C),t=I.subParser("detab")(t,A,C),t=t.replace(/^\n+/g,""),t=t.replace(/\n+$/g,""),A.omitExtraWLInCodeBlocks&&(n=""),t="<pre><code>"+t+n+"</code></pre>",I.subParser("hashBlock")(t,A,C)+a}),g=g.replace(/ยจ0/,""),g=C.converter._dispatch("codeBlocks.after",g,A,C)}),I.subParser("codeSpans",function(g,A,C){"use strict";return void 0===(g=C.converter._dispatch("codeSpans.before",g,A,C))&&(g=""),g=g.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(g,e,r,t){var a=t;return a=a.replace(/^([ \t]*)/g,""),a=a.replace(/[ \t]*$/g,""),a=I.subParser("encodeCode")(a,A,C),a=e+"<code>"+a+"</code>",a=I.subParser("hashHTMLSpans")(a,A,C)}),g=C.converter._dispatch("codeSpans.after",g,A,C)}),I.subParser("completeHTMLDocument",function(g,A,C){"use strict";if(!A.completeHTMLDocument)return g;g=C.converter._dispatch("completeHTMLDocument.before",g,A,C);var I="html",e="<!DOCTYPE HTML>\n",r="",t='<meta charset="utf-8">\n',a="",n="";void 0!==C.metadata.parsed.doctype&&(e="<!DOCTYPE "+C.metadata.parsed.doctype+">\n","html"!==(I=C.metadata.parsed.doctype.toString().toLowerCase())&&"html5"!==I||(t='<meta charset="utf-8">'));for(var o in C.metadata.parsed)if(C.metadata.parsed.hasOwnProperty(o))switch(o.toLowerCase()){case"doctype":break;case"title":r="<title>"+C.metadata.parsed.title+"</title>\n";break;case"charset":t="html"===I||"html5"===I?'<meta charset="'+C.metadata.parsed.charset+'">\n':'<meta name="charset" content="'+C.metadata.parsed.charset+'">\n';break;case"language":case"lang":a=' lang="'+C.metadata.parsed[o]+'"',n+='<meta name="'+o+'" content="'+C.metadata.parsed[o]+'">\n';break;default:n+='<meta name="'+o+'" content="'+C.metadata.parsed[o]+'">\n'}return g=e+"<html"+a+">\n<head>\n"+r+t+n+"</head>\n<body>\n"+g.trim()+"\n</body>\n</html>",g=C.converter._dispatch("completeHTMLDocument.after",g,A,C)}),I.subParser("detab",function(g,A,C){"use strict";return g=C.converter._dispatch("detab.before",g,A,C),g=g.replace(/\t(?=\t)/g," "),g=g.replace(/\t/g,"ยจAยจB"),g=g.replace(/ยจB(.+?)ยจA/g,function(g,A){for(var C=A,I=4-C.length%4,e=0;e<I;e++)C+=" ";return C}),g=g.replace(/ยจA/g," "),g=g.replace(/ยจB/g,""),g=C.converter._dispatch("detab.after",g,A,C)}),I.subParser("ellipsis",function(g,A,C){"use strict";return g=C.converter._dispatch("ellipsis.before",g,A,C),g=g.replace(/\.\.\./g,"โฆ"),g=C.converter._dispatch("ellipsis.after",g,A,C)}),I.subParser("emoji",function(g,A,C){"use strict";if(!A.emoji)return g;return g=(g=C.converter._dispatch("emoji.before",g,A,C)).replace(/:([\S]+?):/g,function(g,A){return I.helper.emojis.hasOwnProperty(A)?I.helper.emojis[A]:g}),g=C.converter._dispatch("emoji.after",g,A,C)}),I.subParser("encodeAmpsAndAngles",function(g,A,C){"use strict";return g=C.converter._dispatch("encodeAmpsAndAngles.before",g,A,C),g=g.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&"),g=g.replace(/<(?![a-z\/?$!])/gi,"<"),g=g.replace(/</g,"<"),g=g.replace(/>/g,">"),g=C.converter._dispatch("encodeAmpsAndAngles.after",g,A,C)}),I.subParser("encodeBackslashEscapes",function(g,A,C){"use strict";return g=C.converter._dispatch("encodeBackslashEscapes.before",g,A,C),g=g.replace(/\\(\\)/g,I.helper.escapeCharactersCallback),g=g.replace(/\\([`*_{}\[\]()>#+.!~=|-])/g,I.helper.escapeCharactersCallback),g=C.converter._dispatch("encodeBackslashEscapes.after",g,A,C)}),I.subParser("encodeCode",function(g,A,C){"use strict";return g=C.converter._dispatch("encodeCode.before",g,A,C),g=g.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/([*_{}\[\]\\=~-])/g,I.helper.escapeCharactersCallback),g=C.converter._dispatch("encodeCode.after",g,A,C)}),I.subParser("escapeSpecialCharsWithinTagAttributes",function(g,A,C){"use strict";return g=(g=C.converter._dispatch("escapeSpecialCharsWithinTagAttributes.before",g,A,C)).replace(/<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,function(g){return g.replace(/(.)<\/?code>(?=.)/g,"$1`").replace(/([\\`*_~=|])/g,I.helper.escapeCharactersCallback)}),g=g.replace(/<!(--(?:(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>/gi,function(g){return g.replace(/([\\`*_~=|])/g,I.helper.escapeCharactersCallback)}),g=C.converter._dispatch("escapeSpecialCharsWithinTagAttributes.after",g,A,C)}),I.subParser("githubCodeBlocks",function(g,A,C){"use strict";return A.ghCodeBlocks?(g=C.converter._dispatch("githubCodeBlocks.before",g,A,C),g+="ยจ0",g=g.replace(/(?:^|\n)(```+|~~~+)([^\s`~]*)\n([\s\S]*?)\n\1/g,function(g,e,r,t){var a=A.omitExtraWLInCodeBlocks?"":"\n";return t=I.subParser("encodeCode")(t,A,C),t=I.subParser("detab")(t,A,C),t=t.replace(/^\n+/g,""),t=t.replace(/\n+$/g,""),t="<pre><code"+(r?' class="'+r+" language-"+r+'"':"")+">"+t+a+"</code></pre>",t=I.subParser("hashBlock")(t,A,C),"\n\nยจG"+(C.ghCodeBlocks.push({text:g,codeblock:t})-1)+"G\n\n"}),g=g.replace(/ยจ0/,""),C.converter._dispatch("githubCodeBlocks.after",g,A,C)):g}),I.subParser("hashBlock",function(g,A,C){"use strict";return g=C.converter._dispatch("hashBlock.before",g,A,C),g=g.replace(/(^\n+|\n+$)/g,""),g="\n\nยจK"+(C.gHtmlBlocks.push(g)-1)+"K\n\n",g=C.converter._dispatch("hashBlock.after",g,A,C)}),I.subParser("hashCodeTags",function(g,A,C){"use strict";g=C.converter._dispatch("hashCodeTags.before",g,A,C);return g=I.helper.replaceRecursiveRegExp(g,function(g,e,r,t){var a=r+I.subParser("encodeCode")(e,A,C)+t;return"ยจC"+(C.gHtmlSpans.push(a)-1)+"C"},"<code\\b[^>]*>","</code>","gim"),g=C.converter._dispatch("hashCodeTags.after",g,A,C)}),I.subParser("hashElement",function(g,A,C){"use strict";return function(g,A){var I=A;return I=I.replace(/\n\n/g,"\n"),I=I.replace(/^\n/,""),I=I.replace(/\n+$/g,""),I="\n\nยจK"+(C.gHtmlBlocks.push(I)-1)+"K\n\n"}}),I.subParser("hashHTMLBlocks",function(g,A,C){"use strict";g=C.converter._dispatch("hashHTMLBlocks.before",g,A,C);var e=["pre","div","h1","h2","h3","h4","h5","h6","blockquote","table","dl","ol","ul","script","noscript","form","fieldset","iframe","math","style","section","header","footer","nav","article","aside","address","audio","canvas","figure","hgroup","output","video","p"],r=function(g,A,I,e){var r=g;return-1!==I.search(/\bmarkdown\b/)&&(r=I+C.converter.makeHtml(A)+e),"\n\nยจK"+(C.gHtmlBlocks.push(r)-1)+"K\n\n"};A.backslashEscapesHTMLTags&&(g=g.replace(/\\<(\/?[^>]+?)>/g,function(g,A){return"<"+A+">"}));for(var t=0;t<e.length;++t)for(var a,n=new RegExp("^ {0,3}(<"+e[t]+"\\b[^>]*>)","im"),o="<"+e[t]+"\\b[^>]*>",s="</"+e[t]+">";-1!==(a=I.helper.regexIndexOf(g,n));){var i=I.helper.splitAtIndex(g,a),l=I.helper.replaceRecursiveRegExp(i[1],r,o,s,"im");if(l===i[1])break;g=i[0].concat(l)}return g=g.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,I.subParser("hashElement")(g,A,C)),g=I.helper.replaceRecursiveRegExp(g,function(g){return"\n\nยจK"+(C.gHtmlBlocks.push(g)-1)+"K\n\n"},"^ {0,3}\x3c!--","--\x3e","gm"),g=g.replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,I.subParser("hashElement")(g,A,C)),g=C.converter._dispatch("hashHTMLBlocks.after",g,A,C)}),I.subParser("hashHTMLSpans",function(g,A,C){"use strict";function I(g){return"ยจC"+(C.gHtmlSpans.push(g)-1)+"C"}return g=C.converter._dispatch("hashHTMLSpans.before",g,A,C),g=g.replace(/<[^>]+?\/>/gi,function(g){return I(g)}),g=g.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g,function(g){return I(g)}),g=g.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g,function(g){return I(g)}),g=g.replace(/<[^>]+?>/gi,function(g){return I(g)}),g=C.converter._dispatch("hashHTMLSpans.after",g,A,C)}),I.subParser("unhashHTMLSpans",function(g,A,C){"use strict";g=C.converter._dispatch("unhashHTMLSpans.before",g,A,C);for(var I=0;I<C.gHtmlSpans.length;++I){for(var e=C.gHtmlSpans[I],r=0;/ยจC(\d+)C/.test(e);){var t=RegExp.$1;if(e=e.replace("ยจC"+t+"C",C.gHtmlSpans[t]),10===r){console.error("maximum nesting of 10 spans reached!!!");break}++r}g=g.replace("ยจC"+I+"C",e)}return g=C.converter._dispatch("unhashHTMLSpans.after",g,A,C)}),I.subParser("hashPreCodeTags",function(g,A,C){"use strict";g=C.converter._dispatch("hashPreCodeTags.before",g,A,C);return g=I.helper.replaceRecursiveRegExp(g,function(g,e,r,t){var a=r+I.subParser("encodeCode")(e,A,C)+t;return"\n\nยจG"+(C.ghCodeBlocks.push({text:g,codeblock:a})-1)+"G\n\n"},"^ {0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>","^ {0,3}</code>\\s*</pre>","gim"),g=C.converter._dispatch("hashPreCodeTags.after",g,A,C)}),I.subParser("headers",function(g,A,C){"use strict";function e(g){var e,r;if(A.customizedHeaderId){var t=g.match(/\{([^{]+?)}\s*$/);t&&t[1]&&(g=t[1])}return e=g,r=I.helper.isString(A.prefixHeaderId)?A.prefixHeaderId:!0===A.prefixHeaderId?"section-":"",A.rawPrefixHeaderId||(e=r+e),e=A.ghCompatibleHeaderId?e.replace(/ /g,"-").replace(/&/g,"").replace(/ยจT/g,"").replace(/ยจD/g,"").replace(/[&+$,\/:;=?@"#{}|^ยจ~\[\]`\\*)(%.!'<>]/g,"").toLowerCase():A.rawHeaderId?e.replace(/ /g,"-").replace(/&/g,"&").replace(/ยจT/g,"ยจ").replace(/ยจD/g,"$").replace(/["']/g,"-").toLowerCase():e.replace(/[^\w]/g,"").toLowerCase(),A.rawPrefixHeaderId&&(e=r+e),C.hashLinkCounts[e]?e=e+"-"+C.hashLinkCounts[e]++:C.hashLinkCounts[e]=1,e}g=C.converter._dispatch("headers.before",g,A,C);var r=isNaN(parseInt(A.headerLevelStart))?1:parseInt(A.headerLevelStart),t=A.smoothLivePreview?/^(.+)[ \t]*\n={2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n=+[ \t]*\n+/gm,a=A.smoothLivePreview?/^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n-+[ \t]*\n+/gm;g=(g=g.replace(t,function(g,t){var a=I.subParser("spanGamut")(t,A,C),n=A.noHeaderId?"":' id="'+e(t)+'"',o="<h"+r+n+">"+a+"</h"+r+">";return I.subParser("hashBlock")(o,A,C)})).replace(a,function(g,t){var a=I.subParser("spanGamut")(t,A,C),n=A.noHeaderId?"":' id="'+e(t)+'"',o=r+1,s="<h"+o+n+">"+a+"</h"+o+">";return I.subParser("hashBlock")(s,A,C)});var n=A.requireSpaceBeforeHeadingText?/^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm:/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;return g=g.replace(n,function(g,t,a){var n=a;A.customizedHeaderId&&(n=a.replace(/\s?\{([^{]+?)}\s*$/,""));var o=I.subParser("spanGamut")(n,A,C),s=A.noHeaderId?"":' id="'+e(a)+'"',i=r-1+t.length,l="<h"+i+s+">"+o+"</h"+i+">";return I.subParser("hashBlock")(l,A,C)}),g=C.converter._dispatch("headers.after",g,A,C)}),I.subParser("horizontalRule",function(g,A,C){"use strict";g=C.converter._dispatch("horizontalRule.before",g,A,C);var e=I.subParser("hashBlock")("<hr />",A,C);return g=g.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm,e),g=g.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm,e),g=g.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm,e),g=C.converter._dispatch("horizontalRule.after",g,A,C)}),I.subParser("images",function(g,A,C){"use strict";function e(g,A,e,r,t,a,n,o){var s=C.gUrls,i=C.gTitles,l=C.gDimensions;if(e=e.toLowerCase(),o||(o=""),g.search(/\(<?\s*>? ?(['"].*['"])?\)$/m)>-1)r="";else if(""===r||null===r){if(""!==e&&null!==e||(e=A.toLowerCase().replace(/ ?\n/g," ")),r="#"+e,I.helper.isUndefined(s[e]))return g;r=s[e],I.helper.isUndefined(i[e])||(o=i[e]),I.helper.isUndefined(l[e])||(t=l[e].width,a=l[e].height)}A=A.replace(/"/g,""").replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback);var c='<img src="'+(r=r.replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback))+'" alt="'+A+'"';return o&&(c+=' title="'+(o=o.replace(/"/g,""").replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback))+'"'),t&&a&&(c+=' width="'+(t="*"===t?"auto":t)+'"',c+=' height="'+(a="*"===a?"auto":a)+'"'),c+=" />"}return g=(g=C.converter._dispatch("images.before",g,A,C)).replace(/!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,e),g=g.replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,function(g,A,C,I,r,t,a,n){return I=I.replace(/\s/g,""),e(g,A,C,I,r,t,0,n)}),g=g.replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,e),g=g.replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,e),g=g.replace(/!\[([^\[\]]+)]()()()()()/g,e),g=C.converter._dispatch("images.after",g,A,C)}),I.subParser("italicsAndBold",function(g,A,C){"use strict";function I(g,A,C){return A+g+C}return g=C.converter._dispatch("italicsAndBold.before",g,A,C),g=A.literalMidWordUnderscores?(g=(g=g.replace(/\b___(\S[\s\S]*)___\b/g,function(g,A){return I(A,"<strong><em>","</em></strong>")})).replace(/\b__(\S[\s\S]*)__\b/g,function(g,A){return I(A,"<strong>","</strong>")})).replace(/\b_(\S[\s\S]*?)_\b/g,function(g,A){return I(A,"<em>","</em>")}):(g=(g=g.replace(/___(\S[\s\S]*?)___/g,function(g,A){return/\S$/.test(A)?I(A,"<strong><em>","</em></strong>"):g})).replace(/__(\S[\s\S]*?)__/g,function(g,A){return/\S$/.test(A)?I(A,"<strong>","</strong>"):g})).replace(/_([^\s_][\s\S]*?)_/g,function(g,A){return/\S$/.test(A)?I(A,"<em>","</em>"):g}),g=A.literalMidWordAsterisks?(g=(g=g.replace(/([^*]|^)\B\*\*\*(\S[\s\S]+?)\*\*\*\B(?!\*)/g,function(g,A,C){return I(C,A+"<strong><em>","</em></strong>")})).replace(/([^*]|^)\B\*\*(\S[\s\S]+?)\*\*\B(?!\*)/g,function(g,A,C){return I(C,A+"<strong>","</strong>")})).replace(/([^*]|^)\B\*(\S[\s\S]+?)\*\B(?!\*)/g,function(g,A,C){return I(C,A+"<em>","</em>")}):(g=(g=g.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g,function(g,A){return/\S$/.test(A)?I(A,"<strong><em>","</em></strong>"):g})).replace(/\*\*(\S[\s\S]*?)\*\*/g,function(g,A){return/\S$/.test(A)?I(A,"<strong>","</strong>"):g})).replace(/\*([^\s*][\s\S]*?)\*/g,function(g,A){return/\S$/.test(A)?I(A,"<em>","</em>"):g}),g=C.converter._dispatch("italicsAndBold.after",g,A,C)}),I.subParser("lists",function(g,A,C){"use strict";function e(g,e){C.gListLevel++,g=g.replace(/\n{2,}$/,"\n");var r=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(ยจ0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,t=/\n[ \t]*\n(?!ยจ0)/.test(g+="ยจ0");return A.disableForced4SpacesIndentedSublists&&(r=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(ยจ0|\2([*+-]|\d+[.])[ \t]+))/gm),g=g.replace(r,function(g,e,r,a,n,o,s){s=s&&""!==s.trim();var i=I.subParser("outdent")(n,A,C),l="";return o&&A.tasklists&&(l=' class="task-list-item" style="list-style-type: none;"',i=i.replace(/^[ \t]*\[(x|X| )?]/m,function(){var g='<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';return s&&(g+=" checked"),g+=">"})),i=i.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g,function(g){return"ยจA"+g}),e||i.search(/\n{2,}/)>-1?(i=I.subParser("githubCodeBlocks")(i,A,C),i=I.subParser("blockGamut")(i,A,C)):(i=(i=I.subParser("lists")(i,A,C)).replace(/\n$/,""),i=(i=I.subParser("hashHTMLBlocks")(i,A,C)).replace(/\n\n+/g,"\n\n"),i=t?I.subParser("paragraphs")(i,A,C):I.subParser("spanGamut")(i,A,C)),i=i.replace("ยจA",""),i="<li"+l+">"+i+"</li>\n"}),g=g.replace(/ยจ0/g,""),C.gListLevel--,e&&(g=g.replace(/\s+$/,"")),g}function r(g,A){if("ol"===A){var C=g.match(/^ *(\d+)\./);if(C&&"1"!==C[1])return' start="'+C[1]+'"'}return""}function t(g,C,I){var t=A.disableForced4SpacesIndentedSublists?/^ ?\d+\.[ \t]/gm:/^ {0,3}\d+\.[ \t]/gm,a=A.disableForced4SpacesIndentedSublists?/^ ?[*+-][ \t]/gm:/^ {0,3}[*+-][ \t]/gm,n="ul"===C?t:a,o="";if(-1!==g.search(n))!function A(s){var i=s.search(n),l=r(g,C);-1!==i?(o+="\n\n<"+C+l+">\n"+e(s.slice(0,i),!!I)+"</"+C+">\n",n="ul"===(C="ul"===C?"ol":"ul")?t:a,A(s.slice(i))):o+="\n\n<"+C+l+">\n"+e(s,!!I)+"</"+C+">\n"}(g);else{var s=r(g,C);o="\n\n<"+C+s+">\n"+e(g,!!I)+"</"+C+">\n"}return o}return g=C.converter._dispatch("lists.before",g,A,C),g+="ยจ0",g=C.gListLevel?g.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(ยจ0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(g,A,C){return t(A,C.search(/[*+-]/g)>-1?"ul":"ol",!0)}):g.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(ยจ0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(g,A,C,I){return t(C,I.search(/[*+-]/g)>-1?"ul":"ol",!1)}),g=g.replace(/ยจ0/,""),g=C.converter._dispatch("lists.after",g,A,C)}),I.subParser("metadata",function(g,A,C){"use strict";function I(g){C.metadata.raw=g,(g=(g=g.replace(/&/g,"&").replace(/"/g,""")).replace(/\n {4}/g," ")).replace(/^([\S ]+): +([\s\S]+?)$/gm,function(g,A,I){return C.metadata.parsed[A]=I,""})}return A.metadata?(g=C.converter._dispatch("metadata.before",g,A,C),g=g.replace(/^\s*ยซยซยซ+(\S*?)\n([\s\S]+?)\nยปยปยป+\n/,function(g,A,C){return I(C),"ยจM"}),g=g.replace(/^\s*---+(\S*?)\n([\s\S]+?)\n---+\n/,function(g,A,e){return A&&(C.metadata.format=A),I(e),"ยจM"}),g=g.replace(/ยจM/g,""),g=C.converter._dispatch("metadata.after",g,A,C)):g}),I.subParser("outdent",function(g,A,C){"use strict";return g=C.converter._dispatch("outdent.before",g,A,C),g=g.replace(/^(\t|[ ]{1,4})/gm,"ยจ0"),g=g.replace(/ยจ0/g,""),g=C.converter._dispatch("outdent.after",g,A,C)}),I.subParser("paragraphs",function(g,A,C){"use strict";for(var e=(g=(g=(g=C.converter._dispatch("paragraphs.before",g,A,C)).replace(/^\n+/g,"")).replace(/\n+$/g,"")).split(/\n{2,}/g),r=[],t=e.length,a=0;a<t;a++){var n=e[a];n.search(/ยจ(K|G)(\d+)\1/g)>=0?r.push(n):n.search(/\S/)>=0&&(n=(n=I.subParser("spanGamut")(n,A,C)).replace(/^([ \t]*)/g,"<p>"),n+="</p>",r.push(n))}for(t=r.length,a=0;a<t;a++){for(var o="",s=r[a],i=!1;/ยจ(K|G)(\d+)\1/.test(s);){var l=RegExp.$1,c=RegExp.$2;o=(o="K"===l?C.gHtmlBlocks[c]:i?I.subParser("encodeCode")(C.ghCodeBlocks[c].text,A,C):C.ghCodeBlocks[c].codeblock).replace(/\$/g,"$$$$"),s=s.replace(/(\n\n)?ยจ(K|G)\d+\2(\n\n)?/,o),/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(s)&&(i=!0)}r[a]=s}return g=r.join("\n"),g=g.replace(/^\n+/g,""),g=g.replace(/\n+$/g,""),C.converter._dispatch("paragraphs.after",g,A,C)}),I.subParser("runExtension",function(g,A,C,I){"use strict";if(g.filter)A=g.filter(A,I.converter,C);else if(g.regex){var e=g.regex;e instanceof RegExp||(e=new RegExp(e,"g")),A=A.replace(e,g.replace)}return A}),I.subParser("spanGamut",function(g,A,C){"use strict";return g=C.converter._dispatch("spanGamut.before",g,A,C),g=I.subParser("codeSpans")(g,A,C),g=I.subParser("escapeSpecialCharsWithinTagAttributes")(g,A,C),g=I.subParser("encodeBackslashEscapes")(g,A,C),g=I.subParser("images")(g,A,C),g=I.subParser("anchors")(g,A,C),g=I.subParser("autoLinks")(g,A,C),g=I.subParser("simplifiedAutoLinks")(g,A,C),g=I.subParser("emoji")(g,A,C),g=I.subParser("underline")(g,A,C),g=I.subParser("italicsAndBold")(g,A,C),g=I.subParser("strikethrough")(g,A,C),g=I.subParser("ellipsis")(g,A,C),g=I.subParser("hashHTMLSpans")(g,A,C),g=I.subParser("encodeAmpsAndAngles")(g,A,C),A.simpleLineBreaks?/\n\nยจK/.test(g)||(g=g.replace(/\n+/g,"<br />\n")):g=g.replace(/ +\n/g,"<br />\n"),g=C.converter._dispatch("spanGamut.after",g,A,C)}),I.subParser("strikethrough",function(g,A,C){"use strict";return A.strikethrough&&(g=(g=C.converter._dispatch("strikethrough.before",g,A,C)).replace(/(?:~){2}([\s\S]+?)(?:~){2}/g,function(g,e){return function(g){return A.simplifiedAutoLink&&(g=I.subParser("simplifiedAutoLinks")(g,A,C)),"<del>"+g+"</del>"}(e)}),g=C.converter._dispatch("strikethrough.after",g,A,C)),g}),I.subParser("stripLinkDefinitions",function(g,A,C){"use strict";var e=function(g,e,r,t,a,n,o){return e=e.toLowerCase(),r.match(/^data:.+?\/.+?;base64,/)?C.gUrls[e]=r.replace(/\s/g,""):C.gUrls[e]=I.subParser("encodeAmpsAndAngles")(r,A,C),n?n+o:(o&&(C.gTitles[e]=o.replace(/"|'/g,""")),A.parseImgDimensions&&t&&a&&(C.gDimensions[e]={width:t,height:a}),"")};return g=(g+="ยจ0").replace(/^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=ยจ0)|(?=\n\[))/gm,e),g=g.replace(/^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?([^>\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=ยจ0))/gm,e),g=g.replace(/ยจ0/,"")}),I.subParser("tables",function(g,A,C){"use strict";function e(g){return/^:[ \t]*--*$/.test(g)?' style="text-align:left;"':/^--*[ \t]*:[ \t]*$/.test(g)?' style="text-align:right;"':/^:[ \t]*--*[ \t]*:$/.test(g)?' style="text-align:center;"':""}function r(g,e){var r="";return g=g.trim(),(A.tablesHeaderId||A.tableHeaderId)&&(r=' id="'+g.replace(/ /g,"_").toLowerCase()+'"'),g=I.subParser("spanGamut")(g,A,C),"<th"+r+e+">"+g+"</th>\n"}function t(g,e){return"<td"+e+">"+I.subParser("spanGamut")(g,A,C)+"</td>\n"}function a(g){var a,n=g.split("\n");for(a=0;a<n.length;++a)/^ {0,3}\|/.test(n[a])&&(n[a]=n[a].replace(/^ {0,3}\|/,"")),/\|[ \t]*$/.test(n[a])&&(n[a]=n[a].replace(/\|[ \t]*$/,"")),n[a]=I.subParser("codeSpans")(n[a],A,C);var o=n[0].split("|").map(function(g){return g.trim()}),s=n[1].split("|").map(function(g){return g.trim()}),i=[],l=[],c=[],u=[];for(n.shift(),n.shift(),a=0;a<n.length;++a)""!==n[a].trim()&&i.push(n[a].split("|").map(function(g){return g.trim()}));if(o.length<s.length)return g;for(a=0;a<s.length;++a)c.push(e(s[a]));for(a=0;a<o.length;++a)I.helper.isUndefined(c[a])&&(c[a]=""),l.push(r(o[a],c[a]));for(a=0;a<i.length;++a){for(var d=[],p=0;p<l.length;++p)I.helper.isUndefined(i[a][p]),d.push(t(i[a][p],c[p]));u.push(d)}return function(g,A){for(var C="<table>\n<thead>\n<tr>\n",I=g.length,e=0;e<I;++e)C+=g[e];for(C+="</tr>\n</thead>\n<tbody>\n",e=0;e<A.length;++e){C+="<tr>\n";for(var r=0;r<I;++r)C+=A[e][r];C+="</tr>\n"}return C+="</tbody>\n</table>\n"}(l,u)}if(!A.tables)return g;return g=C.converter._dispatch("tables.before",g,A,C),g=g.replace(/\\(\|)/g,I.helper.escapeCharactersCallback),g=g.replace(/^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|ยจ0)/gm,a),g=g.replace(/^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|ยจ0)/gm,a),g=C.converter._dispatch("tables.after",g,A,C)}),I.subParser("underline",function(g,A,C){"use strict";return A.underline?(g=C.converter._dispatch("underline.before",g,A,C),g=A.literalMidWordUnderscores?g.replace(/\b_?__(\S[\s\S]*)___?\b/g,function(g,A){return"<u>"+A+"</u>"}):g.replace(/_?__(\S[\s\S]*?)___?/g,function(g,A){return/\S$/.test(A)?"<u>"+A+"</u>":g}),g=g.replace(/(_)/g,I.helper.escapeCharactersCallback),g=C.converter._dispatch("underline.after",g,A,C)):g}),I.subParser("unescapeSpecialChars",function(g,A,C){"use strict";return g=C.converter._dispatch("unescapeSpecialChars.before",g,A,C),g=g.replace(/ยจE(\d+)E/g,function(g,A){var C=parseInt(A);return String.fromCharCode(C)}),g=C.converter._dispatch("unescapeSpecialChars.after",g,A,C)});"function"==typeof define&&define.amd?define(function(){"use strict";return I}):"undefined"!=typeof module&&module.exports?module.exports=I:this.showdown=I}).call(this);
+//# sourceMappingURL=showdown.min.js.map
www/vincent.demeester.fr/.fancyindex/styles.css
@@ -0,0 +1,196 @@
+/* styles.css
+ * Better styling for of Nginx FancyIndex page
+ * ยฉ 2015-17, Lilian Besson (Naereen) and contributors,
+ * open-sourced under the MIT License, https://lbesson.mit-license.org/
+ * hosted on GitHub, https://GitHub.com/Naereen/Nginx-Fancyindex-Theme
+ */
+
+* {
+ font-family: 'Verdana', sans-serif;
+ margin: 0;
+ padding: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+html {
+ color: #61666c;
+ font-weight: 300;
+ font-size: 1em;
+ line-height: 2em;
+}
+
+body {
+ margin: 0 auto;
+ padding-top: 20px;
+ max-width: 800px;
+}
+
+thead {
+ font-weight: 200;
+ font-size: 1.2em;
+}
+
+h1 {
+ font-weight: 200;
+ text-align: center;
+ font-size: 1.4em;
+ line-height: 3em;
+}
+
+a {
+ color: #5f5f5f;
+ text-decoration: none;
+}
+ a:hover {
+ color: #000;
+ }
+ a.clear, a.clear:link, a.clear:visited {
+ color: #666;
+ padding: 2px 0;
+ font-weight: 400;
+ font-size: 14px;
+ margin: 0 0 0 20px;
+ line-height: 14px;
+ display: inline-block;
+ border-bottom: transparent 1px solid;
+ vertical-align: -10px;
+ -webkit-transition: all 300ms ease-in;
+ -moz-transition: all 300ms ease-in;
+ -ms-transition: all 300ms ease-in;
+ -o-transition: all 300ms ease-in;
+ transition: all 300ms ease-in;
+ }
+
+input {
+ margin: 0 auto;
+ font-size: 100%;
+ vertical-align: middle;
+ *overflow: visible;
+ line-height: normal;
+ font-family: 'Open Sans', sans-serif;
+ font-size: 12px;
+ font-weight: 300;
+ line-height: 18px;
+ color: #555;
+ display: inline-block;
+ height: 20px;
+ padding: 4px 32px 4px 6px;
+ margin-bottom: 9px;
+ font-size: 14px;
+ line-height: 20px;
+ color: #555;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ width: 196px;
+ background-color: #fff;
+ border: 1px solid #ccc;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
+ -webkit-transition: border linear .2s,box-shadow linear .2s;
+ -moz-transition: border linear .2s,box-shadow linear .2s;
+ -o-transition: border linear .2s,box-shadow linear .2s;
+ transition: border linear .2s,box-shadow linear .2s;
+}
+ input:focus {
+ outline: 0;
+ border-color: rgba(0,0,0,0.8);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(0,0,0,0.6);
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(0,0,0,0.6);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(0,0,0,0.6);
+ }
+ input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+ }
+
+#search {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ width: 250px;
+ margin-top: 20px;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ -webkit-appearance: textfield;
+ -webkit-transition: all 300ms ease-in;
+ -moz-transition: all 300ms ease-in;
+ -ms-transition: all 300ms ease-in;
+ -o-transition: all 300ms ease-in;
+ transition: all 300ms ease-in;
+}
+
+table {
+ border-collapse: collapse;
+ font-size: 0.9em;
+ max-width: 100%;
+ margin: 20px auto 0;
+}
+
+tr {
+ outline: 0;
+ border: 0;
+}
+ tr:hover td {
+ background: #f6f6f6;
+ }
+ tr td:first-of-type {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ tr.parent a {
+ color: #9099A3;
+ }
+
+th {
+
+ text-align: left;
+ font-size: .75em;
+ padding-right: 20px;
+}
+ th + th {
+ width: 25%;
+ }
+ th + th + th + th {
+ width: 5%;
+ }
+
+td {
+ padding: 5px 0;
+ outline: 0;
+ border: 0;
+ border-bottom: 1px solid #edf1f5;
+ vertical-align: middle;
+ text-align: left;
+ -webkit-transition: background 300ms ease-in;
+ -moz-transition: background 300ms ease-in;
+ -ms-transition: background 300ms ease-in;
+ -o-transition: background 300ms ease-in;
+ transition: background 300ms ease-in;
+}
+ td:last-child,th:last-child {
+ text-align: right;
+ padding-right: 0;
+ }
+ td a {
+ display: block;
+ }
+
+.parent a:hover {
+ color: #2a2a2a;
+}
+
+footer {
+ font-size:12px;
+ text-align:center;
+}
+footer a {
+ text-decoration: underline;
+ color:#990012;
+}
+
+img { max-width: 100%; }
www/vincent.demeester.fr/about/index.org
@@ -0,0 +1,26 @@
+#+TITLE: About me
+
+I develop mainly in Go, a little bit of Java, a tiny bit of Python ; I'm learning Haskell
+and LISP with Clojure (and also Emacs Lisp). The more I learn about about Functionnal
+languages and their way of thinking, the more I feel enlighten. I'm using Emacs as my main
+editor and IntelliJ IDEA for Java-related stuff. I'm a GNU/Linux user, mainly NixOS
+GNU/Linux. I no longer use or need Microsoftยฎ Windowsยฎ but I'm, sometimes, using Mac OS X
+at work (but I don't really like OS X and Apple in general). I'm a FSFE fellow since 2010
+(and previously a FSF fellow), Framasoft and La Quadrature du Net supporter/donator. I
+also try to support various free software, like Mediagoblin.
+
+* Contact
+
+- Email :: vinSPAMcentAT@demSPAMeesterDOT.fr
+- GnuPG :: [[https://vincent.demeester.fr/about/VincentDemeester.asc][5860 2A88]]
+- Instant messaging ::
+ - vdemeester@jabber.fsfe.org
+ - vdemeester@irc.freenode.net #fsfe #docker #docker-compose #docker-dev ##openweb
+- Socials ::
+ + [[https://twitter.com/vdemeest][@vdemeest]] on Twitter
+ + [[https://github.com/vdemeester][@vdemeester]] on GitHub
+ + [[https://gitlab.com/vdemeester][@vdemeester]] on Gitlab
+
+* Talks
+
+- TODO :: TBD
www/vincent.demeester.fr/assets/.fancyindex/addNginxFancyIndexForm.js
@@ -0,0 +1,33 @@
+// addNginxFancyIndexForm.js
+// Add a small form to filter through the output of Nginx FancyIndex page
+// ยฉ 2017, Lilian Besson (Naereen) and contributors,
+// open-sourced under the MIT License, https://lbesson.mit-license.org/
+// hosted on GitHub, https://GitHub.com/Naereen/Nginx-Fancyindex-Theme
+var form = document.createElement('form');
+var input = document.createElement('input');
+
+input.name = 'filter';
+input.id = 'search';
+input.placeholder = 'Type to search...';
+
+form.appendChild(input);
+
+document.querySelector('h1').after(form);
+
+var listItems = [].slice.call(document.querySelectorAll('#list tbody tr'));
+
+input.addEventListener('keyup', function () {
+ var i,
+ // Word sequence _matching_ to input. All, except last, words must be _complete_.
+ e = "(^|.*[^\\pL])" + this.value.trim().split(/\s+/).join("([^\\pL]|[^\\pL].*[^\\pL])") + ".*$",
+ n = RegExp(e, "i");
+ listItems.forEach(function(item) {
+ item.removeAttribute('hidden');
+ });
+ listItems.filter(function(item) {
+ i = item.querySelector('td').textContent.replace(/\s+/g, " ");
+ return !n.test(i);
+ }).forEach(function(item) {
+ item.hidden = true;
+ });
+});
www/vincent.demeester.fr/assets/.fancyindex/header.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="x-ua-compatible" content="IE=edge">
+ <title>Directory</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="stylesheet" href="https://vincent.demeester.fr/css/new.css">
+ <script type="text/javascript" src="/.fancyindex/jquery.min.js"></script>
+ </head>
+ <body>
+ <header id="top" class="status">
+ <nav>
+ <img src="https://vincent.demeester.fr/images/favicon.ico" id="sitelogo"/> <a href='https://vincent.demeester.fr/'>home</a> /
+ <a href='https://vincent.demeester.fr/posts/'>posts</a> (<a href='https://vincent.demeester.fr/index.xml'>rss</a>) /
+ <a href='https://vincent.demeester.fr/articles/'>articles</a> /
+ <a href='https://vincent.demeester.fr/configurations/'>configurations</a> /
+ <a href='https://dl.sbr.pm/'>files</a> /
+ <a href='https://vincent.demeester.fr/about/'>about</a></li>
+ </nav>
+ </header>
+ <main id="content">
+ <header id="raw_include_HEADER_md">
+ </header>
+<h1>Directory:
www/vincent.demeester.fr/assets/.fancyindex/HEADER.md
@@ -0,0 +1,4 @@
+# Test of a HEADER.md file
+## Test of a HEADER.md file
+### Test of a HEADER.md file
+#### Test of a HEADER.md file
www/vincent.demeester.fr/assets/.fancyindex/jquery.min.js
@@ -0,0 +1,5 @@
+/*! jQuery v2.1.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+/* Used on Lilian Besson's web pages ~ 2011-2014 */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m=a.document,n="2.1.0",o=function(a,b){return new o.fn.init(a,b)},p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};o.fn=o.prototype={jquery:n,constructor:o,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=o.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return o.each(this,a,b)},map:function(a){return this.pushStack(o.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},o.extend=o.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||o.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(o.isPlainObject(d)||(e=o.isArray(d)))?(e?(e=!1,f=c&&o.isArray(c)?c:[]):f=c&&o.isPlainObject(c)?c:{},g[b]=o.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},o.extend({expando:"jQuery"+(n+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===o.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isPlainObject:function(a){if("object"!==o.type(a)||a.nodeType||o.isWindow(a))return!1;try{if(a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(b){return!1}return!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=o.trim(a),a&&(1===a.indexOf("use strict")?(b=m.createElement("script"),b.text=a,m.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":k.call(a)},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?o.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),o.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||o.guid++,f):void 0},now:Date.now,support:l}),o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=o.type(a);return"function"===c||o.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);o.find=t,o.expr=t.selectors,o.expr[":"]=o.expr.pseudos,o.unique=t.uniqueSort,o.text=t.getText,o.isXMLDoc=t.isXML,o.contains=t.contains;var u=o.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(o.isFunction(b))return o.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return o.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return o.filter(b,a,c);b=o.filter(b,a)}return o.grep(a,function(a){return g.call(b,a)>=0!==c})}o.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?o.find.matchesSelector(d,a)?[d]:[]:o.find.matches(a,o.grep(b,function(a){return 1===a.nodeType}))},o.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(o(a).filter(function(){for(b=0;c>b;b++)if(o.contains(e[b],this))return!0}));for(b=0;c>b;b++)o.find(a,e[b],d);return d=this.pushStack(c>1?o.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?o(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=o.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof o?b[0]:b,o.merge(this,o.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:m,!0)),v.test(c[1])&&o.isPlainObject(b))for(c in b)o.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=m.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=m,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):o.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(o):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),o.makeArray(a,this))};A.prototype=o.fn,y=o(m);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};o.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&o(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),o.fn.extend({has:function(a){var b=o(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(o.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?o(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&o.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?o.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(o(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(o.unique(o.merge(this.get(),o(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}o.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return o.dir(a,"parentNode")},parentsUntil:function(a,b,c){return o.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return o.dir(a,"nextSibling")},prevAll:function(a){return o.dir(a,"previousSibling")},nextUntil:function(a,b,c){return o.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return o.dir(a,"previousSibling",c)},siblings:function(a){return o.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return o.sibling(a.firstChild)},contents:function(a){return a.contentDocument||o.merge([],a.childNodes)}},function(a,b){o.fn[a]=function(c,d){var e=o.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=o.filter(d,e)),this.length>1&&(C[a]||o.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return o.each(a.match(E)||[],function(a,c){b[c]=!0}),b}o.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):o.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){o.each(b,function(b,c){var d=o.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&o.each(arguments,function(a,b){var c;while((c=o.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?o.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},o.extend({Deferred:function(a){var b=[["resolve","done",o.Callbacks("once memory"),"resolved"],["reject","fail",o.Callbacks("once memory"),"rejected"],["notify","progress",o.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return o.Deferred(function(c){o.each(b,function(b,f){var g=o.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&o.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?o.extend(a,d):d}},e={};return d.pipe=d.then,o.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&o.isFunction(a.promise)?e:0,g=1===f?a:o.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&o.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;o.fn.ready=function(a){return o.ready.promise().done(a),this},o.extend({isReady:!1,readyWait:1,holdReady:function(a){a?o.readyWait++:o.ready(!0)},ready:function(a){(a===!0?--o.readyWait:o.isReady)||(o.isReady=!0,a!==!0&&--o.readyWait>0||(H.resolveWith(m,[o]),o.fn.trigger&&o(m).trigger("ready").off("ready")))}});function I(){m.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),o.ready()}o.ready.promise=function(b){return H||(H=o.Deferred(),"complete"===m.readyState?setTimeout(o.ready):(m.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},o.ready.promise();var J=o.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===o.type(c)){e=!0;for(h in c)o.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,o.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(o(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};o.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=o.expando+Math.random()}K.uid=1,K.accepts=o.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,o.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(o.isEmptyObject(f))o.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,o.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{o.isArray(b)?d=b.concat(b.map(o.camelCase)):(e=o.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!o.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?o.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}o.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),o.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;
+while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=o.camelCase(d.slice(5)),P(f,d,e[d]));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=o.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),o.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||o.isArray(c)?d=L.access(a,b,o.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=o.queue(a,b),d=c.length,e=c.shift(),f=o._queueHooks(a,b),g=function(){o.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:o.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),o.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?o.queue(this[0],a):void 0===b?this:this.each(function(){var c=o.queue(this,a,b);o._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&o.dequeue(this,a)})},dequeue:function(a){return this.each(function(){o.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=o.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===o.css(a,"display")||!o.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=m.createDocumentFragment(),b=a.appendChild(m.createElement("div"));b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";l.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return m.activeElement}catch(a){}}o.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=o.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof o!==U&&o.event.triggered!==b.type?o.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n&&(l=o.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=o.event.special[n]||{},k=o.extend({type:n,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&o.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(n,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),o.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n){l=o.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||o.removeEvent(a,n,r.handle),delete i[n])}else for(n in i)o.event.remove(a,n+b[j],c,d,!0);o.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,p=[d||m],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||m,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+o.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[o.expando]?b:new o.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:o.makeArray(c,[b]),n=o.event.special[q]||{},e||!n.trigger||n.trigger.apply(d,c)!==!1)){if(!e&&!n.noBubble&&!o.isWindow(d)){for(i=n.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||m)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:n.bindType||q,l=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),l&&l.apply(g,c),l=k&&g[k],l&&l.apply&&o.acceptData(g)&&(b.result=l.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||n._default&&n._default.apply(p.pop(),c)!==!1||!o.acceptData(d)||k&&o.isFunction(d[q])&&!o.isWindow(d)&&(h=d[k],h&&(d[k]=null),o.event.triggered=q,d[q](),o.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=o.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=o.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=o.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((o.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?o(e,this).index(i)>=0:o.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||m,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[o.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new o.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=m),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&o.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return o.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=o.extend(new o.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?o.event.trigger(e,null,b):o.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},o.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},o.Event=function(a,b){return this instanceof o.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.getPreventDefault&&a.getPreventDefault()?Z:$):this.type=a,b&&o.extend(this,b),this.timeStamp=a&&a.timeStamp||o.now(),void(this[o.expando]=!0)):new o.Event(a,b)},o.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z,this.stopPropagation()}},o.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){o.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!o.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.focusinBubbles||o.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){o.event.simulate(b,a.target,o.event.fix(a),!0)};o.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),o.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return o().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=o.guid++)),this.each(function(){o.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,o(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){o.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){o.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?o.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return o.nodeName(a,"table")&&o.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)o.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=o.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&o.nodeName(a,b)?o.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}o.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=o.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||o.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,n=a.length;n>m;m++)if(e=a[m],e||0===e)if("object"===o.type(e))o.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;o.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===o.inArray(e,d))&&(i=o.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f,g,h=o.event.special,i=0;void 0!==(c=a[i]);i++){if(o.acceptData(c)&&(f=c[L.expando],f&&(b=L.cache[f]))){if(d=Object.keys(b.events||{}),d.length)for(g=0;void 0!==(e=d[g]);g++)h[e]?o.event.remove(c,e):o.removeEvent(c,e,b.handle);L.cache[f]&&delete L.cache[f]}delete M.cache[c[M.expando]]}}}),o.fn.extend({text:function(a){return J(this,function(a){return void 0===a?o.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?o.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||o.cleanData(ob(c)),c.parentNode&&(b&&o.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(o.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return o.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(o.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,o.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,n=k-1,p=a[0],q=o.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(c=o.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=o.map(ob(c,"script"),kb),g=f.length;k>j;j++)h=c,j!==n&&(h=o.clone(h,!0,!0),g&&o.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,o.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&o.contains(i,h)&&(h.src?o._evalUrl&&o._evalUrl(h.src):o.globalEval(h.textContent.replace(hb,"")))}return this}}),o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){o.fn[a]=function(a){for(var c,d=[],e=o(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),o(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d=o(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:o.css(d[0],"display");return d.detach(),e}function tb(a){var b=m,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||o("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||o.contains(a.ownerDocument,a)||(g=o.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",e=m.documentElement,f=m.createElement("div"),g=m.createElement("div");g.style.backgroundClip="content-box",g.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===g.style.backgroundClip,f.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",f.appendChild(g);function h(){g.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",e.appendChild(f);var d=a.getComputedStyle(g,null);b="1%"!==d.top,c="4px"===d.width,e.removeChild(f)}a.getComputedStyle&&o.extend(l,{pixelPosition:function(){return h(),b},boxSizingReliable:function(){return null==c&&h(),c},reliableMarginRight:function(){var b,c=g.appendChild(m.createElement("div"));return c.style.cssText=g.style.cssText=d,c.style.marginRight=c.style.width="0",g.style.width="1px",e.appendChild(f),b=!parseFloat(a.getComputedStyle(c,null).marginRight),e.removeChild(f),g.innerHTML="",b}})}(),o.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:0,fontWeight:400},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=o.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=o.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=o.css(a,"border"+R[f]+"Width",!0,e))):(g+=o.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=o.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===o.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):f[g]||(e=S(d),(c&&"none"!==c||!e)&&L.set(d,"olddisplay",e?c:o.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}o.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=o.camelCase(b),i=a.style;return b=o.cssProps[h]||(o.cssProps[h]=Fb(i,h)),g=o.cssHooks[b]||o.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(o.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||o.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]="",i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=o.camelCase(b);return b=o.cssProps[h]||(o.cssProps[h]=Fb(a.style,h)),g=o.cssHooks[b]||o.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||o.isNumeric(f)?f||0:e):e}}),o.each(["height","width"],function(a,b){o.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&zb.test(o.css(a,"display"))?o.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===o.css(a,"boxSizing",!1,e),e):0)}}}),o.cssHooks.marginRight=yb(l.reliableMarginRight,function(a,b){return b?o.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),o.each({margin:"",padding:"",border:"Width"},function(a,b){o.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(o.cssHooks[a+b].set=Gb)}),o.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(o.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=o.css(a,b[g],!1,d);return f}return void 0!==c?o.style(a,b,c):o.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?o(this).show():o(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}o.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(o.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?o.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=o.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){o.fx.step[a.prop]?o.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[o.cssProps[a.prop]]||o.cssHooks[a.prop])?o.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},o.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},o.fx=Kb.prototype.init,o.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(o.cssNumber[a]?"":"px"),g=(o.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(o.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,o.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=o.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k=this,l={},m=a.style,n=a.nodeType&&S(a),p=L.get(a,"fxshow");c.queue||(h=o._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,k.always(function(){k.always(function(){h.unqueued--,o.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],j=o.css(a,"display"),"none"===j&&(j=tb(a.nodeName)),"inline"===j&&"none"===o.css(a,"float")&&(m.display="inline-block")),c.overflow&&(m.overflow="hidden",k.always(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(n?"hide":"show")){if("show"!==e||!p||void 0===p[d])continue;n=!0}l[d]=p&&p[d]||o.style(a,d)}if(!o.isEmptyObject(l)){p?"hidden"in p&&(n=p.hidden):p=L.access(a,"fxshow",{}),f&&(p.hidden=!n),n?o(a).show():k.done(function(){o(a).hide()}),k.done(function(){var b;L.remove(a,"fxshow");for(b in l)o.style(a,b,l[b])});for(d in l)g=Ub(n?p[d]:0,d,k),d in p||(p[d]=g.start,n&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=o.camelCase(c),e=b[d],f=a[c],o.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=o.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=o.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:o.extend({},b),opts:o.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=o.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return o.map(k,Ub,j),o.isFunction(j.opts.start)&&j.opts.start.call(a,j),o.fx.timer(o.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}o.Animation=o.extend(Xb,{tweener:function(a,b){o.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),o.speed=function(a,b,c){var d=a&&"object"==typeof a?o.extend({},a):{complete:c||!c&&b||o.isFunction(a)&&a,duration:a,easing:c&&b||b&&!o.isFunction(b)&&b};return d.duration=o.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in o.fx.speeds?o.fx.speeds[d.duration]:o.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){o.isFunction(d.old)&&d.old.call(this),d.queue&&o.dequeue(this,d.queue)},d},o.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=o.isEmptyObject(a),f=o.speed(b,c,d),g=function(){var b=Xb(this,o.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=o.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&o.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=o.timers,g=d?d.length:0;for(c.finish=!0,o.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),o.each(["toggle","show","hide"],function(a,b){var c=o.fn[b];o.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),o.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){o.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),o.timers=[],o.fx.tick=function(){var a,b=0,c=o.timers;for(Lb=o.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||o.fx.stop(),Lb=void 0},o.fx.timer=function(a){o.timers.push(a),a()?o.fx.start():o.timers.pop()},o.fx.interval=13,o.fx.start=function(){Mb||(Mb=setInterval(o.fx.tick,o.fx.interval))},o.fx.stop=function(){clearInterval(Mb),Mb=null},o.fx.speeds={slow:600,fast:200,_default:400},o.fn.delay=function(a,b){return a=o.fx?o.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=m.createElement("input"),b=m.createElement("select"),c=b.appendChild(m.createElement("option"));a.type="checkbox",l.checkOn=""!==a.value,l.optSelected=c.selected,b.disabled=!0,l.optDisabled=!c.disabled,a=m.createElement("input"),a.value="t",a.type="radio",l.radioValue="t"===a.value}();var Yb,Zb,$b=o.expr.attrHandle;o.fn.extend({attr:function(a,b){return J(this,o.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){o.removeAttr(this,a)})}}),o.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?o.prop(a,b,c):(1===f&&o.isXMLDoc(a)||(b=b.toLowerCase(),d=o.attrHooks[b]||(o.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=o.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void o.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=o.propFix[c]||c,o.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&o.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?o.removeAttr(a,c):a.setAttribute(c,c),c}},o.each(o.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||o.find.attr;$b[b]=function(a,b,d){var e,f;
+return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;o.fn.extend({prop:function(a,b){return J(this,o.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[o.propFix[a]||a]})}}),o.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!o.isXMLDoc(a),f&&(b=o.propFix[b]||b,e=o.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),l.optSelected||(o.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),o.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){o.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;o.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=o.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(o.isFunction(a))return this.each(function(b){o(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?o.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(o.isFunction(a)?function(c){o(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=o(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;o.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=o.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,o(this).val()):a,null==e?e="":"number"==typeof e?e+="":o.isArray(e)&&(e=o.map(e,function(a){return null==a?"":a+""})),b=o.valHooks[this.type]||o.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=o.valHooks[e.type]||o.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),o.extend({valHooks:{select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&o.nodeName(c.parentNode,"optgroup"))){if(b=o(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=o.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=o.inArray(o(d).val(),f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),o.each(["radio","checkbox"],function(){o.valHooks[this]={set:function(a,b){return o.isArray(b)?a.checked=o.inArray(o(a).val(),b)>=0:void 0}},l.checkOn||(o.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),o.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){o.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),o.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=o.now(),dc=/\?/;o.parseJSON=function(a){return JSON.parse(a+"")},o.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&o.error("Invalid XML: "+a),b};var ec,fc,gc=/#.*$/,hc=/([?&])_=[^&]*/,ic=/^(.*?):[ \t]*([^\r\n]*)$/gm,jc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kc=/^(?:GET|HEAD)$/,lc=/^\/\//,mc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,nc={},oc={},pc="*/".concat("*");try{fc=location.href}catch(qc){fc=m.createElement("a"),fc.href="",fc=fc.href}ec=mc.exec(fc.toLowerCase())||[];function rc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(o.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function sc(a,b,c,d){var e={},f=a===oc;function g(h){var i;return e[h]=!0,o.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function tc(a,b){var c,d,e=o.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&o.extend(!0,a,d),a}function uc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function vc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}o.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:fc,type:"GET",isLocal:jc.test(ec[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":pc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":o.parseJSON,"text xml":o.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?tc(tc(a,o.ajaxSettings),b):tc(o.ajaxSettings,a)},ajaxPrefilter:rc(nc),ajaxTransport:rc(oc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=o.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?o(l):o.event,n=o.Deferred(),p=o.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=ic.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(n.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||fc)+"").replace(gc,"").replace(lc,ec[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=o.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=mc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===ec[1]&&h[2]===ec[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(ec[3]||("http:"===ec[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=o.param(k.data,k.traditional)),sc(nc,k,b,v),2===t)return v;i=k.global,i&&0===o.active++&&o.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!kc.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=hc.test(d)?d.replace(hc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(o.lastModified[d]&&v.setRequestHeader("If-Modified-Since",o.lastModified[d]),o.etag[d]&&v.setRequestHeader("If-None-Match",o.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+pc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=sc(oc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=uc(k,v,f)),u=vc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(o.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(o.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?n.resolveWith(l,[r,x,v]):n.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--o.active||o.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return o.get(a,b,c,"json")},getScript:function(a,b){return o.get(a,void 0,b,"script")}}),o.each(["get","post"],function(a,b){o[b]=function(a,c,d,e){return o.isFunction(c)&&(e=e||d,d=c,c=void 0),o.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),o.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){o.fn[b]=function(a){return this.on(b,a)}}),o._evalUrl=function(a){return o.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},o.fn.extend({wrapAll:function(a){var b;return o.isFunction(a)?this.each(function(b){o(this).wrapAll(a.call(this,b))}):(this[0]&&(b=o(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(o.isFunction(a)?function(b){o(this).wrapInner(a.call(this,b))}:function(){var b=o(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=o.isFunction(a);return this.each(function(c){o(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){o.nodeName(this,"body")||o(this).replaceWith(this.childNodes)}).end()}}),o.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},o.expr.filters.visible=function(a){return!o.expr.filters.hidden(a)};var wc=/%20/g,xc=/\[\]$/,yc=/\r?\n/g,zc=/^(?:submit|button|image|reset|file)$/i,Ac=/^(?:input|select|textarea|keygen)/i;function Bc(a,b,c,d){var e;if(o.isArray(b))o.each(b,function(b,e){c||xc.test(a)?d(a,e):Bc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==o.type(b))d(a,b);else for(e in b)Bc(a+"["+e+"]",b[e],c,d)}o.param=function(a,b){var c,d=[],e=function(a,b){b=o.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=o.ajaxSettings&&o.ajaxSettings.traditional),o.isArray(a)||a.jquery&&!o.isPlainObject(a))o.each(a,function(){e(this.name,this.value)});else for(c in a)Bc(c,a[c],b,e);return d.join("&").replace(wc,"+")},o.fn.extend({serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=o.prop(this,"elements");return a?o.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!o(this).is(":disabled")&&Ac.test(this.nodeName)&&!zc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=o(this).val();return null==c?null:o.isArray(c)?o.map(c,function(a){return{name:b.name,value:a.replace(yc,"\r\n")}}):{name:b.name,value:c.replace(yc,"\r\n")}}).get()}}),o.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Cc=0,Dc={},Ec={0:200,1223:204},Fc=o.ajaxSettings.xhr();a.ActiveXObject&&o(a).on("unload",function(){for(var a in Dc)Dc[a]()}),l.cors=!!Fc&&"withCredentials"in Fc,l.ajax=Fc=!!Fc,o.ajaxTransport(function(a){var b;return l.cors||Fc&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Cc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Dc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Ec[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Dc[g]=b("abort"),f.send(a.hasContent&&a.data||null)},abort:function(){b&&b()}}:void 0}),o.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return o.globalEval(a),a}}}),o.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),o.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=o("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),m.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Gc=[],Hc=/(=)\?(?=&|$)|\?\?/;o.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Gc.pop()||o.expando+"_"+cc++;return this[a]=!0,a}}),o.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Hc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Hc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=o.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Hc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||o.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Gc.push(e)),g&&o.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),o.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||m;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=o.buildFragment([a],b,e),e&&e.length&&o(e).remove(),o.merge([],d.childNodes))};var Ic=o.fn.load;o.fn.load=function(a,b,c){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h),a=a.slice(0,h)),o.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&o.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?o("<div>").append(o.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},o.expr.filters.animated=function(a){return o.grep(o.timers,function(b){return a===b.elem}).length};var Jc=a.document.documentElement;function Kc(a){return o.isWindow(a)?a:9===a.nodeType&&a.defaultView}o.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=o.css(a,"position"),l=o(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=o.css(a,"top"),i=o.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),o.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},o.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){o.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,o.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Kc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===o.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),o.nodeName(a[0],"html")||(d=a.offset()),d.top+=o.css(a[0],"borderTopWidth",!0),d.left+=o.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-o.css(c,"marginTop",!0),left:b.left-d.left-o.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Jc;while(a&&!o.nodeName(a,"html")&&"static"===o.css(a,"position"))a=a.offsetParent;return a||Jc})}}),o.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;o.fn[b]=function(e){return J(this,function(b,e,f){var g=Kc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),o.each(["top","left"],function(a,b){o.cssHooks[b]=yb(l.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?o(a).position()[b]+"px":c):void 0})}),o.each({Height:"height",Width:"width"},function(a,b){o.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){o.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return o.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?o.css(b,c,g):o.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),o.fn.size=function(){return this.length},o.fn.andSelf=o.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return o});var Lc=a.jQuery,Mc=a.$;return o.noConflict=function(b){return a.$===o&&(a.$=Mc),b&&a.jQuery===o&&(a.jQuery=Lc),o},typeof b===U&&(a.jQuery=a.$=o),o});
www/vincent.demeester.fr/assets/.fancyindex/new.css
@@ -0,0 +1,605 @@
+:root {
+ ---font-sans: 'Ubuntu Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ ---font-mono: 'Ubuntu Mono', Consolas, monaco, 'Liberation Mono', 'Courier New', Courier, monospace;
+ ---tx-1: #000000;
+ ---tx-2: #1A1A1A;
+ ---tx-3: #666666;
+ ---tx-4: #999999;
+ ---bg-1: #FFFFFF;
+ ---bg-2: #F6F8FA;
+ ---bg-3: #E5E7EB;
+ ---lk-1: #0070F3;
+ ---lk-2: #0366D6;
+ ---lk-tx: #FFFFFF;
+ ---ac-1: #79FFE1;
+ ---ac-tx: #0C4047;
+
+ --content-box-padding: 0.5rem;
+ --aside-width: 12.5rem;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ ---tx-1: #ffffff;
+ ---tx-2: #eeeeee;
+ ---tx-3: #cccccc;
+ ---tx-4: #aaaaaa;
+ ---bg-1: #000000;
+ ---bg-2: #111111;
+ ---bg-3: #222222;
+ ---lk-1: #3291FF;
+ ---lk-2: #0070F3;
+ ---lk-tx: #FFFFFF;
+ ---ac-1: #7928CA;
+ ---ac-tx: #FFFFFF;
+ }
+}
+
+* {
+ /* Reset margins and padding */
+ margin: 0;
+ padding: 0;
+}
+
+address,
+area,
+article,
+aside,
+audio,
+blockquote,
+datalist,
+details,
+dl,
+fieldset,
+figure,
+form,
+input,
+iframe,
+img,
+meter,
+nav,
+ol,
+optgroup,
+option,
+output,
+p,
+pre,
+progress,
+ruby,
+section,
+table,
+textarea,
+ul,
+video {
+ /* Margins for most elements */
+ margin-bottom: 1rem;
+}
+
+html,input,select,button {
+ /* Set body font family and some finicky elements */
+ font-family: var(---font-sans);
+}
+
+body {
+ /* Center body in page */
+ margin: 0 auto;
+ max-width: 70rem;
+ padding: 2rem;
+ border-radius: 6px;
+ overflow-x: hidden;
+ word-break: break-word;
+ overflow-wrap: break-word;
+ background: var(---bg-1);
+
+ /* Main body text */
+ color: var(---tx-2);
+ font-size: 1.03rem;
+ line-height: 1.5;
+}
+
+::selection {
+ /* Set background color for selected text */
+ background: var(---ac-1);
+ color: var(---ac-tx);
+}
+
+h1,h2,h3,h4,h5,h6 {
+ line-height: 1;
+ color: var(---tx-1);
+ padding-top: .875rem;
+}
+
+h1,
+h2,
+h3 {
+ color: var(---tx-1);
+ padding-bottom: 2px;
+ margin-bottom: 8px;
+ border-bottom: 1px solid var(---bg-2);
+}
+
+h4,
+h5,
+h6 {
+ margin-bottom: .3rem;
+}
+
+h1 {
+ font-size: 2.25rem;
+}
+
+h2 {
+ font-size: 1.85rem;
+}
+
+h3 {
+ font-size: 1.55rem;
+}
+
+h4 {
+ font-size: 1.25rem;
+}
+
+h5 {
+ font-size: 1rem;
+}
+
+h6 {
+ font-size: .875rem;
+}
+
+a {
+ color: var(---lk-1);
+}
+
+a:hover {
+ color: var(---lk-2);
+}
+
+abbr:hover {
+ /* Set the '?' cursor while hovering an abbreviation */
+ cursor: help;
+}
+
+blockquote {
+ padding: 1.5rem;
+ background: var(---bg-2);
+ border-left: 5px solid var(---bg-3);
+}
+
+abbr {
+ cursor: help;
+}
+
+blockquote *:last-child {
+ padding-bottom: 0;
+ margin-bottom: 0;
+}
+
+header {
+ background: var(---bg-2);
+ border-bottom: 1px solid var(---bg-3);
+ padding: 1rem 1.5rem;
+
+ /* This sets the right and left margins to cancel out the body's margins. It's width is still the same, but the background stretches across the page's width. */
+
+ margin: -2rem calc(0px - (50vw - 50%)) 2rem;
+
+ /* Shorthand for:
+
+ margin-top: -2rem;
+ margin-bottom: 2rem;
+
+ margin-left: calc(0px - (50vw - 50%));
+ margin-right: calc(0px - (50vw - 50%)); */
+
+ padding-left: calc(50vw - 50%);
+ padding-right: calc(50vw - 50%);
+}
+
+header img#sitelogo {
+ margin-bottom: 0;
+ margin-right: 1em;
+}
+
+header h1,
+header h2,
+header h3 {
+ padding-bottom: 0;
+ border-bottom: 0;
+}
+
+header > *:first-child {
+ margin-top: 0;
+ padding-top: 0;
+}
+
+header > *:last-child {
+ margin-bottom: 0;
+}
+
+main header {
+ background: var(---bg-3);
+}
+
+a button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+ font-size: 1rem;
+ display: inline-block;
+ padding: 6px 12px;
+ text-align: center;
+ text-decoration: none;
+ white-space: nowrap;
+ background: var(---lk-1);
+ color: var(---lk-tx);
+ border: 0;
+ border-radius: 4px;
+ box-sizing: border-box;
+ cursor: pointer;
+ color: var(---lk-tx);
+}
+
+a button[disabled],
+button[disabled],
+input[type="submit"][disabled],
+input[type="reset"][disabled],
+input[type="button"][disabled] {
+ cursor: default;
+ opacity: .5;
+
+ /* Set the [X] cursor while hovering a disabled link */
+ cursor: not-allowed;
+}
+
+.button:focus,
+.button:hover,
+button:focus,
+button:hover,
+input[type="submit"]:focus,
+input[type="submit"]:hover,
+input[type="reset"]:focus,
+input[type="reset"]:hover,
+input[type="button"]:focus,
+input[type="button"]:hover {
+ background: var(---lk-2);
+}
+
+code,
+pre,
+kbd,
+samp {
+ /* Set the font family for monospaced elements */
+ font-family: var(---font-mono);
+}
+
+code,
+samp,
+kbd,
+pre {
+ /* The main preformatted style. This is changed slightly across different cases. */
+ background: var(---bg-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+ padding: 3px 6px;
+}
+
+kbd {
+ /* Makes the kbd element look like a keyboard key */
+ border-bottom: 3px solid var(---bg-3);
+}
+
+pre {
+ padding: 1rem 1.4rem;
+ max-width: 100%;
+ overflow: auto;
+}
+
+pre.src {
+ position: relative;
+}
+pre.src:before {
+ /*display: none;*/
+ position: absolute;
+ background-color: var(---bg-3);
+ /*color: #f3f4f4;*/
+ top: 0;
+ right: 0;
+ padding: 0.2rem 0.5rem;
+}
+
+pre code {
+ /* When <code> is in a <pre>, reset it's formatting to blend in */
+ background: inherit;
+ font-size: inherit;
+ color: inherit;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+code pre {
+ /* When <pre> is in a <code>, reset it's formatting to blend in */
+ display: inline;
+ background: inherit;
+ font-size: inherit;
+ color: inherit;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+details {
+ /* Make the <details> look more "clickable" */
+ padding: .6rem 1rem;
+ background: var(---bg-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+}
+
+summary {
+ /* Makes the <summary> look more like a "clickable" link with the pointer cursor */
+ cursor: pointer;
+ font-weight: bold;
+}
+
+details[open] {
+ /* Adjust the <details> padding while open */
+ padding-bottom: .75rem;
+}
+
+details[open] summary {
+ /* Adjust the <details> padding while open */
+ margin-bottom: 6px;
+}
+
+details[open]>*:last-child {
+ /* Resets the bottom margin of the last element in the <details> while <details> is opened. This prevents double margins/paddings. */
+ margin-bottom: 0;
+}
+
+dt {
+ font-weight: bold;
+}
+
+dd::before {
+ /* Add an arrow to data table definitions */
+ content: 'โ ';
+}
+
+hr {
+ /* Reset the border of the <hr> separator, then set a better line */
+ border: 0;
+ border-bottom: 1px solid var(---bg-3);
+ margin: 1rem auto;
+}
+
+fieldset {
+ margin-top: 1rem;
+ padding: 2rem;
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+}
+
+legend {
+ padding: auto .5rem;
+}
+
+table {
+ /* border-collapse sets the table's elements to share borders, rather than floating as separate "boxes". */
+ border-collapse: collapse;
+ width: 100%
+}
+
+td,
+th {
+ border: 1px solid var(---bg-3);
+ text-align: left;
+ padding: .5rem;
+}
+
+th {
+ background: var(---bg-2);
+}
+
+tr:nth-child(even) {
+ /* Set every other cell slightly darker. Improves readability. */
+ background: var(---bg-2);
+}
+
+table caption {
+ font-weight: bold;
+ margin-bottom: .5rem;
+}
+
+textarea {
+ /* Don't let the <textarea> extend off the screen naturally or when dragged by the user */
+ max-width: 100%;
+}
+
+ol,
+ul {
+ /* Replace the browser default padding */
+ padding-left: 2rem;
+}
+
+li {
+ margin-top: .4rem;
+}
+
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+ margin-bottom: 0;
+}
+
+mark {
+ padding: 3px 6px;
+ background: var(---ac-1);
+ color: var(---ac-tx);
+}
+
+textarea,
+select,
+input {
+ padding: 6px 12px;
+ margin-bottom: .5rem;
+ background: var(---bg-2);
+ color: var(---tx-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+ box-shadow: none;
+ box-sizing: border-box;
+}
+
+img {
+ max-width: 100%;
+}
+
+aside {
+ --aside-offset: 1rem;
+ --aside-offset-lineheight: 1.5rem;
+ background-color: var(---bg-2);
+ padding: calc(var(--content-box-padding) * 0.5) calc(var(--content-box-padding) * 2);
+ padding-top: 1em;
+ margin-bottom: 0em;
+ float: right;
+ width: var(--aside-width);
+ font-size: 0.9rem;
+ line-height: 1.25rem;
+ border: 1px solid var(--bg-3);
+}
+
+figure figcaption {
+ text-align: center;
+ color: var(---tx-2);
+ font-style: italic;
+ margin: 0 2rem;
+}
+
+footer {
+ text-align: center;
+ color: var(---tx-4);
+}
+
+footer a {
+ color: var(---tx-3);
+}
+
+section img {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+section img.shadow {
+ box-shadow: 0 28px 50px rgba(0,0,0,0.16);
+}
+
+div.drawer:before {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 4.4rem;
+ width: 1px;
+ background-color: #555;
+}
+
+div.drawer {
+ display: flex;
+ padding: 0;
+ margin: 1rem;
+ padding-top: 1rem;
+ position: relative;
+ color: #555;
+}
+
+div.drawer h6 {
+ box-sizing: border-box;
+ font-style: italic;
+ flex: 0 0 5rem;
+ margin:0;
+ padding:0;
+ align-self: center;
+ text-align: right;
+ padding-right: 1.2rem;
+}
+
+div.drawer.info:before {
+ background-color: #00529B;
+}
+div.drawer.info {
+ color: #00529B;
+}
+
+div.drawer.note:before {
+ background-color: #9F6000;
+}
+div.drawer.note {
+ color: #9F6000;
+}
+div.drawer.tip:before {
+ background-color: #4F8A10;
+}
+div.drawer.tip {
+ color: #4F8A10;
+}
+div.drawer.warning:before {
+ background-color: #D8000C;
+}
+div.drawer.warning {
+ color: #D8000C;
+}
+div.drawer.results:before {
+ background-color: black;
+}
+div.drawer.results {
+ font-family:monospace,monospace;
+ font-family: var(---font-mono);
+ color: black;
+ width: 100% !important;
+}
+div.drawer.results p {
+ display: block;
+ unicode-bidi: embed;
+ white-space: pre;
+ margin-top: 0;
+}
+div.drawer.results pre {
+ background-color: inherit;
+ border: 0;
+}
+div.drawer.results pre.src:before {
+ background-color: #eee;
+ color: #555;
+}
+
+.tag {
+ font-family:var(---font-mono);
+ font-size: 1rem;
+}
+.tag span {
+ padding:.3em;
+ float:right;
+ margin-right:.5em;
+ border:1px solid #bbb;
+ border-radius:3px;
+ background-clip:padding-box;
+ color:#333;
+ background-color:#eee;
+ line-height:1rem;
+}
+
+.todo {
+ font-family: monospace; color: red;
+}
+.done {
+ font-family: monospace; color: green;
+}
+.priority { font-family: monospace; color: orange; }
+.timestamp { color: #bebebe; }
+.timestamp-kwd { color: #5f9ea0; }
www/vincent.demeester.fr/assets/.fancyindex/showdown.min.js
@@ -0,0 +1,3 @@
+/*! showdown v 1.8.6 - 22-12-2017 */
+(function(){function g(g){"use strict";var A={omitExtraWLInCodeBlocks:{defaultValue:!1,describe:"Omit the default extra whiteline added to code blocks",type:"boolean"},noHeaderId:{defaultValue:!1,describe:"Turn on/off generated header id",type:"boolean"},prefixHeaderId:{defaultValue:!1,describe:"Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic 'section-' prefix",type:"string"},rawPrefixHeaderId:{defaultValue:!1,describe:'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',type:"boolean"},ghCompatibleHeaderId:{defaultValue:!1,describe:"Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)",type:"boolean"},rawHeaderId:{defaultValue:!1,describe:"Remove only spaces, ' and \" from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids",type:"boolean"},headerLevelStart:{defaultValue:!1,describe:"The header blocks level start",type:"integer"},parseImgDimensions:{defaultValue:!1,describe:"Turn on/off image dimension parsing",type:"boolean"},simplifiedAutoLink:{defaultValue:!1,describe:"Turn on/off GFM autolink style",type:"boolean"},excludeTrailingPunctuationFromURLs:{defaultValue:!1,describe:"Excludes trailing punctuation from links generated with autoLinking",type:"boolean"},literalMidWordUnderscores:{defaultValue:!1,describe:"Parse midword underscores as literal underscores",type:"boolean"},literalMidWordAsterisks:{defaultValue:!1,describe:"Parse midword asterisks as literal asterisks",type:"boolean"},strikethrough:{defaultValue:!1,describe:"Turn on/off strikethrough support",type:"boolean"},tables:{defaultValue:!1,describe:"Turn on/off tables support",type:"boolean"},tablesHeaderId:{defaultValue:!1,describe:"Add an id to table headers",type:"boolean"},ghCodeBlocks:{defaultValue:!0,describe:"Turn on/off GFM fenced code blocks support",type:"boolean"},tasklists:{defaultValue:!1,describe:"Turn on/off GFM tasklist support",type:"boolean"},smoothLivePreview:{defaultValue:!1,describe:"Prevents weird effects in live previews due to incomplete input",type:"boolean"},smartIndentationFix:{defaultValue:!1,description:"Tries to smartly fix indentation in es6 strings",type:"boolean"},disableForced4SpacesIndentedSublists:{defaultValue:!1,description:"Disables the requirement of indenting nested sublists by 4 spaces",type:"boolean"},simpleLineBreaks:{defaultValue:!1,description:"Parses simple line breaks as <br> (GFM Style)",type:"boolean"},requireSpaceBeforeHeadingText:{defaultValue:!1,description:"Makes adding a space between `#` and the header text mandatory (GFM Style)",type:"boolean"},ghMentions:{defaultValue:!1,description:"Enables github @mentions",type:"boolean"},ghMentionsLink:{defaultValue:"https://github.com/{u}",description:"Changes the link generated by @mentions. Only applies if ghMentions option is enabled.",type:"string"},encodeEmails:{defaultValue:!0,description:"Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities",type:"boolean"},openLinksInNewWindow:{defaultValue:!1,description:"Open all links in new windows",type:"boolean"},backslashEscapesHTMLTags:{defaultValue:!1,description:"Support for HTML Tag escaping. ex: <div>foo</div>",type:"boolean"},emoji:{defaultValue:!1,description:"Enable emoji support. Ex: `this is a :smile: emoji`",type:"boolean"},underline:{defaultValue:!1,description:"Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `<em>` and `<strong>`",type:"boolean"},completeHTMLDocument:{defaultValue:!1,description:"Outputs a complete html document, including `<html>`, `<head>` and `<body>` tags",type:"boolean"},metadata:{defaultValue:!1,description:"Enable support for document metadata (defined at the top of the document between `ยซยซยซ` and `ยปยปยป` or between `---` and `---`).",type:"boolean"},splitAdjacentBlockquotes:{defaultValue:!1,description:"Split adjacent blockquote blocks",type:"boolean"}};if(!1===g)return JSON.parse(JSON.stringify(A));var C={};for(var I in A)A.hasOwnProperty(I)&&(C[I]=A[I].defaultValue);return C}function A(g,A){"use strict";var C=A?"Error in "+A+" extension->":"Error in unnamed extension",e={valid:!0,error:""};I.helper.isArray(g)||(g=[g]);for(var r=0;r<g.length;++r){var t=C+" sub-extension "+r+": ",a=g[r];if("object"!=typeof a)return e.valid=!1,e.error=t+"must be an object, but "+typeof a+" given",e;if(!I.helper.isString(a.type))return e.valid=!1,e.error=t+'property "type" must be a string, but '+typeof a.type+" given",e;var n=a.type=a.type.toLowerCase();if("language"===n&&(n=a.type="lang"),"html"===n&&(n=a.type="output"),"lang"!==n&&"output"!==n&&"listener"!==n)return e.valid=!1,e.error=t+"type "+n+' is not recognized. Valid values: "lang/language", "output/html" or "listener"',e;if("listener"===n){if(I.helper.isUndefined(a.listeners))return e.valid=!1,e.error=t+'. Extensions of type "listener" must have a property called "listeners"',e}else if(I.helper.isUndefined(a.filter)&&I.helper.isUndefined(a.regex))return e.valid=!1,e.error=t+n+' extensions must define either a "regex" property or a "filter" method',e;if(a.listeners){if("object"!=typeof a.listeners)return e.valid=!1,e.error=t+'"listeners" property must be an object but '+typeof a.listeners+" given",e;for(var o in a.listeners)if(a.listeners.hasOwnProperty(o)&&"function"!=typeof a.listeners[o])return e.valid=!1,e.error=t+'"listeners" property must be an hash of [event name]: [callback]. listeners.'+o+" must be a function but "+typeof a.listeners[o]+" given",e}if(a.filter){if("function"!=typeof a.filter)return e.valid=!1,e.error=t+'"filter" must be a function, but '+typeof a.filter+" given",e}else if(a.regex){if(I.helper.isString(a.regex)&&(a.regex=new RegExp(a.regex,"g")),!(a.regex instanceof RegExp))return e.valid=!1,e.error=t+'"regex" property must either be a string or a RegExp object, but '+typeof a.regex+" given",e;if(I.helper.isUndefined(a.replace))return e.valid=!1,e.error=t+'"regex" extensions must implement a replace string or function',e}}return e}function C(g,A){"use strict";return"ยจE"+A.charCodeAt(0)+"E"}var I={},e={},r={},t=g(!0),a="vanilla",n={github:{omitExtraWLInCodeBlocks:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,disableForced4SpacesIndentedSublists:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghCompatibleHeaderId:!0,ghMentions:!0,backslashEscapesHTMLTags:!0,emoji:!0,splitAdjacentBlockquotes:!0},original:{noHeaderId:!0,ghCodeBlocks:!1},ghost:{omitExtraWLInCodeBlocks:!0,parseImgDimensions:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,smoothLivePreview:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghMentions:!1,encodeEmails:!0},vanilla:g(!0),allOn:function(){"use strict";var A=g(!0),C={};for(var I in A)A.hasOwnProperty(I)&&(C[I]=!0);return C}()};I.helper={},I.extensions={},I.setOption=function(g,A){"use strict";return t[g]=A,this},I.getOption=function(g){"use strict";return t[g]},I.getOptions=function(){"use strict";return t},I.resetOptions=function(){"use strict";t=g(!0)},I.setFlavor=function(g){"use strict";if(!n.hasOwnProperty(g))throw Error(g+" flavor was not found");I.resetOptions();var A=n[g];a=g;for(var C in A)A.hasOwnProperty(C)&&(t[C]=A[C])},I.getFlavor=function(){"use strict";return a},I.getFlavorOptions=function(g){"use strict";if(n.hasOwnProperty(g))return n[g]},I.getDefaultOptions=function(A){"use strict";return g(A)},I.subParser=function(g,A){"use strict";if(I.helper.isString(g)){if(void 0===A){if(e.hasOwnProperty(g))return e[g];throw Error("SubParser named "+g+" not registered!")}e[g]=A}},I.extension=function(g,C){"use strict";if(!I.helper.isString(g))throw Error("Extension 'name' must be a string");if(g=I.helper.stdExtName(g),I.helper.isUndefined(C)){if(!r.hasOwnProperty(g))throw Error("Extension named "+g+" is not registered!");return r[g]}"function"==typeof C&&(C=C()),I.helper.isArray(C)||(C=[C]);var e=A(C,g);if(!e.valid)throw Error(e.error);r[g]=C},I.getAllExtensions=function(){"use strict";return r},I.removeExtension=function(g){"use strict";delete r[g]},I.resetExtensions=function(){"use strict";r={}},I.validateExtension=function(g){"use strict";var C=A(g,null);return!!C.valid||(console.warn(C.error),!1)},I.hasOwnProperty("helper")||(I.helper={}),I.helper.isString=function(g){"use strict";return"string"==typeof g||g instanceof String},I.helper.isFunction=function(g){"use strict";return g&&"[object Function]"==={}.toString.call(g)},I.helper.isArray=function(g){"use strict";return Array.isArray(g)},I.helper.isUndefined=function(g){"use strict";return void 0===g},I.helper.forEach=function(g,A){"use strict";if(I.helper.isUndefined(g))throw new Error("obj param is required");if(I.helper.isUndefined(A))throw new Error("callback param is required");if(!I.helper.isFunction(A))throw new Error("callback param must be a function/closure");if("function"==typeof g.forEach)g.forEach(A);else if(I.helper.isArray(g))for(var C=0;C<g.length;C++)A(g[C],C,g);else{if("object"!=typeof g)throw new Error("obj does not seem to be an array or an iterable object");for(var e in g)g.hasOwnProperty(e)&&A(g[e],e,g)}},I.helper.stdExtName=function(g){"use strict";return g.replace(/[_?*+\/\\.^-]/g,"").replace(/\s/g,"").toLowerCase()},I.helper.escapeCharactersCallback=C,I.helper.escapeCharacters=function(g,A,I){"use strict";var e="(["+A.replace(/([\[\]\\])/g,"\\$1")+"])";I&&(e="\\\\"+e);var r=new RegExp(e,"g");return g=g.replace(r,C)};var o=function(g,A,C,I){"use strict";var e,r,t,a,n,o=I||"",s=o.indexOf("g")>-1,i=new RegExp(A+"|"+C,"g"+o.replace(/g/g,"")),l=new RegExp(A,o.replace(/g/g,"")),c=[];do{for(e=0;t=i.exec(g);)if(l.test(t[0]))e++||(a=(r=i.lastIndex)-t[0].length);else if(e&&!--e){n=t.index+t[0].length;var u={left:{start:a,end:r},match:{start:r,end:t.index},right:{start:t.index,end:n},wholeMatch:{start:a,end:n}};if(c.push(u),!s)return c}}while(e&&(i.lastIndex=r));return c};I.helper.matchRecursiveRegExp=function(g,A,C,I){"use strict";for(var e=o(g,A,C,I),r=[],t=0;t<e.length;++t)r.push([g.slice(e[t].wholeMatch.start,e[t].wholeMatch.end),g.slice(e[t].match.start,e[t].match.end),g.slice(e[t].left.start,e[t].left.end),g.slice(e[t].right.start,e[t].right.end)]);return r},I.helper.replaceRecursiveRegExp=function(g,A,C,e,r){"use strict";if(!I.helper.isFunction(A)){var t=A;A=function(){return t}}var a=o(g,C,e,r),n=g,s=a.length;if(s>0){var i=[];0!==a[0].wholeMatch.start&&i.push(g.slice(0,a[0].wholeMatch.start));for(var l=0;l<s;++l)i.push(A(g.slice(a[l].wholeMatch.start,a[l].wholeMatch.end),g.slice(a[l].match.start,a[l].match.end),g.slice(a[l].left.start,a[l].left.end),g.slice(a[l].right.start,a[l].right.end))),l<s-1&&i.push(g.slice(a[l].wholeMatch.end,a[l+1].wholeMatch.start));a[s-1].wholeMatch.end<g.length&&i.push(g.slice(a[s-1].wholeMatch.end)),n=i.join("")}return n},I.helper.regexIndexOf=function(g,A,C){"use strict";if(!I.helper.isString(g))throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";if(A instanceof RegExp==!1)throw"InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp";var e=g.substring(C||0).search(A);return e>=0?e+(C||0):e},I.helper.splitAtIndex=function(g,A){"use strict";if(!I.helper.isString(g))throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";return[g.substring(0,A),g.substring(A)]},I.helper.encodeEmailAddress=function(g){"use strict";var A=[function(g){return"&#"+g.charCodeAt(0)+";"},function(g){return"&#x"+g.charCodeAt(0).toString(16)+";"},function(g){return g}];return g=g.replace(/./g,function(g){if("@"===g)g=A[Math.floor(2*Math.random())](g);else{var C=Math.random();g=C>.9?A[2](g):C>.45?A[1](g):A[0](g)}return g})},"undefined"==typeof console&&(console={warn:function(g){"use strict";alert(g)},log:function(g){"use strict";alert(g)},error:function(g){"use strict";throw g}}),I.helper.regexes={asteriskDashAndColon:/([*_:~])/g},I.helper.emojis={"+1":"๐","-1":"๐",100:"๐ฏ",1234:"๐ข","1st_place_medal":"๐ฅ","2nd_place_medal":"๐ฅ","3rd_place_medal":"๐ฅ","8ball":"๐ฑ",a:"๐
ฐ๏ธ",ab:"๐",abc:"๐ค",abcd:"๐ก",accept:"๐",aerial_tramway:"๐ก",airplane:"โ๏ธ",alarm_clock:"โฐ",alembic:"โ๏ธ",alien:"๐ฝ",ambulance:"๐",amphora:"๐บ",anchor:"โ๏ธ",angel:"๐ผ",anger:"๐ข",angry:"๐ ",anguished:"๐ง",ant:"๐",apple:"๐",aquarius:"โ๏ธ",aries:"โ๏ธ",arrow_backward:"โ๏ธ",arrow_double_down:"โฌ",arrow_double_up:"โซ",arrow_down:"โฌ๏ธ",arrow_down_small:"๐ฝ",arrow_forward:"โถ๏ธ",arrow_heading_down:"โคต๏ธ",arrow_heading_up:"โคด๏ธ",arrow_left:"โฌ
๏ธ",arrow_lower_left:"โ๏ธ",arrow_lower_right:"โ๏ธ",arrow_right:"โก๏ธ",arrow_right_hook:"โช๏ธ",arrow_up:"โฌ๏ธ",arrow_up_down:"โ๏ธ",arrow_up_small:"๐ผ",arrow_upper_left:"โ๏ธ",arrow_upper_right:"โ๏ธ",arrows_clockwise:"๐",arrows_counterclockwise:"๐",art:"๐จ",articulated_lorry:"๐",artificial_satellite:"๐ฐ",astonished:"๐ฒ",athletic_shoe:"๐",atm:"๐ง",atom_symbol:"โ๏ธ",avocado:"๐ฅ",b:"๐
ฑ๏ธ",baby:"๐ถ",baby_bottle:"๐ผ",baby_chick:"๐ค",baby_symbol:"๐ผ",back:"๐",bacon:"๐ฅ",badminton:"๐ธ",baggage_claim:"๐",baguette_bread:"๐ฅ",balance_scale:"โ๏ธ",balloon:"๐",ballot_box:"๐ณ",ballot_box_with_check:"โ๏ธ",bamboo:"๐",banana:"๐",bangbang:"โผ๏ธ",bank:"๐ฆ",bar_chart:"๐",barber:"๐",baseball:"โพ๏ธ",basketball:"๐",basketball_man:"โน๏ธ",basketball_woman:"โน๏ธ‍โ๏ธ",bat:"๐ฆ",bath:"๐",bathtub:"๐",battery:"๐",beach_umbrella:"๐",bear:"๐ป",bed:"๐",bee:"๐",beer:"๐บ",beers:"๐ป",beetle:"๐",beginner:"๐ฐ",bell:"๐",bellhop_bell:"๐",bento:"๐ฑ",biking_man:"๐ด",bike:"๐ฒ",biking_woman:"๐ด‍โ๏ธ",bikini:"๐",biohazard:"โฃ๏ธ",bird:"๐ฆ",birthday:"๐",black_circle:"โซ๏ธ",black_flag:"๐ด",black_heart:"๐ค",black_joker:"๐",black_large_square:"โฌ๏ธ",black_medium_small_square:"โพ๏ธ",black_medium_square:"โผ๏ธ",black_nib:"โ๏ธ",black_small_square:"โช๏ธ",black_square_button:"๐ฒ",blonde_man:"๐ฑ",blonde_woman:"๐ฑ‍โ๏ธ",blossom:"๐ผ",blowfish:"๐ก",blue_book:"๐",blue_car:"๐",blue_heart:"๐",blush:"๐",boar:"๐",boat:"โต๏ธ",bomb:"๐ฃ",book:"๐",bookmark:"๐",bookmark_tabs:"๐",books:"๐",boom:"๐ฅ",boot:"๐ข",bouquet:"๐",bowing_man:"๐",bow_and_arrow:"๐น",bowing_woman:"๐‍โ๏ธ",bowling:"๐ณ",boxing_glove:"๐ฅ",boy:"๐ฆ",bread:"๐",bride_with_veil:"๐ฐ",bridge_at_night:"๐",briefcase:"๐ผ",broken_heart:"๐",bug:"๐",building_construction:"๐",bulb:"๐ก",bullettrain_front:"๐
",bullettrain_side:"๐",burrito:"๐ฏ",bus:"๐",business_suit_levitating:"๐ด",busstop:"๐",bust_in_silhouette:"๐ค",busts_in_silhouette:"๐ฅ",butterfly:"๐ฆ",cactus:"๐ต",cake:"๐ฐ",calendar:"๐",call_me_hand:"๐ค",calling:"๐ฒ",camel:"๐ซ",camera:"๐ท",camera_flash:"๐ธ",camping:"๐",cancer:"โ๏ธ",candle:"๐ฏ",candy:"๐ฌ",canoe:"๐ถ",capital_abcd:"๐ ",capricorn:"โ๏ธ",car:"๐",card_file_box:"๐",card_index:"๐",card_index_dividers:"๐",carousel_horse:"๐ ",carrot:"๐ฅ",cat:"๐ฑ",cat2:"๐",cd:"๐ฟ",chains:"โ",champagne:"๐พ",chart:"๐น",chart_with_downwards_trend:"๐",chart_with_upwards_trend:"๐",checkered_flag:"๐",cheese:"๐ง",cherries:"๐",cherry_blossom:"๐ธ",chestnut:"๐ฐ",chicken:"๐",children_crossing:"๐ธ",chipmunk:"๐ฟ",chocolate_bar:"๐ซ",christmas_tree:"๐",church:"โช๏ธ",cinema:"๐ฆ",circus_tent:"๐ช",city_sunrise:"๐",city_sunset:"๐",cityscape:"๐",cl:"๐",clamp:"๐",clap:"๐",clapper:"๐ฌ",classical_building:"๐",clinking_glasses:"๐ฅ",clipboard:"๐",clock1:"๐",clock10:"๐",clock1030:"๐ฅ",clock11:"๐",clock1130:"๐ฆ",clock12:"๐",clock1230:"๐ง",clock130:"๐",clock2:"๐",clock230:"๐",clock3:"๐",clock330:"๐",clock4:"๐",clock430:"๐",clock5:"๐",clock530:"๐ ",clock6:"๐",clock630:"๐ก",clock7:"๐",clock730:"๐ข",clock8:"๐",clock830:"๐ฃ",clock9:"๐",clock930:"๐ค",closed_book:"๐",closed_lock_with_key:"๐",closed_umbrella:"๐",cloud:"โ๏ธ",cloud_with_lightning:"๐ฉ",cloud_with_lightning_and_rain:"โ",cloud_with_rain:"๐ง",cloud_with_snow:"๐จ",clown_face:"๐คก",clubs:"โฃ๏ธ",cocktail:"๐ธ",coffee:"โ๏ธ",coffin:"โฐ๏ธ",cold_sweat:"๐ฐ",comet:"โ๏ธ",computer:"๐ป",computer_mouse:"๐ฑ",confetti_ball:"๐",confounded:"๐",confused:"๐",congratulations:"ใ๏ธ",construction:"๐ง",construction_worker_man:"๐ท",construction_worker_woman:"๐ท‍โ๏ธ",control_knobs:"๐",convenience_store:"๐ช",cookie:"๐ช",cool:"๐",policeman:"๐ฎ",copyright:"ยฉ๏ธ",corn:"๐ฝ",couch_and_lamp:"๐",couple:"๐ซ",couple_with_heart_woman_man:"๐",couple_with_heart_man_man:"๐จ‍โค๏ธ‍๐จ",couple_with_heart_woman_woman:"๐ฉ‍โค๏ธ‍๐ฉ",couplekiss_man_man:"๐จ‍โค๏ธ‍๐‍๐จ",couplekiss_man_woman:"๐",couplekiss_woman_woman:"๐ฉ‍โค๏ธ‍๐‍๐ฉ",cow:"๐ฎ",cow2:"๐",cowboy_hat_face:"๐ค ",crab:"๐ฆ",crayon:"๐",credit_card:"๐ณ",crescent_moon:"๐",cricket:"๐",crocodile:"๐",croissant:"๐ฅ",crossed_fingers:"๐ค",crossed_flags:"๐",crossed_swords:"โ๏ธ",crown:"๐",cry:"๐ข",crying_cat_face:"๐ฟ",crystal_ball:"๐ฎ",cucumber:"๐ฅ",cupid:"๐",curly_loop:"โฐ",currency_exchange:"๐ฑ",curry:"๐",custard:"๐ฎ",customs:"๐",cyclone:"๐",dagger:"๐ก",dancer:"๐",dancing_women:"๐ฏ",dancing_men:"๐ฏ‍โ๏ธ",dango:"๐ก",dark_sunglasses:"๐ถ",dart:"๐ฏ",dash:"๐จ",date:"๐
",deciduous_tree:"๐ณ",deer:"๐ฆ",department_store:"๐ฌ",derelict_house:"๐",desert:"๐",desert_island:"๐",desktop_computer:"๐ฅ",male_detective:"๐ต๏ธ",diamond_shape_with_a_dot_inside:"๐ ",diamonds:"โฆ๏ธ",disappointed:"๐",disappointed_relieved:"๐ฅ",dizzy:"๐ซ",dizzy_face:"๐ต",do_not_litter:"๐ฏ",dog:"๐ถ",dog2:"๐",dollar:"๐ต",dolls:"๐",dolphin:"๐ฌ",door:"๐ช",doughnut:"๐ฉ",dove:"๐",dragon:"๐",dragon_face:"๐ฒ",dress:"๐",dromedary_camel:"๐ช",drooling_face:"๐คค",droplet:"๐ง",drum:"๐ฅ",duck:"๐ฆ",dvd:"๐","e-mail":"๐ง",eagle:"๐ฆ
",ear:"๐",ear_of_rice:"๐พ",earth_africa:"๐",earth_americas:"๐",earth_asia:"๐",egg:"๐ฅ",eggplant:"๐",eight_pointed_black_star:"โด๏ธ",eight_spoked_asterisk:"โณ๏ธ",electric_plug:"๐",elephant:"๐",email:"โ๏ธ",end:"๐",envelope_with_arrow:"๐ฉ",euro:"๐ถ",european_castle:"๐ฐ",european_post_office:"๐ค",evergreen_tree:"๐ฒ",exclamation:"โ๏ธ",expressionless:"๐",eye:"๐",eye_speech_bubble:"๐‍๐จ",eyeglasses:"๐",eyes:"๐",face_with_head_bandage:"๐ค",face_with_thermometer:"๐ค",fist_oncoming:"๐",factory:"๐ญ",fallen_leaf:"๐",family_man_woman_boy:"๐ช",family_man_boy:"๐จ‍๐ฆ",family_man_boy_boy:"๐จ‍๐ฆ‍๐ฆ",family_man_girl:"๐จ‍๐ง",family_man_girl_boy:"๐จ‍๐ง‍๐ฆ",family_man_girl_girl:"๐จ‍๐ง‍๐ง",family_man_man_boy:"๐จ‍๐จ‍๐ฆ",family_man_man_boy_boy:"๐จ‍๐จ‍๐ฆ‍๐ฆ",family_man_man_girl:"๐จ‍๐จ‍๐ง",family_man_man_girl_boy:"๐จ‍๐จ‍๐ง‍๐ฆ",family_man_man_girl_girl:"๐จ‍๐จ‍๐ง‍๐ง",family_man_woman_boy_boy:"๐จ‍๐ฉ‍๐ฆ‍๐ฆ",family_man_woman_girl:"๐จ‍๐ฉ‍๐ง",family_man_woman_girl_boy:"๐จ‍๐ฉ‍๐ง‍๐ฆ",family_man_woman_girl_girl:"๐จ‍๐ฉ‍๐ง‍๐ง",family_woman_boy:"๐ฉ‍๐ฆ",family_woman_boy_boy:"๐ฉ‍๐ฆ‍๐ฆ",family_woman_girl:"๐ฉ‍๐ง",family_woman_girl_boy:"๐ฉ‍๐ง‍๐ฆ",family_woman_girl_girl:"๐ฉ‍๐ง‍๐ง",family_woman_woman_boy:"๐ฉ‍๐ฉ‍๐ฆ",family_woman_woman_boy_boy:"๐ฉ‍๐ฉ‍๐ฆ‍๐ฆ",family_woman_woman_girl:"๐ฉ‍๐ฉ‍๐ง",family_woman_woman_girl_boy:"๐ฉ‍๐ฉ‍๐ง‍๐ฆ",family_woman_woman_girl_girl:"๐ฉ‍๐ฉ‍๐ง‍๐ง",fast_forward:"โฉ",fax:"๐ ",fearful:"๐จ",feet:"๐พ",female_detective:"๐ต๏ธ‍โ๏ธ",ferris_wheel:"๐ก",ferry:"โด",field_hockey:"๐",file_cabinet:"๐",file_folder:"๐",film_projector:"๐ฝ",film_strip:"๐",fire:"๐ฅ",fire_engine:"๐",fireworks:"๐",first_quarter_moon:"๐",first_quarter_moon_with_face:"๐",fish:"๐",fish_cake:"๐ฅ",fishing_pole_and_fish:"๐ฃ",fist_raised:"โ",fist_left:"๐ค",fist_right:"๐ค",flags:"๐",flashlight:"๐ฆ",fleur_de_lis:"โ๏ธ",flight_arrival:"๐ฌ",flight_departure:"๐ซ",floppy_disk:"๐พ",flower_playing_cards:"๐ด",flushed:"๐ณ",fog:"๐ซ",foggy:"๐",football:"๐",footprints:"๐ฃ",fork_and_knife:"๐ด",fountain:"โฒ๏ธ",fountain_pen:"๐",four_leaf_clover:"๐",fox_face:"๐ฆ",framed_picture:"๐ผ",free:"๐",fried_egg:"๐ณ",fried_shrimp:"๐ค",fries:"๐",frog:"๐ธ",frowning:"๐ฆ",frowning_face:"โน๏ธ",frowning_man:"๐‍โ๏ธ",frowning_woman:"๐",middle_finger:"๐",fuelpump:"โฝ๏ธ",full_moon:"๐",full_moon_with_face:"๐",funeral_urn:"โฑ๏ธ",game_die:"๐ฒ",gear:"โ๏ธ",gem:"๐",gemini:"โ๏ธ",ghost:"๐ป",gift:"๐",gift_heart:"๐",girl:"๐ง",globe_with_meridians:"๐",goal_net:"๐ฅ
",goat:"๐",golf:"โณ๏ธ",golfing_man:"๐๏ธ",golfing_woman:"๐๏ธ‍โ๏ธ",gorilla:"๐ฆ",grapes:"๐",green_apple:"๐",green_book:"๐",green_heart:"๐",green_salad:"๐ฅ",grey_exclamation:"โ",grey_question:"โ",grimacing:"๐ฌ",grin:"๐",grinning:"๐",guardsman:"๐",guardswoman:"๐‍โ๏ธ",guitar:"๐ธ",gun:"๐ซ",haircut_woman:"๐",haircut_man:"๐‍โ๏ธ",hamburger:"๐",hammer:"๐จ",hammer_and_pick:"โ",hammer_and_wrench:"๐ ",hamster:"๐น",hand:"โ",handbag:"๐",handshake:"๐ค",hankey:"๐ฉ",hatched_chick:"๐ฅ",hatching_chick:"๐ฃ",headphones:"๐ง",hear_no_evil:"๐",heart:"โค๏ธ",heart_decoration:"๐",heart_eyes:"๐",heart_eyes_cat:"๐ป",heartbeat:"๐",heartpulse:"๐",hearts:"โฅ๏ธ",heavy_check_mark:"โ๏ธ",heavy_division_sign:"โ",heavy_dollar_sign:"๐ฒ",heavy_heart_exclamation:"โฃ๏ธ",heavy_minus_sign:"โ",heavy_multiplication_x:"โ๏ธ",heavy_plus_sign:"โ",helicopter:"๐",herb:"๐ฟ",hibiscus:"๐บ",high_brightness:"๐",high_heel:"๐ ",hocho:"๐ช",hole:"๐ณ",honey_pot:"๐ฏ",horse:"๐ด",horse_racing:"๐",hospital:"๐ฅ",hot_pepper:"๐ถ",hotdog:"๐ญ",hotel:"๐จ",hotsprings:"โจ๏ธ",hourglass:"โ๏ธ",hourglass_flowing_sand:"โณ",house:"๐ ",house_with_garden:"๐ก",houses:"๐",hugs:"๐ค",hushed:"๐ฏ",ice_cream:"๐จ",ice_hockey:"๐",ice_skate:"โธ",icecream:"๐ฆ",id:"๐",ideograph_advantage:"๐",imp:"๐ฟ",inbox_tray:"๐ฅ",incoming_envelope:"๐จ",tipping_hand_woman:"๐",information_source:"โน๏ธ",innocent:"๐",interrobang:"โ๏ธ",iphone:"๐ฑ",izakaya_lantern:"๐ฎ",jack_o_lantern:"๐",japan:"๐พ",japanese_castle:"๐ฏ",japanese_goblin:"๐บ",japanese_ogre:"๐น",jeans:"๐",joy:"๐",joy_cat:"๐น",joystick:"๐น",kaaba:"๐",key:"๐",keyboard:"โจ๏ธ",keycap_ten:"๐",kick_scooter:"๐ด",kimono:"๐",kiss:"๐",kissing:"๐",kissing_cat:"๐ฝ",kissing_closed_eyes:"๐",kissing_heart:"๐",kissing_smiling_eyes:"๐",kiwi_fruit:"๐ฅ",koala:"๐จ",koko:"๐",label:"๐ท",large_blue_circle:"๐ต",large_blue_diamond:"๐ท",large_orange_diamond:"๐ถ",last_quarter_moon:"๐",last_quarter_moon_with_face:"๐",latin_cross:"โ๏ธ",laughing:"๐",leaves:"๐",ledger:"๐",left_luggage:"๐
",left_right_arrow:"โ๏ธ",leftwards_arrow_with_hook:"โฉ๏ธ",lemon:"๐",leo:"โ๏ธ",leopard:"๐",level_slider:"๐",libra:"โ๏ธ",light_rail:"๐",link:"๐",lion:"๐ฆ",lips:"๐",lipstick:"๐",lizard:"๐ฆ",lock:"๐",lock_with_ink_pen:"๐",lollipop:"๐ญ",loop:"โฟ",loud_sound:"๐",loudspeaker:"๐ข",love_hotel:"๐ฉ",love_letter:"๐",low_brightness:"๐
",lying_face:"๐คฅ",m:"โ๏ธ",mag:"๐",mag_right:"๐",mahjong:"๐๏ธ",mailbox:"๐ซ",mailbox_closed:"๐ช",mailbox_with_mail:"๐ฌ",mailbox_with_no_mail:"๐ญ",man:"๐จ",man_artist:"๐จ‍๐จ",man_astronaut:"๐จ‍๐",man_cartwheeling:"๐คธ‍โ๏ธ",man_cook:"๐จ‍๐ณ",man_dancing:"๐บ",man_facepalming:"๐คฆ‍โ๏ธ",man_factory_worker:"๐จ‍๐ญ",man_farmer:"๐จ‍๐พ",man_firefighter:"๐จ‍๐",man_health_worker:"๐จ‍โ๏ธ",man_in_tuxedo:"๐คต",man_judge:"๐จ‍โ๏ธ",man_juggling:"๐คน‍โ๏ธ",man_mechanic:"๐จ‍๐ง",man_office_worker:"๐จ‍๐ผ",man_pilot:"๐จ‍โ๏ธ",man_playing_handball:"๐คพ‍โ๏ธ",man_playing_water_polo:"๐คฝ‍โ๏ธ",man_scientist:"๐จ‍๐ฌ",man_shrugging:"๐คท‍โ๏ธ",man_singer:"๐จ‍๐ค",man_student:"๐จ‍๐",man_teacher:"๐จ‍๐ซ",man_technologist:"๐จ‍๐ป",man_with_gua_pi_mao:"๐ฒ",man_with_turban:"๐ณ",tangerine:"๐",mans_shoe:"๐",mantelpiece_clock:"๐ฐ",maple_leaf:"๐",martial_arts_uniform:"๐ฅ",mask:"๐ท",massage_woman:"๐",massage_man:"๐‍โ๏ธ",meat_on_bone:"๐",medal_military:"๐",medal_sports:"๐
",mega:"๐ฃ",melon:"๐",memo:"๐",men_wrestling:"๐คผ‍โ๏ธ",menorah:"๐",mens:"๐น",metal:"๐ค",metro:"๐",microphone:"๐ค",microscope:"๐ฌ",milk_glass:"๐ฅ",milky_way:"๐",minibus:"๐",minidisc:"๐ฝ",mobile_phone_off:"๐ด",money_mouth_face:"๐ค",money_with_wings:"๐ธ",moneybag:"๐ฐ",monkey:"๐",monkey_face:"๐ต",monorail:"๐",moon:"๐",mortar_board:"๐",mosque:"๐",motor_boat:"๐ฅ",motor_scooter:"๐ต",motorcycle:"๐",motorway:"๐ฃ",mount_fuji:"๐ป",mountain:"โฐ",mountain_biking_man:"๐ต",mountain_biking_woman:"๐ต‍โ๏ธ",mountain_cableway:"๐ ",mountain_railway:"๐",mountain_snow:"๐",mouse:"๐ญ",mouse2:"๐",movie_camera:"๐ฅ",moyai:"๐ฟ",mrs_claus:"๐คถ",muscle:"๐ช",mushroom:"๐",musical_keyboard:"๐น",musical_note:"๐ต",musical_score:"๐ผ",mute:"๐",nail_care:"๐
",name_badge:"๐",national_park:"๐",nauseated_face:"๐คข",necktie:"๐",negative_squared_cross_mark:"โ",nerd_face:"๐ค",neutral_face:"๐",new:"๐",new_moon:"๐",new_moon_with_face:"๐",newspaper:"๐ฐ",newspaper_roll:"๐",next_track_button:"โญ",ng:"๐",no_good_man:"๐
‍โ๏ธ",no_good_woman:"๐
",night_with_stars:"๐",no_bell:"๐",no_bicycles:"๐ณ",no_entry:"โ๏ธ",no_entry_sign:"๐ซ",no_mobile_phones:"๐ต",no_mouth:"๐ถ",no_pedestrians:"๐ท",no_smoking:"๐ญ","non-potable_water":"๐ฑ",nose:"๐",notebook:"๐",notebook_with_decorative_cover:"๐",notes:"๐ถ",nut_and_bolt:"๐ฉ",o:"โญ๏ธ",o2:"๐
พ๏ธ",ocean:"๐",octopus:"๐",oden:"๐ข",office:"๐ข",oil_drum:"๐ข",ok:"๐",ok_hand:"๐",ok_man:"๐‍โ๏ธ",ok_woman:"๐",old_key:"๐",older_man:"๐ด",older_woman:"๐ต",om:"๐",on:"๐",oncoming_automobile:"๐",oncoming_bus:"๐",oncoming_police_car:"๐",oncoming_taxi:"๐",open_file_folder:"๐",open_hands:"๐",open_mouth:"๐ฎ",open_umbrella:"โ๏ธ",ophiuchus:"โ",orange_book:"๐",orthodox_cross:"โฆ๏ธ",outbox_tray:"๐ค",owl:"๐ฆ",ox:"๐",package:"๐ฆ",page_facing_up:"๐",page_with_curl:"๐",pager:"๐",paintbrush:"๐",palm_tree:"๐ด",pancakes:"๐ฅ",panda_face:"๐ผ",paperclip:"๐",paperclips:"๐",parasol_on_ground:"โฑ",parking:"๐
ฟ๏ธ",part_alternation_mark:"ใฝ๏ธ",partly_sunny:"โ
๏ธ",passenger_ship:"๐ณ",passport_control:"๐",pause_button:"โธ",peace_symbol:"โฎ๏ธ",peach:"๐",peanuts:"๐ฅ",pear:"๐",pen:"๐",pencil2:"โ๏ธ",penguin:"๐ง",pensive:"๐",performing_arts:"๐ญ",persevere:"๐ฃ",person_fencing:"๐คบ",pouting_woman:"๐",phone:"โ๏ธ",pick:"โ",pig:"๐ท",pig2:"๐",pig_nose:"๐ฝ",pill:"๐",pineapple:"๐",ping_pong:"๐",pisces:"โ๏ธ",pizza:"๐",place_of_worship:"๐",plate_with_cutlery:"๐ฝ",play_or_pause_button:"โฏ",point_down:"๐",point_left:"๐",point_right:"๐",point_up:"โ๏ธ",point_up_2:"๐",police_car:"๐",policewoman:"๐ฎ‍โ๏ธ",poodle:"๐ฉ",popcorn:"๐ฟ",post_office:"๐ฃ",postal_horn:"๐ฏ",postbox:"๐ฎ",potable_water:"๐ฐ",potato:"๐ฅ",pouch:"๐",poultry_leg:"๐",pound:"๐ท",rage:"๐ก",pouting_cat:"๐พ",pouting_man:"๐‍โ๏ธ",pray:"๐",prayer_beads:"๐ฟ",pregnant_woman:"๐คฐ",previous_track_button:"โฎ",prince:"๐คด",princess:"๐ธ",printer:"๐จ",purple_heart:"๐",purse:"๐",pushpin:"๐",put_litter_in_its_place:"๐ฎ",question:"โ",rabbit:"๐ฐ",rabbit2:"๐",racehorse:"๐",racing_car:"๐",radio:"๐ป",radio_button:"๐",radioactive:"โข๏ธ",railway_car:"๐",railway_track:"๐ค",rainbow:"๐",rainbow_flag:"๐ณ๏ธ‍๐",raised_back_of_hand:"๐ค",raised_hand_with_fingers_splayed:"๐",raised_hands:"๐",raising_hand_woman:"๐",raising_hand_man:"๐‍โ๏ธ",ram:"๐",ramen:"๐",rat:"๐",record_button:"โบ",recycle:"โป๏ธ",red_circle:"๐ด",registered:"ยฎ๏ธ",relaxed:"โบ๏ธ",relieved:"๐",reminder_ribbon:"๐",repeat:"๐",repeat_one:"๐",rescue_worker_helmet:"โ",restroom:"๐ป",revolving_hearts:"๐",rewind:"โช",rhinoceros:"๐ฆ",ribbon:"๐",rice:"๐",rice_ball:"๐",rice_cracker:"๐",rice_scene:"๐",right_anger_bubble:"๐ฏ",ring:"๐",robot:"๐ค",rocket:"๐",rofl:"๐คฃ",roll_eyes:"๐",roller_coaster:"๐ข",rooster:"๐",rose:"๐น",rosette:"๐ต",rotating_light:"๐จ",round_pushpin:"๐",rowing_man:"๐ฃ",rowing_woman:"๐ฃ‍โ๏ธ",rugby_football:"๐",running_man:"๐",running_shirt_with_sash:"๐ฝ",running_woman:"๐‍โ๏ธ",sa:"๐๏ธ",sagittarius:"โ๏ธ",sake:"๐ถ",sandal:"๐ก",santa:"๐
",satellite:"๐ก",saxophone:"๐ท",school:"๐ซ",school_satchel:"๐",scissors:"โ๏ธ",scorpion:"๐ฆ",scorpius:"โ๏ธ",scream:"๐ฑ",scream_cat:"๐",scroll:"๐",seat:"๐บ",secret:"ใ๏ธ",see_no_evil:"๐",seedling:"๐ฑ",selfie:"๐คณ",shallow_pan_of_food:"๐ฅ",shamrock:"โ๏ธ",shark:"๐ฆ",shaved_ice:"๐ง",sheep:"๐",shell:"๐",shield:"๐ก",shinto_shrine:"โฉ",ship:"๐ข",shirt:"๐",shopping:"๐",shopping_cart:"๐",shower:"๐ฟ",shrimp:"๐ฆ",signal_strength:"๐ถ",six_pointed_star:"๐ฏ",ski:"๐ฟ",skier:"โท",skull:"๐",skull_and_crossbones:"โ ๏ธ",sleeping:"๐ด",sleeping_bed:"๐",sleepy:"๐ช",slightly_frowning_face:"๐",slightly_smiling_face:"๐",slot_machine:"๐ฐ",small_airplane:"๐ฉ",small_blue_diamond:"๐น",small_orange_diamond:"๐ธ",small_red_triangle:"๐บ",small_red_triangle_down:"๐ป",smile:"๐",smile_cat:"๐ธ",smiley:"๐",smiley_cat:"๐บ",smiling_imp:"๐",smirk:"๐",smirk_cat:"๐ผ",smoking:"๐ฌ",snail:"๐",snake:"๐",sneezing_face:"๐คง",snowboarder:"๐",snowflake:"โ๏ธ",snowman:"โ๏ธ",snowman_with_snow:"โ๏ธ",sob:"๐ญ",soccer:"โฝ๏ธ",soon:"๐",sos:"๐",sound:"๐",space_invader:"๐พ",spades:"โ ๏ธ",spaghetti:"๐",sparkle:"โ๏ธ",sparkler:"๐",sparkles:"โจ",sparkling_heart:"๐",speak_no_evil:"๐",speaker:"๐",speaking_head:"๐ฃ",speech_balloon:"๐ฌ",speedboat:"๐ค",spider:"๐ท",spider_web:"๐ธ",spiral_calendar:"๐",spiral_notepad:"๐",spoon:"๐ฅ",squid:"๐ฆ",stadium:"๐",star:"โญ๏ธ",star2:"๐",star_and_crescent:"โช๏ธ",star_of_david:"โก๏ธ",stars:"๐ ",station:"๐",statue_of_liberty:"๐ฝ",steam_locomotive:"๐",stew:"๐ฒ",stop_button:"โน",stop_sign:"๐",stopwatch:"โฑ",straight_ruler:"๐",strawberry:"๐",stuck_out_tongue:"๐",stuck_out_tongue_closed_eyes:"๐",stuck_out_tongue_winking_eye:"๐",studio_microphone:"๐",stuffed_flatbread:"๐ฅ",sun_behind_large_cloud:"๐ฅ",sun_behind_rain_cloud:"๐ฆ",sun_behind_small_cloud:"๐ค",sun_with_face:"๐",sunflower:"๐ป",sunglasses:"๐",sunny:"โ๏ธ",sunrise:"๐
",sunrise_over_mountains:"๐",surfing_man:"๐",surfing_woman:"๐‍โ๏ธ",sushi:"๐ฃ",suspension_railway:"๐",sweat:"๐",sweat_drops:"๐ฆ",sweat_smile:"๐
",sweet_potato:"๐ ",swimming_man:"๐",swimming_woman:"๐‍โ๏ธ",symbols:"๐ฃ",synagogue:"๐",syringe:"๐",taco:"๐ฎ",tada:"๐",tanabata_tree:"๐",taurus:"โ๏ธ",taxi:"๐",tea:"๐ต",telephone_receiver:"๐",telescope:"๐ญ",tennis:"๐พ",tent:"โบ๏ธ",thermometer:"๐ก",thinking:"๐ค",thought_balloon:"๐ญ",ticket:"๐ซ",tickets:"๐",tiger:"๐ฏ",tiger2:"๐
",timer_clock:"โฒ",tipping_hand_man:"๐‍โ๏ธ",tired_face:"๐ซ",tm:"โข๏ธ",toilet:"๐ฝ",tokyo_tower:"๐ผ",tomato:"๐
",tongue:"๐
",top:"๐",tophat:"๐ฉ",tornado:"๐ช",trackball:"๐ฒ",tractor:"๐",traffic_light:"๐ฅ",train:"๐",train2:"๐",tram:"๐",triangular_flag_on_post:"๐ฉ",triangular_ruler:"๐",trident:"๐ฑ",triumph:"๐ค",trolleybus:"๐",trophy:"๐",tropical_drink:"๐น",tropical_fish:"๐ ",truck:"๐",trumpet:"๐บ",tulip:"๐ท",tumbler_glass:"๐ฅ",turkey:"๐ฆ",turtle:"๐ข",tv:"๐บ",twisted_rightwards_arrows:"๐",two_hearts:"๐",two_men_holding_hands:"๐ฌ",two_women_holding_hands:"๐ญ",u5272:"๐น",u5408:"๐ด",u55b6:"๐บ",u6307:"๐ฏ๏ธ",u6708:"๐ท๏ธ",u6709:"๐ถ",u6e80:"๐ต",u7121:"๐๏ธ",u7533:"๐ธ",u7981:"๐ฒ",u7a7a:"๐ณ",umbrella:"โ๏ธ",unamused:"๐",underage:"๐",unicorn:"๐ฆ",unlock:"๐",up:"๐",upside_down_face:"๐",v:"โ๏ธ",vertical_traffic_light:"๐ฆ",vhs:"๐ผ",vibration_mode:"๐ณ",video_camera:"๐น",video_game:"๐ฎ",violin:"๐ป",virgo:"โ๏ธ",volcano:"๐",volleyball:"๐",vs:"๐",vulcan_salute:"๐",walking_man:"๐ถ",walking_woman:"๐ถ‍โ๏ธ",waning_crescent_moon:"๐",waning_gibbous_moon:"๐",warning:"โ ๏ธ",wastebasket:"๐",watch:"โ๏ธ",water_buffalo:"๐",watermelon:"๐",wave:"๐",wavy_dash:"ใฐ๏ธ",waxing_crescent_moon:"๐",wc:"๐พ",weary:"๐ฉ",wedding:"๐",weight_lifting_man:"๐๏ธ",weight_lifting_woman:"๐๏ธ‍โ๏ธ",whale:"๐ณ",whale2:"๐",wheel_of_dharma:"โธ๏ธ",wheelchair:"โฟ๏ธ",white_check_mark:"โ
",white_circle:"โช๏ธ",white_flag:"๐ณ๏ธ",white_flower:"๐ฎ",white_large_square:"โฌ๏ธ",white_medium_small_square:"โฝ๏ธ",white_medium_square:"โป๏ธ",white_small_square:"โซ๏ธ",white_square_button:"๐ณ",wilted_flower:"๐ฅ",wind_chime:"๐",wind_face:"๐ฌ",wine_glass:"๐ท",wink:"๐",wolf:"๐บ",woman:"๐ฉ",woman_artist:"๐ฉ‍๐จ",woman_astronaut:"๐ฉ‍๐",woman_cartwheeling:"๐คธ‍โ๏ธ",woman_cook:"๐ฉ‍๐ณ",woman_facepalming:"๐คฆ‍โ๏ธ",woman_factory_worker:"๐ฉ‍๐ญ",woman_farmer:"๐ฉ‍๐พ",woman_firefighter:"๐ฉ‍๐",woman_health_worker:"๐ฉ‍โ๏ธ",woman_judge:"๐ฉ‍โ๏ธ",woman_juggling:"๐คน‍โ๏ธ",woman_mechanic:"๐ฉ‍๐ง",woman_office_worker:"๐ฉ‍๐ผ",woman_pilot:"๐ฉ‍โ๏ธ",woman_playing_handball:"๐คพ‍โ๏ธ",woman_playing_water_polo:"๐คฝ‍โ๏ธ",woman_scientist:"๐ฉ‍๐ฌ",woman_shrugging:"๐คท‍โ๏ธ",woman_singer:"๐ฉ‍๐ค",woman_student:"๐ฉ‍๐",woman_teacher:"๐ฉ‍๐ซ",woman_technologist:"๐ฉ‍๐ป",woman_with_turban:"๐ณ‍โ๏ธ",womans_clothes:"๐",womans_hat:"๐",women_wrestling:"๐คผ‍โ๏ธ",womens:"๐บ",world_map:"๐บ",worried:"๐",wrench:"๐ง",writing_hand:"โ๏ธ",x:"โ",yellow_heart:"๐",yen:"๐ด",yin_yang:"โฏ๏ธ",yum:"๐",zap:"โก๏ธ",zipper_mouth_face:"๐ค",zzz:"๐ค",octocat:'<img width="20" height="20" align="absmiddle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAOwUlEQVR42uVbCVyO6RbPmn0sw9gZS0aZO4y5GTEUE2ObxjZjrbHEJVy3sWS5pkaWxjLEkCVDSbSgFLdESaWSLIVUSIi4kvb9f895vi/zbbR+yZ339/tbnu99n/ec/3Oe85xznufV0CjDBaAdwZqwnzCJ0FXjHV70/i8J5oQDhCFV8cJdq1atwqxZs+Ds7Iz4+HhqwgXCLELNKlK6G2Ej4e6lS5ewZcsWzJgxA+fOnWNZFqvzxT1v3boF/qcsBg0ahP3796OwsJAFWKYuIqjfPoS9cXFxWL58Obp06SInh5aWFr//jjoJWLlu3TolAorRuXNn7Ny5k4W4Spgj81xrgj5hLmED4RDhlNRygglBhADCSakpWxFMCHoETUJTwrYHDx7A1NT0je9nPHz4kN/fXl0EeI0aNeqtAjB69+4NPz8/FsSdlXvy5An8/f1hZ2cHCwsLGBsbY/To0cJy9PT0MGDAAAwePBhGRkbClNesWYODBw8iODgYOTk53M/d9evXo27duiW++8iRI3z/ZHURENOjR48ShSjGuHHjhHJ16tQp9TOKaNWqlZKpvw1MHluQOpSvk5eXh5YtW5ZbmarAvHnzmIBd6iCgXnZ2Npo1a1atCWAfwY5SHQTUKCoqQocOHao1AebmHBJgi7p8QBDP6epMwKFDvMDAWF0ELLS1ta3WBNy9e5cJMFIXAdvt7e2rNQHDhw9nAv5D+KKylV9y8+bNCi1pVYWZM2cyCfaVTcDdsqzH7xpBQRxcwqyylLdi5/K+KM/Q0dFhAqIri4Bn1T0AUgVpdmhYUeVHnD59+r1TnjF27Fgm4HhFCThoYmLyXhLQoEGD4mRKsyIE3OrZs+d7SQCDCyZcNSqv8k1evXoFTU3NUr+wzUcfYqRBf8yb/C2WzfoBFoTF08fBdMIITDD8CsP1+kL30x7Q6dYZH7drjfZ0f4fWLdG1Q1t81qMLBvTRwejB/TBl1BDMnzQGS2dMxKo5k7Fs9iSY/jAaBvR8Pc26pZaH02quLZSXgO6xsbGlelGnli1wZKcVMqN8gKcRwItrf+K/VB95doXaLwOJIVSzOU/+2Re5kV7IuuyJrIhTyLt6mmztLBBPNZLHoUAy9fE8UvJ8ikxfj8PwJPQErJeYlkquTZs2MQFLykuANgc/Jb2kn3Z3ZMaQUrmxwO1zyAo7gfRAJ6RfOIyMEFdkXj5F8BTK5lzxQv610yi8QcFatI8gQoCIK7x+hojwRnaE5H4JTiEj9Pjr/rJDqcZyn9b4ovu45LYbdWvXeqtsXMHiSlZ5CegRExPz1hd83PYj5POo0QinXyLFg48hnZTOiQ1Dzr1IZEaeQRoJn0HKZIR7lA2kfHrQUerXHTlx4ZL+rnjjFRGRGeYB5MUj2GnbW+XbuJFrp1heXgI6JCYmvvUFN1x3Aek3SWkapRAXMeJFGS8ge2Xfuog0toaykED3Mpk8+shOk+sv68Y50V9WuKewBKt5094o39atW/mRf5WXgIYZGRlo3Lixys4nj6A6Z1YMcqRCpwU4ouDlUyHk/QA/hNttR25Wlvh/ZthJUsil9ATQ/axkYbqEzDgfL0Ts/x35+aLyTES7IY36Q6w/+Q4/tP6wuUoZ9+7dy7ebVmQZjO/atavKzn32rAdeXkd6KCkXdAxZ13yFcLFnvPD73zrDVrsdTs6eggKSuSjjORHkUGoC0i86Iyc6QPQX7eqMnTodYNuzHU4vnosiaitMSUSavwMy6d3IvEUrzViVMrq5uXEX4ytCgL++vr5Sx7Vr1cIDX0dKkQJfj37Rs3jw1sBxkwlwGD4Ax3+ciN1faCHW76xQRFgAOcjSEMBkIe0x8nLzcez7kTg8Rh/uxuOxR/cTJISFSfq7eATpZCk8CAfXLVFJwIULXHnHoIoQYLtw4UKljps2aogXQcQuef/XAiMDKY+S4DhyEFwpDnCj9f+Afl8EbbWRTANaAdihlYoAMn8aZzyNuYODX/eD29TvRH/7v+qN8H27JdOAyWQfQQ74xPafVRLAPox9WUlK6hIGEgx4f00Kg2JcvHhRqeP6FIwknXemyen/2gLIIeC/CYk49M0AuE4xgtu0sThg8AUCN62TEuBdRgJo2Y+Kxh9D/k59SQiwH9QHobt3SAk4KSGA4oWjm1YqyVi8U6Soj4yOrHM/jTAyKVby/PnzIoNi8L+L4eXlpXoFcLcTgc1rAlISkJeXDxeK2A6P1hdTwI6mQPTJE+WbAlnJyE7PhNO3Q3BkrKGYWtxfHMkkmQLO0ilwA7+vXqAkn66urtBLUZ9iHfm30NBQaPAf165dA0d9vP2UlJSEp0+f4vHjx3j06JH4e+rUqUovcNmyGkiNEkLwklXsBG+ecMUOnfbYod1emG5uboFKJ8jPFVD0l0dBUHqoPDHpQeQEb0qc4FUHe3KAbYUT9JgzDbwOFL5MfN0fXkXhJ5PxSvLt2LFD1Ah5u4z1YJ14l4qnBe8v3rhxAzz4PAVG8nLHivIP0dHRiIiIQGRkpEgmrl69ClW1QBMjQ7LDW8hmU+RRI69ckJIkhL7jfRJBm62R+TJVYq6h0jhBRslsivqenT2MF/7OyI70VmkFhWnPJaS6OyPkt43IycqR9EfWlH7JDQUUTuNhCHR7Ke9YcRp/5coVoQPrcvnyZURFRYmBZlLS0kR8MVLD29sbnp6e8PHxQUBAgCgn8YO8E3z79m3BGKeVc+bMkXuBZt06SA12F/F5Go0gR4C8HBalPZMPXKL8lQKhPAqF+f97KXFyNx6HQsoPsshJ/kmAp2TKkJLISpXvjyxNhMYcDVLOEO+lPDi8B5mamipkZx1YF9YpJCRErAy+vr5CZ9ZdWABhDGEYYTBhAOFz3g4nfMJelNCbkNCpUye5F034mvxIPi1/FM+zQCw0k5B9O0iEr5kRXkqhMJOVf9NXIHjtT7hmaymSoBzKETimkAuFpaF1dkwI9RcmIYaXv3BJXoGCuyIgk5WpefPmKCgoYK46SmX/RKoL69Sfl0WuFEl1HlmWJXE5z6WmTZvKJxxmxkIQ3AuU5APk6NICj4hRT6eITTEEzqWk55HHPjz3cxJhNF5cxeNT9kj2cRDTQjEkzpDtjyyCic5l5fEA7uSHFEefR5pPsahrb2B9QkICFHeJ51HunkdLIg0VLY0BFKdLwllVHp4dHyvst3QuEiiju21vA/+VZkiluIKt4I3RIfWXQ4QgKUxkni47LJWUP3PmjHo2RxVI+CebmKJP6EiFDVurxUgmExe5PHlnPAkn8w4QqW62NCVmYopozid5H0CI9RKE21ggJeAYEeMnfitOnRn5XCfgeJ+VTosWQU8MOc6ZE0cqnUm4fv165SrPBVHCfMI4TowUfmOfsIcdJh92kBWmUcP6GDt8EDZbzIffH5tx3/ewSFjw5LKk0MEFEkZenDBjgew7Yiog5brkt+QrknvJmhIp4Apw/A1bVpjhG/0v5d7Vrl07bNu2TelUSqUoz8uI3Z49OEtBAy+TdP1CqKtwHzvQUxxgTJs2TeX5gdq1a0ObSmCjh+jB+NuvRamL1+3ls77HCip1rTSdJP5eNnMizKndjMLoH42G4bthX+FzHS3UVVEC69evH3799VeKMXJZrlWKclUGAZ5jxoxB02ZNsNlxH74aagBHZyex986HlVTczyGmI58h4CjL2toa48ePFxsUPEotWrQoc0GT0/C2bduiY8eO4ISMcxLeoOFYhS6qm2EpoZG65jmbv+dPSyRZlt5QfVjvtX19AOFNL+aDFNI4m0eFc9Ho5ORkaGtrl5kAVp6DMOk88efEjLe++ZhclZwHTJHEHbs4YOCmLj2645fdvwnTK42zoXtaEHwNDQ3LXdZm5yad3/2r+gQmDsRnIF5KAldX6zdsgG/GG8F44Vzcu3eP2y1K6GPr2rVrK1zbnz59Or/LoaoJCPZ4kCZsjw9GECL79OmDj9q2wb+320C3/5fgPQO6Vrzh+fpcDqxXr16lbHBwgkZXm6okYJr0ECMrX5vraiJ1lArEjrEnzWuOqemiYj9spGd2ee478XkiPsJakmJ83qA05/8qXNurJFLiunXrhpo1a6LxB02wyHIFZpovgOHwYfjZ0hK2lH5u2rwZ5suWYv5ycyUlmjRpgl69eimlrFy3kwuoyOvXr19frm3RokVMwPZ3TYC57E6xVq+e6KzVDSaL/oEp82Zh8IhhWLjGAp/p9oX5ujVKBNjY2MDV1VWuzd3dXaTesm2biUQuZ8u28elSPmKr8a4vdog8GnJpcT1N1KHUuBbt0jSgWuGbzJh3mVhh2TYHBwdxjFa2jVcZnvPVlQBOLXdZWlqW2ZFxNYYVlm07fPgwAgMD5dr4OD5HeHLFFxM+O42DGtXhIkFaMQlcUjIzM0P37t1Ro0YNpZPjPJcVK7SOjo5ybU5OTqIAo0gAh97VlgAZIj4l8Pn4WFaO64ocuXG6zJtDbMqySnC7IgF8uptLVrJtq1evFuWqak+A4j4i4TNpltiJ8LPiNFFFwNGjRyWFyfedAFUny/joekkEuLi4KK0CfykCeFnkiu1flgBeFtl3/D8SsMbKykpOifv37ysRcPz4cVHKUiSA8wwNdR9/VTMBSh9Y8S4Nf2qnSICiBbDzVCRg9uzZTMC+94kAv6FDh8opwRsVHPjItnl4eEDxHNLKlStFXV+2javQ/M1SpZe+1KA4L4G7WDG57fSm/OUbXiqG0ewAFYOeYcN4fwZhvLkp2y4tftrxcltdlf/w+fPn4qNGxTCYU2m6nrRu3VqunT/EoiuZvw6TTZHpyuNNmEaNGsndP3fu3OJAq1N1JOAHDmyKheVtNP4OkE2crULRAW7fvl20EyyLy24a8p+/7WISFixYIMLt4t82bNhQYjXqXREgPq3j74mlX3AmSL8E1eOPIBXnuVT5OsVZpuLnOMeOHeN7vifwiYhYzhC5IpwlOXj1QXWdBmy/XWU/X+UqMZfKBw4cKAobHPlJlZe9h6tOu+7cuSN2dg0MDMSSyZUpmXvaSD+crq/xvl0k9BTCRa7qEPq+5T4t6ffF52WVV+f1P6zyLG30bsU4AAAAAElFTkSuQmCC">',showdown:'<img width="20" height="20" align="absmiddle" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAECtaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzA2NyA3OS4xNTc3NDcsIDIwMTUvMDMvMzAtMjM6NDA6NDIgICAgICAgICI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTUtMDEtMTVUMjE6MDE6MTlaPC94bXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxNy0xMC0yNFQxMzozMTozMCswMTowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPHhtcDpNb2RpZnlEYXRlPjIwMTctMTAtMjRUMTM6MzE6MzArMDE6MDA8L3htcDpNb2RpZnlEYXRlPgogICAgICAgICA8cGhvdG9zaG9wOkNvbG9yTW9kZT4zPC9waG90b3Nob3A6Q29sb3JNb2RlPgogICAgICAgICA8cGhvdG9zaG9wOklDQ1Byb2ZpbGU+c1JHQiBJRUM2MTk2Ni0yLjE8L3Bob3Rvc2hvcDpJQ0NQcm9maWxlPgogICAgICAgICA8cGhvdG9zaG9wOlRleHRMYXllcnM+CiAgICAgICAgICAgIDxyZGY6QmFnPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHBob3Rvc2hvcDpMYXllck5hbWU+UyAtPC9waG90b3Nob3A6TGF5ZXJOYW1lPgogICAgICAgICAgICAgICAgICA8cGhvdG9zaG9wOkxheWVyVGV4dD5TIC08L3Bob3Rvc2hvcDpMYXllclRleHQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgIDwvcGhvdG9zaG9wOlRleHRMYXllcnM+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6N2NkMzQxNzctOWYyZi0yNDRiLWEyYjQtMzU1MzJkY2Y1MWJiPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6M2E1YzgxYmYtYjhiNy0xMWU3LTk0NDktYTQ2MzdlZjJkNjMzPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkhpc3Rvcnk+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jcmVhdGVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTUtMDEtMTVUMjE6MDE6MTlaPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6ODZjNjBkMGQtOGY0Yy01ZTRlLWEwMjQtODI4ZWQyNTIwZDc3PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE3LTEwLTI0VDEzOjMxOjMwKzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoV2luZG93cyk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jb252ZXJ0ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnBhcmFtZXRlcnM+ZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZzwvc3RFdnQ6cGFyYW1ldGVycz4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmRlcml2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnBhcmFtZXRlcnM+Y29udmVydGVkIGZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmc8L3N0RXZ0OnBhcmFtZXRlcnM+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOjdjZDM0MTc3LTlmMmYtMjQ0Yi1hMmI0LTM1NTMyZGNmNTFiYjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNy0xMC0yNFQxMzozMTozMCswMTowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICAgICA8c3RFdnQ6Y2hhbmdlZD4vPC9zdEV2dDpjaGFuZ2VkPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICA8L3htcE1NOkhpc3Rvcnk+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0YW5jZUlEPnhtcC5paWQ6ODZjNjBkMGQtOGY0Yy01ZTRlLWEwMjQtODI4ZWQyNTIwZDc3PC9zdFJlZjppbnN0YW5jZUlEPgogICAgICAgICAgICA8c3RSZWY6ZG9jdW1lbnRJRD54bXAuZGlkOjYwQzVBRTY1RjY5Q0U0MTE5NDVBODU1RTNCQ0E3RUVCPC9zdFJlZjpkb2N1bWVudElEPgogICAgICAgICAgICA8c3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3N0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPC94bXBNTTpEZXJpdmVkRnJvbT4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+NzIwMDAwLzEwMDAwPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WVJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+MTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NjQ8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+NjQ8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/Pse7bzcAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAA1JJREFUeNrsm1+OmlAUhz+aeS9dwZggJn1AnRUMO6jpBgZXULuC2hWUWUGZBTSxKyiuoA4mfUBMnB04K5g+9DihRBHlyh/lJLwIXLgf99xzzu9etZeXFy7Z3nDh1gBoAFy4XeVtQNO0zNcapmUDfUBPnFoBfhQGq6IBaHmjwD4Ahmk5wAD4kKG5J8CNwsAFaHe6DvA9cc0wCgOv8gDka3vA9RHNPgo0D7hNnJtGYWBXxgV2dH4MfMnRRA+Y1WIO2NJ5F/ikoKm3tYsChmkNFHW+fmHQMC1dfHaXPQP3wM1yMdc2B/AOGALTWobBmI1Shu0UGCwX83XyRBQGawHntTtdG5gUNfxVu4CTNqNv6/wWGL7kCc+1AmCYVisl3I2ydD4GYZUCs7IjoLXrxHIx9w9tLAqDCfBwDrXAY457x+cAoCfuwRGjYFUnAGk+PsjR7s8Dn1VeLWCYVlpDw+VivjVHSHt+u9PVJbzGzZXQWTkAkz0V31fATUaEsjVJlQBs4FeGcteLgzgbAALBA+4y3voAeJL8nA0AHfClnM1qm1HhnYUidCSE+KzvSSJUTwAxCOMcpfETMFYpfRUKIAbCFhC3OTJJJwqDWS0BxED0JZ4Pjix1P2+E0loCSMBwyK4S/xc1ojBwag8gMU84cvTKGgmlAYhngu1O9xAXuVE5J1QCQCz3bwHuHvdQui5QKQAxEO6eEKpsFCgTRSXkvdoxSlBMCxhJJbgrrbZRtHCiShN0pRB6PeQ3ckBw2K0oKXMBVYJIP+Nvh9qulFivGoBt1lLQxowT2ykBXCfnhZIglgYACWmqXQv+baioBYCeiCQHm+QEg1O7RhF7hO4OhSAhcJKSFU7qBGADwZeqMMuXn6TUBw8qlaMrirNb4LdhWlP+SWD+cjFfxTpuS2GUpik+o3jFSEkqbJiWn0P0OMSGqlWiOu0TvD+FRHZKAE+oW+cfRmEwqlsesJJEJs8y91QqP+9UL6lqEtz2gpuNEY5sm9sIHln2DRa2aFKGJtiXkZEMiWtgVvRKUSUFkSKt2S7fAGgAXLYpmQQXf36MUChTZdUa2u8/rkvPA6Tz30r4eH3ybcBS5gJ6SaNXb+aABkA1AMxKenclBZLW/He4cYEGwEXb3wEASelexk6LIIIAAAAASUVORK5CYII=">'},I.Converter=function(g){"use strict";function C(g,C){if(C=C||null,I.helper.isString(g)){if(g=I.helper.stdExtName(g),C=g,I.extensions[g])return console.warn("DEPRECATION WARNING: "+g+" is an old extension that uses a deprecated loading method.Please inform the developer that the extension should be updated!"),void function(g,C){"function"==typeof g&&(g=g(new I.Converter));I.helper.isArray(g)||(g=[g]);var e=A(g,C);if(!e.valid)throw Error(e.error);for(var r=0;r<g.length;++r)switch(g[r].type){case"lang":s.push(g[r]);break;case"output":i.push(g[r]);break;default:throw Error("Extension loader error: Type unrecognized!!!")}}(I.extensions[g],g);if(I.helper.isUndefined(r[g]))throw Error('Extension "'+g+'" could not be loaded. It was either not found or is not a valid extension.');g=r[g]}"function"==typeof g&&(g=g()),I.helper.isArray(g)||(g=[g]);var t=A(g,C);if(!t.valid)throw Error(t.error);for(var a=0;a<g.length;++a){switch(g[a].type){case"lang":s.push(g[a]);break;case"output":i.push(g[a])}if(g[a].hasOwnProperty("listeners"))for(var n in g[a].listeners)g[a].listeners.hasOwnProperty(n)&&e(n,g[a].listeners[n])}}function e(g,A){if(!I.helper.isString(g))throw Error("Invalid argument in converter.listen() method: name must be a string, but "+typeof g+" given");if("function"!=typeof A)throw Error("Invalid argument in converter.listen() method: callback must be a function, but "+typeof A+" given");l.hasOwnProperty(g)||(l[g]=[]),l[g].push(A)}var o={},s=[],i=[],l={},c=a,u={parsed:{},raw:"",format:""};!function(){g=g||{};for(var A in t)t.hasOwnProperty(A)&&(o[A]=t[A]);if("object"!=typeof g)throw Error("Converter expects the passed parameter to be an object, but "+typeof g+" was passed instead.");for(var e in g)g.hasOwnProperty(e)&&(o[e]=g[e]);o.extensions&&I.helper.forEach(o.extensions,C)}(),this._dispatch=function(g,A,C,I){if(l.hasOwnProperty(g))for(var e=0;e<l[g].length;++e){var r=l[g][e](g,A,this,C,I);r&&void 0!==r&&(A=r)}return A},this.listen=function(g,A){return e(g,A),this},this.makeHtml=function(g){if(!g)return g;var A={gHtmlBlocks:[],gHtmlMdBlocks:[],gHtmlSpans:[],gUrls:{},gTitles:{},gDimensions:{},gListLevel:0,hashLinkCounts:{},langExtensions:s,outputModifiers:i,converter:this,ghCodeBlocks:[],metadata:{parsed:{},raw:"",format:""}};return g=g.replace(/ยจ/g,"ยจT"),g=g.replace(/\$/g,"ยจD"),g=g.replace(/\r\n/g,"\n"),g=g.replace(/\r/g,"\n"),g=g.replace(/\u00A0/g," "),o.smartIndentationFix&&(g=function(g){var A=g.match(/^\s*/)[0].length,C=new RegExp("^\\s{0,"+A+"}","gm");return g.replace(C,"")}(g)),g="\n\n"+g+"\n\n",g=I.subParser("detab")(g,o,A),g=g.replace(/^[ \t]+$/gm,""),I.helper.forEach(s,function(C){g=I.subParser("runExtension")(C,g,o,A)}),g=I.subParser("metadata")(g,o,A),g=I.subParser("hashPreCodeTags")(g,o,A),g=I.subParser("githubCodeBlocks")(g,o,A),g=I.subParser("hashHTMLBlocks")(g,o,A),g=I.subParser("hashCodeTags")(g,o,A),g=I.subParser("stripLinkDefinitions")(g,o,A),g=I.subParser("blockGamut")(g,o,A),g=I.subParser("unhashHTMLSpans")(g,o,A),g=I.subParser("unescapeSpecialChars")(g,o,A),g=g.replace(/ยจD/g,"$$"),g=g.replace(/ยจT/g,"ยจ"),g=I.subParser("completeHTMLDocument")(g,o,A),I.helper.forEach(i,function(C){g=I.subParser("runExtension")(C,g,o,A)}),u=A.metadata,g},this.setOption=function(g,A){o[g]=A},this.getOption=function(g){return o[g]},this.getOptions=function(){return o},this.addExtension=function(g,A){C(g,A=A||null)},this.useExtension=function(g){C(g)},this.setFlavor=function(g){if(!n.hasOwnProperty(g))throw Error(g+" flavor was not found");var A=n[g];c=g;for(var C in A)A.hasOwnProperty(C)&&(o[C]=A[C])},this.getFlavor=function(){return c},this.removeExtension=function(g){I.helper.isArray(g)||(g=[g]);for(var A=0;A<g.length;++A){for(var C=g[A],e=0;e<s.length;++e)s[e]===C&&s[e].splice(e,1);for(;0<i.length;++e)i[0]===C&&i[0].splice(e,1)}},this.getAllExtensions=function(){return{language:s,output:i}},this.getMetadata=function(g){return g?u.raw:u.parsed},this.getMetadataFormat=function(){return u.format},this._setMetadataPair=function(g,A){u.parsed[g]=A},this._setMetadataFormat=function(g){u.format=g},this._setMetadataRaw=function(g){u.raw=g}},I.subParser("anchors",function(g,A,C){"use strict";var e=function(g,e,r,t,a,n,o){if(I.helper.isUndefined(o)&&(o=""),r=r.toLowerCase(),g.search(/\(<?\s*>? ?(['"].*['"])?\)$/m)>-1)t="";else if(!t){if(r||(r=e.toLowerCase().replace(/ ?\n/g," ")),t="#"+r,I.helper.isUndefined(C.gUrls[r]))return g;t=C.gUrls[r],I.helper.isUndefined(C.gTitles[r])||(o=C.gTitles[r])}var s='<a href="'+(t=t.replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback))+'"';return""!==o&&null!==o&&(s+=' title="'+(o=(o=o.replace(/"/g,""")).replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback))+'"'),A.openLinksInNewWindow&&!/^#/.test(t)&&(s+=' target="ยจE95Eblank"'),s+=">"+e+"</a>"};return g=(g=C.converter._dispatch("anchors.before",g,A,C)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g,e),g=g.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,e),g=g.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,e),g=g.replace(/\[([^\[\]]+)]()()()()()/g,e),A.ghMentions&&(g=g.replace(/(^|\s)(\\)?(@([a-z\d\-]+))(?=[.!?;,[\]()]|\s|$)/gim,function(g,C,e,r,t){if("\\"===e)return C+r;if(!I.helper.isString(A.ghMentionsLink))throw new Error("ghMentionsLink option must be a string");var a=A.ghMentionsLink.replace(/\{u}/g,t),n="";return A.openLinksInNewWindow&&(n=' target="ยจE95Eblank"'),C+'<a href="'+a+'"'+n+">"+r+"</a>"})),g=C.converter._dispatch("anchors.after",g,A,C)});var s=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,i=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,l=/()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,c=/(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gim,u=/<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,d=function(g){"use strict";return function(A,C,e,r,t,a,n){var o=e=e.replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback),s="",i="",l=C||"",c=n||"";return/^www\./i.test(e)&&(e=e.replace(/^www\./i,"http://www.")),g.excludeTrailingPunctuationFromURLs&&a&&(s=a),g.openLinksInNewWindow&&(i=' target="ยจE95Eblank"'),l+'<a href="'+e+'"'+i+">"+o+"</a>"+s+c}},p=function(g,A){"use strict";return function(C,e,r){var t="mailto:";return e=e||"",r=I.subParser("unescapeSpecialChars")(r,g,A),g.encodeEmails?(t=I.helper.encodeEmailAddress(t+r),r=I.helper.encodeEmailAddress(r)):t+=r,e+'<a href="'+t+'">'+r+"</a>"}};I.subParser("autoLinks",function(g,A,C){"use strict";return g=C.converter._dispatch("autoLinks.before",g,A,C),g=g.replace(l,d(A)),g=g.replace(u,p(A,C)),g=C.converter._dispatch("autoLinks.after",g,A,C)}),I.subParser("simplifiedAutoLinks",function(g,A,C){"use strict";return A.simplifiedAutoLink?(g=C.converter._dispatch("simplifiedAutoLinks.before",g,A,C),g=A.excludeTrailingPunctuationFromURLs?g.replace(i,d(A)):g.replace(s,d(A)),g=g.replace(c,p(A,C)),g=C.converter._dispatch("simplifiedAutoLinks.after",g,A,C)):g}),I.subParser("blockGamut",function(g,A,C){"use strict";return g=C.converter._dispatch("blockGamut.before",g,A,C),g=I.subParser("blockQuotes")(g,A,C),g=I.subParser("headers")(g,A,C),g=I.subParser("horizontalRule")(g,A,C),g=I.subParser("lists")(g,A,C),g=I.subParser("codeBlocks")(g,A,C),g=I.subParser("tables")(g,A,C),g=I.subParser("hashHTMLBlocks")(g,A,C),g=I.subParser("paragraphs")(g,A,C),g=C.converter._dispatch("blockGamut.after",g,A,C)}),I.subParser("blockQuotes",function(g,A,C){"use strict";g=C.converter._dispatch("blockQuotes.before",g,A,C),g+="\n\n";var e=/(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm;return A.splitAdjacentBlockquotes&&(e=/^ {0,3}>[\s\S]*?(?:\n\n)/gm),g=g.replace(e,function(g){return g=g.replace(/^[ \t]*>[ \t]?/gm,""),g=g.replace(/ยจ0/g,""),g=g.replace(/^[ \t]+$/gm,""),g=I.subParser("githubCodeBlocks")(g,A,C),g=I.subParser("blockGamut")(g,A,C),g=g.replace(/(^|\n)/g,"$1 "),g=g.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm,function(g,A){var C=A;return C=C.replace(/^ /gm,"ยจ0"),C=C.replace(/ยจ0/g,"")}),I.subParser("hashBlock")("<blockquote>\n"+g+"\n</blockquote>",A,C)}),g=C.converter._dispatch("blockQuotes.after",g,A,C)}),I.subParser("codeBlocks",function(g,A,C){"use strict";g=C.converter._dispatch("codeBlocks.before",g,A,C);return g=(g+="ยจ0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=ยจ0))/g,function(g,e,r){var t=e,a=r,n="\n";return t=I.subParser("outdent")(t,A,C),t=I.subParser("encodeCode")(t,A,C),t=I.subParser("detab")(t,A,C),t=t.replace(/^\n+/g,""),t=t.replace(/\n+$/g,""),A.omitExtraWLInCodeBlocks&&(n=""),t="<pre><code>"+t+n+"</code></pre>",I.subParser("hashBlock")(t,A,C)+a}),g=g.replace(/ยจ0/,""),g=C.converter._dispatch("codeBlocks.after",g,A,C)}),I.subParser("codeSpans",function(g,A,C){"use strict";return void 0===(g=C.converter._dispatch("codeSpans.before",g,A,C))&&(g=""),g=g.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(g,e,r,t){var a=t;return a=a.replace(/^([ \t]*)/g,""),a=a.replace(/[ \t]*$/g,""),a=I.subParser("encodeCode")(a,A,C),a=e+"<code>"+a+"</code>",a=I.subParser("hashHTMLSpans")(a,A,C)}),g=C.converter._dispatch("codeSpans.after",g,A,C)}),I.subParser("completeHTMLDocument",function(g,A,C){"use strict";if(!A.completeHTMLDocument)return g;g=C.converter._dispatch("completeHTMLDocument.before",g,A,C);var I="html",e="<!DOCTYPE HTML>\n",r="",t='<meta charset="utf-8">\n',a="",n="";void 0!==C.metadata.parsed.doctype&&(e="<!DOCTYPE "+C.metadata.parsed.doctype+">\n","html"!==(I=C.metadata.parsed.doctype.toString().toLowerCase())&&"html5"!==I||(t='<meta charset="utf-8">'));for(var o in C.metadata.parsed)if(C.metadata.parsed.hasOwnProperty(o))switch(o.toLowerCase()){case"doctype":break;case"title":r="<title>"+C.metadata.parsed.title+"</title>\n";break;case"charset":t="html"===I||"html5"===I?'<meta charset="'+C.metadata.parsed.charset+'">\n':'<meta name="charset" content="'+C.metadata.parsed.charset+'">\n';break;case"language":case"lang":a=' lang="'+C.metadata.parsed[o]+'"',n+='<meta name="'+o+'" content="'+C.metadata.parsed[o]+'">\n';break;default:n+='<meta name="'+o+'" content="'+C.metadata.parsed[o]+'">\n'}return g=e+"<html"+a+">\n<head>\n"+r+t+n+"</head>\n<body>\n"+g.trim()+"\n</body>\n</html>",g=C.converter._dispatch("completeHTMLDocument.after",g,A,C)}),I.subParser("detab",function(g,A,C){"use strict";return g=C.converter._dispatch("detab.before",g,A,C),g=g.replace(/\t(?=\t)/g," "),g=g.replace(/\t/g,"ยจAยจB"),g=g.replace(/ยจB(.+?)ยจA/g,function(g,A){for(var C=A,I=4-C.length%4,e=0;e<I;e++)C+=" ";return C}),g=g.replace(/ยจA/g," "),g=g.replace(/ยจB/g,""),g=C.converter._dispatch("detab.after",g,A,C)}),I.subParser("ellipsis",function(g,A,C){"use strict";return g=C.converter._dispatch("ellipsis.before",g,A,C),g=g.replace(/\.\.\./g,"โฆ"),g=C.converter._dispatch("ellipsis.after",g,A,C)}),I.subParser("emoji",function(g,A,C){"use strict";if(!A.emoji)return g;return g=(g=C.converter._dispatch("emoji.before",g,A,C)).replace(/:([\S]+?):/g,function(g,A){return I.helper.emojis.hasOwnProperty(A)?I.helper.emojis[A]:g}),g=C.converter._dispatch("emoji.after",g,A,C)}),I.subParser("encodeAmpsAndAngles",function(g,A,C){"use strict";return g=C.converter._dispatch("encodeAmpsAndAngles.before",g,A,C),g=g.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&"),g=g.replace(/<(?![a-z\/?$!])/gi,"<"),g=g.replace(/</g,"<"),g=g.replace(/>/g,">"),g=C.converter._dispatch("encodeAmpsAndAngles.after",g,A,C)}),I.subParser("encodeBackslashEscapes",function(g,A,C){"use strict";return g=C.converter._dispatch("encodeBackslashEscapes.before",g,A,C),g=g.replace(/\\(\\)/g,I.helper.escapeCharactersCallback),g=g.replace(/\\([`*_{}\[\]()>#+.!~=|-])/g,I.helper.escapeCharactersCallback),g=C.converter._dispatch("encodeBackslashEscapes.after",g,A,C)}),I.subParser("encodeCode",function(g,A,C){"use strict";return g=C.converter._dispatch("encodeCode.before",g,A,C),g=g.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/([*_{}\[\]\\=~-])/g,I.helper.escapeCharactersCallback),g=C.converter._dispatch("encodeCode.after",g,A,C)}),I.subParser("escapeSpecialCharsWithinTagAttributes",function(g,A,C){"use strict";return g=(g=C.converter._dispatch("escapeSpecialCharsWithinTagAttributes.before",g,A,C)).replace(/<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,function(g){return g.replace(/(.)<\/?code>(?=.)/g,"$1`").replace(/([\\`*_~=|])/g,I.helper.escapeCharactersCallback)}),g=g.replace(/<!(--(?:(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>/gi,function(g){return g.replace(/([\\`*_~=|])/g,I.helper.escapeCharactersCallback)}),g=C.converter._dispatch("escapeSpecialCharsWithinTagAttributes.after",g,A,C)}),I.subParser("githubCodeBlocks",function(g,A,C){"use strict";return A.ghCodeBlocks?(g=C.converter._dispatch("githubCodeBlocks.before",g,A,C),g+="ยจ0",g=g.replace(/(?:^|\n)(```+|~~~+)([^\s`~]*)\n([\s\S]*?)\n\1/g,function(g,e,r,t){var a=A.omitExtraWLInCodeBlocks?"":"\n";return t=I.subParser("encodeCode")(t,A,C),t=I.subParser("detab")(t,A,C),t=t.replace(/^\n+/g,""),t=t.replace(/\n+$/g,""),t="<pre><code"+(r?' class="'+r+" language-"+r+'"':"")+">"+t+a+"</code></pre>",t=I.subParser("hashBlock")(t,A,C),"\n\nยจG"+(C.ghCodeBlocks.push({text:g,codeblock:t})-1)+"G\n\n"}),g=g.replace(/ยจ0/,""),C.converter._dispatch("githubCodeBlocks.after",g,A,C)):g}),I.subParser("hashBlock",function(g,A,C){"use strict";return g=C.converter._dispatch("hashBlock.before",g,A,C),g=g.replace(/(^\n+|\n+$)/g,""),g="\n\nยจK"+(C.gHtmlBlocks.push(g)-1)+"K\n\n",g=C.converter._dispatch("hashBlock.after",g,A,C)}),I.subParser("hashCodeTags",function(g,A,C){"use strict";g=C.converter._dispatch("hashCodeTags.before",g,A,C);return g=I.helper.replaceRecursiveRegExp(g,function(g,e,r,t){var a=r+I.subParser("encodeCode")(e,A,C)+t;return"ยจC"+(C.gHtmlSpans.push(a)-1)+"C"},"<code\\b[^>]*>","</code>","gim"),g=C.converter._dispatch("hashCodeTags.after",g,A,C)}),I.subParser("hashElement",function(g,A,C){"use strict";return function(g,A){var I=A;return I=I.replace(/\n\n/g,"\n"),I=I.replace(/^\n/,""),I=I.replace(/\n+$/g,""),I="\n\nยจK"+(C.gHtmlBlocks.push(I)-1)+"K\n\n"}}),I.subParser("hashHTMLBlocks",function(g,A,C){"use strict";g=C.converter._dispatch("hashHTMLBlocks.before",g,A,C);var e=["pre","div","h1","h2","h3","h4","h5","h6","blockquote","table","dl","ol","ul","script","noscript","form","fieldset","iframe","math","style","section","header","footer","nav","article","aside","address","audio","canvas","figure","hgroup","output","video","p"],r=function(g,A,I,e){var r=g;return-1!==I.search(/\bmarkdown\b/)&&(r=I+C.converter.makeHtml(A)+e),"\n\nยจK"+(C.gHtmlBlocks.push(r)-1)+"K\n\n"};A.backslashEscapesHTMLTags&&(g=g.replace(/\\<(\/?[^>]+?)>/g,function(g,A){return"<"+A+">"}));for(var t=0;t<e.length;++t)for(var a,n=new RegExp("^ {0,3}(<"+e[t]+"\\b[^>]*>)","im"),o="<"+e[t]+"\\b[^>]*>",s="</"+e[t]+">";-1!==(a=I.helper.regexIndexOf(g,n));){var i=I.helper.splitAtIndex(g,a),l=I.helper.replaceRecursiveRegExp(i[1],r,o,s,"im");if(l===i[1])break;g=i[0].concat(l)}return g=g.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,I.subParser("hashElement")(g,A,C)),g=I.helper.replaceRecursiveRegExp(g,function(g){return"\n\nยจK"+(C.gHtmlBlocks.push(g)-1)+"K\n\n"},"^ {0,3}\x3c!--","--\x3e","gm"),g=g.replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,I.subParser("hashElement")(g,A,C)),g=C.converter._dispatch("hashHTMLBlocks.after",g,A,C)}),I.subParser("hashHTMLSpans",function(g,A,C){"use strict";function I(g){return"ยจC"+(C.gHtmlSpans.push(g)-1)+"C"}return g=C.converter._dispatch("hashHTMLSpans.before",g,A,C),g=g.replace(/<[^>]+?\/>/gi,function(g){return I(g)}),g=g.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g,function(g){return I(g)}),g=g.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g,function(g){return I(g)}),g=g.replace(/<[^>]+?>/gi,function(g){return I(g)}),g=C.converter._dispatch("hashHTMLSpans.after",g,A,C)}),I.subParser("unhashHTMLSpans",function(g,A,C){"use strict";g=C.converter._dispatch("unhashHTMLSpans.before",g,A,C);for(var I=0;I<C.gHtmlSpans.length;++I){for(var e=C.gHtmlSpans[I],r=0;/ยจC(\d+)C/.test(e);){var t=RegExp.$1;if(e=e.replace("ยจC"+t+"C",C.gHtmlSpans[t]),10===r){console.error("maximum nesting of 10 spans reached!!!");break}++r}g=g.replace("ยจC"+I+"C",e)}return g=C.converter._dispatch("unhashHTMLSpans.after",g,A,C)}),I.subParser("hashPreCodeTags",function(g,A,C){"use strict";g=C.converter._dispatch("hashPreCodeTags.before",g,A,C);return g=I.helper.replaceRecursiveRegExp(g,function(g,e,r,t){var a=r+I.subParser("encodeCode")(e,A,C)+t;return"\n\nยจG"+(C.ghCodeBlocks.push({text:g,codeblock:a})-1)+"G\n\n"},"^ {0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>","^ {0,3}</code>\\s*</pre>","gim"),g=C.converter._dispatch("hashPreCodeTags.after",g,A,C)}),I.subParser("headers",function(g,A,C){"use strict";function e(g){var e,r;if(A.customizedHeaderId){var t=g.match(/\{([^{]+?)}\s*$/);t&&t[1]&&(g=t[1])}return e=g,r=I.helper.isString(A.prefixHeaderId)?A.prefixHeaderId:!0===A.prefixHeaderId?"section-":"",A.rawPrefixHeaderId||(e=r+e),e=A.ghCompatibleHeaderId?e.replace(/ /g,"-").replace(/&/g,"").replace(/ยจT/g,"").replace(/ยจD/g,"").replace(/[&+$,\/:;=?@"#{}|^ยจ~\[\]`\\*)(%.!'<>]/g,"").toLowerCase():A.rawHeaderId?e.replace(/ /g,"-").replace(/&/g,"&").replace(/ยจT/g,"ยจ").replace(/ยจD/g,"$").replace(/["']/g,"-").toLowerCase():e.replace(/[^\w]/g,"").toLowerCase(),A.rawPrefixHeaderId&&(e=r+e),C.hashLinkCounts[e]?e=e+"-"+C.hashLinkCounts[e]++:C.hashLinkCounts[e]=1,e}g=C.converter._dispatch("headers.before",g,A,C);var r=isNaN(parseInt(A.headerLevelStart))?1:parseInt(A.headerLevelStart),t=A.smoothLivePreview?/^(.+)[ \t]*\n={2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n=+[ \t]*\n+/gm,a=A.smoothLivePreview?/^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n-+[ \t]*\n+/gm;g=(g=g.replace(t,function(g,t){var a=I.subParser("spanGamut")(t,A,C),n=A.noHeaderId?"":' id="'+e(t)+'"',o="<h"+r+n+">"+a+"</h"+r+">";return I.subParser("hashBlock")(o,A,C)})).replace(a,function(g,t){var a=I.subParser("spanGamut")(t,A,C),n=A.noHeaderId?"":' id="'+e(t)+'"',o=r+1,s="<h"+o+n+">"+a+"</h"+o+">";return I.subParser("hashBlock")(s,A,C)});var n=A.requireSpaceBeforeHeadingText?/^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm:/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;return g=g.replace(n,function(g,t,a){var n=a;A.customizedHeaderId&&(n=a.replace(/\s?\{([^{]+?)}\s*$/,""));var o=I.subParser("spanGamut")(n,A,C),s=A.noHeaderId?"":' id="'+e(a)+'"',i=r-1+t.length,l="<h"+i+s+">"+o+"</h"+i+">";return I.subParser("hashBlock")(l,A,C)}),g=C.converter._dispatch("headers.after",g,A,C)}),I.subParser("horizontalRule",function(g,A,C){"use strict";g=C.converter._dispatch("horizontalRule.before",g,A,C);var e=I.subParser("hashBlock")("<hr />",A,C);return g=g.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm,e),g=g.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm,e),g=g.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm,e),g=C.converter._dispatch("horizontalRule.after",g,A,C)}),I.subParser("images",function(g,A,C){"use strict";function e(g,A,e,r,t,a,n,o){var s=C.gUrls,i=C.gTitles,l=C.gDimensions;if(e=e.toLowerCase(),o||(o=""),g.search(/\(<?\s*>? ?(['"].*['"])?\)$/m)>-1)r="";else if(""===r||null===r){if(""!==e&&null!==e||(e=A.toLowerCase().replace(/ ?\n/g," ")),r="#"+e,I.helper.isUndefined(s[e]))return g;r=s[e],I.helper.isUndefined(i[e])||(o=i[e]),I.helper.isUndefined(l[e])||(t=l[e].width,a=l[e].height)}A=A.replace(/"/g,""").replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback);var c='<img src="'+(r=r.replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback))+'" alt="'+A+'"';return o&&(c+=' title="'+(o=o.replace(/"/g,""").replace(I.helper.regexes.asteriskDashAndColon,I.helper.escapeCharactersCallback))+'"'),t&&a&&(c+=' width="'+(t="*"===t?"auto":t)+'"',c+=' height="'+(a="*"===a?"auto":a)+'"'),c+=" />"}return g=(g=C.converter._dispatch("images.before",g,A,C)).replace(/!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,e),g=g.replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,function(g,A,C,I,r,t,a,n){return I=I.replace(/\s/g,""),e(g,A,C,I,r,t,0,n)}),g=g.replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,e),g=g.replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,e),g=g.replace(/!\[([^\[\]]+)]()()()()()/g,e),g=C.converter._dispatch("images.after",g,A,C)}),I.subParser("italicsAndBold",function(g,A,C){"use strict";function I(g,A,C){return A+g+C}return g=C.converter._dispatch("italicsAndBold.before",g,A,C),g=A.literalMidWordUnderscores?(g=(g=g.replace(/\b___(\S[\s\S]*)___\b/g,function(g,A){return I(A,"<strong><em>","</em></strong>")})).replace(/\b__(\S[\s\S]*)__\b/g,function(g,A){return I(A,"<strong>","</strong>")})).replace(/\b_(\S[\s\S]*?)_\b/g,function(g,A){return I(A,"<em>","</em>")}):(g=(g=g.replace(/___(\S[\s\S]*?)___/g,function(g,A){return/\S$/.test(A)?I(A,"<strong><em>","</em></strong>"):g})).replace(/__(\S[\s\S]*?)__/g,function(g,A){return/\S$/.test(A)?I(A,"<strong>","</strong>"):g})).replace(/_([^\s_][\s\S]*?)_/g,function(g,A){return/\S$/.test(A)?I(A,"<em>","</em>"):g}),g=A.literalMidWordAsterisks?(g=(g=g.replace(/([^*]|^)\B\*\*\*(\S[\s\S]+?)\*\*\*\B(?!\*)/g,function(g,A,C){return I(C,A+"<strong><em>","</em></strong>")})).replace(/([^*]|^)\B\*\*(\S[\s\S]+?)\*\*\B(?!\*)/g,function(g,A,C){return I(C,A+"<strong>","</strong>")})).replace(/([^*]|^)\B\*(\S[\s\S]+?)\*\B(?!\*)/g,function(g,A,C){return I(C,A+"<em>","</em>")}):(g=(g=g.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g,function(g,A){return/\S$/.test(A)?I(A,"<strong><em>","</em></strong>"):g})).replace(/\*\*(\S[\s\S]*?)\*\*/g,function(g,A){return/\S$/.test(A)?I(A,"<strong>","</strong>"):g})).replace(/\*([^\s*][\s\S]*?)\*/g,function(g,A){return/\S$/.test(A)?I(A,"<em>","</em>"):g}),g=C.converter._dispatch("italicsAndBold.after",g,A,C)}),I.subParser("lists",function(g,A,C){"use strict";function e(g,e){C.gListLevel++,g=g.replace(/\n{2,}$/,"\n");var r=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(ยจ0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,t=/\n[ \t]*\n(?!ยจ0)/.test(g+="ยจ0");return A.disableForced4SpacesIndentedSublists&&(r=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(ยจ0|\2([*+-]|\d+[.])[ \t]+))/gm),g=g.replace(r,function(g,e,r,a,n,o,s){s=s&&""!==s.trim();var i=I.subParser("outdent")(n,A,C),l="";return o&&A.tasklists&&(l=' class="task-list-item" style="list-style-type: none;"',i=i.replace(/^[ \t]*\[(x|X| )?]/m,function(){var g='<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';return s&&(g+=" checked"),g+=">"})),i=i.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g,function(g){return"ยจA"+g}),e||i.search(/\n{2,}/)>-1?(i=I.subParser("githubCodeBlocks")(i,A,C),i=I.subParser("blockGamut")(i,A,C)):(i=(i=I.subParser("lists")(i,A,C)).replace(/\n$/,""),i=(i=I.subParser("hashHTMLBlocks")(i,A,C)).replace(/\n\n+/g,"\n\n"),i=t?I.subParser("paragraphs")(i,A,C):I.subParser("spanGamut")(i,A,C)),i=i.replace("ยจA",""),i="<li"+l+">"+i+"</li>\n"}),g=g.replace(/ยจ0/g,""),C.gListLevel--,e&&(g=g.replace(/\s+$/,"")),g}function r(g,A){if("ol"===A){var C=g.match(/^ *(\d+)\./);if(C&&"1"!==C[1])return' start="'+C[1]+'"'}return""}function t(g,C,I){var t=A.disableForced4SpacesIndentedSublists?/^ ?\d+\.[ \t]/gm:/^ {0,3}\d+\.[ \t]/gm,a=A.disableForced4SpacesIndentedSublists?/^ ?[*+-][ \t]/gm:/^ {0,3}[*+-][ \t]/gm,n="ul"===C?t:a,o="";if(-1!==g.search(n))!function A(s){var i=s.search(n),l=r(g,C);-1!==i?(o+="\n\n<"+C+l+">\n"+e(s.slice(0,i),!!I)+"</"+C+">\n",n="ul"===(C="ul"===C?"ol":"ul")?t:a,A(s.slice(i))):o+="\n\n<"+C+l+">\n"+e(s,!!I)+"</"+C+">\n"}(g);else{var s=r(g,C);o="\n\n<"+C+s+">\n"+e(g,!!I)+"</"+C+">\n"}return o}return g=C.converter._dispatch("lists.before",g,A,C),g+="ยจ0",g=C.gListLevel?g.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(ยจ0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(g,A,C){return t(A,C.search(/[*+-]/g)>-1?"ul":"ol",!0)}):g.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(ยจ0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(g,A,C,I){return t(C,I.search(/[*+-]/g)>-1?"ul":"ol",!1)}),g=g.replace(/ยจ0/,""),g=C.converter._dispatch("lists.after",g,A,C)}),I.subParser("metadata",function(g,A,C){"use strict";function I(g){C.metadata.raw=g,(g=(g=g.replace(/&/g,"&").replace(/"/g,""")).replace(/\n {4}/g," ")).replace(/^([\S ]+): +([\s\S]+?)$/gm,function(g,A,I){return C.metadata.parsed[A]=I,""})}return A.metadata?(g=C.converter._dispatch("metadata.before",g,A,C),g=g.replace(/^\s*ยซยซยซ+(\S*?)\n([\s\S]+?)\nยปยปยป+\n/,function(g,A,C){return I(C),"ยจM"}),g=g.replace(/^\s*---+(\S*?)\n([\s\S]+?)\n---+\n/,function(g,A,e){return A&&(C.metadata.format=A),I(e),"ยจM"}),g=g.replace(/ยจM/g,""),g=C.converter._dispatch("metadata.after",g,A,C)):g}),I.subParser("outdent",function(g,A,C){"use strict";return g=C.converter._dispatch("outdent.before",g,A,C),g=g.replace(/^(\t|[ ]{1,4})/gm,"ยจ0"),g=g.replace(/ยจ0/g,""),g=C.converter._dispatch("outdent.after",g,A,C)}),I.subParser("paragraphs",function(g,A,C){"use strict";for(var e=(g=(g=(g=C.converter._dispatch("paragraphs.before",g,A,C)).replace(/^\n+/g,"")).replace(/\n+$/g,"")).split(/\n{2,}/g),r=[],t=e.length,a=0;a<t;a++){var n=e[a];n.search(/ยจ(K|G)(\d+)\1/g)>=0?r.push(n):n.search(/\S/)>=0&&(n=(n=I.subParser("spanGamut")(n,A,C)).replace(/^([ \t]*)/g,"<p>"),n+="</p>",r.push(n))}for(t=r.length,a=0;a<t;a++){for(var o="",s=r[a],i=!1;/ยจ(K|G)(\d+)\1/.test(s);){var l=RegExp.$1,c=RegExp.$2;o=(o="K"===l?C.gHtmlBlocks[c]:i?I.subParser("encodeCode")(C.ghCodeBlocks[c].text,A,C):C.ghCodeBlocks[c].codeblock).replace(/\$/g,"$$$$"),s=s.replace(/(\n\n)?ยจ(K|G)\d+\2(\n\n)?/,o),/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(s)&&(i=!0)}r[a]=s}return g=r.join("\n"),g=g.replace(/^\n+/g,""),g=g.replace(/\n+$/g,""),C.converter._dispatch("paragraphs.after",g,A,C)}),I.subParser("runExtension",function(g,A,C,I){"use strict";if(g.filter)A=g.filter(A,I.converter,C);else if(g.regex){var e=g.regex;e instanceof RegExp||(e=new RegExp(e,"g")),A=A.replace(e,g.replace)}return A}),I.subParser("spanGamut",function(g,A,C){"use strict";return g=C.converter._dispatch("spanGamut.before",g,A,C),g=I.subParser("codeSpans")(g,A,C),g=I.subParser("escapeSpecialCharsWithinTagAttributes")(g,A,C),g=I.subParser("encodeBackslashEscapes")(g,A,C),g=I.subParser("images")(g,A,C),g=I.subParser("anchors")(g,A,C),g=I.subParser("autoLinks")(g,A,C),g=I.subParser("simplifiedAutoLinks")(g,A,C),g=I.subParser("emoji")(g,A,C),g=I.subParser("underline")(g,A,C),g=I.subParser("italicsAndBold")(g,A,C),g=I.subParser("strikethrough")(g,A,C),g=I.subParser("ellipsis")(g,A,C),g=I.subParser("hashHTMLSpans")(g,A,C),g=I.subParser("encodeAmpsAndAngles")(g,A,C),A.simpleLineBreaks?/\n\nยจK/.test(g)||(g=g.replace(/\n+/g,"<br />\n")):g=g.replace(/ +\n/g,"<br />\n"),g=C.converter._dispatch("spanGamut.after",g,A,C)}),I.subParser("strikethrough",function(g,A,C){"use strict";return A.strikethrough&&(g=(g=C.converter._dispatch("strikethrough.before",g,A,C)).replace(/(?:~){2}([\s\S]+?)(?:~){2}/g,function(g,e){return function(g){return A.simplifiedAutoLink&&(g=I.subParser("simplifiedAutoLinks")(g,A,C)),"<del>"+g+"</del>"}(e)}),g=C.converter._dispatch("strikethrough.after",g,A,C)),g}),I.subParser("stripLinkDefinitions",function(g,A,C){"use strict";var e=function(g,e,r,t,a,n,o){return e=e.toLowerCase(),r.match(/^data:.+?\/.+?;base64,/)?C.gUrls[e]=r.replace(/\s/g,""):C.gUrls[e]=I.subParser("encodeAmpsAndAngles")(r,A,C),n?n+o:(o&&(C.gTitles[e]=o.replace(/"|'/g,""")),A.parseImgDimensions&&t&&a&&(C.gDimensions[e]={width:t,height:a}),"")};return g=(g+="ยจ0").replace(/^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=ยจ0)|(?=\n\[))/gm,e),g=g.replace(/^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?([^>\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=ยจ0))/gm,e),g=g.replace(/ยจ0/,"")}),I.subParser("tables",function(g,A,C){"use strict";function e(g){return/^:[ \t]*--*$/.test(g)?' style="text-align:left;"':/^--*[ \t]*:[ \t]*$/.test(g)?' style="text-align:right;"':/^:[ \t]*--*[ \t]*:$/.test(g)?' style="text-align:center;"':""}function r(g,e){var r="";return g=g.trim(),(A.tablesHeaderId||A.tableHeaderId)&&(r=' id="'+g.replace(/ /g,"_").toLowerCase()+'"'),g=I.subParser("spanGamut")(g,A,C),"<th"+r+e+">"+g+"</th>\n"}function t(g,e){return"<td"+e+">"+I.subParser("spanGamut")(g,A,C)+"</td>\n"}function a(g){var a,n=g.split("\n");for(a=0;a<n.length;++a)/^ {0,3}\|/.test(n[a])&&(n[a]=n[a].replace(/^ {0,3}\|/,"")),/\|[ \t]*$/.test(n[a])&&(n[a]=n[a].replace(/\|[ \t]*$/,"")),n[a]=I.subParser("codeSpans")(n[a],A,C);var o=n[0].split("|").map(function(g){return g.trim()}),s=n[1].split("|").map(function(g){return g.trim()}),i=[],l=[],c=[],u=[];for(n.shift(),n.shift(),a=0;a<n.length;++a)""!==n[a].trim()&&i.push(n[a].split("|").map(function(g){return g.trim()}));if(o.length<s.length)return g;for(a=0;a<s.length;++a)c.push(e(s[a]));for(a=0;a<o.length;++a)I.helper.isUndefined(c[a])&&(c[a]=""),l.push(r(o[a],c[a]));for(a=0;a<i.length;++a){for(var d=[],p=0;p<l.length;++p)I.helper.isUndefined(i[a][p]),d.push(t(i[a][p],c[p]));u.push(d)}return function(g,A){for(var C="<table>\n<thead>\n<tr>\n",I=g.length,e=0;e<I;++e)C+=g[e];for(C+="</tr>\n</thead>\n<tbody>\n",e=0;e<A.length;++e){C+="<tr>\n";for(var r=0;r<I;++r)C+=A[e][r];C+="</tr>\n"}return C+="</tbody>\n</table>\n"}(l,u)}if(!A.tables)return g;return g=C.converter._dispatch("tables.before",g,A,C),g=g.replace(/\\(\|)/g,I.helper.escapeCharactersCallback),g=g.replace(/^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|ยจ0)/gm,a),g=g.replace(/^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|ยจ0)/gm,a),g=C.converter._dispatch("tables.after",g,A,C)}),I.subParser("underline",function(g,A,C){"use strict";return A.underline?(g=C.converter._dispatch("underline.before",g,A,C),g=A.literalMidWordUnderscores?g.replace(/\b_?__(\S[\s\S]*)___?\b/g,function(g,A){return"<u>"+A+"</u>"}):g.replace(/_?__(\S[\s\S]*?)___?/g,function(g,A){return/\S$/.test(A)?"<u>"+A+"</u>":g}),g=g.replace(/(_)/g,I.helper.escapeCharactersCallback),g=C.converter._dispatch("underline.after",g,A,C)):g}),I.subParser("unescapeSpecialChars",function(g,A,C){"use strict";return g=C.converter._dispatch("unescapeSpecialChars.before",g,A,C),g=g.replace(/ยจE(\d+)E/g,function(g,A){var C=parseInt(A);return String.fromCharCode(C)}),g=C.converter._dispatch("unescapeSpecialChars.after",g,A,C)});"function"==typeof define&&define.amd?define(function(){"use strict";return I}):"undefined"!=typeof module&&module.exports?module.exports=I:this.showdown=I}).call(this);
+//# sourceMappingURL=showdown.min.js.map
www/vincent.demeester.fr/assets/.fancyindex/styles.css
@@ -0,0 +1,196 @@
+/* styles.css
+ * Better styling for of Nginx FancyIndex page
+ * ยฉ 2015-17, Lilian Besson (Naereen) and contributors,
+ * open-sourced under the MIT License, https://lbesson.mit-license.org/
+ * hosted on GitHub, https://GitHub.com/Naereen/Nginx-Fancyindex-Theme
+ */
+
+* {
+ font-family: 'Verdana', sans-serif;
+ margin: 0;
+ padding: 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+html {
+ color: #61666c;
+ font-weight: 300;
+ font-size: 1em;
+ line-height: 2em;
+}
+
+body {
+ margin: 0 auto;
+ padding-top: 20px;
+ max-width: 800px;
+}
+
+thead {
+ font-weight: 200;
+ font-size: 1.2em;
+}
+
+h1 {
+ font-weight: 200;
+ text-align: center;
+ font-size: 1.4em;
+ line-height: 3em;
+}
+
+a {
+ color: #5f5f5f;
+ text-decoration: none;
+}
+ a:hover {
+ color: #000;
+ }
+ a.clear, a.clear:link, a.clear:visited {
+ color: #666;
+ padding: 2px 0;
+ font-weight: 400;
+ font-size: 14px;
+ margin: 0 0 0 20px;
+ line-height: 14px;
+ display: inline-block;
+ border-bottom: transparent 1px solid;
+ vertical-align: -10px;
+ -webkit-transition: all 300ms ease-in;
+ -moz-transition: all 300ms ease-in;
+ -ms-transition: all 300ms ease-in;
+ -o-transition: all 300ms ease-in;
+ transition: all 300ms ease-in;
+ }
+
+input {
+ margin: 0 auto;
+ font-size: 100%;
+ vertical-align: middle;
+ *overflow: visible;
+ line-height: normal;
+ font-family: 'Open Sans', sans-serif;
+ font-size: 12px;
+ font-weight: 300;
+ line-height: 18px;
+ color: #555;
+ display: inline-block;
+ height: 20px;
+ padding: 4px 32px 4px 6px;
+ margin-bottom: 9px;
+ font-size: 14px;
+ line-height: 20px;
+ color: #555;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ width: 196px;
+ background-color: #fff;
+ border: 1px solid #ccc;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
+ -webkit-transition: border linear .2s,box-shadow linear .2s;
+ -moz-transition: border linear .2s,box-shadow linear .2s;
+ -o-transition: border linear .2s,box-shadow linear .2s;
+ transition: border linear .2s,box-shadow linear .2s;
+}
+ input:focus {
+ outline: 0;
+ border-color: rgba(0,0,0,0.8);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(0,0,0,0.6);
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(0,0,0,0.6);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(0,0,0,0.6);
+ }
+ input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+ }
+
+#search {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ width: 250px;
+ margin-top: 20px;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ -webkit-appearance: textfield;
+ -webkit-transition: all 300ms ease-in;
+ -moz-transition: all 300ms ease-in;
+ -ms-transition: all 300ms ease-in;
+ -o-transition: all 300ms ease-in;
+ transition: all 300ms ease-in;
+}
+
+table {
+ border-collapse: collapse;
+ font-size: 0.9em;
+ max-width: 100%;
+ margin: 20px auto 0;
+}
+
+tr {
+ outline: 0;
+ border: 0;
+}
+ tr:hover td {
+ background: #f6f6f6;
+ }
+ tr td:first-of-type {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ tr.parent a {
+ color: #9099A3;
+ }
+
+th {
+
+ text-align: left;
+ font-size: .75em;
+ padding-right: 20px;
+}
+ th + th {
+ width: 25%;
+ }
+ th + th + th + th {
+ width: 5%;
+ }
+
+td {
+ padding: 5px 0;
+ outline: 0;
+ border: 0;
+ border-bottom: 1px solid #edf1f5;
+ vertical-align: middle;
+ text-align: left;
+ -webkit-transition: background 300ms ease-in;
+ -moz-transition: background 300ms ease-in;
+ -ms-transition: background 300ms ease-in;
+ -o-transition: background 300ms ease-in;
+ transition: background 300ms ease-in;
+}
+ td:last-child,th:last-child {
+ text-align: right;
+ padding-right: 0;
+ }
+ td a {
+ display: block;
+ }
+
+.parent a:hover {
+ color: #2a2a2a;
+}
+
+footer {
+ font-size:12px;
+ text-align:center;
+}
+footer a {
+ text-decoration: underline;
+ color:#990012;
+}
+
+img { max-width: 100%; }
www/vincent.demeester.fr/css/fonts/Merriweather-Black.otf
Binary file
www/vincent.demeester.fr/css/fonts/Merriweather-Bold.otf
Binary file
www/vincent.demeester.fr/css/fonts/Merriweather-BoldItalic.otf
Binary file
www/vincent.demeester.fr/css/fonts/Merriweather-HeavyItalic.otf
Binary file
www/vincent.demeester.fr/css/fonts/Merriweather-Italic.otf
Binary file
www/vincent.demeester.fr/css/fonts/Merriweather-Light.otf
Binary file
www/vincent.demeester.fr/css/fonts/Merriweather-LightItalic.otf
Binary file
www/vincent.demeester.fr/css/fonts/Merriweather-Regular.otf
Binary file
www/vincent.demeester.fr/css/new.css
@@ -0,0 +1,605 @@
+:root {
+ ---font-sans: sans-serif;
+ ---font-mono: monospace;
+ ---tx-1: #000000;
+ ---tx-2: #1A1A1A;
+ ---tx-3: #666666;
+ ---tx-4: #999999;
+ ---bg-1: #FFFFFF;
+ ---bg-2: #F6F8FA;
+ ---bg-3: #E5E7EB;
+ ---lk-1: #0070F3;
+ ---lk-2: #0366D6;
+ ---lk-tx: #FFFFFF;
+ ---ac-1: #79FFE1;
+ ---ac-tx: #0C4047;
+
+ --content-box-padding: 0.5rem;
+ --aside-width: 12.5rem;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ ---tx-1: #ffffff;
+ ---tx-2: #eeeeee;
+ ---tx-3: #cccccc;
+ ---tx-4: #aaaaaa;
+ ---bg-1: #000000;
+ ---bg-2: #111111;
+ ---bg-3: #222222;
+ ---lk-1: #3291FF;
+ ---lk-2: #0070F3;
+ ---lk-tx: #FFFFFF;
+ ---ac-1: #7928CA;
+ ---ac-tx: #FFFFFF;
+ }
+}
+
+* {
+ /* Reset margins and padding */
+ margin: 0;
+ padding: 0;
+}
+
+address,
+area,
+article,
+aside,
+audio,
+blockquote,
+datalist,
+details,
+dl,
+fieldset,
+figure,
+form,
+input,
+iframe,
+img,
+meter,
+nav,
+ol,
+optgroup,
+option,
+output,
+p,
+pre,
+progress,
+ruby,
+section,
+table,
+textarea,
+ul,
+video {
+ /* Margins for most elements */
+ margin-bottom: 1rem;
+}
+
+html,input,select,button {
+ /* Set body font family and some finicky elements */
+ font-family: var(---font-sans);
+}
+
+body {
+ /* Center body in page */
+ margin: 0 auto;
+ max-width: 70rem;
+ padding: 2rem;
+ border-radius: 6px;
+ overflow-x: hidden;
+ word-break: break-word;
+ overflow-wrap: break-word;
+ background: var(---bg-1);
+
+ /* Main body text */
+ color: var(---tx-2);
+ font-size: 1.03rem;
+ line-height: 1.5;
+}
+
+::selection {
+ /* Set background color for selected text */
+ background: var(---ac-1);
+ color: var(---ac-tx);
+}
+
+h1,h2,h3,h4,h5,h6 {
+ line-height: 1;
+ color: var(---tx-1);
+ padding-top: .875rem;
+}
+
+h1,
+h2,
+h3 {
+ color: var(---tx-1);
+ padding-bottom: 2px;
+ margin-bottom: 8px;
+ border-bottom: 1px solid var(---bg-2);
+}
+
+h4,
+h5,
+h6 {
+ margin-bottom: .3rem;
+}
+
+h1 {
+ font-size: 2.25rem;
+}
+
+h2 {
+ font-size: 1.85rem;
+}
+
+h3 {
+ font-size: 1.55rem;
+}
+
+h4 {
+ font-size: 1.25rem;
+}
+
+h5 {
+ font-size: 1rem;
+}
+
+h6 {
+ font-size: .875rem;
+}
+
+a {
+ color: var(---lk-1);
+}
+
+a:hover {
+ color: var(---lk-2);
+}
+
+abbr:hover {
+ /* Set the '?' cursor while hovering an abbreviation */
+ cursor: help;
+}
+
+blockquote {
+ padding: 1.5rem;
+ background: var(---bg-2);
+ border-left: 5px solid var(---bg-3);
+}
+
+abbr {
+ cursor: help;
+}
+
+blockquote *:last-child {
+ padding-bottom: 0;
+ margin-bottom: 0;
+}
+
+header {
+ background: var(---bg-2);
+ border-bottom: 1px solid var(---bg-3);
+ padding: 1rem 1.5rem;
+
+ /* This sets the right and left margins to cancel out the body's margins. It's width is still the same, but the background stretches across the page's width. */
+
+ margin: -2rem calc(0px - (50vw - 50%)) 2rem;
+
+ /* Shorthand for:
+
+ margin-top: -2rem;
+ margin-bottom: 2rem;
+
+ margin-left: calc(0px - (50vw - 50%));
+ margin-right: calc(0px - (50vw - 50%)); */
+
+ padding-left: calc(50vw - 50%);
+ padding-right: calc(50vw - 50%);
+}
+
+header img#sitelogo {
+ margin-bottom: 0;
+ margin-right: 1em;
+}
+
+header h1,
+header h2,
+header h3 {
+ padding-bottom: 0;
+ border-bottom: 0;
+}
+
+header > *:first-child {
+ margin-top: 0;
+ padding-top: 0;
+}
+
+header > *:last-child {
+ margin-bottom: 0;
+}
+
+main header {
+ background: var(---bg-3);
+}
+
+a button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+ font-size: 1rem;
+ display: inline-block;
+ padding: 6px 12px;
+ text-align: center;
+ text-decoration: none;
+ white-space: nowrap;
+ background: var(---lk-1);
+ color: var(---lk-tx);
+ border: 0;
+ border-radius: 4px;
+ box-sizing: border-box;
+ cursor: pointer;
+ color: var(---lk-tx);
+}
+
+a button[disabled],
+button[disabled],
+input[type="submit"][disabled],
+input[type="reset"][disabled],
+input[type="button"][disabled] {
+ cursor: default;
+ opacity: .5;
+
+ /* Set the [X] cursor while hovering a disabled link */
+ cursor: not-allowed;
+}
+
+.button:focus,
+.button:hover,
+button:focus,
+button:hover,
+input[type="submit"]:focus,
+input[type="submit"]:hover,
+input[type="reset"]:focus,
+input[type="reset"]:hover,
+input[type="button"]:focus,
+input[type="button"]:hover {
+ background: var(---lk-2);
+}
+
+code,
+pre,
+kbd,
+samp {
+ /* Set the font family for monospaced elements */
+ font-family: var(---font-mono);
+}
+
+code,
+samp,
+kbd,
+pre {
+ /* The main preformatted style. This is changed slightly across different cases. */
+ background: var(---bg-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+ padding: 3px 6px;
+}
+
+kbd {
+ /* Makes the kbd element look like a keyboard key */
+ border-bottom: 3px solid var(---bg-3);
+}
+
+pre {
+ padding: 1rem 1.4rem;
+ max-width: 100%;
+ overflow: auto;
+}
+
+pre.src {
+ position: relative;
+}
+pre.src:before {
+ /*display: none;*/
+ position: absolute;
+ background-color: var(---bg-3);
+ /*color: #f3f4f4;*/
+ top: 0;
+ right: 0;
+ padding: 0.2rem 0.5rem;
+}
+
+pre code {
+ /* When <code> is in a <pre>, reset it's formatting to blend in */
+ background: inherit;
+ font-size: inherit;
+ color: inherit;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+code pre {
+ /* When <pre> is in a <code>, reset it's formatting to blend in */
+ display: inline;
+ background: inherit;
+ font-size: inherit;
+ color: inherit;
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+details {
+ /* Make the <details> look more "clickable" */
+ padding: .6rem 1rem;
+ background: var(---bg-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+}
+
+summary {
+ /* Makes the <summary> look more like a "clickable" link with the pointer cursor */
+ cursor: pointer;
+ font-weight: bold;
+}
+
+details[open] {
+ /* Adjust the <details> padding while open */
+ padding-bottom: .75rem;
+}
+
+details[open] summary {
+ /* Adjust the <details> padding while open */
+ margin-bottom: 6px;
+}
+
+details[open]>*:last-child {
+ /* Resets the bottom margin of the last element in the <details> while <details> is opened. This prevents double margins/paddings. */
+ margin-bottom: 0;
+}
+
+dt {
+ font-weight: bold;
+}
+
+dd::before {
+ /* Add an arrow to data table definitions */
+ content: 'โ ';
+}
+
+hr {
+ /* Reset the border of the <hr> separator, then set a better line */
+ border: 0;
+ border-bottom: 1px solid var(---bg-3);
+ margin: 1rem auto;
+}
+
+fieldset {
+ margin-top: 1rem;
+ padding: 2rem;
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+}
+
+legend {
+ padding: auto .5rem;
+}
+
+table {
+ /* border-collapse sets the table's elements to share borders, rather than floating as separate "boxes". */
+ border-collapse: collapse;
+ width: 100%
+}
+
+td,
+th {
+ border: 1px solid var(---bg-3);
+ text-align: left;
+ padding: .5rem;
+}
+
+th {
+ background: var(---bg-2);
+}
+
+tr:nth-child(even) {
+ /* Set every other cell slightly darker. Improves readability. */
+ background: var(---bg-2);
+}
+
+table caption {
+ font-weight: bold;
+ margin-bottom: .5rem;
+}
+
+textarea {
+ /* Don't let the <textarea> extend off the screen naturally or when dragged by the user */
+ max-width: 100%;
+}
+
+ol,
+ul {
+ /* Replace the browser default padding */
+ padding-left: 2rem;
+}
+
+li {
+ margin-top: .4rem;
+}
+
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+ margin-bottom: 0;
+}
+
+mark {
+ padding: 3px 6px;
+ background: var(---ac-1);
+ color: var(---ac-tx);
+}
+
+textarea,
+select,
+input {
+ padding: 6px 12px;
+ margin-bottom: .5rem;
+ background: var(---bg-2);
+ color: var(---tx-2);
+ border: 1px solid var(---bg-3);
+ border-radius: 4px;
+ box-shadow: none;
+ box-sizing: border-box;
+}
+
+img {
+ max-width: 100%;
+}
+
+aside {
+ --aside-offset: 1rem;
+ --aside-offset-lineheight: 1.5rem;
+ background-color: var(---bg-2);
+ padding: calc(var(--content-box-padding) * 0.5) calc(var(--content-box-padding) * 2);
+ padding-top: 1em;
+ margin-bottom: 0em;
+ float: right;
+ width: var(--aside-width);
+ font-size: 0.9rem;
+ line-height: 1.25rem;
+ border: 1px solid var(--bg-3);
+}
+
+figure figcaption {
+ text-align: center;
+ color: var(---tx-2);
+ font-style: italic;
+ margin: 0 2rem;
+}
+
+footer {
+ text-align: center;
+ color: var(---tx-4);
+}
+
+footer a {
+ color: var(---tx-3);
+}
+
+section img {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+section img.shadow {
+ box-shadow: 0 28px 50px rgba(0,0,0,0.16);
+}
+
+div.drawer:before {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 4.4rem;
+ width: 1px;
+ background-color: #555;
+}
+
+div.drawer {
+ display: flex;
+ padding: 0;
+ margin: 1rem;
+ padding-top: 1rem;
+ position: relative;
+ color: #555;
+}
+
+div.drawer h6 {
+ box-sizing: border-box;
+ font-style: italic;
+ flex: 0 0 5rem;
+ margin:0;
+ padding:0;
+ align-self: center;
+ text-align: right;
+ padding-right: 1.2rem;
+}
+
+div.drawer.info:before {
+ background-color: #00529B;
+}
+div.drawer.info {
+ color: #00529B;
+}
+
+div.drawer.note:before {
+ background-color: #9F6000;
+}
+div.drawer.note {
+ color: #9F6000;
+}
+div.drawer.tip:before {
+ background-color: #4F8A10;
+}
+div.drawer.tip {
+ color: #4F8A10;
+}
+div.drawer.warning:before {
+ background-color: #D8000C;
+}
+div.drawer.warning {
+ color: #D8000C;
+}
+div.drawer.results:before {
+ background-color: black;
+}
+div.drawer.results {
+ font-family:monospace,monospace;
+ font-family: var(---font-mono);
+ color: black;
+ width: 100% !important;
+}
+div.drawer.results p {
+ display: block;
+ unicode-bidi: embed;
+ white-space: pre;
+ margin-top: 0;
+}
+div.drawer.results pre {
+ background-color: inherit;
+ border: 0;
+}
+div.drawer.results pre.src:before {
+ background-color: #eee;
+ color: #555;
+}
+
+.tag {
+ font-family:var(---font-mono);
+ font-size: 1rem;
+}
+.tag span {
+ padding:.3em;
+ float:right;
+ margin-right:.5em;
+ border:1px solid #bbb;
+ border-radius:3px;
+ background-clip:padding-box;
+ color:#333;
+ background-color:#eee;
+ line-height:1rem;
+}
+
+.todo {
+ font-family: monospace; color: red;
+}
+.done {
+ font-family: monospace; color: green;
+}
+.priority { font-family: monospace; color: orange; }
+.timestamp { color: #bebebe; }
+.timestamp-kwd { color: #5f9ea0; }
www/vincent.demeester.fr/css/site.css
@@ -0,0 +1,353 @@
+@font-face {
+ font-family: "Merriweather";
+ src: url("/css/fonts/Merriweather-Regular.otf") format("opentype");
+}
+@font-face {
+ font-family: "Merriweather";
+ font-weight: bold;
+ src: url("/css/fonts/Merriweather-Bold.otf") format("opentype");
+}
+@font-face {
+ font-family: "Merriweather";
+ font-weight: bold;
+ font-style: italic;
+ src: url("/css/fonts/Merriweather-BoldItalic.otf") format("opentype");
+}
+@font-face {
+ font-family: "Merriweather";
+ font-style: italic;
+ src: url("/css/fonts/Merriweather-Italic.otf") format("opentype");
+}
+@font-face {
+ font-family: "Merriweather";
+ font-weight: lighter;
+ font-style: italic;
+ src: url("/css/fonts/Merriweather-LightItalic.otf") format("opentype");
+}
+@font-face {
+ font-family: "Merriweather";
+ font-weight: lighter;
+ src: url("/css/fonts/Merriweather-Light.otf") format("opentype");
+}
+
+html{
+ margin: 1rem 2rem;
+ font-size: 106.25%;
+ --body-vertical-margin: 1rem;
+ --body-horizontal-margin: 1rem;
+ --content-box-padding: 0.5rem;
+ --font-main: Georgia, sans-serif;
+ --font-mono: 'Ubuntu Mono','Fira Code','Deja Vu Sans Mono','Bitstream Vera Sans Mono','Source Code Pro','Courier New',monospace;
+ --font-quote: "Fresco", Georgia, serif;
+ --font-sans: Avenir Next, Avenir, system-ui, sans-serif;
+ --font-header: 'Merriweather','Linux Libertine','Georgia','Times',serif;
+ --figure-offset: 0;
+ --figcaption-padding: 0;
+ --aside-width: 12.5rem;
+ --column-gap: 2rem;
+ --padding: 1rem;
+}
+
+body {
+ font-family: var(--font-main);
+ max-width: 70rem;
+ min-width: 30rem;
+ line-height: 1.4rem;
+ margin: 0 auto;
+}
+
+p {
+ word-wrap: break-word;
+}
+body > header{
+ margin-bottom: 4em;
+}
+
+body > header nav {
+ float:right;
+}
+
+body > header nav ul li {
+ display: inline-block;
+ list-style: none;
+ padding: 0 0.5rem;
+}
+
+main {
+ font-size: 1.1rem;
+ font-family: var(--font-sans);
+}
+
+div.index h1 {
+ font-family: "Merriweather", "Linux Libertine", "Georgia", "Times", serif;
+ font-size: 2rem;
+ line-height: 2rem;
+ font-weight: bolder;
+}
+
+div.index h2 {
+ font-family: "Merriweather", "Linux Libertine", "Georgia", "Times", serif;
+ font-size: 1.5rem;
+ line-height: 2rem;
+}
+
+nav#table-of-contents {
+ background: #f2f2f2;
+ padding: 0.2rem 1rem;
+ font-size: 90%;
+}
+
+nav#table-of-contents h2 {
+ font-family: var(--font-sans);
+ font-weight: bold;
+ font-style: italic;
+}
+
+nav#table-of-contents li {
+ list-style-type: square;
+}
+
+nav#table-of-contents li a {
+ color: black;
+}
+nav#table-of-contents li a:hover {
+ color: #33f;
+ background-color: inherit;
+}
+
+code {
+ background-color: #f3f4f4;
+ font-family: var(--font-mono);
+ padding: 0.1rem 0.3rem;
+ border: 1px solid #e1e1e1;
+ border-radius: 4px;
+}
+
+blockquote code {
+ background-color: #999;
+ border-color: #666;
+ color: white;
+}
+
+pre {
+ background-color: #f3f4f4;
+ font-family: var(--font-mono);
+ white-space: pre-wrap;
+ overflow: auto;
+ overflow-x: auto;
+ margin: 1.25rem calc(-1 * var(--content-box-padding));
+ padding: var(--content-box-padding);
+ border: 1px solid #999;
+}
+
+pre.src {
+ position: relative;
+}
+
+pre.src:before {
+ /*display: none;*/
+ position: absolute;
+ background-color: #999;
+ color: #f3f4f4;
+ top: 0;
+ right: 0;
+ padding: 0.2rem 0.5rem;
+}
+
+aside {
+ --aside-offset: 1rem;
+ --aside-offset-lineheight: 1.5rem;
+ background-color: #f8f8f8;
+ padding: calc(var(--content-box-padding) * 0.5) calc(var(--content-box-padding) * 2);
+ float: right;
+ width: var(--aside-width);
+ font-size: 0.9rem;
+ line-height: 1.25rem;
+ border: 1px solid #ccc;
+}
+
+a { text-decoration: none; color: #339; }
+a:hover { color: #33f; background-color: #f6f6f6; }
+
+blockquote {
+ font-family: var(--font-quote);
+ text-rendering: optimizeLegibility;
+ line-height: 1.4;
+ font-style: italic;
+ background-color: #e0e0e0;
+ border-radius: 0.5em;
+ width: 90%;
+ margin: 1em auto;
+ padding: 0.2rem 1.2rem;
+}
+
+h1, h2, h3, h4 {
+ font-family: var(--font-header);
+}
+main header h1 {
+ font-size: 300%;
+ line-height: 3.8rem;
+}
+
+figure figcaption {
+ text-align: center;
+ color: #666;
+ font-style: italic;
+ margin: 0 2rem;
+}
+
+footer {
+ text-align: center;
+ color: #999;
+}
+
+footer a {
+ color: #666;
+}
+
+section img {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+
+section img.shadow {
+ box-shadow: 0 28px 50px rgba(0,0,0,0.16);
+}
+
+table {
+ margin:1em auto;
+ border-top:2px solid;
+ border-collapse:collapse
+}
+table,thead {
+ border-bottom:2px solid
+}
+table td+td,table th+th {
+ border-left:1px solid gray
+}
+table tr {
+ border-top:1px solid #d3d3d3
+}
+td,th {
+ padding:.3em .6em;
+ vertical-align:middle
+}
+
+.title { text-align: center;
+ margin-bottom: 1.5rem; }
+.subtitle {
+ text-align: center;
+ font-size: medium;
+ font-weight: bold;
+ margin-top:0;
+ color: #999;
+}
+
+div.drawer:before {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 6.4rem;
+ width: 1px;
+ background-color: #555;
+}
+
+div.drawer {
+ display: flex;
+ padding: 0;
+ margin: 1rem;
+ margin-left: -7rem;
+ position: relative;
+ color: #555;
+}
+
+div.drawer h6 {
+ box-sizing: border-box;
+ font-style: italic;
+ flex: 0 0 7rem;
+ margin:0;
+ padding:0;
+ align-self: center;
+ text-align: right;
+ padding-right: 1.2rem;
+}
+
+div.drawer.info:before {
+ background-color: #00529B;
+}
+div.drawer.info {
+ color: #00529B;
+}
+
+div.drawer.note:before {
+ background-color: #9F6000;
+}
+div.drawer.note {
+ color: #9F6000;
+}
+div.drawer.tip:before {
+ background-color: #4F8A10;
+}
+div.drawer.tip {
+ color: #4F8A10;
+}
+div.drawer.warning:before {
+ background-color: #D8000C;
+}
+div.drawer.warning {
+ color: #D8000C;
+}
+div.drawer.results:before {
+ background-color: black;
+}
+div.drawer.results {
+ font-family:monospace,monospace;
+ font-family: var(--font-mono);
+ color: black;
+ width: 100% !important;
+}
+div.drawer.results p {
+ display: block;
+ unicode-bidi: embed;
+ white-space: pre;
+ margin-top: 0;
+}
+div.drawer.results pre {
+ background-color: inherit;
+ border: 0;
+}
+div.drawer.results pre.src:before {
+ background-color: #eee;
+ color: #555;
+}
+
+.tag {
+ font-family:var(--font-mono);
+ font-size: 1rem;
+}
+.tag span {
+ padding:.3em;
+ float:right;
+ margin-right:.5em;
+ border:1px solid #bbb;
+ border-radius:3px;
+ background-clip:padding-box;
+ color:#333;
+ background-color:#eee;
+ line-height:1rem;
+}
+
+.todo { font-family: monospace; color: red; }
+.done { font-family: monospace; color: green; }
+.priority { font-family: monospace; color: orange; }
+.timestamp { color: #bebebe; }
+.timestamp-kwd { color: #5f9ea0; }
+.org-right { margin-left: auto; margin-right: 0px; text-align: right; }
+.org-left { margin-left: 0px; margin-right: auto; text-align: left; }
+.org-center { margin-left: auto; margin-right: auto; text-align: center; }
+.underline { text-decoration: underline; }
+#postamble p, #preamble p { font-size: 90%; margin: .2em; }
+p.verse { margin-left: 3%; }
www/vincent.demeester.fr/css/syntax.css
@@ -0,0 +1,280 @@
+pre.src:hover:before { display: inline;}
+/* Languages per Org manual */
+pre.src-asymptote:before { content: 'Asymptote'; }
+pre.src-awk:before { content: 'Awk'; }
+pre.src-C:before { content: 'C'; }
+/* pre.src-C++ doesn't work in CSS */
+pre.src-clojure:before { content: 'Clojure'; }
+pre.src-css:before { content: 'CSS'; }
+pre.src-D:before { content: 'D'; }
+pre.src-ditaa:before { content: 'ditaa'; }
+pre.src-dot:before { content: 'Graphviz'; }
+pre.src-calc:before { content: 'Emacs Calc'; }
+pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
+pre.src-fortran:before { content: 'Fortran'; }
+pre.src-gnuplot:before { content: 'gnuplot'; }
+pre.src-haskell:before { content: 'Haskell'; }
+pre.src-hledger:before { content: 'hledger'; }
+pre.src-java:before { content: 'Java'; }
+pre.src-js:before { content: 'Javascript'; }
+pre.src-latex:before { content: 'LaTeX'; }
+pre.src-ledger:before { content: 'Ledger'; }
+pre.src-lisp:before { content: 'Lisp'; }
+pre.src-lilypond:before { content: 'Lilypond'; }
+pre.src-lua:before { content: 'Lua'; }
+pre.src-matlab:before { content: 'MATLAB'; }
+pre.src-mscgen:before { content: 'Mscgen'; }
+pre.src-ocaml:before { content: 'Objective Caml'; }
+pre.src-octave:before { content: 'Octave'; }
+pre.src-org:before { content: 'Org mode'; }
+pre.src-oz:before { content: 'OZ'; }
+pre.src-plantuml:before { content: 'Plantuml'; }
+pre.src-processing:before { content: 'Processing.js'; }
+pre.src-python:before { content: 'Python'; }
+pre.src-R:before { content: 'R'; }
+pre.src-ruby:before { content: 'Ruby'; }
+pre.src-sass:before { content: 'Sass'; }
+pre.src-scheme:before { content: 'Scheme'; }
+pre.src-screen:before { content: 'Gnu Screen'; }
+pre.src-sed:before { content: 'Sed'; }
+pre.src-sh:before { content: 'shell'; }
+pre.src-sql:before { content: 'SQL'; }
+pre.src-sqlite:before { content: 'SQLite'; }
+/* additional languages in org.el's org-babel-load-languages alist */
+pre.src-forth:before { content: 'Forth'; }
+pre.src-io:before { content: 'IO'; }
+pre.src-J:before { content: 'J'; }
+pre.src-makefile:before { content: 'Makefile'; }
+pre.src-maxima:before { content: 'Maxima'; }
+pre.src-perl:before { content: 'Perl'; }
+pre.src-picolisp:before { content: 'Pico Lisp'; }
+pre.src-scala:before { content: 'Scala'; }
+pre.src-shell:before { content: 'Shell Script'; }
+pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
+/* additional language identifiers per \"defun org-babel-execute\"
+ in ob-*.el */
+pre.src-cpp:before { content: 'C++'; }
+pre.src-abc:before { content: 'ABC'; }
+pre.src-coq:before { content: 'Coq'; }
+pre.src-groovy:before { content: 'Groovy'; }
+/* additional language identifiers from org-babel-shell-names in
+ ob-shell.el: ob-shell is the only babel language using a lambda to put
+ the execution function name together. */
+pre.src-go:before { content: 'go'; }
+pre.src-bash:before { content: 'bash'; }
+pre.src-csh:before { content: 'csh'; }
+pre.src-ash:before { content: 'ash'; }
+pre.src-dash:before { content: 'dash'; }
+pre.src-ksh:before { content: 'ksh'; }
+pre.src-mksh:before { content: 'mksh'; }
+pre.src-posh:before { content: 'posh'; }
+/* Additional Emacs modes also supported by the LaTeX listings package */
+pre.src-ada:before { content: 'Ada'; }
+pre.src-asm:before { content: 'Assembler'; }
+pre.src-caml:before { content: 'Caml'; }
+pre.src-delphi:before { content: 'Delphi'; }
+pre.src-html:before { content: 'HTML'; }
+pre.src-idl:before { content: 'IDL'; }
+pre.src-mercury:before { content: 'Mercury'; }
+pre.src-metapost:before { content: 'MetaPost'; }
+pre.src-modula-2:before { content: 'Modula-2'; }
+pre.src-pascal:before { content: 'Pascal'; }
+pre.src-ps:before { content: 'PostScript'; }
+pre.src-prolog:before { content: 'Prolog'; }
+pre.src-simula:before { content: 'Simula'; }
+pre.src-tcl:before { content: 'tcl'; }
+pre.src-tex:before { content: 'TeX'; }
+pre.src-plain-tex:before { content: 'Plain TeX'; }
+pre.src-verilog:before { content: 'Verilog'; }
+pre.src-vhdl:before { content: 'VHDL'; }
+pre.src-xml:before { content: 'XML'; }
+pre.src-nxml:before { content: 'XML'; }
+pre.src-yaml:before { content: 'YAML'; }
+pre.src-toml:before { content: 'TOML'; }
+/* add a generic configuration mode; LaTeX export needs an additional
+ (add-to-list 'org-latex-listings-langs '(conf \" \")) in .emacs */
+pre.src-conf:before { content: 'Configuration File'; }
+
+table { border-collapse:collapse; }
+caption.t-above { caption-side: top; }
+caption.t-bottom { caption-side: bottom; }
+td, th { vertical-align:top; }
+th.org-right { text-align: center; }
+th.org-left { text-align: center; }
+th.org-center { text-align: center; }
+td.org-right { text-align: right; }
+td.org-left { text-align: left; }
+td.org-center { text-align: center; }
+dt { font-weight: bold; }
+.footpara { display: inline; }
+.footdef { margin-bottom: 1em; }
+.figure { padding: 1em; }
+.figure p { text-align: center; }
+.inlinetask {
+ padding: 10px;
+ border: 2px solid gray;
+ margin: 10px;
+ background: #ffffcc;
+}
+#org-div-home-and-up
+ { text-align: right; font-size: 70%; white-space: nowrap; }
+textarea { overflow-x: auto; }
+.linenr { font-size: smaller }
+.code-highlighted { background-color: #ffff00; }
+.org-info-js_info-navigation { border-style: none; }
+#org-info-js_console-label
+ { font-size: 10px; font-weight: bold; white-space: nowrap; }
+.org-info-js_search-highlight
+ { background-color: #ffff00; color: #000000; font-weight: bold; }
+.org-svg { width: 90%; }
+
+/******************************
+ * Syntax highlighting
+ ***
+ * Source: https://github.com/fniessen/org-html-themes/blob/master/styles/bigblow/css/htmlize.css
+ ******************************/
+.org-bold { /* bold */ font-weight: bold; }
+.org-bold-italic { /* bold-italic */ font-weight: bold; font-style: italic; }
+.org-buffer-menu-buffer { /* buffer-menu-buffer */ font-weight: bold; }
+.org-builtin { /* font-lock-builtin-face */ color: #7a378b; }
+.org-button { /* button */ text-decoration: underline; }
+.org-calendar-today { /* calendar-today */ text-decoration: underline; }
+.org-change-log-acknowledgement { /* change-log-acknowledgement */ color: #b22222; }
+.org-change-log-conditionals { /* change-log-conditionals */ color: #a0522d; }
+.org-change-log-date { /* change-log-date */ color: #8b2252; }
+.org-change-log-email { /* change-log-email */ color: #a0522d; }
+.org-change-log-file { /* change-log-file */ color: #0000ff; }
+.org-change-log-function { /* change-log-function */ color: #a0522d; }
+.org-change-log-list { /* change-log-list */ color: #a020f0; }
+.org-change-log-name { /* change-log-name */ color: #008b8b; }
+.org-comint-highlight-input { /* comint-highlight-input */ font-weight: bold; }
+.org-comint-highlight-prompt { /* comint-highlight-prompt */ color: #00008b; }
+.org-comment { /* font-lock-comment-face */ color: #b22222; }
+.org-comment-delimiter { /* font-lock-comment-delimiter-face */ color: #b22222; }
+.org-completions-annotations { /* completions-annotations */ font-style: italic; }
+.org-completions-common-part { /* completions-common-part */ color: #000000; background-color: #ffffff; }
+.org-completions-first-difference { /* completions-first-difference */ font-weight: bold; }
+.org-constant { /* font-lock-constant-face */ color: #008b8b; }
+.org-diary { /* diary */ color: #ff0000; }
+.org-diff-context { /* diff-context */ color: #7f7f7f; }
+.org-diff-file-header { /* diff-file-header */ background-color: #b3b3b3; font-weight: bold; }
+.org-diff-function { /* diff-function */ background-color: #cccccc; }
+.org-diff-header { /* diff-header */ background-color: #cccccc; }
+.org-diff-hunk-header { /* diff-hunk-header */ background-color: #cccccc; }
+.org-diff-index { /* diff-index */ background-color: #b3b3b3; font-weight: bold; }
+.org-diff-nonexistent { /* diff-nonexistent */ background-color: #b3b3b3; font-weight: bold; }
+.org-diff-refine-change { /* diff-refine-change */ background-color: #d9d9d9; }
+.org-dired-directory { /* dired-directory */ color: #0000ff; }
+.org-dired-flagged { /* dired-flagged */ color: #ff0000; font-weight: bold; }
+.org-dired-header { /* dired-header */ color: #228b22; }
+.org-dired-ignored { /* dired-ignored */ color: #7f7f7f; }
+.org-dired-mark { /* dired-mark */ color: #008b8b; }
+.org-dired-marked { /* dired-marked */ color: #ff0000; font-weight: bold; }
+.org-dired-perm-write { /* dired-perm-write */ color: #b22222; }
+.org-dired-symlink { /* dired-symlink */ color: #a020f0; }
+.org-dired-warning { /* dired-warning */ color: #ff0000; font-weight: bold; }
+.org-doc { /* font-lock-doc-face */ color: #8b2252; }
+.org-escape-glyph { /* escape-glyph */ color: #a52a2a; }
+.org-file-name-shadow { /* file-name-shadow */ color: #7f7f7f; }
+.org-flyspell-duplicate { /* flyspell-duplicate */ color: #cdad00; font-weight: bold; text-decoration: underline; }
+.org-flyspell-incorrect { /* flyspell-incorrect */ color: #ff4500; font-weight: bold; text-decoration: underline; }
+.org-fringe { /* fringe */ background-color: #f2f2f2; }
+.org-function-name { /* font-lock-function-name-face */ color: #0000ff; }
+.org-header-line { /* header-line */ color: #333333; background-color: #e5e5e5; }
+.org-help-argument-name { /* help-argument-name */ font-style: italic; }
+.org-highlight { /* highlight */ background-color: #b4eeb4; }
+.org-holiday { /* holiday */ background-color: #ffc0cb; }
+.org-isearch { /* isearch */ color: #b0e2ff; background-color: #cd00cd; }
+.org-isearch-fail { /* isearch-fail */ background-color: #ffc1c1; }
+.org-italic { /* italic */ font-style: italic; }
+.org-keyword { /* font-lock-keyword-face */ color: #a020f0; }
+.org-lazy-highlight { /* lazy-highlight */ background-color: #afeeee; }
+.org-link { /* link */ color: #0000ff; text-decoration: underline; }
+.org-link-visited { /* link-visited */ color: #8b008b; text-decoration: underline; }
+.org-log-edit-header { /* log-edit-header */ color: #a020f0; }
+.org-log-edit-summary { /* log-edit-summary */ color: #0000ff; }
+.org-log-edit-unknown-header { /* log-edit-unknown-header */ color: #b22222; }
+.org-match { /* match */ background-color: #ffff00; }
+.org-next-error { /* next-error */ background-color: #eedc82; }
+.org-nobreak-space { /* nobreak-space */ color: #a52a2a; text-decoration: underline; }
+.org-org-archived { /* org-archived */ color: #7f7f7f; }
+.org-org-block { /* org-block */ color: #7f7f7f; }
+.org-org-block-begin-line { /* org-block-begin-line */ color: #b22222; }
+.org-org-block-end-line { /* org-block-end-line */ color: #b22222; }
+.org-org-checkbox { /* org-checkbox */ font-weight: bold; }
+.org-org-checkbox-statistics-done { /* org-checkbox-statistics-done */ color: #228b22; font-weight: bold; }
+.org-org-checkbox-statistics-todo { /* org-checkbox-statistics-todo */ color: #ff0000; font-weight: bold; }
+.org-org-clock-overlay { /* org-clock-overlay */ background-color: #ffff00; }
+.org-org-code { /* org-code */ color: #7f7f7f; }
+.org-org-column { /* org-column */ background-color: #e5e5e5; }
+.org-org-column-title { /* org-column-title */ background-color: #e5e5e5; font-weight: bold; text-decoration: underline; }
+.org-org-date { /* org-date */ color: #a020f0; text-decoration: underline; }
+.org-org-document-info { /* org-document-info */ color: #191970; }
+.org-org-document-info-keyword { /* org-document-info-keyword */ color: #7f7f7f; }
+.org-org-document-title { /* org-document-title */ color: #191970; font-size: 144%; font-weight: bold; }
+.org-org-done { /* org-done */ color: #228b22; font-weight: bold; }
+.org-org-drawer { /* org-drawer */ color: #0000ff; }
+.org-org-ellipsis { /* org-ellipsis */ color: #b8860b; text-decoration: underline; }
+.org-org-footnote { /* org-footnote */ color: #a020f0; text-decoration: underline; }
+.org-org-formula { /* org-formula */ color: #b22222; }
+.org-org-headline-done { /* org-headline-done */ color: #bc8f8f; }
+.org-org-hide { /* org-hide */ color: #ffffff; }
+.org-org-latex-and-export-specials { /* org-latex-and-export-specials */ color: #8b4513; }
+.org-org-level-1 { /* org-level-1 */ color: #0000ff; }
+.org-org-level-2 { /* org-level-2 */ color: #a0522d; }
+.org-org-level-3 { /* org-level-3 */ color: #a020f0; }
+.org-org-level-4 { /* org-level-4 */ color: #b22222; }
+.org-org-level-5 { /* org-level-5 */ color: #228b22; }
+.org-org-level-6 { /* org-level-6 */ color: #008b8b; }
+.org-org-level-7 { /* org-level-7 */ color: #7a378b; }
+.org-org-level-8 { /* org-level-8 */ color: #8b2252; }
+.org-org-link { /* org-link */ color: #0000ff; text-decoration: underline; }
+.org-org-meta-line { /* org-meta-line */ color: #b22222; }
+.org-org-mode-line-clock { /* org-mode-line-clock */ color: #000000; background-color: #bfbfbf; }
+.org-org-mode-line-clock-overrun { /* org-mode-line-clock-overrun */ color: #000000; background-color: #ff0000; }
+.org-org-quote { /* org-quote */ color: #7f7f7f; }
+.org-org-scheduled { /* org-scheduled */ color: #006400; }
+.org-org-scheduled-previously { /* org-scheduled-previously */ color: #b22222; }
+.org-org-scheduled-today { /* org-scheduled-today */ color: #006400; }
+.org-org-sexp-date { /* org-sexp-date */ color: #a020f0; }
+.org-org-special-keyword { /* org-special-keyword */ color: #a020f0; }
+.org-org-table { /* org-table */ color: #0000ff; }
+.org-org-tag { /* org-tag */ font-weight: bold; }
+.org-org-target { /* org-target */ text-decoration: underline; }
+.org-org-time-grid { /* org-time-grid */ color: #b8860b; }
+.org-org-todo { /* org-todo */ color: #ff0000; font-weight: bold; }
+.org-org-upcoming-deadline { /* org-upcoming-deadline */ color: #b22222; }
+.org-org-verbatim { /* org-verbatim */ color: #7f7f7f; }
+.org-org-verse { /* org-verse */ color: #7f7f7f; }
+.org-org-warning { /* org-warning */ color: #ff0000; font-weight: bold; }
+.org-outline-1 { /* outline-1 */ color: #0000ff; }
+.org-outline-2 { /* outline-2 */ color: #a0522d; }
+.org-outline-3 { /* outline-3 */ color: #a020f0; }
+.org-outline-4 { /* outline-4 */ color: #b22222; }
+.org-outline-5 { /* outline-5 */ color: #228b22; }
+.org-outline-6 { /* outline-6 */ color: #008b8b; }
+.org-outline-7 { /* outline-7 */ color: #7a378b; }
+.org-outline-8 { /* outline-8 */ color: #8b2252; }
+.org-preprocessor { /* font-lock-preprocessor-face */ color: #7a378b; }
+.org-query-replace { /* query-replace */ color: #b0e2ff; background-color: #cd00cd; }
+.org-regexp-grouping-backslash { /* font-lock-regexp-grouping-backslash */ font-weight: bold; }
+.org-regexp-grouping-construct { /* font-lock-regexp-grouping-construct */ font-weight: bold; }
+.org-region { /* region */ background-color: #eedc82; }
+.org-secondary-selection { /* secondary-selection */ background-color: #ffff00; }
+.org-shadow { /* shadow */ color: #7f7f7f; }
+.org-show-paren-match { /* show-paren-match */ background-color: #40e0d0; }
+.org-show-paren-mismatch { /* show-paren-mismatch */ color: #ffffff; background-color: #a020f0; }
+.org-string { /* font-lock-string-face */ color: #8b2252; }
+.org-tool-bar { /* tool-bar */ color: #000000; background-color: #bfbfbf; }
+.org-tooltip { /* tooltip */ color: #000000; background-color: #ffffe0; }
+.org-trailing-whitespace { /* trailing-whitespace */ background-color: #ff0000; }
+.org-type { /* font-lock-type-face */ color: #228b22; }
+.org-underline { /* underline */ text-decoration: underline; }
+.org-variable-name { /* font-lock-variable-name-face */ color: #a0522d; }
+.org-warning { /* font-lock-warning-face */ color: #ff0000; font-weight: bold; }
+.org-widget-button { /* widget-button */ font-weight: bold; }
+.org-widget-button-pressed { /* widget-button-pressed */ color: #ff0000; }
+.org-widget-documentation { /* widget-documentation */ color: #006400; }
+.org-widget-field { /* widget-field */ background-color: #d9d9d9; }
+.org-widget-inactive { /* widget-inactive */ color: #7f7f7f; }
+.org-widget-single-line-field { /* widget-single-line-field */ background-color: #d9d9d9; }
www/vincent.demeester.fr/images/2012/velo_casse.jpg
Binary file
www/vincent.demeester.fr/images/2014/03/83029.jpg
@@ -0,0 +1,1 @@
+../../../../../.git/annex/objects/kP/4F/SHA256E-s358707--d69a2e9bf43ad36b5f0cd9235a831d906d003935b0b6fbd95c2b80d18e558325.jpg/SHA256E-s358707--d69a2e9bf43ad36b5f0cd9235a831d906d003935b0b6fbd95c2b80d18e558325.jpg
\ No newline at end of file
www/vincent.demeester.fr/images/2014/03/iXnpyHj1JibDI-small.png
@@ -0,0 +1,1 @@
+../../../../../.git/annex/objects/71/60/SHA256E-s1633871--87b97ff1bdc8197ece9476a38f56ff20c3e5a31e37e18fbf6f16edfa2289739c.png/SHA256E-s1633871--87b97ff1bdc8197ece9476a38f56ff20c3e5a31e37e18fbf6f16edfa2289739c.png
\ No newline at end of file
www/vincent.demeester.fr/images/2014/03/wallpaper-1470931.jpg
@@ -0,0 +1,1 @@
+../../../../../.git/annex/objects/6G/Vp/SHA256E-s621197--7f7762eb56ed58c2646550ec497a7038d2306b4d2a96568e1539b0a014a40231.jpg/SHA256E-s621197--7f7762eb56ed58c2646550ec497a7038d2306b4d2a96568e1539b0a014a40231.jpg
\ No newline at end of file
www/vincent.demeester.fr/images/2016/firefox-place-awesomebar-example.png
Binary file
www/vincent.demeester.fr/images/2016/firefox-place-bookmark-toolbar.png
Binary file
www/vincent.demeester.fr/images/2016/firefox-place-most-visited-today.png
Binary file
www/vincent.demeester.fr/images/2019/01/desk1.jpg
Binary file
www/vincent.demeester.fr/images/emacs/2020-02-29-13-46-08.png
Binary file
www/vincent.demeester.fr/images/emacs/2020-02-29-14-41-59.png
Binary file
www/vincent.demeester.fr/images/emacs/2020-03-03-21-57-41.png
Binary file
www/vincent.demeester.fr/images/emacs/2020-03-03-21-59-22.png
Binary file
www/vincent.demeester.fr/images/sandbox/long-img.png
Binary file
www/vincent.demeester.fr/images/sandbox/pic-demo.png
Binary file
www/vincent.demeester.fr/images/sandbox/some_filename.png
Binary file
www/vincent.demeester.fr/images/tekton/tekton-horizontal-color.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/07/P3/SHA256E-s235244--ffbafb40375b39fd398efc1f2be318a89e5a0245af726af802317b4f61b2a74d.png/SHA256E-s235244--ffbafb40375b39fd398efc1f2be318a89e5a0245af726af802317b4f61b2a74d.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 Blogging with Emacs, and Emacs only.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/xM/Qp/SHA256E-s971495--728a775298fbed863232da8ce70d2c62e9e415c7445ee4a4071530d08645fce0.png/SHA256E-s971495--728a775298fbed863232da8ce70d2c62e9e415c7445ee4a4071530d08645fce0.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 GTD in 15 minutes โ A Pragmatic Guide to Getting Things Done.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/91/Kp/SHA256E-s2259811--97fb71efcef48811aea10b5ef941da4ac514abf335147483b448f27489f53b67.png/SHA256E-s2259811--97fb71efcef48811aea10b5ef941da4ac514abf335147483b448f27489f53b67.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 Idioms of Dynamic Languages Will Crichton.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/2P/wx/SHA256E-s2427851--8c0acbaa75df2f509487d9ba5e9c1c2d47989d600c789e0c61509b229bc25685.png/SHA256E-s2427851--8c0acbaa75df2f509487d9ba5e9c1c2d47989d600c789e0c61509b229bc25685.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 kind.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/jM/wj/SHA256E-s353626--737d6587861cf35afa6efb1346dea5ba34898302ed5f6ebbda7502b835631be4.png/SHA256E-s353626--737d6587861cf35afa6efb1346dea5ba34898302ed5f6ebbda7502b835631be4.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 Local-first software You own your data, in spite of the cloud.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/3x/5K/SHA256E-s6491477--9b3d2c4cd13b9586d14c382bf9ac2596aa1bc555696655f22b856e6bdb35c43a.png/SHA256E-s6491477--9b3d2c4cd13b9586d14c382bf9ac2596aa1bc555696655f22b856e6bdb35c43a.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 Peter Bourgon ยท Programming with errors.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/8F/f7/SHA256E-s268614--2c2d98aededc35ed1661d5f5b162c54642011fd37af271e61d25f63677cf4a03.png/SHA256E-s268614--2c2d98aededc35ed1661d5f5b162c54642011fd37af271e61d25f63677cf4a03.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 RSS feeds and how to use them.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/X4/Z9/SHA256E-s227063--c81d8b3d8924cd772af639ac8c9e805f8d7e4396e99ae90184367bebd16dd07c.png/SHA256E-s227063--c81d8b3d8924cd772af639ac8c9e805f8d7e4396e99ae90184367bebd16dd07c.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 Subset Park Digital Minimalism for the Working Hacker.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/FX/Z4/SHA256E-s1280552--b7d115e8e6e729e874568c04fbce5ba3fece260cbea0ad7fef543f70fb5841ac.png/SHA256E-s1280552--b7d115e8e6e729e874568c04fbce5ba3fece260cbea0ad7fef543f70fb5841ac.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 Vincent Demeester.png
@@ -0,0 +1,1 @@
+../../../../.git/annex/objects/pJ/6Q/SHA256E-s1401227--14f5799ec65c28c4f19d69dcff697e9f4eac0ca9bc8ddcb6e783c9fa75ce45d2.png/SHA256E-s1401227--14f5799ec65c28c4f19d69dcff697e9f4eac0ca9bc8ddcb6e783c9fa75ce45d2.png
\ No newline at end of file
www/vincent.demeester.fr/images/www-inspirations/Screenshot_2020-03-22 Zettelkasten.png
Binary file
www/vincent.demeester.fr/images/2020-04-15-16-12-54.png
Binary file
www/vincent.demeester.fr/images/bg.png
Binary file
www/vincent.demeester.fr/images/bg_blue.png
Binary file
www/vincent.demeester.fr/images/bg_gray.png
Binary file
www/vincent.demeester.fr/images/bg_green.png
Binary file
www/vincent.demeester.fr/images/bg_red.png
Binary file
www/vincent.demeester.fr/images/bg_yellow.png
Binary file
www/vincent.demeester.fr/images/comments.png
Binary file
www/vincent.demeester.fr/images/email.png
Binary file
www/vincent.demeester.fr/images/favicon.ico
Binary file
www/vincent.demeester.fr/images/favicon.png
Binary file
www/vincent.demeester.fr/images/fsfe.blogs.png
Binary file
www/vincent.demeester.fr/images/github.png
Binary file
www/vincent.demeester.fr/images/identi.png
Binary file
www/vincent.demeester.fr/images/imessage.png
Binary file
www/vincent.demeester.fr/images/key.png
Binary file
www/vincent.demeester.fr/images/lastfm.png
Binary file
www/vincent.demeester.fr/images/linkedin.png
Binary file
www/vincent.demeester.fr/images/logo.shortbrain.png
Binary file
www/vincent.demeester.fr/images/sbr-big.png
Binary file
www/vincent.demeester.fr/images/sbr-medium.png
Binary file
www/vincent.demeester.fr/images/sbr-small.png
Binary file
www/vincent.demeester.fr/images/stackoverflow.png
Binary file
www/vincent.demeester.fr/images/star.png
Binary file
www/vincent.demeester.fr/images/user_gray.png
Binary file
www/vincent.demeester.fr/images/vde.png
@@ -0,0 +1,1 @@
+../../../.git/annex/objects/J2/0X/SHA256E-s266717--a54f64874c8bb24992190a618a929571491b40b1b04645fd3e8012243fbac997.png/SHA256E-s266717--a54f64874c8bb24992190a618a929571491b40b1b04645fd3e8012243fbac997.png
\ No newline at end of file
www/vincent.demeester.fr/legacy/posts/2012-05-07-reinit-and-jekyll/index.html
@@ -0,0 +1,161 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2012-05-07-reinit-and-jekyll/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="" class="gray">
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Reinit and Jekyll</h1><a href='https://vincent.demeester.fr/posts/2012-05-07-reinit-and-jekyll/'></a>
+ <address class="signature">
+ <span class="date">Mon, 7 May, 2012</span>
+ <span class="words">(300 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#me">me</a></li>
+
+
+
+
+
+ <li class="tag tag-intro"><a href="/tags/#intro">intro<span>1</span></a></li>
+
+
+ <li class="tag tag-jekyll"><a href="/tags/#jekyll">jekyll<span>4</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>Two weeks ago, my <em>online</em> personal server has been attacked and, somehow, died. I’m in the process
+of re-installation of it but I’m going to hardened a bit the security on it. Anyway, this crash meant
+that every piece of site I maintain has been down. That’s why I moved this <em>identity site</em> on the
+github pages, using a CNAME ; That way I can crash as much as I want my server(s), this page should
+still be up for a while.</p>
+
+<p>And I’m switching on Jekyll for this website as It is supported by Github page, easy to use and easy
+to deploy elsewhere (if one day I want to move from Github).</p>
+
+<p>The rest of the post is going to be used as a <em>sandbox</em> post to test the site styles.</p>
+
+<blockquote>
+<p>This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.</p>
+
+<p>Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.</p>
+</blockquote>
+
+<h2 id="highlight">Highlight</h2>
+
+<div class="highlight"><pre class="chroma"><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">foo</span>
+ <span class="nb">puts</span> <span class="s1">'foo'</span>
+<span class="k">end</span></code></pre></div>
+
+<p>Some bash scriptโฆ</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="cp">#!/bin/bash
+</span><span class="cp"></span>update_gems<span class="o">()</span> <span class="o">{</span>
+ <span class="nb">echo</span> <span class="s2">"Update gems for all versions ? (y/N)"</span>
+ <span class="nb">read</span> UPDATE_GEMS
+ <span class="nb">test</span> -z <span class="s2">"</span><span class="si">${</span><span class="nv">UPDATE_GEMS</span><span class="si">}</span><span class="s2">"</span> <span class="o">&&</span> <span class="nv">UPDATE_GEMS</span><span class="o">=</span><span class="s2">"n"</span>
+ <span class="k">if</span> <span class="nb">test</span> <span class="s2">"</span><span class="si">${</span><span class="nv">UPDATE_GEMS</span><span class="si">}</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">"y"</span><span class="p">;</span> <span class="k">then</span>
+ <span class="k">for</span> version in <span class="sb">`</span>ls --color<span class="o">=</span>never <span class="nv">$HOME</span>/.rbenv/versions<span class="sb">`</span><span class="p">;</span> <span class="k">do</span>
+ <span class="nb">echo</span> <span class="s2">"Updating </span><span class="si">${</span><span class="nv">version</span><span class="p">%/</span><span class="si">}</span><span class="s2">"</span>
+ <span class="nv">RBENV_VERSION</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">version</span><span class="p">%/</span><span class="si">}</span><span class="s2">"</span> rbenv <span class="nb">exec</span> gem update
+ <span class="nv">RBENV_VERSION</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">version</span><span class="p">%/</span><span class="si">}</span><span class="s2">"</span> rbenv <span class="nb">exec</span> gem install bundler
+ <span class="k">done</span>
+ <span class="k">fi</span>
+<span class="o">}</span>
+
+update_gems</code></pre></div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2012-05-08-gitolite-quick-and-dirty-mirror/" title="Gitolite quick and dirty mirror">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/about/" title="About">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2012-05-08-gitolite-quick-and-dirty-mirror/index.html
@@ -0,0 +1,243 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2012-05-08-gitolite-quick-and-dirty-mirror/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="" class="gray">
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Gitolite quick and dirty mirror</h1><a href='https://vincent.demeester.fr/posts/2012-05-08-gitolite-quick-and-dirty-mirror/'></a>
+ <address class="signature">
+ <span class="date">Tue, 8 May, 2012</span>
+ <span class="words">(700 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-gitolite"><a href="/tags/#gitolite">gitolite<span>1</span></a></li>
+
+
+ <li class="tag tag-git"><a href="/tags/#git">git<span>3</span></a></li>
+
+
+ <li class="tag tag-linux"><a href="/tags/#linux">linux<span>4</span></a></li>
+
+
+ <li class="tag tag-mirror"><a href="/tags/#mirror">mirror<span>1</span></a></li>
+
+
+ <li class="tag tag-github"><a href="/tags/#github">github<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>I’m running a gitolite <em>instance</em> on my personal server to manage my repositories
+(personnal, private or public) ; and I am quickly going to share with you how I
+setup a <em>quick and dirty</em> mirror feature.</p>
+
+<p>First, I am using <strong>gitolite 3</strong>. The mirroring we are going to setup is not the
+<em>supported</em> <a href="http://sitaramc.github.com/gitolite/mirroring.html">mirroring <strong>built-in</strong></a>.
+We are going to implement a simplier way to set mirror thing :</p>
+
+<ol>
+<li>Write a custom gitolite command ; the idea is to be able to write <code>git-config</code>
+stuff.</li>
+<li>Write a hook that take a specific <code>git-config</code> (let say <code>mirror.url</code>) and do
+a simple mirroring.</li>
+</ol>
+
+<h1 id="gitolite-commands">Gitolite commands</h1>
+
+<p>Gitolite 3 has been rewritten to be more flexible : <a href="http://sitaramc.github.com/gitolite/g3why.html">Why a completely new version</a>.
+The rewrite made it really easy to extend gitolite. <del>I’ve fork <a href="https://github.com/vdemeester/gitolite">gitolite</a> on github</del>
+I’ve created a <a href="http://github.com/vdemeester/vdemeester-gitolite-local-code">repository git</a>
+to easily add commands to my gitolite instance via <em>local code</em>. The gitolite command I wrote is
+a quick and dirty script in shell to add <code>git config</code>. The source should speek
+for itself ; It <em>should</em> include some way to check if the given config is not
+already present in the <code>gitolite-admin</code> configuration file โ and so might be
+rewritten in <code>Perl</code>.</p>
+
+<p>The command is <code>write-git-config</code> because a <code>git-config</code> command already exists
+in the built-in commands.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="cp">#!/bin/sh
+</span><span class="cp"></span>
+<span class="c1"># Usage: ssh git@host write-git-config <repo> <key> <value></span>
+#
+<span class="c1"># Set git-config value for user-created ("wild") repo.</span>
+
+die<span class="o">()</span> <span class="o">{</span> <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span> ><span class="p">&</span><span class="m">2</span><span class="p">;</span> <span class="nb">exit</span> <span class="m">1</span><span class="p">;</span> <span class="o">}</span>
+usage<span class="o">()</span> <span class="o">{</span> perl -lne <span class="s1">'print substr($_, 2) if /^# Usage/../^$/'</span> < <span class="nv">$0</span><span class="p">;</span> <span class="nb">exit</span> <span class="m">1</span><span class="p">;</span> <span class="o">}</span>
+<span class="o">[</span> -z <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&&</span> <span class="o">[</span> -z <span class="s2">"</span><span class="nv">$2</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&&</span> <span class="o">[</span> -z <span class="s2">"</span><span class="nv">$3</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&&</span> usage
+<span class="o">[</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="o">=</span> <span class="s2">"-h"</span> <span class="o">]</span> <span class="o">&&</span> usage
+<span class="o">[</span> -z <span class="s2">"</span><span class="nv">$GL_USER</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&&</span> die GL_USER not <span class="nb">set</span>
+
+<span class="c1"># ----------------------------------------------------------------------</span>
+<span class="nv">repo</span><span class="o">=</span><span class="nv">$1</span><span class="p">;</span> <span class="nb">shift</span>
+<span class="nv">key</span><span class="o">=</span><span class="nv">$1</span><span class="p">;</span> <span class="nb">shift</span>
+<span class="nv">value</span><span class="o">=</span><span class="nv">$1</span><span class="p">;</span> <span class="nb">shift</span>
+
+<span class="c1"># this shell script takes arguments that are completely under the user's</span>
+<span class="c1"># control, so make sure you quote those suckers!</span>
+
+<span class="k">if</span> gitolite query-rc -q WRITER_CAN_UPDATE_DESC
+<span class="k">then</span>
+ gitolite access -q <span class="s2">"</span><span class="nv">$repo</span><span class="s2">"</span> <span class="nv">$GL_USER</span> W any <span class="o">||</span> die You are not authorised
+<span class="k">else</span>
+ gitolite creator <span class="s2">"</span><span class="nv">$repo</span><span class="s2">"</span> <span class="nv">$GL_USER</span> <span class="o">||</span> die You are not authorised
+<span class="k">fi</span>
+
+<span class="c1"># if it passes, $repo is a valid repo name so it is known to contain only sane</span>
+<span class="c1"># characters. This is because 'gitolite creator' return true only if there</span>
+<span class="c1"># *is* a repo of that name and it has a gl-creator file that contains the same</span>
+<span class="c1"># text as $GL_USER.</span>
+
+<span class="nv">configfile</span><span class="o">=</span><span class="sb">`</span>gitolite query-rc GL_REPO_BASE<span class="sb">`</span>/<span class="s2">"</span><span class="nv">$repo</span><span class="s2">"</span>.git/config
+
+git config --file <span class="s2">"</span><span class="nv">$configfile</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$key</span><span class="s2">"</span> <span class="s2">"</span><span class="nv">$value</span><span class="s2">"</span></code></pre></div>
+
+<h1 id="gitolite-hooks">Gitolite hooks</h1>
+
+<p>The next step is to write a quick <code>post-receive</code> hook that check if there is a
+certain <code>git-config</code> entry and run <code>git push --mirror</code>. The file is in
+<code>$HOME/.gitolite/hooks/common/post-receive</code> ; you could add a better system to
+hooks (to be able to add “dynamic” hooks, โฆ).</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="cp">#!/bin/sh
+</span><span class="cp"></span>
+<span class="c1"># Simple gitolite mirroring</span>
+
+<span class="c1"># flush STDIN coming from git, because gitolite's own post-receive.mirrorpush</span>
+<span class="c1"># script does the same thing</span>
+<span class="o">[</span> -t <span class="m">0</span> <span class="o">]</span> <span class="o">||</span> cat >/dev/null
+
+<span class="o">[</span> -z <span class="s2">"</span><span class="nv">$GL_REPO</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&&</span> die GL_REPO not <span class="nb">set</span>
+
+<span class="nv">target</span><span class="o">=</span><span class="sb">`</span>git config --get mirror.url<span class="sb">`</span>
+<span class="o">[</span> -z <span class="s2">"</span><span class="nv">$target</span><span class="s2">"</span> <span class="o">]</span> <span class="o">&&</span> <span class="nb">exit</span> <span class="m">0</span>
+
+<span class="c1"># Support a REPO variable for wildcard mirrors</span>
+<span class="nv">gl_repo_escaped</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span> <span class="nv">$GL_REPO</span> <span class="p">|</span> sed <span class="s1">'s/\//\\\//g'</span><span class="k">)</span>
+<span class="nv">target</span><span class="o">=</span><span class="k">$(</span><span class="nb">echo</span> <span class="nv">$target</span> <span class="p">|</span> sed -e <span class="s2">"s/REPO/</span><span class="nv">$gl_repo_escaped</span><span class="s2">/g"</span><span class="k">)</span>
+
+<span class="c1"># Do the mirror push</span>
+git push --mirror <span class="nv">$target</span></code></pre></div>
+
+<p>The next, and final step is to run <code>gitolite compile</code> to update links to hooks
+for every repositories.</p>
+
+<h1 id="for-real">For real</h1>
+
+<p>And finaly, this is the final step you’ll do.</p>
+
+<pre><code>$ ssh git@host write-git-config vincent/vcsh-home mirror.url git@github.com:vdemeester/vcsh-home.git
+$ git push
+Counting objects: 5, done.
+Delta compression using up to 2 threads.
+Compressing objects: 100% (3/3), done.
+Writing objects: 100% (3/3), 294 bytes, done.
+Total 3 (delta 2), reused 0 (delta 0)
+remote: To git@github.com:vdemeester/vcsh-home.git
+remote: 65681a8..701c990 master -> master
+To git@host:vincent/vcsh-home.git
+ 65681a8..701c990 master -> master
+</code></pre>
+
+<p>And that should be it !</p>
+
+<p><strong>Update 2012/10/04</strong> : Moved from gitolite fork to <em>gitolite local code</em>
+repository.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2012-05-13-jekyll-foreman-guard-bundler/" title="Jekyll Forman Guard Bundler">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2012-05-07-reinit-and-jekyll/" title="Reinit and Jekyll">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2012-05-13-jekyll-foreman-guard-bundler/index.html
@@ -0,0 +1,194 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2012-05-13-jekyll-foreman-guard-bundler/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="" class="gray">
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Jekyll Forman Guard Bundler</h1><a href='https://vincent.demeester.fr/posts/2012-05-13-jekyll-foreman-guard-bundler/'></a>
+ <address class="signature">
+ <span class="date">Sun, 13 May, 2012</span>
+ <span class="words">(300 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-jekyll"><a href="/tags/#jekyll">jekyll<span>4</span></a></li>
+
+
+ <li class="tag tag-ruby"><a href="/tags/#ruby">ruby<span>1</span></a></li>
+
+
+ <li class="tag tag-bundler"><a href="/tags/#bundler">bundler<span>1</span></a></li>
+
+
+ <li class="tag tag-guard"><a href="/tags/#guard">guard<span>1</span></a></li>
+
+
+ <li class="tag tag-foreman"><a href="/tags/#foreman">foreman<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>This post is a quick “How did I setup my Jekyll environnement ?”. We are going
+all the tools that are quite awesome in Ruby.</p>
+
+<h1 id="goal">Goal</h1>
+
+<p>The goal is simple :</p>
+
+<ol>
+<li>I want to be able to install any dependent <a href="http://rubygems.org">Gem</a> with a
+<em>on-liner</em> command</li>
+<li>I want to be able to run a <em>Jekyll server</em> that auto updates.</li>
+</ol>
+
+<p>We are going to play with : <a href="http://gembundler.com/">Bundler</a>,
+<a href="https://github.com/guard/guard">Guard</a> and <a href="https://github.com/ddollar/foreman">foreman</a>.</p>
+
+<h2 id="bundler">Bundler</h2>
+
+<p>Bundler let us run <code>bundle install</code> to get all Ruby Gems we will need ; It use
+a file name <code>Gemfile</code>. The gems we need are simple : <code>jekyll</code>, <code>guard</code> and some
+Guard extensions.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-ruby" data-lang="ruby"><span class="n">source</span> <span class="s2">"http://rubygems.org"</span>
+
+<span class="n">gem</span> <span class="s1">'jekyll'</span>
+<span class="n">gem</span> <span class="s1">'guard'</span>
+<span class="n">gem</span> <span class="s1">'guard-jekyll2'</span>
+<span class="n">gem</span> <span class="s1">'guard-shell'</span>
+<span class="n">gem</span> <span class="s1">'guard-bundler'</span></code></pre></div>
+
+<h2 id="guard">Guard</h2>
+
+<blockquote>
+<p>Guard is a command line tool to easily handle events on file system modifications.</p>
+</blockquote>
+
+<p>Guard will be watching file we told him and run action in consequence ; The file
+is name <code>Guardfile</code>.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-ruby" data-lang="ruby"><span class="n">guard</span> <span class="s1">'jekyll2'</span> <span class="k">do</span>
+ <span class="n">watch</span> <span class="sr">%r{.*}</span>
+<span class="k">end</span>
+
+<span class="n">guard</span> <span class="ss">:bundler</span> <span class="k">do</span>
+ <span class="n">watch</span><span class="p">(</span><span class="s1">'Gemfile'</span><span class="p">)</span>
+<span class="k">end</span>
+<span class="c1"># vim:filetype=ruby</span></code></pre></div>
+
+<h2 id="foreman">Foreman</h2>
+
+<p>Finally, foreman will let us declare our processes and will handle the start,
+forward the output and handle the shutdown. It can then export its configuration
+into more <em>production-ready</em> file (<code>init</code>, <code>upstard</code>, โฆ) ; It uses a file named
+<code>Procfile</code>.</p>
+
+<p>We will tell foreman to run :</p>
+
+<ul>
+<li>The jekyll build-in server : <code>jekyll --server</code></li>
+<li>Guard, to handle file changes <em>in background</em>.</li>
+</ul>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">web: bundle <span class="nb">exec</span> jekyll --server
+guard: bundle <span class="nb">exec</span> guard</code></pre></div>
+
+<p>And that’s all folk. Now, you just need to run foreman in the Jekyll-powered
+directory and edit your files.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2012-07-21-news/" title="News">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2012-05-08-gitolite-quick-and-dirty-mirror/" title="Gitolite quick and dirty mirror">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2012-07-21-news/index.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2012-07-21-news/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr" class="gray">
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">News</h1><a href='https://vincent.demeester.fr/posts/2012-07-21-news/'></a>
+ <address class="signature">
+ <span class="date">Sat, 21 July, 2012</span>
+ <span class="words">(300 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#me">me</a></li>
+
+
+
+
+
+ <li class="tag tag-news"><a href="/tags/#news">news<span>1</span></a></li>
+
+
+ <li class="tag tag-cyclisme"><a href="/tags/#cyclisme">cyclisme<span>1</span></a></li>
+
+
+ <li class="tag tag-vaadin"><a href="/tags/#vaadin">vaadin<span>1</span></a></li>
+
+
+ <li class="tag tag-java"><a href="/tags/#java">java<span>4</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <p>Je suis restรฉ assez longtemps silencieux, ร cause du boulot entre autre. Je
+vais donc remรฉdier un peu ร รงa en publiant un petit post <em>news</em> :-).</p>
+
+<ul>
+<li>Je suis fan de cyclisme. Mon vรฉlo de course est ma seconde paire de jambes.
+Enfin, le mot juste serait plutรดt รฉtait. Il y a quelques semaines, en
+rentrant du boulot, j’ai sentis un grosse vibration, puis plus moyen de
+tourner les pรฉdales. Intriguรฉ, j’ai jetรฉ un coup d’ลil au vรฉlo, et <em>oh rage
+oh dรฉsespoir</em> j’ai dรฉcouvert que la <em>fourche arriรจre</em> du vรฉlo c’รฉtait tout
+simplement fendue.</li>
+</ul>
+
+<p><img src="/images/2012/velo_casse.jpg" alt="Fourche arriรจre du vรฉlo" title="Fourche arriรจre du vรฉlo" /></p>
+
+<p>Il ne me restait plus que mes yeux pour pleurer et mes jambes pour faire les
+ 7kms qui restait ร effectuer jusqu’ร mon appartement.</p>
+
+<p>Bien entendu ce n’est que matรฉriel mais ce vรฉlo avait une grande importance
+ sentimentale : il avait mon รขge et appartenait ร mon pรจre quand j’รฉtais
+ petit.</p>
+
+<p>Maintenant il ne reste plus qu’ร sortir la carte bleue pour m’en procurer un
+ nouveauโฆ</p>
+
+<ul>
+<li><p>Je suis actuellement en vacances pour deux petites semaines (ouf !). Cela me
+permet, entre autre, de me rรฉentrainer ร monter des cols (vu que je suis
+dans les Alpes) ; parce qu’ร Bordeaux, c’est assez difficile d’en trouver.
+Par contre il me reste beaucoup de boulot pour retrouver ma forme d’il
+y a une dizaine d’annรฉe et de monter facilement le <em>Grand Colombier</em> !</p></li>
+
+<li><p>Je joue pas mal avec <a href="http://vaadin.com">Vaadin</a> en ce moment,
+principalement pour le boulot. J’annonce donc deux petits projets en cours :</p>
+
+<ol>
+<li><a href="http://vdemeester.github.com/vaadin-container-utils">vaadin-container-utils</a></li>
+<li>librarie utilitaire pour la crรฉation de Container vaadin.</li>
+<li><a href="http://vdemeester.github.com/vaadin-composite-layout">vaadin-composite-layout</a></li>
+<li>un composant vaadin hautement flexible (mais je suis mauvais pour les
+noms).</li>
+</ol></li>
+</ul>
+
+<p>Et “c’est tout pour le moment”.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2012-07-23-maven-release-gitflow/" title="Maven Release Gitflow">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2012-05-13-jekyll-foreman-guard-bundler/" title="Jekyll Forman Guard Bundler">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2012-07-23-maven-release-gitflow/index.html
@@ -0,0 +1,204 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2012-07-23-maven-release-gitflow/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr" class="gray">
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Maven Release Gitflow</h1><a href='https://vincent.demeester.fr/posts/2012-07-23-maven-release-gitflow/'></a>
+ <address class="signature">
+ <span class="date">Mon, 23 July, 2012</span>
+ <span class="words">(400 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-maven"><a href="/tags/#maven">maven<span>2</span></a></li>
+
+
+ <li class="tag tag-java"><a href="/tags/#java">java<span>4</span></a></li>
+
+
+ <li class="tag tag-git"><a href="/tags/#git">git<span>3</span></a></li>
+
+
+ <li class="tag tag-gitflow"><a href="/tags/#gitflow">gitflow<span>1</span></a></li>
+
+
+ <li class="tag tag-release"><a href="/tags/#release">release<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>I like a lot the <a href="http://nvie.com/posts/a-successful-git-branching-model/">gitflow</a> way of managing project.
+When working on maven project, there is few great plugins that helps to get
+the work done. One of them is <a href="http://maven.apache.org/plugins/maven-release-plugin">maven-release-plugin</a>.</p>
+
+<p>Inspired on this <a href="https://gist.github.com/1043970">gist</a>, I’ve come with
+a cool way of doing things (let say we want to release a 0.1 version of an
+artifact) :</p>
+
+<h1 id="prepare-the-pom-xml">Prepare the pom.xml.</h1>
+
+<p>It needs <code><scm></code> entries, <code><distributionManagement></code> entries
+(to know where to deploy the release artifact) and few options for the
+maven-release-plugin :</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-xml" data-lang="xml"><span class="nt"><project></span>
+
+ <span class="c"><!-- [โฆ] --></span>
+ <span class="nt"><build></span>
+ <span class="nt"><plugins></span>
+ <span class="c"><!-- [โฆ] --></span>
+ <span class="nt"><plugin></span>
+ <span class="nt"><groupId></span>org.apache.maven.plugins<span class="nt"></groupId></span>
+ <span class="nt"><artifactId></span>maven-release-plugin<span class="nt"></artifactId></span>
+ <span class="nt"><version></span>2.3.2<span class="nt"></version></span>
+ <span class="nt"><configuration></span>
+ <span class="nt"><tagNameFormat></span>v@{project.version}<span class="nt"></tagNameFormat></span>
+ <span class="nt"><pushChanges></span>false<span class="nt"></pushChanges></span>
+ <span class="nt"><localCheckout></span>true<span class="nt"></localCheckout></span>
+ <span class="nt"></configuration></span>
+ <span class="nt"></plugin></span>
+ <span class="c"><!-- [โฆ] --></span>
+ <span class="nt"></plugins></span>
+ <span class="nt"></build></span>
+ <span class="c"><!-- [โฆ] --></span>
+
+<span class="nt"></project></span></code></pre></div>
+
+<p>Few explanation here :</p>
+
+<ul>
+<li><code>tagNameFormat</code> is here to change the default tag name (which is <code>${project.artifactId}-${project.version}</code>) to a better one.</li>
+<li><code>pushChanges</code> set to <code>false</code> tells maven-release-plugin not to push
+changes (this will become useful)</li>
+<li><code>localCheckout</code> set to <code>true</code> tells maven-release-plugin to clone from
+local repository (not distant). This is especially useful here because we
+didn’t push anything (so not setting this option would result in a failure).</li>
+</ul>
+
+<h1 id="the-real-stuff">The real stuff</h1>
+
+<p>First create a release branch from develop.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">$ git checkout -b release/v0.1 develop</code></pre></div>
+
+<p>Then run the maven release stuff.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">$ mvn release:prepare <span class="c1"># change the pom, commit and tag version, and</span>
+ <span class="c1"># re-change pom (by incrementing SNAPSHOT version)</span>
+$ mvn release:perform <span class="c1"># get the tagged version, compile and deploy</span></code></pre></div>
+
+<p>And the real fun begins.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">$ git checkout develop <span class="c1"># get back to the develop branch</span>
+$ git merge --no-ff release/v0.1 <span class="c1"># merge the version back into develop</span>
+$ git checkout master <span class="c1"># go to the master branch</span>
+$ git merge --no-ff release/v0.1~1 <span class="c1"># merge the version back into master but</span>
+ <span class="c1"># the tagged version instead of the release/v0.1 HEAD</span>
+$ git branch -D release/v0.1 <span class="c1"># Removing the release branch</span>
+$ git push --all <span class="o">&&</span> git push --tags <span class="c1"># Finally push everything</span></code></pre></div>
+
+<p>The real magic here is the <code>git merge --no-ff release/v0.1~1</code> which will
+merge into master the commit before the HEAD of the branch <code>release/v0.1</code>.</p>
+
+<p>The next step would be to create a helper script that automates this and
+verify that the <code>pom.xml</code> has the right configuration options.</p>
+
+<p><strong>Edit 17:58</strong> : You can take a look <a href="https://github.com/vdemeester/java-config/blob/master/bin/mvn-release-flow">here</a></p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2012-12-16-gollum-comme-wiki-personnel/" title="Gollum Comme Wiki Personnel">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2012-07-21-news/" title="News">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2012-12-16-gollum-comme-wiki-personnel/index.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2012-12-16-gollum-comme-wiki-personnel/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr" class="gray">
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Gollum Comme Wiki Personnel</h1><a href='https://vincent.demeester.fr/posts/2012-12-16-gollum-comme-wiki-personnel/'></a>
+ <address class="signature">
+ <span class="date">Sun, 16 December, 2012</span>
+ <span class="words">(500 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#me">me</a></li>
+
+
+
+
+
+ <li class="tag tag-wiki"><a href="/tags/#wiki">wiki<span>1</span></a></li>
+
+
+ <li class="tag tag-gollum"><a href="/tags/#gollum">gollum<span>1</span></a></li>
+
+
+ <li class="tag tag-github"><a href="/tags/#github">github<span>2</span></a></li>
+
+
+ <li class="tag tag-personnel"><a href="/tags/#personnel">personnel<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>Il y a environ 4 mois j’ai eu un accident de vรฉlo ; un traumatisme crรขnien, des brulures sur la face, quelques points de sutures, un doigt cassรฉ et une hernie discale m’ont clouรฉ (et me clou encore) plus que d’habitude sur ma chaise de bureau. Le bon cรดtรฉ des choses, c’est que cela m’a permit de me poser et de rรฉflรฉchir une bonne faรงon d’รชtre efficace et organiser, au travail et ร la maison :-).</p>
+
+<p>Une des principales <em>action</em> que j’ai pris est d’utiliser un wiki local et synchronisรฉ sur <em>tout</em> mes PCs. Le <em>format</em> wiki est assez adaptรฉ ร une prise de note et ร la crรฉation de contenu plus complet (comme des <a href="http://shortbrain.org">articles</a> ou de la documentation pour des projets en cours). Les conditions รฉtaient les suivantes :</p>
+
+<ul>
+<li>Facilitรฉ de mise en place.</li>
+<li>Pas de base de donnรฉes.</li>
+<li><em>Merging</em> facile (<a href="http://git-scm.com">git</a> <em>rules my world</em>).</li>
+<li><a href="http://daringfireball.net/projects/markdown/">Markdown</a> comme syntaxe, car utilisรฉ ร peu prรจs partout (blogs, articles, READMEs, documentations).</li>
+<li>รditable ร partir d’une interface web ou de mon รฉditeur favoris.</li>
+</ul>
+
+<p>L’outil qui remplit presque toutes ces conditions s’appelle <a href="https://github.com/github/gollum">gollum</a>. C’est un moteur wiki, รฉcris en ruby, qui se base sur un repository <a href="http://git-scm.com">git</a>. Il est dรฉvelopper par l’รฉquipe de <a href="http://github.com">Github</a> et c’est celui qui est utilisรฉ par les pages wiki lร -bas. Il permet d’utiliser ร peu prรจs n’importe quel syntaxe (dont <a href="https://github.com/github/github-flavored-markdown">github-markdown</a> qui est assez proche de celle de <a href="http://johnmacfarlane.net/pandoc">pandoc</a>). Par ailleurs, comme il se base sur <a href="http://git-scm.com">git</a>, les points <em>“pas de base de donnรฉes”</em>, <em>“merging facile”</em> et <em>“รฉditable รฉgalement ร partir de mon รฉditeur favoris”</em> sont toutes remplies.</p>
+
+<p>Avec <a href="https://github.com/github/gollum">Gollum</a> vous avez un wiki markdown dรฉcentralisรฉ, รฉditable via une interface web ou via votre รฉditeur favoris.</p>
+
+<h2 id="mise-en-place">Mise en place</h2>
+
+<p>La mise en place est relativement simple ; aprรจs tout dรฉpend du besoin que vous avez. L’installation se fait par <a href="rubygems.org">RubyGem</a> ou en clonant le repository.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="c1"># Installation de gollum et du format markdown de github</span>
+$ gem install gollum gitub-markdown</code></pre></div>
+
+<p>Si vous n’utilisez pas <a href="https://github.com/sstephenson/rbenv">rbenv</a> ou <a href="https://rvm.io/">rvm</a> il est probable qu’il faille lancer la commande en root ou utiliser sudo.</p>
+
+<p>Ensuite, il suffit de lancer <a href="https://github.com/github/gollum">Gollum</a> dans un dossier qui est un repository git ; le tour est jouรฉ</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="c1"># J'ulitise ~/desktop/wiki pour mon wiki</span>
+$ <span class="nb">cd</span> ~/desktop/wiki <span class="o">&&</span> gollum</code></pre></div>
+
+<p>L’idรฉe finale est d’automatiser deux choses :</p>
+
+<ol>
+<li>Le dรฉmarrage de gollum</li>
+<li>La synchronisation du repository avec les diffรฉrents autres <em>remotes</em></li>
+</ol>
+
+<p>Suivant le systรจme d’exploitation et/ou la distribution utilisรฉes, il y a รฉnormรฉment de possibilitรฉ d’effectuer cette automatisation. Dans mon cas, j’ai une <a href="http://debian.org">Debian</a> assez light, avec surtout plein de scripts. Je dรฉmarre donc <a href="https://github.com/github/gollum">Gollum</a> au dรฉmarrage de ma session grรขce ร une script qui est lancรฉ dans la foulรฉe du gestionnaire de fenรชtre. La synchronisation se fait grรขce ร une tรขche planifiรฉe <em>cron</em> qui est “distribuรฉ” sur chacune de mes machines.</p>
+
+<p><em>C’est tout pour le moment</em> ;-).</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2013-09-08-maven-tmpfs/" title="Maven Tmpfs">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2012-07-23-maven-release-gitflow/" title="Maven Release Gitflow">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2013-09-08-maven-tmpfs/index.html
@@ -0,0 +1,274 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2013-09-08-maven-tmpfs/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Maven Tmpfs</h1><a href='https://vincent.demeester.fr/posts/2013-09-08-maven-tmpfs/'></a>
+ <address class="signature">
+ <span class="date">Sun, 8 September, 2013</span>
+ <span class="words">(600 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-maven"><a href="/tags/#maven">maven<span>2</span></a></li>
+
+
+ <li class="tag tag-tmpfs"><a href="/tags/#tmpfs">tmpfs<span>1</span></a></li>
+
+
+ <li class="tag tag-ssd"><a href="/tags/#ssd">ssd<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <p>Je suis un utilisateur convaincu de [maven](), malgrรฉ ces dรฉfauts, le moto
+<strong>“Convention over configuration”</strong> me va vraiment bien. Que ce soit au boulot ou
+ร la maison, j’ai plus d’ordinateurs รฉquipรฉs de ssd (ou de mรฉmoire flash) que de
+disque traditionnel (mรฉcanique ?). Pour augmenter un peu la durรฉe de vie de
+ces disques SSD, j’ai cherchรฉ ร savoir comment <em>dรฉporter</em> le <em>build</em> de maven
+(qui, pour rappel, se passe dans le dossier <code>target/</code>) hors du SSD ; ici ce
+sera dans le dossier <code>/tmp/</code> qui est montรฉ en mรฉmoire (merci <code>tmpfs</code>),
+mais on peut imaginer dรฉporter รงa sur un autre disque, etc.. Aprรจs quelques
+recherches j’ai trouvรฉs quelques inspirations.</p>
+
+<blockquote>
+<p><strong>Limitations</strong></p>
+
+<p>Dans la solution prรฉsentรฉe ci-dessous les principales limitations sont
+les suivantes (que j’essaierais de diminuer au fil du temp ;P) :</p>
+
+<ol>
+<li>Il est nรฉcessaire de modifier le pom.xml du projet ; cela ne s’appliquera
+donc pas ร tous les projets maven sans modification du pom.xml.</li>
+<li>Cela ne fonctionne que sur une plateforme qui support les liens
+symboliques (Linux, Mac OS X, et autre UNIX).</li>
+<li>Cela ne fonctionne qu’avec Java 7 ou plus.</li>
+<li>Si vous utilisez m2e, il va gentillement gueuler et c’est moche ; pour
+rรฉsoudre le problรจme, il faut faire un tour vers <a href="http://wiki.eclipse.org/M2E_plugin_execution_not_covered">M2E plugin execution
+not covered</a>.</li>
+</ol>
+</blockquote>
+
+<p>Pour [maven](), le dossier <code>target/</code> vient de la propriรฉtรฉ
+<code>project.build.directory</code>. Dans la thรฉorie, il suffirait de modifier (dans
+<code>$HOME/.m2/settings.xml</code>) cette propriรฉtรฉ et le tour serait jouer.
+Malheuresement ce n’est pas possible, <code>project.build.directory</code> est une
+propriรฉtรฉ interne et n’est, ร priori, pas modifiable.</p>
+
+<p>Notre souhait est le suivant :</p>
+
+<ol>
+<li>Le build doit se faire dans <code>/tmp/m2/</code>, ce qui pour un projet se traduit
+par <code>/tmp/m2/${groupId}:${artifactId}</code>.</li>
+<li>Le dossier <code>target/</code> dans les sources est un lien symbolique vers le
+dossier dans <code>/tmp/m2/</code></li>
+<li>On passe par un <strong>profile</strong> qui n’est <strong>pas actif</strong> par dรฉfaut (pour ne pas
+faire chier le monde) mais <strong>activable via une propriรฉtรฉ</strong> (maven nous permet
+de le faire et c’est cool <code>^_^</code>). La propriรฉtรฉ utilisรฉe sera
+<code>external.build.root</code>.</li>
+</ol>
+
+<p>Le code ci-dessous est repris directement de mon inspiration<sup class="footnote-ref" id="fnref:inspiration"><a href="#fn:inspiration">1</a></sup>. Il
+s’occupe de crรฉer le dossier <code>${groupId}:${artifactId}</code> dans
+<code>external.build.root</code> et de faire le lien dans le dossier courant.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-xml" data-lang="xml"><span class="nt"><project></span>
+ <span class="c"><!-- [โฆ] --></span>
+ <span class="nt"><profiles></span>
+ <span class="nt"><profile></span>
+ <span class="nt"><id></span>external-build-dir<span class="nt"></id></span>
+ <span class="nt"><activation></span>
+ <span class="nt"><activeByDefault></span>false<span class="nt"></activeByDefault></span>
+ <span class="nt"><property></span>
+ <span class="nt"><name></span>external.build.root<span class="nt"></name></span>
+ <span class="nt"></property></span>
+ <span class="nt"></activation></span>
+ <span class="nt"><build></span>
+ <span class="nt"><plugins></span>
+ <span class="nt"><plugin></span>
+ <span class="nt"><groupId></span>com.alexecollins.maven.plugin<span class="nt"></groupId></span>
+ <span class="nt"><artifactId></span>script-maven-plugin<span class="nt"></artifactId></span>
+ <span class="nt"><version></span>1.0.0<span class="nt"></version></span>
+ <span class="nt"><executions></span>
+ <span class="nt"><execution></span>
+ <span class="nt"><id></span>prep-work-tree<span class="nt"></id></span>
+ <span class="nt"><goals></span>
+ <span class="nt"><goal></span>execute<span class="nt"></goal></span>
+ <span class="nt"></goals></span>
+ <span class="nt"><phase></span>initialize<span class="nt"></phase></span>
+ <span class="nt"><configuration></span>
+ <span class="nt"><script></span>
+ import java.nio.file.*
+ def dir =
+ "${external.build.root}/${project.groupId}:${project.artifactId}"
+ println "using Maven dir ${dir}"
+ def dirPath = Paths.get(dir)
+ if (!Files.exists(dirPath)) {
+ Files.createDirectories(dirPath)
+ }
+ def target = Paths.get("${project.build.directory}")
+ if (!Files.exists(target)) {
+ Files.createSymbolicLink(target, dirPath)
+ }<span class="nt"></script></span>
+ <span class="nt"></configuration></span>
+ <span class="nt"></execution></span>
+ <span class="nt"><execution></span>
+ <span class="nt"><id></span>drop-symlink<span class="nt"></id></span>
+ <span class="nt"><goals></span>
+ <span class="nt"><goal></span>execute<span class="nt"></goal></span>
+ <span class="nt"></goals></span>
+ <span class="nt"><phase></span>clean<span class="nt"></phase></span>
+ <span class="nt"><configuration></span>
+ <span class="nt"><script></span>
+ import java.nio.file.*
+ def target = Paths.get("${project.build.directory}")
+ if (Files.isSymbolicLink(target)) {
+ Files.delete(target)
+ }
+ <span class="nt"></script></span>
+ <span class="nt"></configuration></span>
+ <span class="nt"></execution></span>
+ <span class="nt"></executions></span>
+ <span class="nt"><dependencies></span>
+ <span class="nt"><dependency></span>
+ <span class="nt"><groupId></span>org.codehaus.groovy<span class="nt"></groupId></span>
+ <span class="nt"><artifactId></span>groovy<span class="nt"></artifactId></span>
+ <span class="nt"><version></span>1.8.6<span class="nt"></version></span>
+ <span class="nt"></dependency></span>
+ <span class="nt"></dependencies></span>
+ <span class="nt"><configuration></span>
+ <span class="nt"><language></span>groovy<span class="nt"></language></span>
+ <span class="nt"></configuration></span>
+ <span class="nt"></plugin></span>
+ <span class="nt"></plugins></span>
+ <span class="nt"></build></span>
+ <span class="nt"></profile></span>
+ <span class="nt"></profiles></span>
+ <span class="c"><!-- [โฆ] --></span>
+<span class="nt"></project></span></code></pre></div>
+
+<p>Ainsi, il suffit ensuite d’avoir quelques choses du genre dans son
+<code>$HOME/.m2/settings.xml</code> pour que les builds qui ont ce profil se <em>build</em>
+dans <code>/tmp/m2/</code>. On peut aussi ne rien avoir dans <code>$HOME/.m2/settings.xml</code>
+et utilise <code>-Dexternal.build.root=/tmp/m2/</code> avec la commande <code>mvn</code>.</p>
+
+<div class="highlight"><pre class="chroma"><code class="language-xml" data-lang="xml"><span class="nt"><settings></span>
+ <span class="c"><!-- [โฆ] --></span>
+ <span class="nt"><profiles></span>
+ <span class="nt"><profile></span>
+ <span class="nt"><id></span>build-in-ramfs<span class="nt"></id></span>
+ <span class="nt"><properties></span>
+ <span class="nt"><external.build.root></span>/tmp/m2/<span class="nt"></external.build.root></span>
+ <span class="nt"></properties></span>
+ <span class="nt"></profile></span>
+ <span class="nt"></profiles></span>
+ <span class="nt"><activeProfiles></span>
+ <span class="nt"><activeProfile></span>build-in-ramfs<span class="nt"></activeProfile></span>
+ <span class="nt"></activeProfiles></span>
+ <span class="c"><!-- [โฆ] --></span>
+<span class="nt"></settings></span></code></pre></div>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:inspiration"><a href="http://elehack.net/writings/programming/maven-target-in-tmpfs">Putting Maven build directories out-of-tree</a> par <a href="http://elehack.net/">Michal Ekstrand</a>
+ <a class="footnote-return" href="#fnref:inspiration"><sup>[return]</sup></a></li>
+</ol>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2013-10-12-podcasts/" title="Podcasts">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2012-12-16-gollum-comme-wiki-personnel/" title="Gollum Comme Wiki Personnel">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2013-10-12-podcasts/index.html
@@ -0,0 +1,177 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2013-10-12-podcasts/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr" class="gray">
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Podcasts</h1><a href='https://vincent.demeester.fr/posts/2013-10-12-podcasts/'></a>
+ <address class="signature">
+ <span class="date">Sat, 12 October, 2013</span>
+ <span class="words">(400 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#me">me</a></li>
+
+
+
+
+
+ <li class="tag tag-music"><a href="/tags/#music">music<span>1</span></a></li>
+
+
+ <li class="tag tag-podcast"><a href="/tags/#podcast">podcast<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<blockquote>
+<p>Voici un petit billet prรฉsentant les diffรฉrents podcast que j’รฉcoute plus ou
+moins rรฉguliรจrement.</p>
+</blockquote>
+
+<p>J’รฉcoute รฉnormรฉment de musique et de podcast ; je passe beaucoup de temps avec
+des รฉcouteurs sur la tรชte ou la chaine hifi en route. Les podcasts ont une grande
+place. Voici une liste plus ou moins bien triรฉs de ceux auxquels je suis
+souscrit et/ou que j’รฉcoute en ce moment. Je tiendrais peut-รชtre ce post
+ร jour ou en crรฉerait un nouveau sinon :-).</p>
+
+<h2 id="geek-co">Geek & co</h2>
+
+<p>Je suis un developpeur, un geek et convaincu des logiciels libres, les
+podcasts qui suivent reflรจte assez cette partie lร de mon identitรฉ.</p>
+
+<ul>
+<li><a href="http://www.captainweb.net/">L’apรฉro de Captain (fr)</a> : dans le genre geeky, dรฉjantรฉ et sauvage, en franรงais, on ne fait pas mieux. Pas vraiment safe for work, et pas tout ร fait “libriste” comme j’aime, les tranches de rires sont garanties ; mรชme si parfois on est un peu verreux d’avoir รฉcouter jusqu’ร la fin et le bien nommรฉ “wazzuf”.</li>
+<li><a href="http://www.agencetousgeeks.com/">Agence Tous Geeks (fr)</a> : fils cachรฉ de l’apรฉro du captain, on y retrouve des amis (et membres de ce dernier), mais c’est un peu plus calme.</li>
+<li><a href="http://bazingcast.com/about/">Bazingcast (fr)</a> : podcast geek, plus posรฉ que les deux prรฉcรฉdents mais avec
+des dรฉbats, des trolls et tout ce que l’on peut attendre de geeks.</li>
+<li><a href="http://www.captainposix.net/">Parole de Tux (fr-be)</a> : podcast venant de nos voisin belge, pas trop long et plutรดt sympa ; et si comme moi vous adorez l’accent belge, c’est le top.</li>
+<li><a href="http://faif.us/">Free as in Freedom (en)</a> : podcast parlant de logiciel
+libre principalement cรดtรฉ license, truc lรฉgal, etc.. en anglais, faut
+parfois s’accrocher.</li>
+<li><a href="http://episodes.gitminutes.com/">Git Minutes (en)</a> : podcast ร propos de
+Git et des outils de son รฉcosystรจme (vcsh, etc..).</li>
+</ul>
+
+<h2 id="radio">Radio</h2>
+
+<p>J’aime bien la radio, bien plus que la tรฉlรฉvision (que j’allume si peu qu’ร
+chaque fois la box se met ร jour <code>;-p</code>).</p>
+
+<ul>
+<li><a href="http://www.franceinter.fr/emission-laura-leishman-project">France Inter - LLP (Laura leishman Project)</a></li>
+<li><a href="http://radiofrance-podcast.net/podcast09/rss_12265.xml">Le Mouv’ - Laura Leishman Project</a></li>
+<li><a href="http://www.franceinter.fr/emission-interception">France Inter - Interception</a></li>
+<li><a href="http://www.la-bas.org/">France Inter - lร -bas si j’y suis</a></li>
+<li><a href="http://www.franceculture.fr/podcast/4689840">France Culture - Pixel</a></li>
+<li><a href="http://www.franceculture.fr/podcast/4685228">France Culture - Place de la toile</a></li>
+<li><a href="http://www.franceculture.fr/podcast/4689418">France Culture - Philippe Meyer</a></li>
+<li><a href="http://radiofrance-podcast.net/podcast09/rss_12582.xml">Le Mouv’ - Glitch (sur le Mouv’)</a></li>
+<li><a href="http://radiofrance-podcast.net/podcast09/rss_12691.xml">Le Mouv’ - Code Source</a></li>
+<li><a href="http://radiofrance-podcast.net/podcast09/rss_12190.xml">Le Mouv’ - Suivez le geek</a></li>
+<li><a href="http://www.divergence-fm.org/-http-www-divergence-fm-org-ecrire-exec-rubrique-id_rubrique-61-.html">Divergence Numerique</a></li>
+</ul>
+
+<h2 id="musique">Musique</h2>
+
+<p>Les podcast suivant sont purement musique, tous musique <em>techno</em> ou
+trance (que j’aime bien).</p>
+
+<ul>
+<li><a href="http://podcasts.flaix.fr/corstencountdown">Ferry Corsten - Corsten Countdown</a></li>
+<li><a href="http://www.galexmusic.com/podcast/gareth.xml">Gareth Emery Podcast</a></li>
+<li><a href="http://feedproxy.feedburner.com/Tiestos_club_life">Tiesto Club Life</a></li>
+<li><a href="http://oakenfold.libsyn.com/rss">Oakenfold Perfecto Podcast</a></li>
+</ul>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2014-03-24-redesign-et-r%C3%A9solutions/" title="Redesign Et Rรฉsolutions">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2013-09-08-maven-tmpfs/" title="Maven Tmpfs">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2014-03-24-redesign-et-rรฉsolutions/index.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2014-03-24-redesign-et-r%C3%A9solutions/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Redesign Et Rรฉsolutions</h1><a href='https://vincent.demeester.fr/posts/2014-03-24-redesign-et-r%C3%A9solutions/'></a>
+ <address class="signature">
+ <span class="date">Mon, 24 March, 2014</span>
+ <span class="words">(600 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#me">me</a></li>
+
+
+
+
+
+ <li class="tag tag-jekyll"><a href="/tags/#jekyll">jekyll<span>4</span></a></li>
+
+
+ <li class="tag tag-design"><a href="/tags/#design">design<span>1</span></a></li>
+
+
+ <li class="tag tag-images"><a href="/tags/#images">images<span>1</span></a></li>
+
+
+ <li class="tag tag-redesign"><a href="/tags/#redesign">redesign<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>Un <em>tout petit</em> post pour parler rapidement, entre autre, du redesign de <a href="http://vincent.demeester.fr">vincent.demeester.fr</a> et de mes rรฉsolutions.</p>
+
+<h2 id="redesign">Redesign</h2>
+
+<p>Les raisons de ce redesign sont assez simple : je change d’employeur et de ville (retour sur Paris <code>\o/</code>).
+Cela fait pas mal de changement, et en voulant mettre ร jour la page d’accueil (ce que je n’ai toujours pas
+fait <code>;-P</code>), j’avais envie de <em>dรฉmรฉnager</em> le site en quelques sortes.</p>
+
+<p>Pour l’inspiration c’est assez facile ร trouver, regarder <a href="http://medium.com">medium</a>, le site de
+<a href="http://www.viksit.com/">Viksit Gaur</a> ou encore celui de <a href="http://silent-strength.com/">Michael</a> (coucou <code>:-P</code>).
+J’adore ce genre de site, assez รฉpurรฉ mais avec une partie fixe (ร gauche ou ร droite) et avec des images changeantes.</p>
+
+<p>Les images en fond de l’espace de gauche peuvent changer d’une page ร l’autre. Je suis en train de m’amuser un peu
+avec <a href="http://jekyllrb.com">Jekyll</a>. Il faut que je trouve un moyen d’optimiser un peu les images que j’utilise
+parce que lร je joue un peu le bourrin.</p>
+
+<h2 id="rรฉsolutions">Rรฉsolutions</h2>
+
+<p>Nouvelle annรฉe, nouveau boulot, implique nouvelles rรฉsolutions. Il y a deux aspects ร ces <em>rรฉsolutions</em> : sur un plan
+informatique/geek/travail/organisation, et sur un plan purement <em>physique</em>.</p>
+
+<p>Mon retour sur Paris devrait me permettre de participer ร un peu plus d’รฉvรจnements, notamment du cรดtรฉ des Java User Group, mais
+aussi FSFE, et j’en passe. Je compte รฉgalement continuรฉ ร jouer le <em>factotum</em> en me gardant un peu de temps au niveau
+personnel pour travailler sur des aspects <em>geek</em> que je n’aurais peut-รชtre pas l’occasion de pratiquer au travail.
+Au niveau de mes <em>points d’entrรฉes</em> sur le web, je compte remettre un peu en route la partie blog de ce site et
+tourner shortbrain.org (ou autre) en un site plus “documentation” en me basant sur mes notes (powered by <a href="http://org-mode.org">org-mode</a>).
+Je me suis รฉgalement remis ร <a href="https://www.gnu.org/software/emacs/">Gnu Emacs</a> et <em>oh god</em> qu’est-ce que c’est bon <code>:-D</code>.</p>
+
+<p>Au niveau phyisque, dans la continuitรฉ de la fin 2012, l’annรฉe 2013 a probablement รฉtรฉ la pire de ma vie. Les
+problรจmes de dos c’est pas facile tous les jours.. En fรฉvrier, j’avais peur de ne jamais remonter sur un vรฉlo ; en Mai
+je remontais pour la premiรจre fois sur le vรฉlo, en Septembre je faisais 40km par semaine et en dรฉcembre j’รฉtais
+presque capable de faire 30km en une journรฉe. Mรจme si l’annรฉe 2014 a mal commencรฉ (je me suis felรฉ un cรดte en Janvier),
+mes objectifs pour cette annรฉe et les futurs sont nettement plus positif. Le <a href="http://fitbit.com">fitbit</a> que j’ai
+acquis en Fรฉvrier me permet d’avoir un objectif de marche (certes assez modeste) de 10000 pas et 8,05 km par jour.
+Je compte bien me fixer d’autre objectifs : monter la barre plus haut (15000 voir plus), faire 50km de vรฉlo
+sur une journรฉe.</p>
+
+<p>Les objectifs physiques ร trรจs long termes sont รฉgalement assez simples : retrouver ma forme physique et ne plus รชtre
+gรฉnรฉ ร cause du dos. En gros c’est : รชtre capable de faire 120km de vรฉlo et monter des cols (Col du Sapenay, Mont Revard)
+et ร long terme, faire des courses de footing (i.e. 10km, Paris-Versaille, Semi-marathon, marathon :D).</p>
+
+<p>Sur ce, je vais retourner ร mes cartons :-P.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2014-10-27-docker-1.3-ecosystem/" title="Docker 1.3 et son รฉcosystรจme">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2013-10-12-podcasts/" title="Podcasts">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2014-10-27-docker-1.3-ecosystem/index.html
@@ -0,0 +1,383 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2014-10-27-docker-1.3-ecosystem/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Docker 1.3 et son รฉcosystรจme</h1><a href='https://vincent.demeester.fr/posts/2014-10-27-docker-1.3-ecosystem/'></a>
+ <address class="signature">
+ <span class="date">Mon, 27 October, 2014</span>
+ <span class="words">(1700 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#zenika">zenika</a></li>
+
+
+
+
+
+ <li class="tag tag-docker"><a href="/tags/#docker">docker<span>3</span></a></li>
+
+
+ <li class="tag tag-fig"><a href="/tags/#fig">fig<span>1</span></a></li>
+
+
+ <li class="tag tag-hub"><a href="/tags/#hub">hub<span>1</span></a></li>
+
+
+ <li class="tag tag-boot2docker"><a href="/tags/#boot2docker">boot2docker<span>1</span></a></li>
+
+
+ <li class="tag tag-container"><a href="/tags/#container">container<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+<div class="notice">Cet article est disponible sur le <a href="http://blog.zenika.com/">Blog de Zenika</a> ร l'adresse suivante : <a href="http://blog.zenika.com/index.php?post/2014/10/27/Docker-1-3-et-son-ecosysteme">http://blog.zenika.com/index.php?post/2014/10/27/Docker-1-3-et-son-ecosysteme</a>. Cet publication me sert de mirroir / sauvegarde.</div>
+
+<p>Le <strong>16 octobre dernier</strong>, <ins>Docker est passรฉ en version 1.3</ins>. C'est une
+bonne occasion de faire un point sur ce qu'apportent les mises ร jour
+qui sont sorties depuis la 1.0. Nous allons รฉgalement en profiter pour
+regarder les news <strong>importantes</strong> de l'รฉcosystรจme Docker.</p>
+
+
+<p><img src="/public/Billet_0511/docker_container_engine_logo.png" alt="Docker" title="Docker" /></p>
+
+
+<p>Rappel trรจs rapide, <strong>Docker est une plate-forme ouverte ร destination des dรฉveloppeurs et administrateurs systรจmes visant ร faciliter la construction et le dรฉploiement d'applications distribuรฉes</strong>. De maniรจre
+moins marketing, l'idรฉe derriรจre Docker est d'<strong>automatiser</strong> le <strong>dรฉploiement</strong> d'environnements sous forme de <strong>conteneurs lรฉgers</strong>, portables et auto-suffisants ; les conteneurs permettant d'isoler
+l'exรฉcution des applications dans des contextes d'exรฉcution. Pour ce
+faire, Docker, รฉcris en <a href="http://golang.org/">Go</a>, reprend les bases de <strong>LXC</strong>, utilise les fonctionnalitรฉs
+du <strong>noyau Linux</strong> (CGroups, Namespaces, โฆ) et se base <em>initialement</em> sur un
+systรจme de fichier "en oignons" AUFS ; D'autres backend sont supportรฉs
+รฉgalement comme BTRFS ou <em>devicemapper</em> (LVM).</p>
+
+
+<p>Depuis le 9 juin 2014 et la release de la version 1.0 "production-read", l'รฉquipe derriรจre Docker n'a pas chomรฉ et 3
+nouvelles mises ร jour sont sorties depuis ; ร savoir que les
+<em>releases</em> de Docker se font ร un rythme prรฉ-dรฉfini, "ร -la" Linux,
+tout ce qui est prรชt et testรฉ est intรฉgrรฉ ร la release qui
+suit. Voyons, de faรงon non-exhaustive, quelles sont les princiales
+amรฉliorations apportรฉes par ces diffรฉrentes versions.</p>
+
+<h4>Hub : Images officielles et language stack</h4>
+
+
+<p>Le <strong>Hub</strong>, tel qu'il a รฉtรฉ nommรฉ aprรจs la sortie de Docker 1.0 est <strong>un dรฉpรดt des images Docker</strong> de tout-un-chacun qui souhaite les partager.</p>
+
+
+<p>Au dรฉbut de l'รฉtรฉ, Docker Inc. a annoncรฉ l'apparition des <strong>dรฉpots officiels</strong>. L'idรฉe est d'estampiller des images Docker comme officielles,
+c'est ร dire vรฉrifiรฉes et garanties comme รฉtant issues et supportรฉes par
+les mainteneurs des projets. De nombreuses images officielles existent
+dรฉjร pour les principaux projets open-source, comme Ubuntu, MongoDB,
+etc. Toute communautรฉ open-source ou mรชme tout รฉditeur logiciel peut
+entrer en contact avec l'รฉquipe Docker pour voir son/ses images
+estampillรฉes "officielles", aprรจs validation. Cette รฉtiquette vient se
+rajouter ร l'รฉtiquette "<em>automated build repository</em>", prรฉcรฉdement
+appelรฉe <em>verified</em> (ce qui prรฉtait ร confusion) qui donne la garantie
+ร l'utilisateur que l'image a รฉtรฉ construite de maniรจre automatique
+par l'infrastructure de Docker Inc. Il est รฉgalement ร noter que la version
+1.3.0 de Docker apporte la vรฉrification de la provenance et de
+l'intรฉgritรฉ des images officielles via signature รฉlectronique ; mรชme si
+pour l'instant c'est en <em>work-in-progress</em>.</p>
+
+
+<p>Un autre ajout rรฉcent au Docker Hub, datant de fin septembre, vaut le
+dรฉtour : les l<strong>anguage stack</strong>, des images de bases <em>pre-construites</em> avec tous les outils nรฉcessaires pour faire tourner une application dans un langage donnรฉ. Un dรฉveloppeur souhaitant rapidement construire
+un conteneur avec, par exemple, une application Clojure, n'a plus
+besoin de <em>rรฉinventer la roue</em> (i.e. partir d'une image de base, installer
+le JDK, installer lein, etc.). Il lui suffit de partir d'une des
+<em>language stack</em>, ici clojure.</p>
+
+<pre class="bash code bash" style="font-family:inherit">FROM clojure
+COPY . <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>src<span style="color: #000000; font-weight: bold;">/</span>app
+WORKDIR <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>src<span style="color: #000000; font-weight: bold;">/</span>app
+CMD <span style="color: #7a0874; font-weight: bold;">[</span><span style="color: #ff0000;">"lein"</span>, <span style="color: #ff0000;">"run"</span><span style="color: #7a0874; font-weight: bold;">]</span></pre>
+
+
+<h4>Restart policies (1.2.0)</h4>
+
+
+<p>Docker 1.2 a apportรฉ une option en plus ร la commande <code>run</code> :
+<code>--restart</code>. Il permet de dรฉfinir une <strong>politique de redรฉmarrage</strong> dans
+le cas oรน le conteneurs viendrait ร mourrir, que ce soit de maniรจre
+normale (code de retour ร 0) ou inattendue (<em>failure</em>, code de retour
+diffรฉrent de 0). Trois options sont disponibles pour l'instant :</p>
+
+<ul>
+<li><strong>no</strong> : pas de redรฉmarrage, fonctionnement par dรฉfaut.</li>
+<li><strong>on-failure</strong>: redรฉmarrage automatique si le conteneur s'est terminรฉ de faรงon anormale. Il est possible d'ajouter un nombre maximum de redรฉmarrage ; avec <code>--restart=on-failure:3</code> docker essaiera de redรฉmarrer 3 fois avant d'abandonner.</li>
+<li><strong>always</strong> : redรฉmarrage automatique, tout le temps, erreurs ou pas.</li>
+</ul>
+
+<h4>Injection de processus (1.3.0)</h4>
+
+
+<p>La possibilitรฉ de voir ce qui se passe dans le container, et par
+consรฉquent de s'en servir pour debugger, s'est averรฉ longtemps
+complexe. Dans les <em>premiers jours</em> de Docker, l'installation d'un
+dรฉmon ssh รฉtait une solution commune. Cependant, celร complexifiait la
+crรฉation d'un conteneur ; en effet, Docker est fait pour lancer et isoler
+une seule commande, l'ajout d'un dรฉmon sshd imposait alors de mettre
+en place une solution du type <em>init</em> comme supervisord, runit, ou
+autres. Un article de Jรฉrรดme Petazonni, employรฉ Docker Inc,
+a mis les choses au point :
+<strong><a href="http://jpetazzo.github.io/2014/06/23/docker-ssh-considered-evil/">If you run SSHD in your Docker containers, you're doing it wrong!</a></strong>,
+littรฉralement "<em>Si vous faites tourner SSHD dans vos container Docker, vous vous trompez</em>". Jรฉrรดme avait crรฉรฉ ร l'รฉpoque un outil,
+<a href="https://github.com/jpetazzo/nsenter">nsenter</a>, qui รฉtait (et est toujours) installable en passant par un container, histoire de montrer
+un peu de magie.</p>
+
+
+<p>La version 1.3 de Docker intรจgre un nouvelle commande, <code>exec</code> qui
+n'est autre que nsenter, en mieux, directement intรฉgrรฉ ร Docker, plus
+besoin de passer par un outil externe. <strong>Il devient donc possible d'executer n'importe quelle process ร l'intรฉrieur donc container, qui est en cours d'exรฉcution</strong>. Ainsi un simple <code>docker exec -it ubuntu_bash bash</code> et
+nous voici dans une session bash ร l'intรฉrieur du conteneur. Bien
+entendu, comme pour nsenter, cela ne change pas l'idรฉe derriรจre Docker
+qui est "une application par conteneur" ; la commande <code>exec</code> est
+surtout prรฉsente pour rรฉpondre ร des problรฉmatiques de <em>debug</em> et de
+<em>developpement</em>.</p>
+
+
+<h4>Cycle de vie dโun container (1.3.0)</h4>
+
+
+<p>Une autre nouvelle commande arrive avec la version 1.3.0 de Docker,
+c'est <code>create</code>. Beaucoup d'utilisateur ont demandรฉ d'รชtre capable
+de sรฉparer la crรฉation initiale de conteneur et son lancement ;
+auparavant il n'existait que la commande <code>run</code> qui faisait les deux
+d'un coup.</p>
+
+<pre class="bash code bash" style="font-family:inherit">$ docker create <span style="color: #660033;">-t</span> <span style="color: #660033;">-i</span> fedora <span style="color: #c20cb9; font-weight: bold;">bash</span>
+6d8af538ec541dd581ebc2a24153a28329acb5268abe5ef868c1f1a261221752
+$ docker start <span style="color: #660033;">-a</span> <span style="color: #660033;">-i</span> 6d8af538ec5
+bash-<span style="color: #000000;">4.2</span><span style="color: #666666; font-style: italic;">#</span></pre>
+
+
+<h4>Options de sรฉcuritรฉ (1.3.0)</h4>
+
+
+<p>Les utilisateurs de SELinux ou AppArmor vont รชtre content, la commande
+<code>--security-opt</code>, arrivรฉe avec la version 1.3.0, permet les <em>labels</em>
+et <em>profiles</em> de ces derniers, ce qui donne quelque chose comme :</p>
+
+<pre class="bash code bash" style="font-family:inherit">docker run <span style="color: #660033;">--security-opt</span> label:<span style="color: #7a0874; font-weight: bold;">type</span>:svirt_apache <span style="color: #660033;">-i</span> <span style="color: #660033;">-t</span> centos <span style="color: #c20cb9; font-weight: bold;">bash</span></pre>
+
+
+<p>L'avantage principal de cette nouvelle commande, c'est, sur
+les systรจmes qui sont configurรฉs avec SELinux ou AppArmor, de pouvoir
+donner des privilรจges de maniรจre plus fine qu'avec l'option
+<code>--privileged</code> (qui donne tout) et ainsi diminuer les risques
+potentiels.</p>
+
+
+<h4>Boot2docker</h4>
+
+
+<p>Docker s'appuyant sur des fonctionnalitรฉes de noyau Linux, son usage
+est <em>limitรฉ</em> ร un systรจme hรดte avec un noyau Linux. Le projet
+boot2docker vise ร enlever cette barriรจre en <strong>permettant d'avoir la commande docker sous Mac OS X et Windows</strong>. Il s'agit ni plus ni moins
+d'une machine virtuelle VirtualBox lรฉgรจre, basรฉe sur la distribution
+Tiny Core Linux, pour avoir un <em>overhead</em> le plus faible possible.
+L'utilisation de boot2docker n'est pas encore totalement transparente,
+principalement pour la gestion des ports ou encore du montage des
+volumes du Host (OS X ou Windows) dans le conteneur Docker. La version
+1.3 de docker, et la version correspondante de boot2docker, permettent
+maintenant aux utiliseurs de Mac OS X de monter leur dossier <em>hรดtes</em>
+dans le conteneur.</p>
+
+
+<h4>Fig 1.0</h4>
+
+
+<p><a href="http://www.fig.sh/">Fig</a> est un outil de dรฉveloppement basรฉ sur Docker, รฉcrit en Python. L'idรฉe est de
+dรฉfinir son environnement via un fichier YAML, que ce soit pour le
+code sur lequel nous travaillons mais รฉgalement les services externes
+desquels notre application dรฉpend (Base de donnรฉes, ''Message
+queue'', etc.).</p>
+
+
+<p>Nous avons donc, par exemple, un <code>Dockerfile</code> :</p>
+
+<pre class="bash code bash" style="font-family:inherit">FROM clojure:lein-2.5.0
+ADD . <span style="color: #000000; font-weight: bold;">/</span>code
+WORKDIR <span style="color: #000000; font-weight: bold;">/</span>code
+RUN lein run</pre>
+
+
+
+<p>Et un <code>fig.yml</code> :</p>
+
+<pre>[yaml]
+web:
+ build: .
+ command: lein run
+ links:
+ - db
+ ports:
+ - "8000:8000"
+db:
+ image: postgres
+</pre>
+
+
+<p>Enfin un petit <code>fig up</code> et c'est gagnรฉ, nous obtenons notre base de donnรฉes
+relationnelle qui tourne, notre appli qui a รฉtรฉ construite et qui
+tourne aussi, et qui est liรฉ ร notre conteneur db. Il existe bien d'autres
+commandes (<code>start</code>, <code>stop</code>, <code>destroy</code>, etc.).</p>
+
+
+<p>Fig รฉtait initialement dรฉveloppรฉ par <a href="https://www.orchardup.com/">Orchard</a>, qui a รฉtรฉ acquis cette
+annรฉe par Docker Inc. Ce 17 octobre, l'รฉquipe Docker a donc fait un release 1.0 de
+Fig en ajoutant le support ร docker 1.3 et ร boot2docker. Un certain nombre de commandes et de
+nouvelles fonctionnalitรฉes ont รฉtรฉs ajoutรฉes, notament :</p>
+
+<ul>
+<li><code>fig port</code>, qui liste les ports par service,</li>
+<li><code>fig pull</code>, qui rรฉcupรจre la derniรจre version d'un service,</li>
+<li><code>fig restart</code>, qui redรฉmarre les conteneurs (<code>stop</code> et <code>start</code>)</li>
+<li>le support de <code>.dockerignore</code></li>
+<li>le support de connection en TLS au daemon Docker</li>
+<li>et pas mal d'autres options.</li>
+</ul>
+
+<p>Mais l'annonce principale accompagnant cette version est que <strong>Fig ne recevra plus de mise ร jour majeure ร partir de cette version 1.0</strong>
+puisque l'รฉquipe Docker travaille pour <strong>intรฉgrer les fonctionnalitรฉs</strong>
+que Fig apporte, <strong>directement dans Docker</strong> ; ce qui est une
+excellente nouvelle.</p>
+
+
+<h4>Partenariat avec Microsoft</h4>
+
+
+<p>Cela transpirait ces derniers mois, dans les diffรฉrentes confรฉrences
+et meetups, Microsoft s'intรฉressait de trรจs prรชt ร Docker. C'est
+maintenant officiel, <strong>Docker Inc et Microsoft sont partenaires</strong>. Le
+partenariat couvre pour l'instant les sujets suivants :</p>
+
+<ul>
+<li>Ajouter le support de windows comme hรดte Docker.</li>
+<li>Pour Microsoft, supporter les API <em>open-orchestration</em> de Docker.</li>
+<li>Intรฉgration de Docker dans Microsoft Azure.</li>
+<li>Collaboration รฉtroite sur les applications qui ont besoin de plusieurs conteneur (i.e. ce que Fig fait de mieux), et le support d'application qui sont composรฉs de conteneurs Linux et Windows.</li>
+</ul>
+
+<p>Le but <em>ultime</em> de Docker quand il a รฉtรฉ distribuรฉ de faรงon libre
+รฉtait : "__Construire le 'bouton' qui permet ร toutes applications
+d'รชtre construites et dรฉployรฉes sur n'importe quel serveur, n'importe
+oรน.__" (C'est nettement plus classe en anglais : โ''To build the โbuttonโ
+that enables any application to be built and deployed on any server,
+anywhere.''โ). Ce partenariat est donc une nouvelle marche en direction
+de ce dernier.</p>
+
+
+<h4>Conclusion</h4>
+
+
+<p>Un an et demi aprรจs la premiรจre <em>release</em> publique de Docker et prรจs
+de 5 mois aprรจs la version 1.0, Docker et sa communautรฉ avancent
+toujours aussi vite. Comme Solomon Hykes (CTO et co-fondateur de dotCould)
+avait dit lors de la dockerCon 14 : "<strong>la valeur rรฉelle de docker n'est pas la technologie, mais le fait que les gens se mettent d'accord sur quelque chose</strong>" ; Docker Inc. pousse principalement dans le sens de la
+standardisation. Le dรฉveloppement de
+<a href="https://github.com/docker/libcontainer">libcontainer</a>,
+<a href="https://github.com/docker/libchan">libchan</a> et
+<a href="https://github.com/docker/libswarm">libswarm</a> sont des projets qui
+vont dans ce sens. La communautรฉe est toute aussi <em>bouillante</em> d'idรฉes
+et chaque jour voit de nouveau projet plus intรฉressant les uns que les
+autres.</p>
+
+
+<p>Enfin la <strong><a href="http://europe.dockercon.com/">dockerCon Europe</a>, les 4 et 5 dรฉcembre 2014</strong> viendra couronner une annรฉe trรจs riche du cรดtรฉ de Docker et
+de son รฉcosystรจme. Rendez-vous mi-dรฉcembre pour faire un petit retour
+ sur la premiรจre confรฉrence europรฉenne Docker ;-).</>
+
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2015-05-01-orgmode-et-jekyll/" title="Orgmode et Jekyll">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2014-03-24-redesign-et-r%C3%A9solutions/" title="Redesign Et Rรฉsolutions">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2015-05-01-orgmode-et-jekyll/index.html
@@ -0,0 +1,260 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2015-05-01-orgmode-et-jekyll/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Orgmode et Jekyll</h1><a href='https://vincent.demeester.fr/posts/2015-05-01-orgmode-et-jekyll/'></a>
+ <address class="signature">
+ <span class="date">Fri, 1 May, 2015</span>
+ <span class="words">(900 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-jekyll"><a href="/tags/#jekyll">jekyll<span>4</span></a></li>
+
+
+ <li class="tag tag-blog"><a href="/tags/#blog">blog<span>2</span></a></li>
+
+
+ <li class="tag tag-emacs"><a href="/tags/#emacs">emacs<span>2</span></a></li>
+
+
+ <li class="tag tag-orgmode"><a href="/tags/#orgmode">orgmode<span>2</span></a></li>
+
+
+ <li class="tag tag-html"><a href="/tags/#html">html<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <div id="outline-container-sec-1" class="outline-2">
+<h2 id="sec-1">Un peu plus d'un an..</h2>
+<div class="outline-text-2" id="text-1">
+<p>
+.. que je n'ai rien postรฉ ici. Le temps passe bien vite, mais c'est plutรดt une bonne chose. Je crois que quelque chose me manquait pour poster ici plus souvent.
+</p>
+
+<blockquote>
+<p>
+Au niveau de mes points d'entrรฉes sur le web, je compte remettre un peu en route la partie blog de ce site et tourner shortbrain.org (ou autre) en un site plus "documentation" en me basant sur mes notes (powered by org-mode). <b>Je me suis รฉgalement remis ร Gnu Emacs et oh god qu'est-ce que c'est bon</b> :-D.
+</p>
+</blockquote>
+
+<p>
+C'est ce que j'รฉcrivais il y a un an, et effectivement c'est toujours aussi bon <code>;-D</code>. J'ai commencรฉ ร utiliser <code>org-mode</code> de maniรจre assez intensive, pour mettre en place mon <i>personal kanban</i> mais รฉgalement pour prendre mes notes. Et plus je l'utilise, plus j'ai du mal m'en passer et ร aller dans mon dossier hรฉbergeant ce site pour y รฉcrire en Markdown. Il me fallait donc trouver une astuce pour convertir certaines notes en post pour Jekyll. C'est maintenant chose faite (aprรจs 6 mois dans ma TODO-listโฆ), et voici comment je m'en sors.
+</p>
+
+<p>
+L'idรฉe gรฉnรฉrale est assez simple :
+</p>
+
+<ol class="org-ol">
+<li>Utiliser un dossier particulier pour les notes destinรฉ ร ce blog
+</li>
+<li>Exporter, au format html, ces notes dans le bon dossier (<code>_posts</code>)
+</li>
+<li>โฆ et c'est tout en fait :) โ c'รฉtait pas <i>ben</i> compliquรฉ !
+</li>
+</ol>
+</div>
+</div>
+
+<div id="outline-container-sec-2" class="outline-2">
+<h2 id="sec-2">Les fichiers org</h2>
+<div class="outline-text-2" id="text-2">
+<p>
+Tous mes fichiers <code>org-mode</code> sont dans un ensemble de dossiers bien particulier โ cela n'a pas grand chose d'important ร faire ici, mais รงa permet de suivre la configuration qui suit. Il s'agit du dossier <code>~/desktop/org/</code>, et de ces fils : <code>todos</code> pour ce que je dois faire et <code>notes</code> pour ma prise de note. Dans <code>notes</code> on trouve donc des dossiers et en particulier un qui se nomme <code>vdf</code> (pour Vincent.Demeester.Fr).
+</p>
+
+<p>
+La seule diffรฉrence que les fichiers <code>.org</code> ont dans ce dossier par rapport aux autres, c'est le dรฉbut du fichier. En effet, <a href="http://jekyllrb.com/">Jekyll</a> a besoin d'une entรชte en <code>YAML</code> pour le layout, les tags, la catรฉgorie et plein d'autres trucs. Le fichier <code>org</code> de ce billet ressemble ร รงa par example :
+</p>
+
+<pre class="example">
+#+BEGIN_HTML
+---
+layout: post
+category: developement
+tags: jekyll blog emacs orgmode html
+lang: fr
+---
+#+END_HTML
+* Un peu plus d'un an..
+
+.. que je n'ai rien postรฉ ici. Le temps passe bien vite, mais c'est plutรดt une bonne chose. Je crois que quelque chose me manquait pour poster ici.
+
+[โฆ]
+</pre>
+
+<p>
+Les utilisateurs de Jekyll reconnaitront les <code>---</code> et le format du header. <code>#+BEGIN_HTML</code> et <code>#+END_HTML</code> sont lร pour dire ร <code>org-mode</code> d'exporter un bloc en HTML sans l'interprรฉter โ c'est une faรงon de mettre du HTML dans un document <code>org</code> si on peut pas faire ce qu'on veut avec le <i>markup</i>. Ici รงa nous permet d'exporter tel quel le header de <a href="http://jekyllrb.com/">Jekyll</a> en haut du HTML gรฉnรฉrรฉ, pratique !
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-3" class="outline-2">
+<h2 id="sec-3">Configuration de org-mode</h2>
+<div class="outline-text-2" id="text-3">
+<p>
+Il reste maintenant ร configurer le <i>projet de publication</i> (publishing project) dans Emacs. Je vais mettre ici juste la partie intรฉressante, donc pour plus d'information sur comment publier des fichiers org-mode avec Emacs, c'est par <a href="http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html">ici</a> pour un tutoriel (j'adore <a href="http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html">worg</a> soit dit en passant :P).
+</p>
+
+<p>
+L'idรฉe c'est de dรฉfinir un projet avec plusieurs <i>components</i>, un pour les fichiers <code>org</code>, un pour les fichiers <code>css</code> et un pour les <i>assets</i> (images, vidรฉos, โฆ). On souhaite รฉgalement ne pas gรฉnรฉrer de table des matiรจres (TOC) et ne gรฉnerer que le <i>body</i> (pas de <code><head></code>, โฆ). Et รงa se prรฉsente comme suit.
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-emacs-lisp"><span class="org-comment-delimiter">;; </span><span class="org-comment">Variables</span>
+<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setq</span> <span class="org-rainbow-identifiers-identifier-9">vdf-base-directory</span> <span class="org-string">"~/desktop/org/notes/vdf/"</span>
+ <span class="org-rainbow-identifiers-identifier-11">vdf-site-directory</span> <span class="org-string">"~/src/github/vdemeester/vdemeester.github.com"</span>
+ <span class="org-rainbow-identifiers-identifier-4">vdf-publishing-directory</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-identifiers-identifier-15">expand-file-name</span> <span class="org-string">"_posts"</span> <span class="org-rainbow-identifiers-identifier-11">vdf-site-directory</span><span class="org-rainbow-delimiters-depth-2">)</span>
+ <span class="org-rainbow-identifiers-identifier-2">vdf-css-publishing-directory</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-identifiers-identifier-15">expand-file-name</span> <span class="org-string">"css"</span> <span class="org-rainbow-identifiers-identifier-11">vdf-site-directory</span><span class="org-rainbow-delimiters-depth-2">)</span>
+ <span class="org-rainbow-identifiers-identifier-15">vdf-assets-publishing-directory</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-identifiers-identifier-15">expand-file-name</span> <span class="org-string">"assets"</span> <span class="org-rainbow-identifiers-identifier-11">vdf-site-directory</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
+
+<span class="org-comment-delimiter">;; </span><span class="org-comment">Project</span>
+<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setq</span> <span class="org-rainbow-identifiers-identifier-12">org-publish-project-alist</span>
+ `<span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-3">(</span><span class="org-string">"vdf-notes"</span>
+ <span class="org-builtin">:base-directory</span> ,<span class="org-rainbow-identifiers-identifier-9">vdf-base-directory</span>
+ <span class="org-builtin">:base-extension</span> <span class="org-string">"org"</span>
+ <span class="org-builtin">:publishing-directory</span> ,<span class="org-rainbow-identifiers-identifier-4">vdf-publishing-directory</span>
+ <span class="org-builtin">:exclude</span> <span class="org-string">"FIXME"</span>
+ <span class="org-builtin">:section-numbers</span> <span class="org-rainbow-identifiers-identifier-2">nil</span>
+ <span class="org-builtin">:with-toc</span> <span class="org-rainbow-identifiers-identifier-2">nil</span>
+ <span class="org-builtin">:with-drawers</span> <span class="org-rainbow-identifiers-identifier-8">t</span>
+ <span class="org-builtin">:htmlized-source</span> <span class="org-rainbow-identifiers-identifier-8">t</span>
+ <span class="org-builtin">:publishing-function</span> <span class="org-rainbow-identifiers-identifier-7">org-html-publish-to-html</span>
+ <span class="org-builtin">:headline-levels</span> <span class="org-rainbow-identifiers-identifier-8">4</span>
+ <span class="org-builtin">:body-only</span> <span class="org-rainbow-identifiers-identifier-8">t</span><span class="org-rainbow-delimiters-depth-3">)</span>
+ <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-string">"vdf-static-css"</span>
+ <span class="org-builtin">:base-directory</span> ,<span class="org-rainbow-identifiers-identifier-9">vdf-base-directory</span>
+ <span class="org-builtin">:base-extension</span> <span class="org-string">"css"</span>
+ <span class="org-builtin">:publishing-directory</span> ,<span class="org-rainbow-identifiers-identifier-2">vdf-css-publishing-directory</span>
+ <span class="org-builtin">:recursive</span> <span class="org-rainbow-identifiers-identifier-8">t</span>
+ <span class="org-builtin">:publishing-function</span> <span class="org-rainbow-identifiers-identifier-5">org-publish-attachment</span>
+ <span class="org-rainbow-delimiters-depth-3">)</span>
+ <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-string">"vdf-static-assets"</span>
+ <span class="org-builtin">:base-directory</span> ,<span class="org-rainbow-identifiers-identifier-9">vdf-base-directory</span>
+ <span class="org-builtin">:base-extension</span> <span class="org-string">"png</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">jpg</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">gif</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">pdf</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">mp3</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">ogg"</span>
+ <span class="org-builtin">:publishing-directory</span> ,<span class="org-rainbow-identifiers-identifier-15">vdf-assets-publishing-directory</span>
+ <span class="org-builtin">:recursive</span> <span class="org-rainbow-identifiers-identifier-8">t</span>
+ <span class="org-builtin">:publishing-function</span> <span class="org-rainbow-identifiers-identifier-5">org-publish-attachment</span>
+ <span class="org-rainbow-delimiters-depth-3">)</span>
+ <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-string">"vdf"</span> <span class="org-builtin">:components</span> <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-string">"vdf-notes"</span> <span class="org-string">"vdf-static-css"</span> <span class="org-string">"vdf-static-assets"</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
+ <span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
+</pre>
+</div>
+
+<p>
+J'utilise des variables, c'est pas indispensable mais c'est plus pratique. Il y a trois <i>components</i>, chacun dรฉfinit les fichiers qu'il traite grรขce ร <code>:base-extension</code>. Intรฉressons-nous surtout ร <code>vdf-notes</code> puisque c'est celui qui nous sort les fichiers <code>HTML</code> ร partir des fichiers <code>org</code>. On se passe de table des matiรจres grรขce ร <code>:with-toc nil</code>, on ne gรฉnรจre que le <i>body</i> grรขce ร <code>:body-only t</code> et on รฉvite les numรฉros de sections avec <code>:section-numbers nil</code>. Le bonus vient avec <code>:htmlized-source t</code> puisque du coup, les parties sources (entre <code>#+BEGIN_SRC</code> et <code>#+END_SRC</code>) sont exportรฉs avec les mรชmes couleurs que j'ai dans ma configuration Emacs (avec les <a href="https://github.com/vdemeester/emacs-config#raindow-identifiers">rainbow-identifiers</a>, voir ce post <a href="https://medium.com/@evnbr/coding-in-color-3a6db2743a1e">lร </a> รฉgalement).
+</p>
+
+<p>
+Il ne reste plus qu'ร publier le projet quand on le souhaite avec <code>org-publish</code> โ je vous laisse lire la documentation pour savoir comment on fait.
+</p>
+
+<p>
+Et c'est tout bon. Un petit <code>bundle exec jekyll serve --watch</code> pour voir le rendu โ et quand on est content on commit. Et c'est la fรชte <code>\o/</code>.
+</p>
+
+<p>
+C'est tout pour le moment, la frรฉquence des billets de ce blog devrait s'incrรฉmenter un peu maintenant.
+</p>
+</div>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2015-05-09-migration-to-hugo/" title="Migration vers hugo">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2014-10-27-docker-1.3-ecosystem/" title="Docker 1.3 et son รฉcosystรจme">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2015-05-09-migration-to-hugo/index.html
@@ -0,0 +1,229 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2015-05-09-migration-to-hugo/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Migration vers hugo</h1><a href='https://vincent.demeester.fr/posts/2015-05-09-migration-to-hugo/'></a>
+ <address class="signature">
+ <span class="date">Sat, 9 May, 2015</span>
+ <span class="words">(500 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-hugo"><a href="/tags/#hugo">hugo<span>1</span></a></li>
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-blog"><a href="/tags/#blog">blog<span>2</span></a></li>
+
+
+ <li class="tag tag-emacs"><a href="/tags/#emacs">emacs<span>2</span></a></li>
+
+
+ <li class="tag tag-orgmode"><a href="/tags/#orgmode">orgmode<span>2</span></a></li>
+
+
+ <li class="tag tag-html"><a href="/tags/#html">html<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <p>
+Et voilร , une semaine aprรจs m'รชtre remis en route sur ce blog, je fais
+dรฉjร une migration <code>>_<</code>. Je me suis rendu compte que <a href="http://jekyllrb.com/">Jekyll</a>
+m'รฉnervait un peu, et comme je suis ร fond dans <a href="http://golang.org/">go</a> en ce moment, j'ai
+regardรฉ du cรดtรฉ des gรฉnรฉrateurs de sites static et <a href="http://gohugo.io/">Hugo</a> a clairement
+retenu mon attention.
+</p>
+
+<div id="outline-container-sec-1" class="outline-2">
+<h2 id="sec-1">Pourquoi Hugo ?</h2>
+<div class="outline-text-2" id="text-1">
+<blockquote>
+<p>
+<b>Make the Web Fun Again</b>
+</p>
+
+<p>
+Introducing Hugo, a new idea around making website creation simple again. Hugo flexibly works with many formats and is ideal for blogs, docs, portfolios and much more. Hugoโs speed fosters creativity and makes building a website fun again.
+</p>
+</blockquote>
+
+<p>
+Presque tout est dit dans cette citation.
+</p>
+
+<ul class="org-ul">
+<li>Hugo est rapide.
+</li>
+<li>Le systรจme de content est un rรฉgale.
+</li>
+<li>L'organisation d'un <i>projet hugo</i> est simple :
+<ul class="org-ul">
+<li><code>content</code> pour le contenu, avec ce qu'on veut dedans,
+</li>
+<li><code>static</code> pour le contenu statique (<code>css</code>, <code>javascript</code>, <code>images</code>, โฆ),
+</li>
+<li><code>layouts</code> pour les templates (super facile de mettre des templates diffรฉrents en fonction des contenus, voir <a href="http://gohugo.io/templates/content/">ici</a>),
+</li>
+<li><code>themes</code> pour les themes applicables (qui dรฉfinissent eux mรชme <code>layouts</code> et <code>static</code>.
+</li>
+</ul>
+</li>
+<li>Le systรจme de template est <a href="http://gohugo.io/templates/go-templates/">puissant</a> et un vrai rรฉgale.
+</li>
+<li>Le mode <code>server</code> a la possiblitรฉ de surveiller les fichiers(avec le <i>flag</i> <code>-w</code>, et implรฉmente <a href="http://gohugo.io/extras/livereload/">LiveReload</a> ce qui est un petit bonus non nรฉgligeable.
+</li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-sec-2" class="outline-2">
+<h2 id="sec-2">Ce qui changes</h2>
+<div class="outline-text-2" id="text-2">
+<p>
+Le principale changement est sur le/les repository utilisรฉs. Avant tout รฉtait dans <a href="https://github.com/vdemeester/vdemeester.github.com">vdemeester.github.com</a>, puisque c'est github qui gรฉnรฉrait le rรฉsultat final avec Jekyll. Ce n'est maintenant plus le cas : <a href="https://github.com/vdemeester/blog">blog</a> hรฉberge les sources du blog (les fichiers content en Markdown ou <i>HTML-from-orgmode</i> ainsi que les templates et la configuration <a href="http://gohugo.io/">Hugo</a> โ <a href="https://github.com/vdemeester/vdemeester.github.com">vdemeester.github.com</a> hรฉberge dรฉsormais le rรฉsultat.
+</p>
+
+<p>
+J'en ai profitรฉ รฉgalement pour faire quelques ajustements graphique, principalement sur les tags qui ont maintenant, parfois, des couleurs diffรฉrentes.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-3" class="outline-2">
+<h2 id="sec-3">Intรฉgration avec Emacs & orgmode</h2>
+<div class="outline-text-2" id="text-3">
+<p>
+Il me manque encore quelques petits <i>trucs</i> pour rendre รงa automatique, mais dans l'idรฉe, voilร le workflow que j'utilise quand je publie un article (comme maintenant) :
+</p>
+
+<ol class="org-ol">
+<li>Dรฉmarre <code>hugo server -w</code> dans mon repository <code>blog</code>.
+</li>
+<li>Je crรฉer mon fichier <code>org</code> au bon endroit (soit <code>$HOME/desktop/org/notes/vdf/monfichier.org</code>). Par rapport au <a href="http://vincent.demeester.fr/posts/2015-05-01-orgmode-et-jekyll/">billet prรฉcรฉdent</a>, le header de mes fichiers <code>org</code> change un peu :
+
+<pre class="example">
+#+begin_html
++++
+title="Migration vers hugo"
+date="2015-05-09"
+categories=["developement"]
+tags=["hugo","golang","blog","emacs","orgmode","html"]
+lang="fr"
++++
+#+end_html
+
+Et voilร , une semaine aprรจs m'รชtre remis en route sur ce blog, je fais dรฉjร une migration =>_<=. Je me suis rendu compte que [[http://jekyllrb.com/][Jekyll]] m'รฉnervait un peu, et comme je suis ร fond dans [[http://golang.org/][go]] en ce moment, j'ai regardรฉ du cรดtรฉ des gรฉnรฉrateurs de sites static et [[http://gohugo.io/][Hugo]] a clairement retenu mon attention.
+</pre>
+</li>
+
+<li>J'exรฉcute <code>org-publish-current-project</code> (qu'il faut que je <i>bind</i> pour รฉviter de me le taper ร la main..)
+</li>
+<li>Et je regarde le rรฉsultat dans mon navigateur (merci encore <a href="http://gohugo.io/extras/livereload/">LiveReload</a>).
+</li>
+</ol>
+
+<p>
+Pour me simplifier la vie, il me resterais ร dรฉmarrer et arrรชter facilement <code>hugo server -w</code> dans le bon dossier directement depuis emacs (un peu ร -la <code>compile</code>), <i>binder</i> <code>org-publish-current-project</code> et un petit script final qui copie le rendu de <code>blog</code> vers <code>vincent.demeester.fr</code> et qui commit (le tout appellable depuis Emacs <code>;-P</code>).
+</p>
+</div>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2015-06-01-docker-1.6-ecosystem/" title="Docker 1.6 et son รฉcosystรจme">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2015-05-01-orgmode-et-jekyll/" title="Orgmode et Jekyll">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2015-06-01-docker-1.6-ecosystem/index.html
@@ -0,0 +1,610 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2015-06-01-docker-1.6-ecosystem/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Docker 1.6 et son รฉcosystรจme</h1><a href='https://vincent.demeester.fr/posts/2015-06-01-docker-1.6-ecosystem/'></a>
+ <address class="signature">
+ <span class="date">Mon, 1 June, 2015</span>
+ <span class="words">(3100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#zenika">zenika</a></li>
+
+
+
+
+
+ <li class="tag tag-docker"><a href="/tags/#docker">docker<span>3</span></a></li>
+
+
+ <li class="tag tag-compose"><a href="/tags/#compose">compose<span>1</span></a></li>
+
+
+ <li class="tag tag-swarm"><a href="/tags/#swarm">swarm<span>1</span></a></li>
+
+
+ <li class="tag tag-machine"><a href="/tags/#machine">machine<span>1</span></a></li>
+
+
+ <li class="tag tag-cluster"><a href="/tags/#cluster">cluster<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+<div class="notice">Cet article est disponible sur le <a href="http://blog.zenika.com/">Blog de Zenika</a> ร l'adresse suivante : <a href="http://blog.zenika.com/index.php?post/2015/06/01/Docker-1-6-et-son-ecosysteme">http://blog.zenika.com/index.php?post/2015/06/01/Docker-1-6-et-son-ecosysteme</a>. Cet publication me sert de mirroir / sauvegarde.</div>
+
+<div id="outline-container-sec-1" class="outline-2">
+<h2 id="sec-1">Introduction</h2>
+<div class="outline-text-2" id="text-1">
+<p>
+Le 28 octobre dernier, nous avions parlรฉ de la sortie de Docker 1.3, des รฉvolutions entre la version 1 et cette derniรจre et de son รฉcosystรจme. Je vous proposes de remettre รงa, bientรดt 6 mois aprรจs, avec un peu le mรชme plan : les principales nouveautรฉs entre la version 1.3 et 1.6 (et il y en a <code>;-)</code>), l'รฉvolution de l'รฉcosystรจme qui gravite autour et un peu de <i>social</i> avec les meetups et รฉvรจnements qui se sont passรฉs depuis.
+</p>
+
+
+<div class="figure">
+<p><img src="./img/docker-16/docker_container_engine_logo.png" alt="docker_container_engine_logo.png" />
+</p>
+</div>
+
+<p>
+Rappel <i>ultra</i> rapide, <b>Docker est une plate-forme ouverte ร destination des dรฉveloppeurs et administrateurs systรจmes visant ร faciliter la construction et le dรฉploiement d'applications distribuรฉes</b>. De maniรจre moins marketing, l'idรฉe derriรจre Docker est d'automatiser le dรฉploiement d'environnements sous forme de conteneurs lรฉgers, portables et auto-suffisants ; les conteneurs permettant d'isoler l'exรฉcution des applications dans des contextes d'exรฉcution. Pour ce
+faire, Docker, รฉcrit en Go, reprend les bases de LXC, utilise les fonctionnalitรฉs du noyau Linux (CGroups, Namespaces, โฆ) et se base initialement sur un systรจme de fichier "en oignons" AUFS ; D'autres backends sont supportรฉs รฉgalement comme BTRFS ou devicemapper (LVM).
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-2" class="outline-2">
+<h2 id="sec-2">Ovelay filesystem storage driver (1.4.0)</h2>
+<div class="outline-text-2" id="text-2">
+<p>
+La release 1.4.0 de Docker (et la 1.3.3 en parallรจle) a surtout รฉtรฉ une gigantesque <i>bugfix party</i>, histoire de rendre les fonctionnalitรฉs arrivรฉes auparavant plus stable โ la release note se trouve <a href="https://github.com/docker/docker/blob/master/CHANGELOG.md#140-2014-12-11">ici</a>.
+</p>
+
+<p>
+La principale nouveautรฉe de cette version est l'apparation d'un nouveau <i>storage driver</i>, il s'agit d'<b>OverlayFs</b>. Il s'agit d'un mรฉcanisme de montage permettant de superposer dans un rรฉpertoire le contenu de plusieurs autres rรฉpertoires.
+</p>
+
+<p>
+Initialement Docker est basรฉ <b><a href="http://en.wikipedia.org/wiki/Aufs">Aufs</a></b> qui fait, pour simplifier, la mรชme chose. Le problรจme avec aufs est qu'il n'est pas intรฉgrรฉ dans le noyau Linux (i.e. dans les sources officielles), contrairement ร OverlayFS qui a fait son apparition avec le noyau <a href="https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=e9be9d5e76e34872f0c37d72e25bc27fe9e2c54c">3.18</a>. Il รฉtait donc nรฉcessaire de disposer d'un noyau patchรฉ ; Le noyau Linux de Debian et de sess dรฉrivรฉs (Ubuntu, etc.) ont ce <i>patchset</i> aufs de base mais ce n'est pas le cas de toutes les distributions. L'idรฉe de cette intรฉgration est assez simple : supporter le maximum de distributions en se basant sur une <i>feature</i> du noyau. C'est donc bien รฉvidemment le <i>driver</i> d'avenir pour Docker ; attention cependant, la peinture est encore un peu fraรฎche <code>;-P</code>.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-3" class="outline-2">
+<h2 id="sec-3">Support d'IPv6 (1.5.0)</h2>
+<div class="outline-text-2" id="text-3">
+<p>
+Les adresses IPv4 commencent a se faire <a href="http://en.wikipedia.org/wiki/IPv4_address_exhaustion">rare</a>, il est donc important que Docker supporte IPv6. C'est dรฉsormais le cas avec la version 1.5.0, mรชme si ce n'est pas activรฉ par dรฉfaut. Pour activer le support de l'IPv6 (en plus de l'IPv4), il faut ajouter le <i>flag</i> <code>--ipv6</code> au daemon. Docker va donc mettre en place le <i>bridge</i> <code>docker0</code> avec en plus un IPv6 en mode local, avec l'adresse <code>fe80::1</code>.
+</p>
+
+<p>
+Par dรฉfaut les containers qui seront crรฉรฉs n'auront qu'une adresse locale. Pour avoir une adresse IPv6 routable ร votre conteneur, il est nรฉcessaire de lui prรฉciser un <i>sous-rรฉseau</i> (subnet) dans lequel il va piocher son adresse. Cela se fait grรขce ร l'argument <code>--fixed-cidr-v6</code>.
+</p>
+
+
+<div class="org-src-container">
+
+<pre class="src src-sh"><span style="color: #783778;">docker</span> <span style="color: #43783f;">-d</span> <span style="color: #374478;">--ipv6</span> <span style="color: #78683f;">--fixed-cidr-v6</span>=<span style="color: #008000;">"2001:db8:1::/64"</span>
+</pre>
+</div>
+
+<p>
+Comme je ne suis pas un pro de l'IPv6, pour plus d'information, et si l'anglais ne vous fait pas peur, c'est dans la <a href="https://docs.docker.com/articles/networking/#ipv6">documentation "networking"</a> de Docker.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-4" class="outline-2">
+<h2 id="sec-4">Conteneurs en lecture seule (1.5.0)</h2>
+<div class="outline-text-2" id="text-4">
+<p>
+Une autre fonctionnalitรฉ assez sympathique qui est arrivรฉ avec cette version 1.5.0 est les conteneurs en lecture seule โ c'est Michael Crosby qui s'est occupรฉ d'<a href="https://github.com/docker/docker/pull/10093">implรฉmenter รงa</a>. L'intรฉrรชt des conteneurs en lecture seule est de permettre de <b>contrรดler oรน l'application</b> ร l'intรฉrieur de votre conteneur <b>peut รฉcrire ou modifier des fichiers</b>. En combinant ceci avec les volumes, vous pouvez vous assurez des emplacements dans lesquels votre conteneur va persister des รฉtats ou donnรฉes (le/les volumes), puisqu'il ne sera pas possible d'รฉcrire ailleurs de toute faรงon.
+</p>
+
+<p>
+Pour activer cette fonctionnalitรฉ, c'est l'argument <code>--read-only</code>.
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-sh"><span style="color: #783778;">docker</span> <span style="color: #513f78;">run</span> <span style="color: #43783f;">--read-only</span> <span style="color: #5e7837;">-v</span> <span style="color: #5e7837;">/volume/writable</span> <span style="color: #3f7178;">busybox</span> <span style="color: #783778;">touch</span> <span style="color: #5e7837;">/volume/writable</span>
+</pre>
+</div>
+
+<p>
+Une autre utilisation des conteneurs en lecture seule est que cela donne la possibilitรฉ de faire du debug <i>post-mortem</i> d'un conteneur (en production par exemple). Cela nous permet de redรฉmarrer un conteneur qui aurait plantรฉ, en lecture seule avec le systรจme de fichier dans l'รฉtat du crash.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-5" class="outline-2">
+<h2 id="sec-5">Les labels pour le ยซ daemon ยป, les images et les conteneurs (1.6.0)</h2>
+<div class="outline-text-2" id="text-5">
+<blockquote>
+<p>
+One Meta Data to Rule Them All
+</p>
+</blockquote>
+
+<p>
+Une des deux fonctionnalitรฉs trรจs attendue de la rรฉcente version 1.6.0 sont les labels. En un mot, et pour le faire ยซ ร -la ยป <i>le seigneur des anneaux</i>, les labels peuvent se rรฉsumer en "<b>Une metadata pour les gouverner tous</b>" (รงa le fait vachement mieux en anglais en fait).
+</p>
+
+<p>
+Les labels s'appliquent sur le <i>daemon</i>, les images et les conteneurs. C'est un peu un mรฉlange entre des tags et des variables d'environnements puisque il s'agit d'un couple <b>clรฉ/valeur</b>.
+</p>
+
+<p>
+L'ajout de label sur le <i>daemon</i> se fait grรขce ร l'argument โ roulement de tambour โ <code>--label</code> (<code>\o/</code>). La principale utilitรฉ pour l'instant est son utilisation conjointe avec Swarm dont nous parlerons un peu plus bas ; mais en deux mots, cela permet de filtrer les <i>engines</i> sur lesquels on va <i>taper</i>.
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-sh"><span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">Souvent, c'est dans DOCKER_OPTS du fichier /etc/default/docker</span>
+<span style="color: #783778;">docker</span> <span style="color: #43783f;">-d</span> <span style="color: #784437;">-H</span> <span style="color: #4f5c7e;">unix://var/run/docker.sock</span> <span style="color: #7a4f7e;">--label</span> <span style="color: #BA36A5;">storage</span>=<span style="color: #5e7837;">ssd</span> <span style="color: #7a4f7e;">--label</span> <span style="color: #BA36A5;">type</span>=<span style="color: #5e7837;">laptop</span>
+</pre>
+</div>
+
+<p>
+L'ajout d'un label sur une image se fait dans le fichier <code>Dockerfile</code>, et l'ajout d'un label sur un conteneur, grรขce ร l'argument <code>--label</code> pour rester cohรฉrent. Construisons une image inutile mais en lui appliquant un label :
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-sh"><span style="color: #37785e;">FROM</span> <span style="color: #3f7178;">busybox</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">Support du multi-line pour LABEL</span>
+<span style="color: #783778;">LABEL</span> <span style="color: #BA36A5;">vendor</span>=<span style="color: #78683f;">zenika</span> <span style="color: #008000;">\</span>
+ <span style="color: #784437;">com.zenika.lang</span>=<span style="color: #374478;">golang</span> <span style="color: #008000;">\</span>
+ <span style="color: #78683f;">com.zenika.version</span>=<span style="color: #43783f;">0.1</span>
+<span style="color: #7a4f7e;">CMD</span> [<span style="color: #008000;">"echo"</span><span style="color: #7e544f;">,</span> <span style="color: #008000;">"zenika"</span>]
+</pre>
+</div>
+
+<p>
+Nous allons maintenant construire cette image et lancer un conteneur ร partir de cette derniรจre avec un autre label.
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-sh">$ <span style="color: #783778;">docker</span> <span style="color: #7e544f;">build</span> <span style="color: #7a4f7e;">-t</span> <span style="color: #4f7e67;">zenikaapp</span> <span style="color: #374478;">.</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">[…]</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #513f78;">run</span> <span style="color: #4f5c7e;">--name</span> <span style="color: #783f5a;">test</span> <span style="color: #7a4f7e;">--label</span> <span style="color: #783f5a;">com.zenika.foo</span>=<span style="color: #784437;">bar</span> <span style="color: #4f7e67;">zenikaapp</span>
+<span style="color: #78683f;">zenika</span>
+</pre>
+</div>
+
+<p>
+L'idรฉe c'est que maintenant, lorsque l'on va regarder la liste d'images ou de conteneurs ร disposition sur notre <i>engine</i>, nous allons pouvoir <b>filtrer</b> par label, comme suit :
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-sh">$ <span style="color: #783778;">docker</span> <span style="color: #707e4f;">images</span> <span style="color: #4f5c7e;">--filter</span> <span style="color: #008000;">"label=vendor=zenika"</span> <span style="color: #4f5c7e;">--filter</span> <span style="color: #008000;">"label=com.zenika.lang=golang"</span>
+<span style="color: #784437;">REPOSITORY</span> <span style="color: #3f7178;">TAG</span> <span style="color: #707e4f;">IMAGE</span> <span style="color: #707e4f;">ID</span> <span style="color: #7e544f;">CREATED</span> <span style="color: #784437;">VIRTUAL</span> <span style="color: #4f7e67;">SIZE</span>
+<span style="color: #4f7e67;">zenikaapp</span> <span style="color: #7a4f7e;">latest</span> <span style="color: #784437;">66ffda023118</span> <span style="color: #5e7837;">43</span> <span style="color: #7e544f;">seconds</span> <span style="color: #43783f;">ago</span> <span style="color: #783778;">2.433</span> <span style="color: #7e544f;">MB</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #43783f;">ps</span> <span style="color: #784437;">-a</span> <span style="color: #4f5c7e;">--filter</span> <span style="color: #008000;">"label=com.zenika.foo=bar"</span>
+<span style="color: #374478;">CONTAINER</span> <span style="color: #707e4f;">ID</span> <span style="color: #707e4f;">IMAGE</span> <span style="color: #78683f;">COMMAND</span> <span style="color: #7e544f;">CREATED</span> [<span style="color: #374478;">…</span>] <span style="color: #707e4f;">NAMES</span>
+<span style="color: #513f78;">37e9a37caf57</span> <span style="color: #513f78;">zenikaapp:latest</span> <span style="color: #008000;">"echo zenika"</span> <span style="color: #43783f;">About</span> <span style="color: #78683f;">a</span> <span style="color: #37785e;">minute</span> <span style="color: #43783f;">ago</span> [<span style="color: #374478;">…</span>] <span style="color: #783f5a;">test</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">On peut également regarder les labels avec inspect</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #374478;">inspect</span> <span style="color: #3f7178;">-f</span> <span style="color: #008000;">"{{json .ContainerConfig.Labels }}"</span> <span style="color: #783f5a;">zenikaap</span>
+{<span style="color: #008000;">"com.zenika.lang"</span><span style="color: #707e4f;">:</span><span style="color: #008000;">"golang"</span><span style="color: #7e544f;">,</span><span style="color: #008000;">"com.zenika.version"</span><span style="color: #707e4f;">:</span><span style="color: #008000;">"0.1"</span><span style="color: #7e544f;">,</span><span style="color: #008000;">"vendor"</span><span style="color: #707e4f;">:</span><span style="color: #008000;">"zenika"</span>}
+$ <span style="color: #783778;">docker</span> <span style="color: #374478;">inspect</span> <span style="color: #3f7178;">-f</span> <span style="color: #008000;">"{{json .Config.Labels }}"</span> <span style="color: #783f5a;">test</span>
+{<span style="color: #008000;">"com.zenika.foo"</span><span style="color: #707e4f;">:</span><span style="color: #008000;">"bar"</span><span style="color: #7e544f;">,</span><span style="color: #008000;">"com.zenika.lang"</span><span style="color: #707e4f;">:</span><span style="color: #008000;">"golang"</span><span style="color: #7e544f;">,</span><span style="color: #008000;">"com.zenika.version"</span><span style="color: #707e4f;">:</span><span style="color: #008000;">"0.1"</span><span style="color: #7e544f;">,</span><span style="color: #008000;">"vendor"</span><span style="color: #707e4f;">:</span><span style="color: #008000;">"zenika"</span>}
+</pre>
+</div>
+
+<p>
+On peut imaginer beaucoup d'usage de ces labels. Par example, avec <a href="http://rancher.com">Rancher</a>, ils sont utilisรฉs pour faciliter la configuration du load-balancer (<a href="http://rancher.com/docker-labels/">ici</a>) โ ils utilisent un label <code>io.rancher.service.provides</code> qui permettra ร ce dernier de trouver automatiquement ces petits. Je vous laisse imaginer vos propres <i>use-cases</i>.
+</p>
+
+<p>
+Il y a une partie de la documentation qui parle exclusivement des labels, avec une petite partie sur les <i>best-practice</i> de nommage des labels, c'est <a href="https://docs.docker.com/userguide/labels-custom-metadata/">ici</a>.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-6" class="outline-2">
+<h2 id="sec-6">Logging drivers \o/ (1.6.0)</h2>
+<div class="outline-text-2" id="text-6">
+<p>
+Un <i>gros reproche</i> qui รฉtait fait ร Docker รฉtait sa gestion trรจs <b>simpliste</b> des logs des conteneurs. Plusieurs critiques รฉtaient faites :
+</p>
+
+<ol class="org-ol">
+<li>Tout faire sortir sur <code>stdout</code> et <code>stderr</code> n'est pas vraiment une habitude de nos jours, surtout dans des langages comme Java oรน l'utilisation de <i>logger</i> (Log4j, Slf4j, โฆ) est trรจs rรฉpandue. Cela rend le portage vers docker de certaines applications un peu plus fastidieux.
+</li>
+<li>Il n'y avait aucun mรฉcanisme de <i>rotation</i> de logs โ et comme en plus le dossier dans lequel les logs รฉtaient รฉcris est un peu enfoui dans <code>/var/lib/docker</code>, cela pouvait poser quelques problรจme si des conteneurs รฉtaient un peu trop bavards..
+</li>
+<li>La solution utilisรฉe pour sauvegarder ces logs et pourquoi pas les centraliser (avec ELK par exemple), รฉtait d'utiliser un volume, souvent partagรฉ entre applications, et de dรฉmarrer un conteneur pour gรฉrer cette analyse, centralisation, โฆ. Non seulement ce n'est pas trรจs optimal, mais cela nรฉcessitait de configurer chaque application (donc chaque conteneur) โ et <code>docker logs</code> perdait tout son intรฉrรชt.
+</li>
+</ol>
+
+<p>
+Avec la version 1.6.0, les <i>logging driver</i> permettent une gestion des logs un peu plus optimale, ou au moins plus flexible. Il est donc maintenant possible de prรฉciser le <i>logging driver</i> ร utiliser. Ils en existent 3 pour l'instant :
+</p>
+
+<ol class="org-ol">
+<li><code>json-file</code> correspond au comportement par dรฉfaut de Docker avant la 1.6 et reste la valeur par dรฉfaut
+</li>
+<li><code>syslog</code> qui permet de connecter les logs de nos conteneurs dans notre vรฉnรฉrable syslog (ou en tout cas quelqu'un qui parl le syslog).
+</li>
+<li><code>none</code> qui est le magicien puisqu'il nous permet de faire taire complรจtement un conteneur <code>o/</code>.
+</li>
+</ol>
+
+<p>
+Il est possible de dรฉfinir le logging driver ร deux endroits :
+</p>
+
+<ol class="org-ol">
+<li>sur le <b>daemon</b> pour la valeur par dรฉfaut de tous les conteneurs.
+</li>
+</ol>
+
+<div class="org-src-container">
+
+<pre class="src src-sh">$ <span style="color: #783778;">docker</span> <span style="color: #43783f;">-d</span> <span style="color: #5e7837;">--log-driver</span>=<span style="color: #008000;">"json-file"</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">Pour faire taire les conteneurs par défaut</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #43783f;">-d</span> <span style="color: #5e7837;">--log-driver</span>=<span style="color: #008000;">"none"</span>
+</pre>
+</div>
+
+<ol class="org-ol">
+<li>en option de la command <b>run</b> (ou de la commande <b>create</b>).
+</li>
+</ol>
+
+<div class="org-src-container">
+
+<pre class="src src-sh">$ <span style="color: #783778;">docker</span> <span style="color: #513f78;">run</span> <span style="color: #5e7837;">--log-driver</span>=<span style="color: #3f7178;">syslog</span> <span style="color: #3f7178;">ubuntu</span> <span style="color: #008000;">\</span>
+ <span style="color: #37785e;">/bin/bash</span> <span style="color: #784437;">-c</span> <span style="color: #008000;">'while true; do echo "Hello"; sleep1; done'</span>
+$ <span style="color: #707e4f;">tail</span> <span style="color: #3f7178;">-f</span> <span style="color: #784437;">/var/log/syslog</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">[…]</span>
+<span style="color: #374478;">May</span> <span style="color: #3f7178;">28</span> <span style="color: #3f7178;">17:39:01</span> <span style="color: #7e544f;">dev1</span> <span style="color: #783778;">docker</span>[<span style="color: #5e7837;">116314</span>]<span style="color: #707e4f;">:</span> <span style="color: #513f78;">0e5b67244c00:</span> <span style="color: #4f7e67;">Hello</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">[…]</span>
+</pre>
+</div>
+
+<p>
+Une option <code>--log-opts</code> est รฉgalement prรฉsente pour passer des options additionnelles au driver si celui-ci les supporte. Notons รฉgalement qu'un driver pour <code>systemd</code> devrait arriver avec la version 1.7.
+</p>
+
+<p>
+La pull-request ayant permis d'intรฉgrer cette fonctionnalitรฉ se trouve <a href="https://github.com/docker/docker/pull/10568">ici</a>.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-7" class="outline-2">
+<h2 id="sec-7">Client Windows natif (1.6.0)</h2>
+<div class="outline-text-2" id="text-7">
+<p>
+Enfin, on s'en doutait un peu aprรจs l'annonce du partenariat entre Docker Microsoft, รงa bosse beaucoup pour porter Docker vers Windows. La premiรจre รฉtape รฉtait de fournir un client natif pour Windows. C'est chose faite avec cette version 1.6. Maintenant beaucoup de travail est effectuรฉ pour rendre le <i>engine</i> plus portable, il n'y a qu'ร suivre un peu les pull-request avec un tag <code>os/windows</code> ou encore cette trรจs rรฉcente pull-request avec un titre plutรดt รฉvocateur : ยซ <a href="https://github.com/docker/docker/pull/13554">Windows: The real Windows exec driver is here</a> ยป.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-8" class="outline-2">
+<h2 id="sec-8">Divers</h2>
+<div class="outline-text-2" id="text-8">
+<p>
+Il y a pas mal d'autres options qui sont arrivรฉes depuis la version 1.3.0, nous allons en parcourir certaines rapidement โ parce que sinon cet article va faire 100 pages ;-p :
+</p>
+
+<ul class="org-ul">
+<li><b>Stats</b> (1.5.0) : une commande <code>stats</code> (et donc une API derriรจre) permet de rรฉcupรฉrer quelques statistiques par conteneur, c'est simple pour l'instant.
+</li>
+<li>Depuis la version 1.5.0 il est possible de spรฉcifier le ficher Dockerfile grรขce ร l'option <code>-f</code> de la commande build โ jusqu'ร maintenant docker regardait uniquement le dossier spรฉcifiรฉ et cherchait le fichier <code>Dockerfile</code>. Cela permet donc, par exemple, d'avoir plusieurs <code>Dockerfile</code> dans un dossier.
+</li>
+</ul>
+
+<div class="org-src-container">
+
+<pre class="src src-sh">$ <span style="color: #783778;">docker</span> <span style="color: #7e544f;">build</span> <span style="color: #7a4f7e;">-t</span> <span style="color: #5e7837;">monimage</span> <span style="color: #3f7178;">-f</span> <span style="color: #43783f;">backend.Dockerfile</span> <span style="color: #374478;">.</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">[…] Build the backend</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #7e544f;">build</span> <span style="color: #7a4f7e;">-t</span> <span style="color: #5e7837;">monimage</span> <span style="color: #3f7178;">-f</span> <span style="color: #4f7e67;">frontend.Dockerfile</span> <span style="color: #374478;">.</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">[…] Build the frontend</span>
+</pre>
+</div>
+
+<ul class="org-ul">
+<li>Le <i>registry</i> voit son API passer en V2, principalement pour amรฉliorer les transferts. L'implรฉmentation officielle a รฉtรฉ rรฉรฉcrite en Go (ร la place de Python) et se nomme maintenant <a href="https://github.com/docker/distribution">distribution</a>.
+</li>
+<li>La commande <code>commit est dotรฉe, depuis la version 1.6.0, d'une option =--change</code> qui permet d'appliquer une instruction supportรฉe par les <code>Dockerfile</code> โ voir <a href="https://docs.docker.com/reference/commandline/cli/#commit">ici</a>.
+</li>
+<li>Docker a publiรฉ un petit document ยซ <a href="https://github.com/docker/docker/blob/master/image/spec/v1.md">Docker Image Specification</a> ยป qui a pour but de dรฉfinir le format des images utilisรฉes par Docker, permettant ร d'autres notamment des potentiels conccurents, d'implรฉmenter des images qui seraient compatible.
+</li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-sec-9" class="outline-2">
+<h2 id="sec-9">ร venir</h2>
+<div class="outline-text-2" id="text-9">
+<p>
+L'une des principales nouveautรฉs qui devrait arriver avec la version 1.7 de Docker, c'est l'intรฉgration d'une <b>nouvelle stack rรฉseau</b> avec l'intรฉgration du projet <a href="https://github.com/docker/libnetwork">libnetwork</a>, si tout se passe bien. On pourra noter รฉgalement de nouveaux <i>logging driver</i>, avec notamment un <code>rollover</code> driver ou encore le <code>systemd</code> driver. On peut noter รฉgalement l'arrivรฉe d'un <i>filesystem driver</i> pour ZFS (voici la <a href="https://github.com/docker/docker/pull/9411">pull-request</a>). Le Docker Birthday รฉtant passรฉ par lร , beaucoup de corrections de bugs, de nouvelles petites fonctionnalitรฉs, une meilleure couverture de code par les tests unitaires (<code>o/</code>).
+</p>
+
+<p>
+La RC1 est disponible depuis le 28 mai, <a href="https://github.com/docker/docker/releases/tag/v1.7.0-rc1">ici</a> et la <a href="https://github.com/docker/docker/pull/13528">pull-request</a> associรฉe, donc ร vos tests !
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-10" class="outline-2">
+<h2 id="sec-10">รcosystรจme</h2>
+<div class="outline-text-2" id="text-10">
+<p>
+Trois projets ยซ Docker ยป sont apparus depuis le dernier article : Compose, Swarm et Machine. Prรฉsentons les trรจs rapidement.
+</p>
+</div>
+
+<div id="outline-container-sec-10-1" class="outline-3">
+<h3 id="sec-10-1">Compose</h3>
+<div class="outline-text-3" id="text-10-1">
+<p>
+Compose est le nouveau nom de Fig. Fig รฉtait dรฉveloppรฉ par Orchard qui a รฉtรฉ rachetรฉ par Docker. Pour rappel, l'idรฉe est de dรฉfinir son environnement via un fichier YAML, que ce soit pour le code sur lequel nous travaillons mais รฉgalement les services externes desquels notre application dรฉpend (Base de donnรฉes, ''Message queue'', etc.).
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-yaml"><span style="color: #BA36A5;">web</span>:
+ <span style="color: #BA36A5;">build</span>: .
+ <span style="color: #BA36A5;">command</span>: lein run
+ <span style="color: #BA36A5;">links</span>:
+ - db
+ <span style="color: #BA36A5;">ports</span>:
+ - <span style="color: #008000;">"8000:8000"</span>
+<span style="color: #BA36A5;">db</span>:
+ <span style="color: #BA36A5;">image</span>: postgres
+</pre>
+</div>
+
+<p>
+Compose est en version 1.2 โ depuis la version 1.0, la majoritรฉ des modifications sont des corrections de bugs et des ajouts pour suivre les modifications et nouvelles fonctionnalitรฉs de Docker (<code>env-file</code>, <code>dns_search</code>, <code>add_host</code>, <code>restart</code>, <code>volumes_from</code>, <code>net</code>, โฆ). La commande est maintenant <code>docker-compose</code> ร la place de <code>fig</code> et le fichier <code>docker-compose.yml</code> ร la place de <code>fig.yml</code> โ pour des raisons de rรฉtro-compatibilitรฉ, Compose continue de lire les <code>fig.yml</code>.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-10-2" class="outline-3">
+<h3 id="sec-10-2">Swarm & Machine</h3>
+<div class="outline-text-3" id="text-10-2">
+<p>
+Deux nouveaux projets ont fait leur apparition dans l'escarcelle de Docker Inc. : Swarm et Machine. Swarm est le <i>clustering</i> ร moyenne รฉchelle vu par Docker. Machine permet de provisionner Docker sur diffรฉrents providers : amazon aws, google compute engine, azure, Virtualbox pour ne citer qu'eux โ mais beaucoup d'autres sont dรฉjร supportรฉs.
+</p>
+
+<p>
+Voilร ce que Jรฉrรดme Petazzoni dit ร propos de Swarm :
+</p>
+
+<blockquote>
+<p>
+Un systรจme de cluster utilisant lโAPI Docker et compatible avec tous les outils de lโรฉcosystรจme maison. On peut utiliser les commandes classiques Docker pour piloter le cluster
+</p>
+</blockquote>
+
+<p>
+L'idรฉe principale de Swarm est <b>Je veux parler ร mon cluster Docker de la mรชme faรงon que je parle avec mon daemon Docker</b>. Cela se traduit assez simplement par : <b>Swarm expose la mรชme API que docker</b>. C'est une idรฉe simple et terriblement puissante puisque cela veut dire que je peux administrer mon cluster avec les mรชmes commandes que j'utilise quand je travaille en local. Swarm a pour but de piloter des clusters d'une taille relativement petite (moins de 1000 machines). Pour les clusters de plus grande taille, il existe de trรจs bonnes solutions, comme <a href="http://mesos.apache.org/">Mesos</a>, et ce n'est pas le but de Docker Inc. de venir les concurrencer, bien au contraire.
+</p>
+
+<p>
+Pour faire simple, swarm c'est un <b>manager</b> et des <b>agents</b> (un par engine) โ les agents s'enregistrent auprรจs du master par le biais d'un <i>service discovery</i>. Swarm dispose d'un petit service de discovery mais qui n'est lร que pour <i>la dรฉmo</i> ; il est possible et conseillรฉ de le connecter ร des solutions existantes, pour l'instant <a href="https://github.com/hashicorp/consul">consul</a> et <a href="https://github.com/coreos/etcd">etcd</a>.
+</p>
+
+<p>
+Un bout de code vaut mieux qu'un long discours, voici comment <i>bootstraper</i> un cluster Swarm, avec l'aide de Machine pour รชtre <i>funky</i>.
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-sh"><span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">On crée un cluster simple avec son id</span>
+$ <span style="color: #7a4f7e;">swarm</span> <span style="color: #783f5a;">create</span>
+<span style="color: #3f7178;">50862dcedd53c2f584adfb00e85bac4b</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">On démarre des agents</span>
+$ <span style="color: #43783f;">docker-machine</span> <span style="color: #783f5a;">create</span> <span style="color: #43783f;">-d</span> <span style="color: #374478;">azure</span> <span style="color: #4f5c7e;">--swarm</span> <span style="color: #4f5c7e;">--swarm-discovery</span> <span style="color: #4f7e67;">token://50862dcedd53c2f584adfb00e85bac4b</span> <span style="color: #43783f;">node1</span>
+<span style="color: #3f7178;">INFO</span>[<span style="color: #7a4f7e;">0000</span>] <span style="color: #5e7837;">Creating</span> <span style="color: #513f78;">SSH</span> <span style="color: #5e7837;">key...</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">[…]</span>
+$ <span style="color: #43783f;">docker-machine</span> <span style="color: #783f5a;">create</span> <span style="color: #43783f;">-d</span> <span style="color: #7e544f;">digitalocean</span> <span style="color: #4f5c7e;">--swarm</span> <span style="color: #4f5c7e;">--swarm-discovery</span> <span style="color: #4f7e67;">token://50862dcedd53c2f584adfb00e85bac4b</span> <span style="color: #783f5a;">node2</span>
+<span style="color: #3f7178;">INFO</span>[<span style="color: #7a4f7e;">0000</span>] <span style="color: #5e7837;">Creating</span> <span style="color: #513f78;">SSH</span> <span style="color: #5e7837;">key...</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">[…]</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">On démarre le master</span>
+$ <span style="color: #43783f;">docker-machine</span> <span style="color: #783f5a;">create</span> <span style="color: #43783f;">-d</span> <span style="color: #78683f;">virtualbox</span> <span style="color: #4f5c7e;">--swarm</span> <span style="color: #707e4f;">--swarm-master</span> <span style="color: #4f5c7e;">--swarm-discovery</span> <span style="color: #4f7e67;">token://50862dcedd53c2f584adfb00e85bac4b</span> <span style="color: #374478;">manager</span>
+</pre>
+</div>
+
+<p>
+Maintenant que l'on dispose d'un petit cluster, en pointant dessus (merci Machine) on va pouvoir lancer des commandes docker.
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-sh">$ $(<span style="color: #43783f;">docker-machine</span> <span style="color: #7a4f7e;">env</span> <span style="color: #4f5c7e;">--swarm</span> <span style="color: #374478;">manager</span>)
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">Le bon vieux info</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #784437;">info</span>
+<span style="color: #3f7178;">Containers:</span> <span style="color: #4f5c7e;">4</span>
+<span style="color: #4f5c7e;">Nodes:</span> <span style="color: #7e544f;">3</span>
+ <span style="color: #374478;">manager:</span> <span style="color: #7e544f;">192.168.99.103:2376</span>
+ <span style="color: #78683f;">└</span> <span style="color: #3f7178;">Containers:</span> <span style="color: #513f78;">2</span>
+ <span style="color: #78683f;">└</span> <span style="color: #4f7e67;">Reserved</span> <span style="color: #4f5c7e;">CPUs:</span> <span style="color: #784437;">0</span> <span style="color: #783778;">/</span> <span style="color: #4f5c7e;">4</span>
+ <span style="color: #78683f;">└</span> <span style="color: #4f7e67;">Reserved</span> <span style="color: #7a4f7e;">Memory:</span> <span style="color: #784437;">0</span> <span style="color: #4f7e67;">B</span> <span style="color: #783778;">/</span> <span style="color: #707e4f;">999.9</span> <span style="color: #783f5a;">MiB</span>
+ <span style="color: #78683f;">node1:</span> <span style="color: #513f78;">45.55.160.223:2376</span>
+ <span style="color: #78683f;">└</span> <span style="color: #3f7178;">Containers:</span> <span style="color: #78683f;">1</span>
+ <span style="color: #78683f;">└</span> <span style="color: #4f7e67;">Reserved</span> <span style="color: #4f5c7e;">CPUs:</span> <span style="color: #784437;">0</span> <span style="color: #783778;">/</span> <span style="color: #78683f;">1</span>
+ <span style="color: #78683f;">└</span> <span style="color: #4f7e67;">Reserved</span> <span style="color: #7a4f7e;">Memory:</span> <span style="color: #784437;">0</span> <span style="color: #4f7e67;">B</span> <span style="color: #783778;">/</span> <span style="color: #4f7e67;">490</span> <span style="color: #783f5a;">MiB</span>
+ <span style="color: #513f78;">node2:</span> <span style="color: #707e4f;">swarm-nwde2.cloudapp.net:2376</span>
+ <span style="color: #78683f;">└</span> <span style="color: #3f7178;">Containers:</span> <span style="color: #78683f;">1</span>
+ <span style="color: #78683f;">└</span> <span style="color: #4f7e67;">Reserved</span> <span style="color: #4f5c7e;">CPUs:</span> <span style="color: #784437;">0</span> <span style="color: #783778;">/</span> <span style="color: #78683f;">1</span>
+ <span style="color: #78683f;">└</span> <span style="color: #4f7e67;">Reserved</span> <span style="color: #7a4f7e;">Memory:</span> <span style="color: #784437;">0</span> <span style="color: #4f7e67;">B</span> <span style="color: #783778;">/</span> <span style="color: #7e544f;">1.639</span> <span style="color: #3f7178;">GiB</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">On démarre des nginx</span>
+$ <span style="color: #4f7e67;">for</span> <span style="color: #7a4f7e;">i</span><span style="color: #0000FF;"> in</span> <span style="color: #FF1493;">`seq 1 3`</span>; <span style="color: #0000FF;">do</span> <span style="color: #783778;">docker</span> <span style="color: #513f78;">run</span> <span style="color: #43783f;">-d</span> <span style="color: #783f5a;">-p</span> <span style="color: #7a4f7e;">80:80</span> <span style="color: #783778;">nginx</span>; <span style="color: #0000FF;">done</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #43783f;">ps</span>
+<span style="color: #374478;">CONTAINER</span> <span style="color: #707e4f;">ID</span> <span style="color: #707e4f;">IMAGE</span> <span style="color: #78683f;">COMMAND</span> <span style="color: #78683f;">...</span> <span style="color: #3f7178;">PORTS</span> <span style="color: #707e4f;">NAMES</span>
+<span style="color: #374478;">9bff07d8ee18</span> <span style="color: #78683f;">nginx:1.7</span> <span style="color: #008000;">"nginx -g 'daemon of ... 443/tcp, 104.210.33.180:80->80/tcp node1/loving_torvalds</span>
+<span style="color: #008000;">457ed59c9bb3 nginx:1.7 "</span><span style="color: #783778;">nginx</span> <span style="color: #78683f;">-g</span> <span style="color: #008000;">'daemon of ... 443/tcp, 45.55.160.223:80->80/tcp node2/drunk_swartz</span>
+<span style="color: #008000;">6013be18cdbc nginx:1.7 "nginx -g '</span><span style="color: #3f7178;">daemon</span> <span style="color: #5e7837;">of</span> <span style="color: #78683f;">...</span> <span style="color: #784437;">443/tcp,</span> <span style="color: #4f7e67;">192.168.99.103:80-</span>><span style="color: #5e7837;">80/tcp</span> <span style="color: #707e4f;">manager/condescending_galileo</span>
+</pre>
+</div>
+
+<p>
+On voit qu'on a dรฉmarrรฉ nginx sur les 3 nลuds. Swarm a quelques stratรฉgies pour dรฉmarrer un conteneur sur un nลud ou l'autre :
+</p>
+
+<ul class="org-ul">
+<li><code>spread</code> va รฉparpiller les conteneurs pour que chaque nลud en ait le moins possible (rรฉpartis).
+</li>
+<li><code>binpack</code> va faire l'inverse (tout sur le mรชme nลud jusqu'ร ce que ses ressources soient รฉpuisรฉs).
+</li>
+<li><code>random</code> qui fait <i>au pif</i>.
+</li>
+</ul>
+
+<p>
+Il est รฉgalement possible de mettre des contraintes lors du lancement d'un conteneur, en utilisant le flag <code>-e</code> de <code>docker run</code> (<code>-e</code> = variables d'environnement).
+</p>
+
+
+<div class="org-src-container">
+
+<pre class="src src-sh"><span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">Démarrer postgres sur un host qui a le label storage=ssd</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #513f78;">run</span> <span style="color: #43783f;">-d</span> <span style="color: #707e4f;">-e</span> <span style="color: #4f5c7e;">constraint:</span><span style="color: #4f5c7e;">storage</span>==<span style="color: #5e7837;">ssd</span> <span style="color: #4f5c7e;">--name</span> <span style="color: #4f7e67;">postgres</span> <span style="color: #4f7e67;">postgres</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">Démarrer redis à coté du conteneur dont le nom est postgres</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #513f78;">run</span> <span style="color: #43783f;">-d</span> <span style="color: #707e4f;">-e</span> <span style="color: #4f5c7e;">affinity:</span><span style="color: #4f5c7e;">container</span>==<span style="color: #4f7e67;">postgres</span> <span style="color: #4f5c7e;">--name</span> <span style="color: #7e544f;">redis</span> <span style="color: #7e544f;">redis</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">Démarer backend où tu veux, mais comme les links sont des contraintes</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">implicites il démarrera sur le même host que postgres ET redis</span>
+<span style="color: #8D8D84;"># </span><span style="color: #8D8D84; font-style: italic;">(ou ne démarrera pas ces derniers ne sont pas au même endroit)</span>
+$ <span style="color: #783778;">docker</span> <span style="color: #513f78;">run</span> <span style="color: #43783f;">-d</span> <span style="color: #374478;">--link</span> <span style="color: #3f7178;">redis:redis</span> <span style="color: #374478;">--link</span> <span style="color: #784437;">postgres:db</span> <span style="color: #4f5c7e;">--name</span> <span style="color: #78683f;">backend</span> <span style="color: #78683f;">backend</span>
+</pre>
+</div>
+
+<p>
+On pourrait faire un article dรฉdiรฉ ร Swarm (ce qui sera probablement le cas dans un avenir assez proche) donc je vous laisse le dรฉcouvrir via <a href="https://github.com/docker/swarm/">github</a>.
+</p>
+</div>
+</div>
+</div>
+
+<div id="outline-container-sec-11" class="outline-2">
+<h2 id="sec-11">Levรฉes de fonds et acquisitons</h2>
+<div class="outline-text-2" id="text-11">
+<p>
+Docker est sur toutes les lรจvres en ce moment. Il est donc normal que cela attire รฉgalement des capitaux. Le 14 avril dernier, Docker annonรงait une nouvelle levรฉe de fonds de <b>95 millions</b> de dollars. Aprรจs celle de <i>40 millions</i> en Septembre 2014, on peut se dire que Docker Inc. a de beaux jours ร venir.
+</p>
+
+<p>
+Docker Inc. ยซ mange ยป aussi quelques startups, puisque aprรจs Orchard, qui รฉditait fig (devenu docker-compose), ils ont fait l'acquisition de <a href="http://socketplane.io/">Socketplane</a> et <a href="https://kitematic.com/">Kitematic</a>. Kitematic est un outil <i>desktop</i> qui permet de facilement utiliser Docker sous Mac OS X, une belle application, un peu ยซ clickodrome ยป <code>;-P</code>. <a href="http://socketplane.io/">Socketplane</a> est une solution rรฉseau qui connectait Open vSwitch avec Docker โ nulle doute que la rรฉcente libnetwork vient de lร .
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-12" class="outline-2">
+<h2 id="sec-12">รvรจnements</h2>
+<div class="outline-text-2" id="text-12">
+<p>
+Nous allons finir avec une liste non-exhaustive et un peu orientรฉe des รฉvรจnements <i>marquants</i> qui se sont passรฉs ces derniers mois :
+</p>
+
+<ul class="org-ul">
+<li>Le <a href="https://blog.docker.com/2014/11/docker-tour-de-france/">Docker Tour de France</a>, avec notament un <a href="http://www.meetup.com/Docker-Paris/events/218767688/">hackathon</a> organisรฉ ร l'<a href="http://www.epitech.eu/paris/ecole-informatique-paris.aspx">Epitech</a>, oรน notre <a href="https://twitter.com/mariolet">Mario Loriedo</a> national a bootstrapรฉ son projet Sublime-docker avec <a href="https://github.com/mjbright">Mike Bright</a> et ร du coup gagnรฉ sa place ร la DockerCon de 2015.
+</li>
+<li>Les <a href="http://blog.zenika.com/index.php?post/2015/02/19/NightClazz-Docker-Avance">Nightclazz</a> <a href="http://zenika.github.io/NC-Docker-Decouverte/">dรฉcouverte</a> et <a href="http://zenika.github.io/NC-Docker-Avance/#/">avancรฉe</a> hรฉbergรฉ par Zenika, prรฉsentรฉ par Mario Loriedo et moi-mรชme ;-).
+</li>
+<li>La DockerCon Europe.
+</li>
+<li>Le <a href="http://docker.party/">Docker Birthday</a>, gigantesque <i>Open-source-athon</i> tout autour du monde โ une vรฉritable rรฉussite, tant au niveau de l'organisation (des รฉvรจnements, la prรฉparation en amont des <i>issues</i>, etc.) que de ce qu'il en est <a href="https://blog.docker.com/2015/05/dockers-2nd-birthday-by-the-numbers/">ressorti</a>.
+</li>
+</ul>
+</div>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2015-07-31-config-managment-intro/" title="Gestion de configuration : introduction">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2015-05-09-migration-to-hugo/" title="Migration vers hugo">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2015-07-31-config-managment-intro/index.html
@@ -0,0 +1,387 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2015-07-31-config-managment-intro/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Gestion de configuration : introduction</h1><a href='https://vincent.demeester.fr/posts/2015-07-31-config-managment-intro/'></a>
+ <address class="signature">
+ <span class="date">Fri, 31 July, 2015</span>
+ <span class="words">(1300 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#configurations">configurations</a></li>
+
+
+
+
+
+ <li class="tag tag-git"><a href="/tags/#git">git<span>3</span></a></li>
+
+
+ <li class="tag tag-myrepos"><a href="/tags/#myrepos">myrepos<span>1</span></a></li>
+
+
+ <li class="tag tag-mr"><a href="/tags/#mr">mr<span>1</span></a></li>
+
+
+ <li class="tag tag-vcsh"><a href="/tags/#vcsh">vcsh<span>1</span></a></li>
+
+
+ <li class="tag tag-linux"><a href="/tags/#linux">linux<span>4</span></a></li>
+
+
+ <li class="tag tag-posix"><a href="/tags/#posix">posix<span>1</span></a></li>
+
+
+ <li class="tag tag-shell"><a href="/tags/#shell">shell<span>2</span></a></li>
+
+
+ <li class="tag tag-sharing"><a href="/tags/#sharing">sharing<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <p>
+Cela doit faire au moins 2 ans que je souhaite partager la faรงon dont
+je gรจre mes configurations (en anglais <i>dotfiles</i>). Comme j'ai
+longtemps repoussรฉ l'รฉchรฉance, probablement de peur d'avoir un roman ร
+รฉcrire, je vais en faire une sรฉrie de petits billets de blog dont
+celui-ci est l'introduction. Nous y aborderons donc mon besoin, et mes
+choix.
+</p>
+
+<div id="outline-container-sec-1" class="outline-2">
+<h2 id="sec-1">Besoin(s)</h2>
+<div class="outline-text-2" id="text-1">
+<p>
+En bon <b>geek</b> que je suis, je suis fan des <i>dotfiles</i>. Les <i>dotfiles</i>
+โ fichiers de configurations โ sont de petits fichiers, habituellement
+dans notre dossier personnel (votre <i>$HOME</i>), qui nous permettent de
+paramรฉtrer et personnaliser nos outils de tous les jours. C'est
+principalement vrai pour des outils en ligne de commande โ et รงa tombe
+bien, j'adore โ mais pas uniquement limitรฉ ร ces derniers.
+</p>
+
+<p>
+Je vais faire un trรจs petit apartรฉ sur le pourquoi de cette
+personnalisation :
+</p>
+
+<ul class="org-ul">
+<li>C'est <b>fun</b> ร faire et c'est relativement important de mon point de vue.
+</li>
+<li>C'est <b>รฉducatif</b> ou formateur ; on lit les documentations de nos
+outils, leurs fonctionnalitรฉs un peu cachรฉes. On va souvent dรฉcouvrir
+un peu la philosophie dans laquelle l'outil a รฉtรฉ crรฉรฉ. C'est en
+mettant les <i>mains dans le cambouis</i> et en <i>foutant un gros bordel</i>
+que j'ai le plus appris (รงa va du <i>langage</i> shell et d'autres
+langages de scripts, de POSIX, au noyau linux ou encore au LISP avec
+GNU/Emacs).
+</li>
+<li>Cela fait <b>gagner du temps</b> et de maniรจre non nรฉgligeable. Je suis
+nรฉ <span class="underline">courageux mais terriblement fainรฉant</span> (et oui c'est possible
+<code>:-P</code>), j'aime pas trop me rรฉpรฉter quand รงa devient un peu compliquรฉ
+/ chiant (e.g. <code>docker run monimage args</code> รงa va, <code>docker run</code> avec
+<code>-v /tmp:/tmp -v /var/run/docker.socket:/var/run/docker.socket [โฆ]</code>
+et <code>run monimage arg1 arg2 arg3 [โฆ]</code> moins dรฉjร ).
+</li>
+</ul>
+
+<p>
+Mais revenons ร nos moutons et faisons une petite liste de mes besoins, un
+peu en vrac :
+</p>
+
+<ul class="org-ul">
+<li>J'ai plusieurs ordinateurs (laptop/desktop/serveurs) et je souhaite
+avoir mes configurations <b>synchronisรฉes</b> entre ceux-ci โ et ce de
+maniรจre simple, c'est ร dire <i>une commande ร exรฉcuter</i>.
+</li>
+<li>C'est liรฉ au point prรฉcรฉdent mais, je ne <i>peux pas vivre</i> sans
+outil de gestion de version, comme <b>git</b>. Il me faut donc un outil
+ou ensemble d'outil qui sache utiliser des outils de gestion de
+version <i>du marchรฉ</i>.
+
+
+<div class="figure">
+<p><img src="./img/git-all-the-thing.jpg" alt="git-all-the-thing.jpg" />
+</p>
+</div>
+</li>
+
+<li>En fonction de mes ordinateurs, mes besoins de configuration
+changent. Il me faut donc un outil <b>flexible</b> qui me permette de dire
+par exemple : sur ce PC j'ai un serveur <code>Xorg</code> donc j'ai besoin de
+mes configuration xorg, de celle de mon <i>window manager</i>, etc. โ et
+inversement sur ce serveur j'ai besoin de python et haskell mais pas
+de xorg..
+</li>
+<li>Je ne souhaites pas avoir ร faire des liens symboliques, ou de
+scripts d'installation. Je trouves que รงa rends les choses plus
+compliquรฉes. Du coup il faut que je puisse avoir <b>plusieurs <i>dรฉpรดts
+de configuration</i></b> (repository) qui pointent au mรชme endroit, sans
+que ce soit le bordel.
+</li>
+<li>Le <b>partage</b> est important pour moi. Il en dรฉcoule deux choses :
+<ol class="org-ol">
+<li>Il faut que je puisse documenter un peu mon repository, avec un
+bon vieux <code>README</code> ; sans que chaque <code>README</code> se marche dessus.
+</li>
+<li>Il y a quelques <b>informations</b> qui sont <b>personnelles</b>, comme par
+exemple les clรฉs ssh. Il me faut donc รชtre capable d'avoir des
+<i>dรฉpรดts publiques</i> et des <i>dรฉpรดts privรฉs</i>. C'est grandement facilitรฉ
+par l'aspect <i>flexibilitรฉ</i> <code>:-)</code>.
+</li>
+</ol>
+</li>
+<li>Un bonus que je souhaite, est de pouvoir disposer de <b>hooks</b>, un peu
+ร la maniรจre de git (voir <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">ici</a>). L'idรฉe est de pouvoir <b>gรฉnรฉrer</b> un
+fichier de configuration ร partir d'un ensemble de fichiers qui
+viendraient de diffรฉrents dรฉpรดts. Le meilleur exemple que je peux
+donner c'est <code>~/.ssh/config</code> dans lequel je vais y mettre des bouts
+publiques que je souhaites partager (comme le <code>Host *</code> avec des
+trucs cool comme <code>ControlPersist</code>, on en parlera plus tard) et des
+bouts privรฉs (mes hosts privรฉs, avec mes configurations de
+<i>rebonds</i>, etc..).
+</li>
+</ul>
+
+<p>
+Cette liste a mis un certain temps ร se former dans ma tรชte, mais une
+fois qu'elle รฉtait formรฉe, j'ai pu assez facilement faire des choix.
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-2" class="outline-2">
+<h2 id="sec-2">Choix</h2>
+<div class="outline-text-2" id="text-2">
+<p>
+Deux outils et un peu d'organisation permettent de rรฉpondre ร mes
+besoins. Les deux outils sont <code>vcsh</code> et <code>myrepos</code> (anciennement appelรฉ
+<code>mr</code>), fait par respectivement Richard Hartmann et Joey Hess (tout
+deux assez impliquรฉ dans la communautรฉ Debian).
+</p>
+</div>
+
+<div id="outline-container-sec-2-1" class="outline-3">
+<h3 id="sec-2-1">vcsh</h3>
+<div class="outline-text-3" id="text-2-1">
+<p>
+En un mot, <a href="https://github.com/RichiH/vcsh">vcsh</a> permet de maintenir plusieurs <i>repository</i> <a href="http://git-scm.com/">git</a> dans
+un seul dossier. Par dรฉfaut tous les <i>repository</i> git maintenus par
+<code>vcsh</code> pointent vers le dossier <code>$HOME</code>, mais il est possible
+d'utiliser un autre dossier.
+</p>
+
+<p>
+L'idรฉe est de pouvoir disposer de plusieurs repository par <i>famille
+d'application</i>, par exemple <code>vim</code>, <code>ssh</code>, <code>emacs</code>, <code>zsh</code>, etc. Cela
+permet ainsi d'avoir diffรฉrents ensemble de configurations sur
+diffรฉrentes machines et pour diffรฉrents utilisateurs. Cela apporte
+une trรจs grande flexibilitรฉ et facilite le partage de configuration
+(au sein d'une entreprise ou d'un projet par exemple) tout en
+laissant la place ร la dรฉfinition de configuration(s)
+personnalisรฉ(s).
+</p>
+
+<p>
+En bonus, <code>vcsh</code> supporte un systรจme de hook, permettant d'exรฉcuter
+des commandes ร diffรฉrents moments du <i>workflow</i> โ c'est la seule
+partie qui manquant ร <code>vcsh</code> de mon point de vue alors j'y ai
+apportรฉ ma petit pierre.
+</p>
+
+<p>
+<code>vcsh</code> est la clรฉ de voรปte de ma gestion de configuration. Sans le
+travail formidable de <a href="http://richardhartmann.de/">Richard Hartmann</a>, je ne sais pas comment je
+ferais..
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-2-2" class="outline-3">
+<h3 id="sec-2-2">myrepos</h3>
+<div class="outline-text-3" id="text-2-2">
+<p>
+En un mot, <a href="https://myrepos.branchable.com/">myrepos</a> est un outil permettant de <i>gรฉrer</i> plusieurs
+repository (git, subversion, mercurial, โฆ) avec une seule
+commande : <code>mr</code>. C'est simple et efficace :
+</p>
+
+<ul class="org-ul">
+<li><code>mr u</code> (ou <code>mr update</code>) pour rรฉcupรฉrer les derniรจres modifications (<code>git pull</code>,
+<code>svn up</code>, โฆ).
+</li>
+<li><code>mr -d $HOME/.config u</code> pour rรฉcupรฉrer les derniรจres modifications
+des repository qui sont dans <code>$HOME/.config</code>.
+</li>
+<li><code>mr -j 6 u</code> pour parallรฉliser la rรฉcupรฉration (ici 6 jobs en parallรจle).
+</li>
+<li><code>mr p</code> pour pousser des modifications (<code>git push</code>, โฆ).
+</li>
+<li><code>mr run</code> pour lancer un commande (j'utilise รงa tous les jours).
+</li>
+</ul>
+
+<p>
+Il est รฉgalement possible de personnaliser les commandes ร lancer lors
+d'un <i>update</i> ou autre (toutes les commandes), et mรชme en dรฉfinir des
+nouvelles. Cela se prรฉsente comme suit :
+</p>
+
+
+<div class="org-src-container">
+
+<pre class="src src-conf">[<span class="org-type">foo</span>]
+<span class="org-variable-name">checkout</span> = git@github.com:joeyh/foo.git
+<span class="org-variable-name">update</span> = git pull --rebase
+
+[<span class="org-type">bar</span>]
+<span class="org-comment-delimiter"># </span><span class="org-comment">This repository has an upstream, which I've forked;</span>
+<span class="org-comment-delimiter"># </span><span class="org-comment">set up a remote on checkout.</span>
+<span class="org-variable-name">checkout</span> =
+ git clone git@github.com:joeyh/bar.git
+ cd bar
+ git remote add upstream git@github.com:barbar/bar.git
+<span class="org-comment-delimiter"># </span><span class="org-comment">make `mr zap` integrate from upstream</span>
+<span class="org-variable-name">zap</span> =
+ git pull upstream
+ git merge upstream/master
+ git push origin master
+
+[<span class="org-type">mystuff</span>]
+<span class="org-variable-name">checkout</span> = git@github.com:joeyh/foo.git
+<span class="org-comment-delimiter"># </span><span class="org-comment">Skip if the current user is not joey</span>
+<span class="org-variable-name">skip</span> = test `whoami` != joey
+
+[<span class="org-type">DEFAULT</span>]
+<span class="org-comment-delimiter"># </span><span class="org-comment">Teach mr how to `mr gc` in git repos.</span>
+<span class="org-variable-name">git_gc</span> = git gc <span class="org-string">"$@"</span>
+</pre>
+</div>
+
+<p>
+Une autre fonctionnalitรฉ qui m'est totalement indispensable est ce
+qu'on appel les <code>fixup(s)</code>. Il est en effet possible d'exรฉcuter une ou
+plusieurs commandes (shell) aprรจs un <code>update</code> (ou via la commande
+<code>fixup</code>). C'est grรขce ร ce systรจme la que je gรฉnรจre mes fichiers de
+configuration en provenance de plusieurs repository (comme
+<code>$HOME/.ssh/config</code> ou encore <code>$HOME/.gitconfig</code>).
+</p>
+
+<p>
+<code>myrepos</code> est l'exemple de l'outil simple et efficace qui fait une
+chose et le fait trรจs bien, et dont je n'arrive pas ร me passer
+<code>:-D</code>. Je l'utilise รฉgalement dans plein d'autres cas, comme par
+exemple pour mettre ร jour mes <i>forks</i> de projets open-source.
+</p>
+</div>
+</div>
+</div>
+
+<div id="outline-container-sec-3" class="outline-2">
+<h2 id="sec-3">Conclusion</h2>
+<div class="outline-text-2" id="text-3">
+<p>
+Et voilร , c'est tout pour cette introduction <code>;-)</code>. La prochaine
+partie se penchera sur la <b>structure</b> que j'utilise ainsi que le
+repository principal qui est <a href="https://github.com/vdemeester/vcsh-home"><b>vcsh-home</b></a>. Dans les parties suivantes
+on parlera des autres repository et donc des configurations
+spรฉcifiques pour les diffรฉrents outils (comme <a href="https://github.com/vdemeester/sh-config">sh-config</a>,
+<a href="https://github.com/vdemeester/emacs-config">emacs-config</a> ou encore <a href="https://github.com/vdemeester/go-config">go-config</a>). On parlera aussi probablement de
+<code>git-annex</code> dans le futur.
+</p>
+</div>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2016-09-18-firefox-places-and-bookmarks/" title="Firefox hidden feature โ places in bookmarks">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2015-06-01-docker-1.6-ecosystem/" title="Docker 1.6 et son รฉcosystรจme">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2016-09-18-firefox-places-and-bookmarks/index.html
@@ -0,0 +1,332 @@
+<!DOCTYPE html>
+
+<html lang="fr">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2016-09-18-firefox-places-and-bookmarks/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="fr"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Firefox hidden feature โ places in bookmarks</h1><a href='https://vincent.demeester.fr/posts/2016-09-18-firefox-places-and-bookmarks/'></a>
+ <address class="signature">
+ <span class="date">Mon, 19 September, 2016</span>
+ <span class="words">(1100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#configurations">configurations</a></li>
+
+
+
+
+
+ <li class="tag tag-firefox"><a href="/tags/#firefox">firefox<span>1</span></a></li>
+
+
+ <li class="tag tag-place"><a href="/tags/#place">place<span>1</span></a></li>
+
+
+ <li class="tag tag-bookmark"><a href="/tags/#bookmark">bookmark<span>1</span></a></li>
+
+
+ <li class="tag tag-hidden"><a href="/tags/#hidden">hidden<span>1</span></a></li>
+
+
+ <li class="tag tag-tips"><a href="/tags/#tips">tips<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <p>
+Je rรฉalise que j'utilise Firefox depuis bien plus de 10 ans maintenant
+(on doit รชtre ร minimum 15 ans en faitโฆ). Et je me souviens d'un temps
+oรน je souhaitais rendre mes <i>bookmarks</i> (marque-pages ๐ผ)
+dynamique. Aprรจs tout ils existent de base dans Firefox (e.g. <code>Most
+visited</code>), il doit donc รชtre possible d'en faire soit mรชme.
+</p>
+
+<p>
+Il fut un temps oรน c'รฉtait facile ร mettre en place โ ouvrir la
+gestion des marques pages, chercher quelque chose et <i>cliquer</i> sur le
+bouton <code>save</code> pour sauvegarder cette recherche en tant de bookmark
+dynamique.
+</p>
+
+<p>
+<span class="underline">Note</span>: comme j'avais grave luttรฉ ร l'รฉpoque, et que j'ai encore luttรฉ
+cette fois ci, cet article va me servir de pense-bรชte pour le futur.
+</p>
+
+<div id="outline-container-sec-1" class="outline-2">
+<h2 id="sec-1">Places</h2>
+<div class="outline-text-2" id="text-1">
+<p>
+C'est le petit nom que possรจde cette fonctionnalitรฉ dans le cลur de
+Firefox. C'est un nom relativement commun, du coup รงa n'aide pas trop
+la recherche d'informationโฆ Le meilleur endroit pour se documenter
+reste alors le <a href="https://developer.mozilla.org">Mozilla Developer Network</a>โฆ
+</p>
+
+<p>
+Et ce qu'on peut lire sur cette <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Places">page</a> c'est :
+</p>
+
+<blockquote>
+<p>
+Places is the bookmarks and history management system introduced in
+Firefox 3. It offers increased flexibility and complex querying to
+make handling the places the user goes easier and more
+convenient. It also includes new features including favicon storage
+and the ability to annotate pages with arbitrary information.
+</p>
+</blockquote>
+
+<p>
+C'est donc un mรฉcanisme interne qui permet d'annoter des pages
+(bookmarks, history, โฆ) et surtout un <i>requรชtage</i> plus complexe et
+flexible que le systรจme prรฉcรฉdent. On peut noter รฉgalement que c'est
+arrivรฉ en version 3, et qu'ร la date du jour, la version courante de
+Firefox est la 48. En espรฉrant donc que ce soit toujours le systรจme en
+place (<i>spoiler alert: รงa a l'air d'รชtre le cas</i>).
+</p>
+
+
+<div class="figure">
+<p><img src="/images/2016/firefox-place-awesomebar-example.png" alt="firefox-place-awesomebar-example.png" />
+</p>
+<p><span class="figure-number">Figure 1:</span> An example of places usage in the awesome bar</p>
+</div>
+
+<p>
+Les petits <i>encarts</i> en noir ci-dessus sont un exemple de ces
+<i>places</i>. Ici il s'agit des <b>tags</b> qui ont รฉtรฉs apposer sur les
+bookmarks ; on voit d'ailleurs que ce sont des bookmarks puisqu'ils
+ont une petite รฉtoile ร cรดtรฉ du joli petit <code>favicon</code>. Firefox a pris
+les termes que j'ai รฉcrit dans la barre d'url et ร faire une recherche
+dans les <i>places</i> suivant diffรฉrents critรจres (l'url, les tags pour
+les bookmarks, โฆ).
+</p>
+</div>
+</div>
+
+<div id="outline-container-sec-2" class="outline-2">
+<h2 id="sec-2">Places dans les bookmarks</h2>
+<div class="outline-text-2" id="text-2">
+<p>
+L'idรฉe est d'utiliser cette fonctionnalitรฉ pour faire des bookmarks
+dynamique. Pour poser un peu de contexte, j'utilise surtout la
+bookmark toolbar pour accรฉder ร des pages dont j'ai besoin (au hasard,
+le webmail du boulot, une page prรฉcise d'issues sur github, des pages
+de guide/rรฉfรฉrence/manuel sur des outils que j'utiliseโฆ) et รฉgalement
+en mode <i>read that later</i>.
+</p>
+
+
+<div class="figure">
+<p><img src="/images/2016/firefox-place-bookmark-toolbar.png" alt="firefox-place-bookmark-toolbar.png" />
+</p>
+<p><span class="figure-number">Figure 2:</span> Ma <i>bookmark</i> toolbar</p>
+</div>
+
+<p>
+Par exemple, dans mon dossier <code>inbox</code>, il y a plusieurs sous-dossiers
+(en fait des dossiers dynamique, mais j'y reviendrais plus tard),
+genre <code>docker</code>, <code>nix</code>, <code>golang</code>, <code>java</code>, etc. Tout ce qui <i>traรฎne</i>
+dans <code>inbox</code> est ร lire ou ร trier (<code>inbox</code> se rรฉfรจre un peu ร ce que
+l'on peut voir avec GTD). Chaque sous dossier รฉtait une sorte de
+<i>filtre</i> par projet, langage ou /whatever/โฆ
+</p>
+
+<p>
+Nous allons donc ruser un peu et utiliser les <i>places</i> dans nos
+bookmarks pour en faire des dossiers dynamique, ร l'instar de <code>Most
+Visited</code>. Pour se faire, il faut dรฉjร trouver un peu de documentation
+sur l'utilisation de ces fameuses <i>places</i> au sein de bookmarks โ et
+รงa pรจche un peuโฆ Toujours sur le <a href="https://developer.mozilla.org">Mozilla Developer Network</a>, une page
+<i>un peu cachรฉ</i> nous rรฉvรจle quelques informations : <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Places/Places_query_URIs">Places query URIs</a>.
+</p>
+
+<blockquote>
+<p>
+You can use a <code>place</code> URI as a bookmark. For example, if you right-click
+on the toolbar and choose "New Bookmark," you can enter a place URI
+there to create a new query on your toolbar that, when clicked, will
+reveal a popup containing the results of the query.
+</p>
+</blockquote>
+
+<p>
+Victoire <code>\o/</code>, il <i>suffit</i> de crรฉer un bookmark avec comme <code>URI</code>
+une <code>place:โฆ</code> URI et c'est gagnรฉ. Ainsi, un bookmark avec comme <code>URI</code>
+<code>place:terms=nixos</code> me retournera un dossier dynamique qui contiens
+tous les liens (<i>history</i>, <i>bookmarks</i>, โฆ) qui contiennent le mot
+<code>nixos</code> โ en gros l'รฉquivalent de ce que nous aurions si nous tapions
+<code>nixos</code> dans la <i>awesomebar</i>.
+</p>
+
+<p>
+Si l'on regarde d'un peu plus prรจs <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Places/Places_query_URIs">Places query URIs</a>, il y a une
+longue liste de paramรจtres possible. Il y en a pour presque tous les
+goรปts : le temps (utile pour afficher l'historique, mais pas trop),
+les visites, le type de <i>place</i> (<i>bookmark</i>, <i>history</i>, โฆ), le
+domaine de l'รฉlรฉment, le dossier dans lequel il se trouve, l'<code>URI</code>,
+les tagsโฆ j'en passe et des meilleurs.
+</p>
+
+<p>
+Si par exemple, je souhaite n'afficher que les pages visitรฉs
+aujourd'hui, triรฉs par nombre de visites et limitรฉs ร 10 rรฉsultats, je
+peux mettre comme <code>URI</code> :
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-http">place:queryType=0&sort=8&maxResults=10&beginTimeRef=1&beginTime=0
+</pre>
+</div>
+
+<p>
+Et on obtiens รงa :
+</p>
+
+
+<div class="figure">
+<p><img src="/images/2016/firefox-place-most-visited-today.png" alt="firefox-place-most-visited-today.png" />
+</p>
+</div>
+
+<p>
+Mais revenons ร nos moutons, moi ce que je souhaite, c'est faire des
+dossiers dynamique par <code>tag</code>, i.e. les tags que l'on peut setter
+lorsqu'on ajoute un bookmark. Et รงa tombe bien, un des paramรจtres
+s'appelle <code>tag</code> et fait exactement รงa. Je souhaite รฉgalement pouvoir
+faire des <code>ET</code> sur mes tags โ par exemple, dans mon dossier
+<code>inbox/nixos</code> je veux tous les bookmarks qui sont tagguรฉs <code>inbox</code> <b>et</b>
+<code>nixos</code>. Et c'est simple, il suffit de lui donner les deux.
+</p>
+
+<div class="org-src-container">
+
+<pre class="src src-http">place:tag=inbox&tag=nixos
+</pre>
+</div>
+</div>
+</div>
+
+<div id="outline-container-sec-3" class="outline-2">
+<h2 id="sec-3">Rรฉtrospective</h2>
+<div class="outline-text-2" id="text-3">
+<p>
+Voilร , vous avez maintenant tout ce qu'il faut pour faire des dossiers
+dynamiques dans vos bookmarks Firefox et vous organiser au mieux (
+<i>ou pas</i>). Quelques points ร noter :
+</p>
+
+<ul class="org-ul">
+<li>L'icรดne du dossier dynamique โ ou mรชme la fonctionnalitรฉ ร
+proprement parler= n'apparaรฎt pas de suite. Il faut parfois
+redรฉmarrez Firefox pour profiter du nouveau dossier dynamique.
+</li>
+<li>Une fois que le bookmark est vu comme un dossier dynamique, il n'est
+plus possible d'รฉditer l'<code>URI</code>. Si vous voulez en changer un, il
+faut tout bonnement le recrรฉer.
+</li>
+<li>Bien que ce soit une fonctionnalitรฉ que je trouve gรฉniale, il y a
+peu de <i>presse</i> sur le sujet et ร mon grand รฉtonnement, aucun plugin
+pour gรฉrer รงa plus proprement. Est-ce le signe qu'un jour ce ne sera
+plus supporter, je n'en ai aucune idรฉe.
+</li>
+<li>Un point trรจs positif si vous utilisez Firefox Sync : รงa marche bien
+(pas vraiment รฉtonnant en fait), ces dossiers se synchronise comme
+le reste et seront donc ร disponible quelque soit l'appareil sur lequel
+vous utilisez firefox <code>\o/</code>.
+</li>
+</ul>
+</div>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2017-01-01-go-testing-functionnal-builders/" title="Golang testing โ functional arguments for wonderful builders">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2015-07-31-config-managment-intro/" title="Gestion de configuration : introduction">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2017-01-01-go-testing-functionnal-builders/index.html
@@ -0,0 +1,585 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2017-01-01-go-testing-functionnal-builders/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="en"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ functional arguments for wonderful builders</h1><a href='https://vincent.demeester.fr/posts/2017-01-01-go-testing-functionnal-builders/'></a>
+ <address class="signature">
+ <span class="date">Sun, 1 January, 2017</span>
+ <span class="words">(1600 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-builder"><a href="/tags/#builder">builder<span>1</span></a></li>
+
+
+ <li class="tag tag-functionnal"><a href="/tags/#functionnal">functionnal<span>2</span></a></li>
+
+
+ <li class="tag tag-java"><a href="/tags/#java">java<span>4</span></a></li>
+
+
+ <li class="tag tag-featured"><a href="/tags/#featured">featured<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <blockquote>
+<p>
+Programming is not easy; even the best programmers are incapable of
+writing programs that work exactly as intended every time. Therefore
+an important part of the software development process is
+testing. Writing tests for our code is a good way to ensure quality
+and improve reliability.
+</p>
+</blockquote>
+
+<p>
+Go programs, when properly implemented, are fairly simple to test
+programatically. The <code>testing</code> built-in library and the features of
+the language itself offer plenty of ways to write good tests. As this
+is a subject I particularly like, I'm gonna write a bunch of articles
+about it, that, <i>hopefully</i> do not get old or boring.
+</p>
+
+<p>
+I'm not going to start by introducing how <code>testing</code> works, it's
+already widely described in <a href="https://golang.org/pkg/testing/">the <code>testing</code> godoc</a>, <a href="https://blog.golang.org/examples">some</a> <a href="https://www.golang-book.com/books/intro/12">articles</a> and
+<a href="https://jonathanmh.com/golang-unit-testing-for-absolute-beginners/">blogs</a>. I'm going to jump ahead on a more advanced techinque to write
+tests, the <code>builders</code> for tests.
+</p>
+
+<p>
+One of the most important characteristic of a <b>unit test</b> (and any
+type of test really) is <b>readability</b>. This means it should be <i>easy
+to read</i> but most importantly it should <b>clearly show the intent of
+the test</b>. The setup (and cleanup) of the tests should be as small as
+possible to avoid the noise. And as we are going to see below, <code>go</code>
+makes it pretty easy to do so.
+</p>
+
+<div id="outline-container-org1afcfe7" class="outline-2">
+<h2 id="org1afcfe7">Builders in tests</h2>
+<div class="outline-text-2" id="text-org1afcfe7">
+<p>
+Sometimes, your need to create data structure for your test that
+might take a lot of line and introduce noise. In <code>golang</code> we don't
+have method overload or even <i>constructors</i> as some other language
+have. This means most of the time, we end up building our data using
+directly the struct expression, as below.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-rainbow-identifiers-identifier-5">node</span> := &<span class="org-type">Node</span>{
+ <span class="org-constant">Name</span>: <span class="org-string">"carthage"</span>,
+ <span class="org-constant">Hostname</span>: <span class="org-string">"carthage.sbr.pm"</span>,
+ <span class="org-constant">Platform</span>: <span class="org-type">Platform</span>{
+ <span class="org-constant">Architecture</span>: <span class="org-string">"x86_64"</span>,
+ <span class="org-constant">OS</span>: <span class="org-string">"linux"</span>,
+ },
+}
+</pre>
+</div>
+
+<p>
+Let's imagine we have a <code>Validate</code> function that make sure the
+specified <code>Node</code> is supported on our structure. We would write some
+tests that ensure that.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">TestValidateLinuxIsSupported</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-6">valid</span> := <span class="org-function-name">Validate</span>(&<span class="org-type">Node</span>{
+ <span class="org-constant">Name</span>: <span class="org-string">"carthage"</span>,
+ <span class="org-constant">Hostname</span>: <span class="org-string">"carthage.sbr.pm"</span>,
+ <span class="org-constant">Platform</span>: &<span class="org-type">Platform</span>{
+ <span class="org-constant">Architecture</span>: <span class="org-string">"x86_64"</span>,
+ <span class="org-constant">OS</span>: <span class="org-string">"linux"</span>,
+ },
+ })
+ <span class="org-keyword">if</span> !<span class="org-rainbow-identifiers-identifier-6">valid</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-string">"linux should be supported, it was not"</span>)
+ }
+}
+
+<span class="org-keyword">func</span> <span class="org-function-name">TestValidateDarwinIsNotSupported</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-6">valid</span> := <span class="org-function-name">Validate</span>(&<span class="org-type">Node</span>{
+ <span class="org-constant">Name</span>: <span class="org-string">"babylon"</span>,
+ <span class="org-constant">Hostname</span>: <span class="org-string">"babylon.sbr.pm"</span>,
+ <span class="org-constant">Platform</span>: &<span class="org-type">Platform</span>{
+ <span class="org-constant">Architecture</span>: <span class="org-string">"x86_64"</span>,
+ <span class="org-constant">OS</span>: <span class="org-string">"darwin"</span>,
+ },
+ })
+ <span class="org-keyword">if</span> <span class="org-rainbow-identifiers-identifier-6">valid</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-string">"darwin should not be supported, it was"</span>)
+ }
+}
+</pre>
+</div>
+
+<p>
+This is quickly hard to read, there is too much noise on that
+test. We setup a whole <code>Node</code> struct, but the only thing we really
+intend to test is the <code>Platform.OS</code> part. The rest is just required
+fields for the function to correctly compile and run.
+</p>
+
+<p>
+This is where test builders (and builders in general) comes into
+play. In <a href="http://www.growing-object-oriented-software.com/">Growing Object-Oriented Software Guided by Tests</a>, the
+Chapter 22 "Constructing Complex Test Data" is exactly about that
+and guide us through the why and the how of these builders. The
+examples in the book are in <code>java</code> and uses wisely the
+object-oriented nature of the language. Here is an example from the
+book.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-java"><span class="org-comment-delimiter">// </span><span class="org-comment">I just want an order from a customer that has no post code</span>
+<span class="org-type">Order</span> <span class="org-variable-name">order</span> = <span class="org-rainbow-identifiers-identifier-12">anOrder</span>()
+ .<span class="org-rainbow-identifiers-identifier-7">from</span>(<span class="org-rainbow-identifiers-identifier-13">aCustomer</span>().<span class="org-rainbow-identifiers-identifier-11">with</span>(<span class="org-rainbow-identifiers-identifier-13">anAddress</span>().<span class="org-rainbow-identifiers-identifier-3">withNotPostCode</span>()))
+ .<span class="org-rainbow-identifiers-identifier-10">build</span>()
+</pre>
+</div>
+
+<p>
+These builders helps <b>keep tests expressive</b>, as it's pretty obvious
+when reading it, what we want to test. They remove the <b>visual
+noise</b> you have when building an object (or a <code>struct{}</code> in Go) and
+allows you to put sane default. They also make <b>tests resilient to
+change</b>. If the structure changes, only the builder has to be
+updated, not the tests depending on it. They also make default case
+really simple to write, and special cases not much more complicated.
+</p>
+</div>
+</div>
+
+<div id="outline-container-orgff90129" class="outline-2">
+<h2 id="orgff90129">Builder in Go</h2>
+<div class="outline-text-2" id="text-orgff90129">
+<p>
+The naive way to create builders in <code>go</code> could be to create a
+<code>builder</code> struct that have methods to construct the final struct and
+a <code>build</code> method. Let's see how it looks.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">ANode</span>() *<span class="org-type">NodeBuilder</span> {
+ <span class="org-keyword">return</span> &<span class="org-type">NodeBuilder</span>{
+ <span class="org-constant">node</span>: &<span class="org-type">Node</span>{
+ <span class="org-constant">Name</span>: <span class="org-string">"node"</span>,
+ <span class="org-comment-delimiter">// </span><span class="org-comment">Other defaults</span>
+ },
+ }
+}
+
+<span class="org-keyword">type</span> <span class="org-type">NodeBuilder</span> <span class="org-keyword">struct</span> {
+ <span class="org-rainbow-identifiers-identifier-5">node</span> *<span class="org-rainbow-identifiers-identifier-12">Node</span>
+}
+
+<span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-1">b</span> *<span class="org-type">NodeBuilder</span>) <span class="org-function-name">Build</span>() *<span class="org-type">Node</span> {
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-1">b</span>.<span class="org-rainbow-identifiers-identifier-5">node</span>
+}
+
+<span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-1">b</span> *<span class="org-type">NodeBuilder</span>) <span class="org-function-name">Hostname</span>(<span class="org-rainbow-identifiers-identifier-3">hostname</span> <span class="org-type">string</span>) *<span class="org-type">NodeBuilder</span> {
+ <span class="org-rainbow-identifiers-identifier-1">b</span>.<span class="org-rainbow-identifiers-identifier-5">node</span>.<span class="org-rainbow-identifiers-identifier-10">Hostname</span> = <span class="org-rainbow-identifiers-identifier-3">hostname</span>
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-1">b</span>
+}
+
+<span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-1">b</span> *<span class="org-type">NodeBuilder</span>) <span class="org-function-name">Name</span>(<span class="org-rainbow-identifiers-identifier-3">name</span> <span class="org-type">string</span>) *<span class="org-type">NodeBuilder</span> {
+ <span class="org-rainbow-identifiers-identifier-1">b</span>.<span class="org-rainbow-identifiers-identifier-5">node</span>.<span class="org-rainbow-identifiers-identifier-8">Name</span> = <span class="org-rainbow-identifiers-identifier-3">name</span>
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-1">b</span>
+}
+
+<span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-1">b</span> *<span class="org-type">NodeBuilder</span>) <span class="org-function-name">Platform</span>(<span class="org-rainbow-identifiers-identifier-14">platform</span> *<span class="org-type">Platform</span>) *<span class="org-type">NodeBuilder</span> {
+ <span class="org-rainbow-identifiers-identifier-1">b</span>.<span class="org-rainbow-identifiers-identifier-5">node</span>.<span class="org-rainbow-identifiers-identifier-4">Platform</span> = <span class="org-rainbow-identifiers-identifier-14">platform</span>
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-1">b</span>
+}
+</pre>
+</div>
+
+<p>
+This looks decent, and using it is pretty straightforward. At least
+it make building the <code>struct</code> more expressive, less noisy and
+resilient to change. We can update the previous test as follow.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">TestValidateLinuxIsSupported</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-6">valid</span> := <span class="org-function-name">Validate</span>(<span class="org-function-name">ANode</span>().<span class="org-function-name">Platform</span>(&<span class="org-type">Platform</span>{
+ <span class="org-constant">Architecture</span>: <span class="org-string">"x86_64"</span>,
+ <span class="org-constant">OS</span>: <span class="org-string">"linux"</span>,
+ }).<span class="org-function-name">Build</span>())
+ <span class="org-keyword">if</span> !<span class="org-rainbow-identifiers-identifier-6">valid</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-string">"linux should be supported, it was not"</span>)
+ }
+}
+
+<span class="org-keyword">func</span> <span class="org-function-name">TestValidateDarwinIsNotSupported</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-6">valid</span> := <span class="org-function-name">Validate</span>(<span class="org-function-name">ANode</span>().<span class="org-function-name">Platform</span>(&<span class="org-type">Platform</span>{
+ <span class="org-constant">Architecture</span>: <span class="org-string">"x86_64"</span>,
+ <span class="org-constant">OS</span>: <span class="org-string">"darwin"</span>,
+ }).<span class="org-function-name">Build</span>())
+ <span class="org-keyword">if</span> <span class="org-rainbow-identifiers-identifier-6">valid</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-string">"darwin should not be supported, it was"</span>)
+ }
+}
+</pre>
+</div>
+
+<p>
+There is room for improvement :
+</p>
+
+<ul class="org-ul">
+<li>There is still some noise, mainly <code>build()</code> and the platform
+<code>struct</code>, as it still shows too much.</li>
+<li>It's not that extensible yet. If you want to update the <code>Node</code> a
+certain way that the builder is not written for, you have to
+update the builder.</li>
+<li>The <code>NodeBuilder</code> struct feels a little empty, it's just there to
+hold on the <code>Node</code> being constructed until it is <code>build</code>.</li>
+</ul>
+
+<p>
+One improvement we could make is to have a <code>Platform</code> builder, even
+if it's a small struct here. Let's do that in the same way we did
+with <code>Node</code>.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">APlatform</span>() *<span class="org-type">PlatformBuilder</span> {
+ <span class="org-keyword">return</span> &<span class="org-type">PlatformBuilder</span>{
+ <span class="org-constant">platform</span>: &<span class="org-type">Platform</span>{
+ <span class="org-constant">Architecture</span>: <span class="org-string">"x64_86"</span>,
+ <span class="org-constant">OS</span>: <span class="org-string">"linux"</span>,
+ },
+ }
+}
+
+<span class="org-keyword">type</span> <span class="org-type">PlatformBuilder</span> <span class="org-keyword">struct</span>{
+ <span class="org-rainbow-identifiers-identifier-14">platform</span> *<span class="org-rainbow-identifiers-identifier-4">Platform</span>
+}
+
+<span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-1">b</span> *<span class="org-type">PlatformBuilder</span>) <span class="org-function-name">Build</span>() *<span class="org-type">Platform</span> {
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-1">b</span>.<span class="org-rainbow-identifiers-identifier-14">platform</span>
+}
+
+<span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-1">b</span> *<span class="org-type">PlatformBuilder</span>) <span class="org-function-name">OS</span>(<span class="org-rainbow-identifiers-identifier-2">os</span> <span class="org-type">string</span>) *<span class="org-type">PlatformBuilder</span> {
+ <span class="org-rainbow-identifiers-identifier-1">b</span>.<span class="org-rainbow-identifiers-identifier-14">platform</span>.<span class="org-rainbow-identifiers-identifier-12">OS</span> = <span class="org-rainbow-identifiers-identifier-2">os</span>
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-1">b</span>
+}
+</pre>
+</div>
+
+<p>
+And our tests becomes ๐ป.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">TestValidateLinuxIsSupported</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-6">valid</span> := <span class="org-function-name">Validate</span>(<span class="org-function-name">ANode</span>().<span class="org-function-name">Platform</span>(
+ <span class="org-function-name">APlatform</span>().<span class="org-function-name">OS</span>(<span class="org-string">"linux"</span>).<span class="org-function-name">Build</span>()
+ ).<span class="org-function-name">Build</span>())
+ <span class="org-keyword">if</span> !<span class="org-rainbow-identifiers-identifier-6">valid</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-string">"linux should be supported, it was not"</span>)
+ }
+}
+
+<span class="org-keyword">func</span> <span class="org-function-name">TestValidateDarwinIsNotSupported</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-6">valid</span> := <span class="org-function-name">Validate</span>(<span class="org-function-name">ANode</span>().<span class="org-function-name">Platform</span>(
+ <span class="org-function-name">APlatform</span>().<span class="org-function-name">OS</span>(<span class="org-string">"darwin"</span>).<span class="org-function-name">Build</span>()
+ ).<span class="org-function-name">Build</span>())
+ <span class="org-keyword">if</span> <span class="org-rainbow-identifiers-identifier-6">valid</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-string">"darwin should not be supported, it was"</span>)
+ }
+}
+</pre>
+</div>
+
+<p>
+It does not really improve the visual noise as there is now quite a
+few duplication : several <code>build</code>, <code>APlatform</code> inside <code>Platform</code>, โฆ
+It is a small improvement on readability but not that much compared
+to the previous one. This is were the Go language features comes
+into play.
+</p>
+</div>
+</div>
+
+<div id="outline-container-org28e3042" class="outline-2">
+<h2 id="org28e3042">Functional arguments to the rescue</h2>
+<div class="outline-text-2" id="text-org28e3042">
+<p>
+Go has two interesting feature that are going to be useful here.
+</p>
+
+<p>
+First, a function in Go is a type on its own and thus is considered
+a <i>first class citizen</i>. It means it's possible to pass a function
+as argument, or define a variable that holds it.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">ApplyTo</span>(<span class="org-rainbow-identifiers-identifier-8">s</span> <span class="org-type">string</span>, <span class="org-rainbow-identifiers-identifier-12">fn</span> <span class="org-keyword">func</span>(<span class="org-type">string</span>) <span class="org-type">string</span>) <span class="org-type">string</span> {
+ <span class="org-keyword">return</span> <span class="org-function-name">fn</span>(<span class="org-rainbow-identifiers-identifier-8">s</span>)
+}
+
+<span class="org-keyword">func</span> <span class="org-function-name">world</span>(<span class="org-rainbow-identifiers-identifier-8">s</span> <span class="org-type">string</span>) <span class="org-type">string</span> {
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-9">fmt</span>.<span class="org-function-name">Sprintf</span>(<span class="org-string">"%s, world!"</span>, <span class="org-rainbow-identifiers-identifier-8">s</span>)
+}
+
+<span class="org-comment-delimiter">// </span><span class="org-comment">Usage</span>
+<span class="org-rainbow-identifiers-identifier-1">a</span> := <span class="org-function-name">ApplyTo</span>(<span class="org-string">"hello"</span>, <span class="org-rainbow-identifiers-identifier-9">world</span>)
+<span class="org-comment-delimiter">// </span><span class="org-comment">a == "hello, world!"</span>
+</pre>
+</div>
+
+<p>
+The second feature that comes into play here, is the possiblity to
+have <i>variadic</i> functions. A variadic function is a function that
+takes a variable number of arguments (from <code>0</code> to any number of
+argument).
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">Print</span>(<span class="org-rainbow-identifiers-identifier-9">strs</span> ...<span class="org-type">string</span>) <span class="org-type">string</span> {
+ <span class="org-keyword">for</span> <span class="org-rainbow-identifiers-identifier-8">_</span>, <span class="org-rainbow-identifiers-identifier-8">s</span> := <span class="org-keyword">range</span> <span class="org-rainbow-identifiers-identifier-9">strs</span> {
+ <span class="org-rainbow-identifiers-identifier-9">fmt</span>.<span class="org-function-name">Println</span>(<span class="org-rainbow-identifiers-identifier-8">s</span>)
+ }
+}
+</pre>
+</div>
+
+<p>
+As we are going to see below, combining these two feature makes our
+builders pretty easy to write and to use with simple case, while
+staying very customizable, even outside of the builder. This is
+really well described in a talk from Dave Cheney : <a href="https://www.youtube.com/watch?v=24lFtGHWxAQ&index=15&list=PLMW8Xq7bXrG58Qk-9QSy2HRh2WVeIrs7e">Functional
+options for friendly APIs</a> (<a href="https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis">transcription</a>).
+</p>
+
+<p>
+Let's apply that to our new builders.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">ANode</span>(<span class="org-rainbow-identifiers-identifier-2">nodeBuilders</span> ...<span class="org-keyword">func</span>(*<span class="org-type">Node</span>)) *<span class="org-type">Node</span> {
+ <span class="org-rainbow-identifiers-identifier-5">node</span> := &<span class="org-type">Node</span>{
+ <span class="org-constant">Name</span>: <span class="org-string">"node"</span>,
+ <span class="org-comment-delimiter">// </span><span class="org-comment">Other defaults</span>
+ }
+
+ <span class="org-keyword">for</span> <span class="org-rainbow-identifiers-identifier-8">_</span>, <span class="org-rainbow-identifiers-identifier-10">build</span> := <span class="org-keyword">range</span> <span class="org-rainbow-identifiers-identifier-2">nodeBuilders</span> {
+ <span class="org-function-name">build</span>(<span class="org-rainbow-identifiers-identifier-5">node</span>)
+ }
+
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-5">node</span>
+}
+
+<span class="org-keyword">func</span> <span class="org-function-name">APlatform</span>(<span class="org-rainbow-identifiers-identifier-8">platformBuilders</span> ...<span class="org-keyword">func</span>(*<span class="org-type">Platform</span>)) *<span class="org-type">Platform</span> {
+ <span class="org-rainbow-identifiers-identifier-14">platform</span> := &<span class="org-type">Platform</span>{
+ <span class="org-constant">Architecture</span>: <span class="org-string">"x64_86"</span>,
+ <span class="org-constant">OS</span>: <span class="org-string">"linux"</span>,
+ }
+
+ <span class="org-keyword">for</span> <span class="org-rainbow-identifiers-identifier-8">_</span>, <span class="org-rainbow-identifiers-identifier-10">build</span> := <span class="org-keyword">range</span> <span class="org-rainbow-identifiers-identifier-8">platformBuilders</span> {
+ <span class="org-function-name">build</span>(<span class="org-rainbow-identifiers-identifier-14">platform</span>)
+ }
+
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-14">platform</span>
+}
+</pre>
+</div>
+
+<p>
+And that is it for the actual builder code. It is <b>small</b> and
+simple, there is <b>no more <code>NodeBuilder</code></b> struct, and this is highly
+extensible. Let's see how to use it.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-comment-delimiter">// </span><span class="org-comment">a default node</span>
+<span class="org-rainbow-identifiers-identifier-2">node1</span> := <span class="org-function-name">ANode</span>()
+<span class="org-comment-delimiter">// </span><span class="org-comment">a node with a specific Hostname</span>
+<span class="org-rainbow-identifiers-identifier-5">node2</span> := <span class="org-function-name">ANode</span>(<span class="org-keyword">func</span>(<span class="org-rainbow-identifiers-identifier-15">n</span> *<span class="org-type">Node</span>) {
+ <span class="org-rainbow-identifiers-identifier-15">n</span>.<span class="org-rainbow-identifiers-identifier-10">Hostname</span> = <span class="org-string">"custom-hostname"</span>
+})
+<span class="org-comment-delimiter">// </span><span class="org-comment">a node with a specific name and platform</span>
+<span class="org-rainbow-identifiers-identifier-8">node3</span> := <span class="org-function-name">ANode</span>(<span class="org-keyword">func</span>(<span class="org-rainbow-identifiers-identifier-15">n</span> *<span class="org-type">Node</span>) {
+ <span class="org-rainbow-identifiers-identifier-15">n</span>.<span class="org-rainbow-identifiers-identifier-8">Name</span> = <span class="org-string">"custom-name"</span>
+}, <span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-15">n</span> *<span class="org-type">Node</span>) {
+ <span class="org-rainbow-identifiers-identifier-15">n</span>.<span class="org-rainbow-identifiers-identifier-4">Platform</span> = <span class="org-function-name">APlatform</span>(<span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-10">p</span> *<span class="org-type">Platform</span>) {
+ <span class="org-rainbow-identifiers-identifier-10">p</span>.<span class="org-rainbow-identifiers-identifier-12">OS</span> = <span class="org-string">"darwin"</span>
+ })
+})
+</pre>
+</div>
+
+<p>
+The last step is to define some <i>function builder</i> for common or
+widely used customization, to make this <b>expressive</b>. And let
+complex, <i>one-time</i> function builder in the end of the user. Now our
+tests looks like.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">TestValidateLinuxIsSupported</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-6">valid</span> := <span class="org-function-name">Validate</span>(<span class="org-function-name">ANode</span>(<span class="org-function-name">WithAPlatform</span>(<span class="org-rainbow-identifiers-identifier-2">Linux</span>)))
+ <span class="org-keyword">if</span> !<span class="org-rainbow-identifiers-identifier-6">valid</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-string">"linux should be supported, it was not"</span>)
+ }
+}
+
+<span class="org-keyword">func</span> <span class="org-function-name">TestValidateDarwinIsNotSupported</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-6">valid</span> := <span class="org-function-name">Validate</span>(<span class="org-function-name">ANode</span>(<span class="org-function-name">WithAPlatform</span>(<span class="org-rainbow-identifiers-identifier-15">Darwin</span>)))
+ <span class="org-keyword">if</span> <span class="org-rainbow-identifiers-identifier-6">valid</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-string">"darwin should not be supported, it was"</span>)
+ }
+}
+
+<span class="org-comment-delimiter">// </span><span class="org-comment">Function builders</span>
+<span class="org-keyword">func</span> <span class="org-function-name">WithAPlatform</span>(<span class="org-rainbow-identifiers-identifier-4">builders</span> ...<span class="org-keyword">func</span>(*<span class="org-type">Platform</span>)) <span class="org-keyword">func</span> (<span class="org-rainbow-identifiers-identifier-15">n</span> *<span class="org-type">Node</span>) {
+ <span class="org-keyword">return</span> <span class="org-keyword">func</span>(<span class="org-rainbow-identifiers-identifier-15">n</span> *<span class="org-type">Node</span>) {
+ <span class="org-rainbow-identifiers-identifier-15">n</span>.<span class="org-rainbow-identifiers-identifier-4">Platform</span> = <span class="org-function-name">Platform</span>(<span class="org-rainbow-identifiers-identifier-4">builders</span>...)
+ }
+}
+
+<span class="org-keyword">func</span> <span class="org-function-name">Linux</span>(<span class="org-rainbow-identifiers-identifier-10">p</span> *<span class="org-type">Platform</span>) {
+ <span class="org-rainbow-identifiers-identifier-10">p</span>.<span class="org-rainbow-identifiers-identifier-12">OS</span> = <span class="org-string">"linux"</span>
+}
+
+<span class="org-keyword">func</span> <span class="org-function-name">Darwin</span>(<span class="org-rainbow-identifiers-identifier-10">p</span> *<span class="org-type">Platform</span>) {
+ <span class="org-rainbow-identifiers-identifier-10">p</span>.<span class="org-rainbow-identifiers-identifier-12">OS</span> = <span class="org-string">"darwin"</span>
+}
+</pre>
+</div>
+
+<p>
+The intent is now clear. It's readable and still resilient to
+change. The code <code>Node(WithPlatform(Linux))</code> is easy to understand
+for a human. It makes what are the <i>tested</i> characteristics of
+<code>struct</code> pretty clear. It's easy to combine multiple builders as the
+<code>WithPlatform</code> function shows ๐ผ. It's also easy to create a
+<i>function builder</i>, even in a different package (as long as the ways
+to modify the struct are exported) and complex or <i>on-off</i> builder
+can be embedded in the function call (<code>Node(func(n *Node) { // โฆ
+ })</code>).
+</p>
+
+<p>
+In summary, using these types of builder have several advantages :
+</p>
+
+<ul class="org-ul">
+<li>tests are <b>easy to read</b>, and reduce the visual noise</li>
+<li>tests are <b>resilient to change</b></li>
+<li>builders are <b>easy to compose</b> and very extensible</li>
+<li>builders could even be <b>shared</b> with production code as there is
+nothing tied to <code>testing</code>.</li>
+</ul>
+</div>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2017-04-22-golang-testing-golden-file/" title="Golang testing โ golden file">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2016-09-18-firefox-places-and-bookmarks/" title="Firefox hidden feature โ places in bookmarks">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2017-04-22-golang-testing-golden-file/index.html
@@ -0,0 +1,359 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2017-04-22-golang-testing-golden-file/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang="en"/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ golden file</h1><a href='https://vincent.demeester.fr/posts/2017-04-22-golang-testing-golden-file/'></a>
+ <address class="signature">
+ <span class="date">Sat, 22 April, 2017</span>
+ <span class="words">(900 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-golden"><a href="/tags/#golden">golden<span>1</span></a></li>
+
+
+ <li class="tag tag-file"><a href="/tags/#file">file<span>1</span></a></li>
+
+
+ <li class="tag tag-functionnal"><a href="/tags/#functionnal">functionnal<span>2</span></a></li>
+
+
+ <li class="tag tag-java"><a href="/tags/#java">java<span>4</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <p>
+Tests are all about <b>maintainability</b> and <b>readability</b>. You want the
+least visual noise possible and it should not be a hassle to
+maintain. When testing functions that output a long of string, in case
+of a command line output testing, readability and maintainance tend to
+be tricky to achieve.
+</p>
+
+
+<div id="outline-container-org2f1fc39" class="outline-2">
+<h2 id="org2f1fc39">The problem</h2>
+<div class="outline-text-2" id="text-org2f1fc39">
+<p>
+As an example let's say we want to test out the output of a command
+that displays a list as a table. The output would look like the
+following:
+</p>
+
+<div class="org-src-container">
+<pre class="src src-sh"><span class="org-rainbow-identifiers-identifier-3">ID:</span> <span class="org-rainbow-identifiers-identifier-15">nodeID</span>
+<span class="org-rainbow-identifiers-identifier-4">Name:</span> <span class="org-rainbow-identifiers-identifier-8">defaultNodeName</span>
+<span class="org-rainbow-identifiers-identifier-10">Hostname:</span> <span class="org-rainbow-identifiers-identifier-6">defaultNodeHostname</span>
+<span class="org-rainbow-identifiers-identifier-4">Joined</span> <span class="org-rainbow-identifiers-identifier-1">at:</span> <span class="org-rainbow-identifiers-identifier-11">2009-11-10</span> <span class="org-rainbow-identifiers-identifier-11">23:00:00</span> <span class="org-rainbow-identifiers-identifier-13">+0000</span> <span class="org-rainbow-identifiers-identifier-15">utc</span>
+<span class="org-rainbow-identifiers-identifier-3">Status:</span>
+ <span class="org-rainbow-identifiers-identifier-4">State:</span> <span class="org-rainbow-identifiers-identifier-10">Ready</span>
+ <span class="org-rainbow-identifiers-identifier-11">Availability:</span> <span class="org-rainbow-identifiers-identifier-8">Active</span>
+ <span class="org-rainbow-identifiers-identifier-11">Address:</span> <span class="org-rainbow-identifiers-identifier-13">127.0.0.1</span>
+<span class="org-rainbow-identifiers-identifier-9">Manager</span> <span class="org-rainbow-identifiers-identifier-3">Status:</span>
+ <span class="org-rainbow-identifiers-identifier-11">Address:</span> <span class="org-rainbow-identifiers-identifier-13">127.0.0.1</span>
+ <span class="org-rainbow-identifiers-identifier-3">Raft</span> <span class="org-rainbow-identifiers-identifier-3">Status:</span> <span class="org-rainbow-identifiers-identifier-8">Reachable</span>
+ <span class="org-rainbow-identifiers-identifier-8">Leader:</span> <span class="org-rainbow-identifiers-identifier-15">No</span>
+<span class="org-rainbow-identifiers-identifier-3">Platform:</span>
+ <span class="org-rainbow-identifiers-identifier-15">Operating</span> <span class="org-rainbow-identifiers-identifier-13">System:</span> <span class="org-rainbow-identifiers-identifier-12">linux</span>
+ <span class="org-rainbow-identifiers-identifier-10">Architecture:</span> <span class="org-rainbow-identifiers-identifier-2">x86_64</span>
+<span class="org-rainbow-identifiers-identifier-8">Resources:</span>
+ <span class="org-rainbow-identifiers-identifier-8">CPUs:</span> <span class="org-rainbow-identifiers-identifier-12">0</span>
+ <span class="org-rainbow-identifiers-identifier-9">Memory:</span> <span class="org-rainbow-identifiers-identifier-15">20</span> <span class="org-rainbow-identifiers-identifier-5">MiB</span>
+<span class="org-rainbow-identifiers-identifier-14">Plugins:</span>
+ <span class="org-rainbow-identifiers-identifier-5">Network:</span> <span class="org-rainbow-identifiers-identifier-3">bridge,</span> <span class="org-rainbow-identifiers-identifier-12">overlay</span>
+ <span class="org-rainbow-identifiers-identifier-9">Volume:</span> <span class="org-rainbow-identifiers-identifier-12">local</span>
+<span class="org-rainbow-identifiers-identifier-10">Engine</span> <span class="org-rainbow-identifiers-identifier-14">Version:</span> <span class="org-rainbow-identifiers-identifier-15">1.13.0</span>
+<span class="org-rainbow-identifiers-identifier-10">Engine</span> <span class="org-rainbow-identifiers-identifier-12">Labels:</span>
+ <span class="org-rainbow-identifiers-identifier-11">-</span> <span class="org-variable-name">engine</span> = <span class="org-rainbow-identifiers-identifier-12">label</span>
+</pre>
+</div>
+
+<p>
+Let's see how we would test that output, naively.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">TestNodeInspectPretty</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-14">expected</span> := <span class="org-string">```</span>
+<span class="org-string">ID: nodeID</span>
+<span class="org-string">Name: defaultNodeName</span>
+<span class="org-string">Hostname: defaultNodeHostname</span>
+<span class="org-string">Joined at: 2009-11-10 23:00:00 +0000 utc</span>
+<span class="org-string">Status:</span>
+<span class="org-string"> State: Ready</span>
+<span class="org-string"> Availability: Active</span>
+<span class="org-string"> Address: 127.0.0.1</span>
+<span class="org-string">Manager Status:</span>
+<span class="org-string"> Address: 127.0.0.1</span>
+<span class="org-string"> Raft Status: Reachable</span>
+<span class="org-string"> Leader: No</span>
+<span class="org-string">Platform:</span>
+<span class="org-string"> Operating System: linux</span>
+<span class="org-string"> Architecture: x86_64</span>
+<span class="org-string">Resources:</span>
+<span class="org-string"> CPUs: 0</span>
+<span class="org-string"> Memory: 20 MiB</span>
+<span class="org-string">Plugins:</span>
+<span class="org-string"> Network: bridge, overlay</span>
+<span class="org-string"> Volume: local</span>
+<span class="org-string">Engine Version: 1.13.0</span>
+<span class="org-string">Engine Labels:</span>
+<span class="org-string"> - engine = label</span>
+<span class="org-string">```</span>
+ <span class="org-rainbow-identifiers-identifier-3">buf</span> := <span class="org-builtin">new</span>(<span class="org-type">bytes.Buffer</span>)
+ <span class="org-rainbow-identifiers-identifier-3">cmd</span> := <span class="org-function-name">newInspectCommand</span>(
+ <span class="org-rainbow-identifiers-identifier-5">test</span>.<span class="org-function-name">NewFakeCli</span>(&<span class="org-type">fakeClient</span>{
+ <span class="org-constant">nodeInspectFunc</span>: <span class="org-keyword">func</span>() (<span class="org-type">swarm.Node</span>, []<span class="org-type">byte</span>, <span class="org-type">error</span>) {
+ <span class="org-keyword">return</span> *<span class="org-function-name">Node</span>(<span class="org-function-name">Manager</span>()), []<span class="org-type">byte</span>{}, <span class="org-constant">nil</span>
+ },
+ }, <span class="org-rainbow-identifiers-identifier-3">buf</span>))
+ <span class="org-rainbow-identifiers-identifier-3">cmd</span>.<span class="org-function-name">SetArgs</span>([]<span class="org-type">string</span>{<span class="org-string">"nodeID"</span>})
+ <span class="org-rainbow-identifiers-identifier-3">cmd</span>.<span class="org-function-name">Flags</span>().<span class="org-function-name">Set</span>(<span class="org-string">"pretty"</span>, <span class="org-string">"true"</span>)
+ <span class="org-rainbow-identifiers-identifier-11">assert</span>.<span class="org-function-name">NilError</span>(<span class="org-rainbow-identifiers-identifier-8">t</span>, <span class="org-rainbow-identifiers-identifier-3">cmd</span>.<span class="org-function-name">Execute</span>())
+ <span class="org-rainbow-identifiers-identifier-15">actual</span> := <span class="org-rainbow-identifiers-identifier-3">buf</span>.<span class="org-function-name">String</span>()
+ <span class="org-rainbow-identifiers-identifier-11">assert</span>.<span class="org-function-name">EqualNormalizedString</span>(<span class="org-rainbow-identifiers-identifier-8">t</span>, <span class="org-rainbow-identifiers-identifier-11">assert</span>.<span class="org-rainbow-identifiers-identifier-2">RemoveSpace</span>, <span class="org-rainbow-identifiers-identifier-15">actual</span>, <span class="org-function-name">string</span>(<span class="org-rainbow-identifiers-identifier-14">expected</span>))
+}
+</pre>
+</div>
+
+<p>
+This might look ok as is, but a few problem are present:
+</p>
+
+<ul class="org-ul">
+<li>The output is quite large and adds some noise to the test</li>
+<li><p>
+Lot's of value in the <code>expected</code> string comes from default values
+of our <code>Node</code> builder.
+</p>
+
+<p>
+This means any time we change our builder default values, we would
+need to update this test, <i>painful</i>.
+</p></li>
+<li>If the output changes for a good reason (add a field, fix a typo,
+โฆ), this test has to be updated too.</li>
+</ul>
+</div>
+</div>
+
+<div id="outline-container-org0519f3e" class="outline-2">
+<h2 id="org0519f3e">Golden files to the rescue</h2>
+<div class="outline-text-2" id="text-org0519f3e">
+<p>
+First, let's get back at what is our test about and what we actually
+want to test.
+</p>
+
+<ul class="org-ul">
+<li>We want to ensure, the output of the function does not change by
+mistake (i.e. change that wasn't supposed to change the output)</li>
+<li>We want to have an update version of the output if that was the
+purpose of our change. And we want this update to be the least
+painful possible.</li>
+<li>We don't really care about the final outputs as long as it stays
+the same for the same inputs (i.e. we don't test for any number of
+space, or that word are valid English, or โฆ).</li>
+</ul>
+
+<p>
+This is where the concept of <b>golden file</b> is useful. In a
+nutshell, a golden file is a file where we store the output and that
+will be used by the test as the expected output. This file should be
+updated any time the output changes for good reason. That's that
+simple ๐ผ.
+</p>
+
+<p>
+Once again, the way go <code>testing</code> works, introducing and using golden
+files in our tests is pretty straightforward and easy to use.
+</p>
+
+<p>
+Let's write a small <i>golden file helper</i> so that our test has no
+visual noise, in a <code>golden</code> package.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">var</span> <span class="org-rainbow-identifiers-identifier-3">update</span> = <span class="org-rainbow-identifiers-identifier-15">flag</span>.<span class="org-function-name">Bool</span>(<span class="org-string">"test.update"</span>, <span class="org-constant">false</span>, <span class="org-string">"update golden file"</span>)
+
+<span class="org-comment-delimiter">// </span><span class="org-comment">Get returns the golden file content. If the `test.update` is specified, it updates the</span>
+<span class="org-comment-delimiter">// </span><span class="org-comment">file with the current output and returns it.</span>
+<span class="org-keyword">func</span> <span class="org-function-name">Get</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>, <span class="org-rainbow-identifiers-identifier-15">actual</span> []<span class="org-type">byte</span>, <span class="org-rainbow-identifiers-identifier-5">filename</span> <span class="org-type">string</span>) []<span class="org-type">byte</span> {
+ <span class="org-rainbow-identifiers-identifier-1">golden</span> := <span class="org-rainbow-identifiers-identifier-9">filepath</span>.<span class="org-function-name">Join</span>(<span class="org-string">"testdata"</span>, <span class="org-rainbow-identifiers-identifier-5">filename</span>)
+ <span class="org-keyword">if</span> *<span class="org-rainbow-identifiers-identifier-3">update</span> {
+ <span class="org-keyword">if</span> <span class="org-rainbow-identifiers-identifier-10">err</span> := <span class="org-rainbow-identifiers-identifier-1">ioutil</span>.<span class="org-function-name">WriteFile</span>(<span class="org-rainbow-identifiers-identifier-1">golden</span>, <span class="org-rainbow-identifiers-identifier-15">actual</span>, <span class="org-rainbow-identifiers-identifier-4">0644</span>); <span class="org-rainbow-identifiers-identifier-10">err</span> != <span class="org-constant">nil</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-rainbow-identifiers-identifier-10">err</span>)
+ }
+ }
+ <span class="org-rainbow-identifiers-identifier-14">expected</span>, <span class="org-rainbow-identifiers-identifier-10">err</span> := <span class="org-rainbow-identifiers-identifier-1">ioutil</span>.<span class="org-function-name">ReadFile</span>(<span class="org-rainbow-identifiers-identifier-1">golden</span>)
+ <span class="org-keyword">if</span> <span class="org-rainbow-identifiers-identifier-10">err</span> != <span class="org-constant">nil</span> {
+ <span class="org-rainbow-identifiers-identifier-8">t</span>.<span class="org-function-name">Fatal</span>(<span class="org-rainbow-identifiers-identifier-10">err</span>)
+ }
+ <span class="org-keyword">return</span> <span class="org-rainbow-identifiers-identifier-14">expected</span>
+}
+</pre>
+</div>
+
+<ul class="org-ul">
+<li>We define a <i>global</i> flag, <code>-test.update</code> that will <i>enhance</i> the
+<code>go test</code> command with it (as soon as we import this <code>golden</code> package).</li>
+<li><p>
+We define a <code>golden.Get</code> function that takes the current output
+and the path of the golden file. It also takes <code>testing.T</code> so any
+failure happening here (like reading file, โฆ) will make the test
+fail (one less thing to write in the test calling this function).
+</p>
+
+<p>
+If the flag is present when running the test, it will update the
+file with the actual content.
+</p></li>
+</ul>
+
+<p>
+The initial test becomes.
+</p>
+
+<div class="org-src-container">
+<pre class="src src-go"><span class="org-keyword">func</span> <span class="org-function-name">TestNodeInspectPretty</span>(<span class="org-rainbow-identifiers-identifier-8">t</span> *<span class="org-type">testing.T</span>) {
+ <span class="org-rainbow-identifiers-identifier-3">buf</span> := <span class="org-builtin">new</span>(<span class="org-type">bytes.Buffer</span>)
+ <span class="org-rainbow-identifiers-identifier-3">cmd</span> := <span class="org-function-name">newInspectCommand</span>(
+ <span class="org-rainbow-identifiers-identifier-5">test</span>.<span class="org-function-name">NewFakeCli</span>(&<span class="org-type">fakeClient</span>{
+ <span class="org-constant">nodeInspectFunc</span>: <span class="org-keyword">func</span>() (<span class="org-type">swarm.Node</span>, []<span class="org-type">byte</span>, <span class="org-type">error</span>) {
+ <span class="org-keyword">return</span> *<span class="org-function-name">Node</span>(<span class="org-function-name">Manager</span>()), []<span class="org-type">byte</span>{}, <span class="org-constant">nil</span>
+ },
+ }, <span class="org-rainbow-identifiers-identifier-3">buf</span>))
+ <span class="org-rainbow-identifiers-identifier-3">cmd</span>.<span class="org-function-name">SetArgs</span>([]<span class="org-type">string</span>{<span class="org-string">"nodeID"</span>})
+ <span class="org-rainbow-identifiers-identifier-3">cmd</span>.<span class="org-function-name">Flags</span>().<span class="org-function-name">Set</span>(<span class="org-string">"pretty"</span>, <span class="org-string">"true"</span>)
+ <span class="org-rainbow-identifiers-identifier-11">assert</span>.<span class="org-function-name">NilError</span>(<span class="org-rainbow-identifiers-identifier-8">t</span>, <span class="org-rainbow-identifiers-identifier-3">cmd</span>.<span class="org-function-name">Execute</span>())
+ <span class="org-rainbow-identifiers-identifier-15">actual</span> := <span class="org-rainbow-identifiers-identifier-3">buf</span>.<span class="org-function-name">String</span>()
+ <span class="org-rainbow-identifiers-identifier-14">expected</span> := <span class="org-rainbow-identifiers-identifier-1">golden</span>.<span class="org-function-name">Get</span>(<span class="org-rainbow-identifiers-identifier-8">t</span>, []<span class="org-function-name">byte</span>(<span class="org-rainbow-identifiers-identifier-15">actual</span>), <span class="org-string">"myfile.golden"</span>)
+ <span class="org-rainbow-identifiers-identifier-11">assert</span>.<span class="org-function-name">EqualNormalizedString</span>(<span class="org-rainbow-identifiers-identifier-8">t</span>, <span class="org-rainbow-identifiers-identifier-11">assert</span>.<span class="org-rainbow-identifiers-identifier-2">RemoveSpace</span>, <span class="org-rainbow-identifiers-identifier-15">actual</span>, <span class="org-function-name">string</span>(<span class="org-rainbow-identifiers-identifier-14">expected</span>))
+}
+</pre>
+</div>
+
+<p>
+If we change the output, the workflow becomes the following :
+</p>
+
+<ul class="org-ul">
+<li>run <code>go test</code> and make sure it's failing,</li>
+<li>Validate that the current output is correct,</li>
+<li>run <code>go test -test.update</code> to update the golden file(s),</li>
+<li>re-run <code>go test</code> to make sure it's now green,</li>
+<li>you are done ๐ผ.</li>
+</ul>
+
+<p>
+With this simple trick, our test now <b>contains less noise</b> and is
+way more <b>maintainable</b> (you just have a command to run to update
+the expected content).
+</p>
+</div>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2018-07-28-gotest-tools-intro/" title="Golang testing โ gotest.tools introduction">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2017-01-01-go-testing-functionnal-builders/" title="Golang testing โ functional arguments for wonderful builders">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2018-07-28-gotest-tools-intro/index.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2018-07-28-gotest-tools-intro/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ gotest.tools introduction</h1><a href='https://vincent.demeester.fr/posts/2018-07-28-gotest-tools-intro/'></a>
+ <address class="signature">
+ <span class="date">Sat, 28 July, 2018</span>
+ <span class="words">(400 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-featured"><a href="/tags/#featured">featured<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ I already wrote 2 previous posts about golang and testing. It’s something I care deeply about and I wanted to continue
+ writing about it. It took me a bit more time than I thought, but getting back to it. Since the <a href="http://vincent.demeester.fr/posts/2017-04-22-golang-testing-golden-file/">last post</a>, Daniel Nephin
+ and I worked (but mainly Daniel ๐ค) on bootstrapping a testing helper library.
+
+ <p>Let me introduce it to you this library : <a href="https://gotest.tools"><code>gotest.tools</code></a>. As described in the <a href="https://godoc.org/gotest.tools">godoc</a> package comment, <code>gotest.tools</code> is a
+collection of packages to augment <code>testing</code> and support common patterns. It’s an enhanced and growing version of the
+initial helpers we (the docker/moby maintainers) wrote initially in <a href="https://github.com/docker/docker"><code>docker/docker</code></a> repository. We are using in quite some
+project here at <a href="https://github.com">Docker</a>.</p>
+
+<p>There is a bunch of packages that will all have their own post (linked here when available) :</p>
+
+<ul>
+<li><a href="/posts/2018-08-16-gotest-tools-assertions/"><code>assert</code></a> (with <code>assert/cmp</code> and <code>assert/opt</code>) that provides assertions for comparing expected values to actual values.</li>
+<li><code>env</code> that provides functions to test code that read environment variable or the current working directory.</li>
+<li><a href="/posts/2018-09-14-gotest-tools-fs/"><code>fs</code></a> that provides tools for creating temporary files, and testing the contents and structure of a directory.</li>
+<li><a href="/posts/2018-09-06-gotest-tools-golden/"><code>golden</code></a> that provides tools for comparing large multi-line strings.</li>
+<li><a href="/posts/2018-09-18-gotest-tools-icmd/"><code>icmd</code></a> that executes binaries and provides convenient assertions for testing the results.</li>
+<li><code>poll</code> that provides tools for testing asynchronous code.</li>
+<li><a href="/posts/2018-09-01-gotest-tools-skip/"><code>skip</code></a> that provides functions for skipping a test and printing the source code of the condition used to skip the test.</li>
+</ul>
+
+<p>There is also experimental package, using the <code>x</code> notation (as the golang team uses, for example with <code>golang.org/x/sync</code>) :</p>
+
+<ul>
+<li><code>x/subtest</code> that provides a <code>TestContext</code> to subtests which handles cleanup and provides a <code>testing.TB</code> and <code>context.Context</code>.</li>
+</ul>
+
+<p>There is already some good <code>testing</code> helpers in the Go ecosystem : <a href="https://github.com/stretchr/testify"><code>testify</code></a>, <a href="http://labix.org/gocheck"><code>gocheck</code></a>, <a href="https://github.com/onsi/ginkgo"><code>ginkgo</code></a> and a lot more โ so
+why create a new one ? There is multiple reason for it, most of them can be seen in the following <a href="https://github.com/gotestyourself/gotest.tools/issues/49#issuecomment-362436026">GitHub issue</a>.</p>
+
+<p><a href="https://github.com/dnephin/">Daniel</a> also wrote a very useful converter if your code base is currently using <code>testify</code> : <code>gty-migrate-from-testify</code>.</p>
+<div class="highlight"><pre class="chroma"><code class="language-sh" data-lang="sh">$ go get -u gotest.tools/assert/cmd/gty-migrate-from-testify
+<span class="c1"># [โฆ]</span>
+$ go list <span class="se">\
+</span><span class="se"></span> -f <span class="s1">'{{.ImportPath}} {{if .XTestGoFiles}}{{"\n"}}{{.ImportPath}}_test{{end}}'</span> <span class="se">\
+</span><span class="se"></span> ./... <span class="p">|</span> xargs gty-migrate-from-testify</code></pre></div>
+<p>In the next post, let’s dig into the assertion part of the library, package <code>assert</code> ๐ผ.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2018-08-16-gotest-tools-assertions/" title="Golang testing โ gotest.tools assertions">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2017-04-22-golang-testing-golden-file/" title="Golang testing โ golden file">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2018-08-16-gotest-tools-assertions/index.html
@@ -0,0 +1,443 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2018-08-16-gotest-tools-assertions/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ gotest.tools assertions</h1><a href='https://vincent.demeester.fr/posts/2018-08-16-gotest-tools-assertions/'></a>
+ <address class="signature">
+ <span class="date">Thu, 16 August, 2018</span>
+ <span class="words">(2000 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-assert"><a href="/tags/#assert">assert<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>Faster way to send the same command to each and every <em>pane</em> in your
+ tmux <em>session</em>.</p>
+
+<p>Let’s take a closer look at <a href="https://gotest.tools"><code>gotest.tools</code></a> assertions packages. This is mainly about <code>assert</code>, <code>assert/cmp</code> and
+ <code>assert/opt</code>.</p>
+
+<blockquote>
+<p>Package assert provides assertions for comparing expected values to actual values. When assertion fails a helpful error
+message is printed.</p>
+</blockquote>
+
+<p>There is two main functions (<code>Assert</code> and <code>Check</code>) and some helpers (like <code>NilError</code>, โฆ). They all take a <code>*testing.T</code> as
+ a first argument, pretty common across testing Go libraries. Let’s dive into those !</p>
+
+
+
+
+<div class="ox-hugo-toc toc">
+<div></div>
+
+<div class="heading">Table of Contents</div>
+
+<ul>
+<li><a href="#assert-and-check"><code>Assert</code> and <code>Check</code></a></li>
+<li><a href="#more-assert-helpers">More <code>assert</code> helpers</a></li>
+<li><a href="#cmp-dot-comparison"><code>cmp.Comparison</code></a>
+
+<ul>
+<li><a href="#equality-with-equal-and-deepequal">Equality with <code>Equal</code> and <code>DeepEqual</code></a></li>
+<li><a href="#errors-with-error-errorcontains-and-errortype">Errors with <code>Error</code>, <code>ErrorContains</code> and <code>ErrorType</code></a></li>
+<li><a href="#bonus-with-panics">Bonus with <code>Panics</code></a></li>
+<li><a href="#miscellaneous-with-contains-len-and-nil">Miscellaneous with <code>Contains</code>, <code>Len</code> and <code>Nil</code></a></li>
+<li><a href="#write-your-own-comparison">Write your own <code>Comparison</code></a></li>
+</ul></li>
+<li><a href="#conclusion">Conclusionโฆ</a></li>
+</ul>
+
+<p></div>
+<!--endtoc--></p>
+
+<h2 id="assert-and-check"><code>Assert</code> and <code>Check</code></h2>
+
+<p>Both those functions accept a <code>Comparison</code> (we’ll check what it is later on) and fail the test when that comparison
+fails. The one difference is that <code>Assert</code> will end the test execution at immediately whereas <code>Check</code> will fail the test
+and proceed with the rest of the test case. This is similar to <code>FailNow</code> and <code>Fail</code> from the standard library
+<code>testing</code>. Both have their use cases.</p>
+
+<p>We’ll Use <code>Assert</code> for the rest of the section but any example here would work with <code>Check</code> too. When we said
+<code>Comparison</code> above, it’s mainly the <a href="https://godoc.org/gotest.tools/assert#BoolOrComparison">BoolOrComparison</a> interface โ it can either be a boolean expression, or a
+<a href="https://godoc.org/gotest.tools/assert/cmp#Comparison">cmp.Comparison</a> type. <code>Assert</code> and <code>Check</code> code will be <em>smart</em> enough to detect which one it is.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">ok</span><span class="p">)</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span><span class="p">)</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">foo</span><span class="p">.</span><span class="nf">IsBar</span><span class="p">())</span></code></pre></div>
+<p>So far not anything extra-ordinary. Let’s first look at some more <em>helper</em> functions in the <code>assert</code> package and quickly
+dive a bit deeper with <code>Comparison</code>.</p>
+
+<h2 id="more-assert-helpers">More <code>assert</code> helpers</h2>
+
+<p>The additional helper functions are the following</p>
+
+<ul>
+<li><code>Equal</code> uses the <code>==</code> operator to assert two values are equal.</li>
+<li><code>DeepEqual</code> uses <code>google/go-cmp</code> to assert two values are equal (it’s <em>close</em> to <code>reflect.DeepEqual</code> but not
+quite). We’ll detail a bit more the <em>options</em> part of this function with <code>cmp.DeepEqual</code>.</li>
+<li><code>Error</code> fails if the error is <code>nil</code> <strong>or</strong> the error message is not the expected one.</li>
+<li><code>ErrorContains</code> fails if the error is <code>nil</code> <strong>or</strong> the error message does not contain the expected substring.</li>
+<li><code>ErrorType</code> fails if the error is <code>nil</code> <strong>or</strong> the error type is not the expected type.</li>
+<li><code>NilError</code> fails if the error is not <code>nil</code>.</li>
+</ul>
+
+<p>All those helper functions have a equivalent function in the <code>cmp</code> package that returns a <code>Comparison</code>. I, personally,
+prefer to use <code>assert.Check</code> or <code>assert.Assert</code> in combination with <code>cmp.Comparison</code> as it allows me to write all my
+assertions the same way, with built-ins comparison or with my own โ i.e. <code>assert.Assert(t, is.Equal(โฆ), "message"</code> or
+<code>assert.Assert(t, stackIsUp(c, timeโฆ), "another message")</code>.</p>
+
+<h2 id="cmp-dot-comparison"><code>cmp.Comparison</code></h2>
+
+<p>This is where it get really interesting, <code>gotest.tools</code> tries to make it as easy as possible for you to create
+appropriate comparison โ making you test readable as much as possible.</p>
+
+<p>Let’s look a bit at the <code>cmp.Comparison</code> type.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Comparison</span> <span class="kd">func</span><span class="p">()</span> <span class="nx">Result</span></code></pre></div>
+<p>It’s just a function that returns a <code>cmp.Result</code>, so let’s look at <code>cmp.Result</code> definition.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Result</span> <span class="kd">interface</span> <span class="p">{</span>
+ <span class="nf">Success</span><span class="p">()</span> <span class="kt">bool</span>
+<span class="p">}</span></code></pre></div>
+<p>Result is an <code>interface</code>, thus any <em>struct</em> that provide a function <code>Success</code> that returns a <code>bool</code> can be used as a
+comparison result, making it really easy to use in your code. There is also existing type of result to make it even
+quicker to write your own comparison.</p>
+
+<ul>
+<li><code>ResultSuccess</code> is a constant which is returned to indicate success.</li>
+<li><code>ResultFailure</code> and <code>ResultFailureTemplate</code> return a failed Result with a failure message.</li>
+<li><code>ResultFromError</code> returns <code>ResultSuccess</code> if <code>err</code> is nil. Otherwise <code>ResultFailure</code> is returned with the error
+message as the failure message. It works a bit like the <code>errors.Wrap</code> function of the <a href="https://github.com/pkg/errors"><code>github.com/pkgs/errors</code></a>
+package.</li>
+</ul>
+
+<p>The <code>cmp</code> package comes with a few defined comparison that, we think, should cover a high number of use-cases. Let’s
+look at them.</p>
+
+<h3 id="equality-with-equal-and-deepequal">Equality with <code>Equal</code> and <code>DeepEqual</code></h3>
+
+<blockquote>
+<p>Equal uses the == operator to assert two values are equal and fails the test if they are not equal.</p>
+
+<p>If the comparison fails Equal will use the variable names for x and y as part of the failure message to identify the
+actual and expected values.</p>
+
+<p>If either x or y are a multi-line string the failure message will include a unified diff of the two values. If the
+values only differ by whitespace the unified diff will be augmented by replacing whitespace characters with visible
+characters to identify the whitespace difference.</p>
+</blockquote>
+
+<p>On the other handโฆ</p>
+
+<blockquote>
+<p>DeepEqual uses google/go-cmp (<a href="http://bit.do/go-cmp">http://bit.do/go-cmp</a>) to assert two values are equal and fails the test if they are not
+equal.</p>
+
+<p>Package <a href="https://godoc.org/gotest.tools/assert/opt">https://godoc.org/gotest.tools/assert/opt</a> provides some additional commonly used Options.</p>
+</blockquote>
+
+<p>Using one or the other is as simple as : if you wrote your <code>if</code> with <code>==</code> then use <code>Equal</code>, otherwise use <code>DeepEqual</code>.
+<code>DeepEqual</code> (and usually <code>reflect.DeepEqual</code>) is used when you want to compare anything more complex than primitive
+types. One advantage of using <code>cmp.DeepEqual</code> over <code>reflect.DeepEqual</code> (in an if), is that you get a well crafted
+message that shows the diff between the expected and the actual structs compared โ and you can pass options to it.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">DeepEqual</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">"a"</span><span class="p">,</span> <span class="s">"b"</span><span class="p">},</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">"b"</span><span class="p">,</span> <span class="s">"a"</span><span class="p">}))</span>
+<span class="c1">// Will print something like
+</span><span class="c1">// --- result
+</span><span class="c1">// +++ exp
+</span><span class="c1">// {[]string}[0]:
+</span><span class="c1">// -: "a"
+</span><span class="c1">// +: "b"
+</span><span class="c1">// {[]string}[1]:
+</span><span class="c1">// -: "b"
+</span><span class="c1">// +: "a"
+</span><span class="c1"></span><span class="nx">foo</span> <span class="o">:=</span> <span class="o">&</span><span class="nf">someType</span><span class="p">(</span><span class="nx">a</span><span class="p">:</span> <span class="s">"with"</span><span class="p">,</span> <span class="nx">b</span><span class="p">:</span> <span class="s">"value"</span><span class="p">)</span>
+<span class="nx">bar</span> <span class="o">:=</span> <span class="o">&</span><span class="nf">someType</span><span class="p">(</span><span class="nx">a</span><span class="p">:</span> <span class="s">"with"</span><span class="p">,</span> <span class="nx">b</span><span class="p">:</span> <span class="s">"value"</span><span class="p">)</span>
+<span class="c1">// the following will succeed as foo and bar are _DeepEqual_
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">DeepEqual</span><span class="p">(</span><span class="nx">foo</span><span class="p">,</span> <span class="nx">bar</span><span class="p">))</span></code></pre></div>
+<p>When using <code>DeepEqual</code>, you may end up with really weird behavior(s). You may want to ignore some fields, or consider
+<code>nil</code> slice or map the same as empty ones ; or more common, your <em>struct</em> contains some unexported fields that you
+cannot use when comparing (as they are not exported ๐). In those case, you can use <code>go-cmp</code> options.</p>
+
+<p>Some existing one are :</p>
+
+<ul>
+<li><a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#EquateEmpty"><code>EquateEmpty</code></a> returns a Comparer option that determines all maps and slices with a length of zero to be equal,
+regardless of whether they are nil.</li>
+<li><a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#IgnoreFields"><code>IgnoreFields</code></a> returns an Option that ignores exported fields of the given names on a single struct type. The struct
+type is specified by passing in a value of that type.</li>
+<li><a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#IgnoreUnexported"><code>IgnoreUnexported</code></a> returns an Option that only ignores the immediate unexported fields of a struct, including anonymous
+fields of unexported types.</li>
+<li><a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#SortSlices"><code>SortSlices</code></a> returns a Transformer option that sorts all <code>[]V</code></li>
+<li>โฆ and <a href="https://godoc.org/github.com/google/go-cmp/cmp/cmpopts">more</a> ๐ผ</li>
+</ul>
+
+<p><code>gotest.tools</code> also defines some <strong>and</strong> you can define yours ! As an example, <code>gotest.tools</code> defines <code>TimeWithThreshold</code>
+and <code>DurationWithThreshold</code> that allows to not fails if the time (or duration) is not exactly the same but in the
+specified threshold we specified. Here is the code for <code>DurationWithThreshold</code> for inspiration.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// DurationWithThreshold returns a gocmp.Comparer for comparing time.Duration. The
+</span><span class="c1">// Comparer returns true if the difference between the two Duration values is
+</span><span class="c1">// within the threshold and neither value is zero.
+</span><span class="c1"></span><span class="kd">func</span> <span class="nf">DurationWithThreshold</span><span class="p">(</span><span class="nx">threshold</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">)</span> <span class="nx">gocmp</span><span class="p">.</span><span class="nx">Option</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="nx">gocmp</span><span class="p">.</span><span class="nf">Comparer</span><span class="p">(</span><span class="nf">cmpDuration</span><span class="p">(</span><span class="nx">threshold</span><span class="p">))</span>
+<span class="p">}</span>
+
+<span class="kd">func</span> <span class="nf">cmpDuration</span><span class="p">(</span><span class="nx">threshold</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">)</span> <span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="nx">x</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="nx">y</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="kc">false</span>
+ <span class="p">}</span>
+ <span class="nx">delta</span> <span class="o">:=</span> <span class="nx">x</span> <span class="o">-</span> <span class="nx">y</span>
+ <span class="k">return</span> <span class="nx">delta</span> <span class="o"><=</span> <span class="nx">threshold</span> <span class="o">&&</span> <span class="nx">delta</span> <span class="o">>=</span> <span class="o">-</span><span class="nx">threshold</span>
+ <span class="p">}</span>
+<span class="p">}</span></code></pre></div>
+<p>Another good example for those options is when you want to skip some field. In <a href="https://github.com/docker/docker"><code>docker/docker</code></a> we want to be able to
+easily check for equality between two service specs, but those might have different <code>CreatedAt</code> and <code>UpdatedAt</code> values
+that we usually don’t care about โ what we want is to make sure it happens in the past 20 seconds. You can easily define
+an option for that.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">cmpServiceOpts</span><span class="p">()</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">Option</span> <span class="p">{</span>
+ <span class="kd">const</span> <span class="nx">threshold</span> <span class="p">=</span> <span class="mi">20</span> <span class="o">*</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span>
+
+ <span class="c1">// Apply withinThreshold only for the following fields
+</span><span class="c1"></span> <span class="nx">metaTimeFields</span> <span class="o">:=</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">Path</span><span class="p">)</span><span class="kt">bool</span> <span class="p">{</span>
+ <span class="k">switch</span> <span class="nx">path</span><span class="p">.</span><span class="nf">String</span><span class="p">()</span> <span class="p">{</span>
+ <span class="k">case</span> <span class="s">"Meta.CreatedAt"</span><span class="p">,</span> <span class="s">"Meta.UpdatedAt"</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">true</span>
+ <span class="p">}</span>
+ <span class="k">return</span> <span class="kc">false</span>
+ <span class="p">}</span>
+ <span class="c1">// have a 20s threshold for the time value that will be passed
+</span><span class="c1"></span> <span class="nx">withinThreshold</span> <span class="o">:=</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Comparer</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
+ <span class="nx">delta</span> <span class="o">:=</span> <span class="nx">x</span><span class="p">.</span><span class="nf">Sub</span><span class="p">(</span><span class="nx">y</span><span class="p">)</span>
+ <span class="k">return</span> <span class="nx">delta</span> <span class="p"><</span> <span class="nx">threshold</span> <span class="o">&&</span> <span class="nx">delta</span> <span class="p">></span> <span class="o">-</span><span class="nx">threshold</span>
+ <span class="p">})</span>
+
+ <span class="k">return</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">FilterPath</span><span class="p">(</span><span class="nx">metaTimeFields</span><span class="p">,</span> <span class="nx">withinThreshold</span><span class="p">)</span>
+<span class="p">}</span></code></pre></div>
+<p>I recommend you look at the <a href="https://godoc.org/gotest.tools/assert/opt">gotest.tools/assert/opt</a> documentation to see which one are defined and how to use them.</p>
+
+<h3 id="errors-with-error-errorcontains-and-errortype">Errors with <code>Error</code>, <code>ErrorContains</code> and <code>ErrorType</code></h3>
+
+<p>Checking for errors is <strong>very common</strong> in Go, having <code>Comparison</code> function for it was a requirement.</p>
+
+<ul>
+<li><code>Error</code> fails if the error is <code>nil</code> <strong>or</strong> the error message is not the expected one.</li>
+<li><code>ErrorContains</code> fails if the error is <code>nil</code> <strong>or</strong> the error message does not contain the expected substring.</li>
+<li><code>ErrorType</code> fails if the error is <code>nil</code> <strong>or</strong> the error type is not the expected type.</li>
+</ul>
+
+<p>Let’s first look at the most used : <code>Error</code> and <code>ErrorContains</code>.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">var</span> <span class="nx">err</span> <span class="kt">error</span>
+<span class="c1">// will fail with : expected an error, got nil
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">"message in a bottle"</span><span class="p">))</span>
+<span class="nx">err</span> <span class="p">=</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">Wrap</span><span class="p">(</span><span class="nx">errors</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="s">"other"</span><span class="p">),</span> <span class="s">"wrapped"</span><span class="p">)</span>
+<span class="c1">// will fail with : expected error "other", got "wrapped: other"
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">"other"</span><span class="p">))</span>
+<span class="c1">// will succeed
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ErrorContains</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">"other"</span><span class="p">))</span></code></pre></div>
+<p>As you can see <code>ErrorContains</code> is especially useful when working with <em>wrapped</em> errors.
+Now let’s look at <code>ErrorType</code>.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">var</span> <span class="nx">err</span> <span class="kt">error</span>
+<span class="c1">// will fail with : error is nil, not StubError
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ErrorType</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">StubError</span><span class="p">{}))</span>
+
+<span class="nx">err</span> <span class="o">:=</span> <span class="nx">StubError</span><span class="p">{</span><span class="s">"foo"</span><span class="p">}</span>
+<span class="c1">// will succeed
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ErrorType</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">StubError</span><span class="p">{}))</span>
+
+<span class="c1">// Note that it also work with a function returning an error
+</span><span class="c1"></span><span class="kd">func</span> <span class="nf">foo</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{}</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ErrorType</span><span class="p">(</span><span class="nx">foo</span><span class="p">,</span> <span class="nx">StubError</span><span class="p">{}))</span></code></pre></div>
+<h3 id="bonus-with-panics">Bonus with <code>Panics</code></h3>
+
+<p>Sometimes, a code is supposed to <em>panic</em>, see <a href="https://golang.org/doc/effective%5Fgo.html#panic">Effective Go (#Panic)</a> for more information. And thus, you may want to make
+sure you’re code panics in such cases. It’s always a bit tricky to test a code that panic as you have to use a deferred
+function to recover the panic โ but then if the panic doesn’t happen how do you fail the test ?</p>
+
+<p>This is where <code>Panics</code> comes handy.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">foo</span><span class="p">(</span><span class="nx">shouldPanic</span> <span class="kt">bool</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="nx">shouldPanic</span> <span class="p">{</span>
+ <span class="nb">panic</span><span class="p">(</span><span class="s">"booooooooooh"</span><span class="p">)</span>
+ <span class="p">}</span>
+ <span class="c1">// don't worry, be happy
+</span><span class="c1"></span><span class="p">}</span>
+<span class="c1">// will fail with : did not panic
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Panics</span><span class="p">(</span><span class="nf">foo</span><span class="p">(</span><span class="kc">false</span><span class="p">)))</span>
+<span class="c1">// will succeed
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Panics</span><span class="p">(</span><span class="nf">foo</span><span class="p">(</span><span class="kc">true</span><span class="p">)))</span></code></pre></div>
+<h3 id="miscellaneous-with-contains-len-and-nil">Miscellaneous with <code>Contains</code>, <code>Len</code> and <code>Nil</code></h3>
+
+<p>Those last three <em>built-in</em> <code>Comparison</code> are pretty straightforward.</p>
+
+<ul>
+<li><p><code>Contains</code> succeeds if item is in collection. Collection may be a string, map, slice, or array.</p>
+
+<p>If collection is a string, item must also be a string, and is compared using <code>strings.Contains()</code>. If collection is a
+Map, contains will succeed if item is a key in the map. If collection is a slice or array, item is compared to each
+item in the sequence using <code>=reflect.DeepEqual()=</code>.</p></li>
+
+<li><p><code>Len</code> succeeds if the sequence has the expected length.</p></li>
+
+<li><p><code>Nil</code> succeeds if obj is a nil interface, pointer, or function.</p></li>
+</ul>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// Contains works on string, map, slice or arrays
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"foobar"</span><span class="p">,</span> <span class="s">"foo"</span><span class="p">))</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Contains</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">"a"</span><span class="p">,</span> <span class="s">"b"</span><span class="p">,</span> <span class="s">"c"</span><span class="p">},</span> <span class="s">"b"</span><span class="p">))</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="s">"a"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"b"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s">"c"</span><span class="p">:</span> <span class="mi">4</span><span class="p">},</span> <span class="s">"b"</span><span class="p">))</span>
+
+<span class="c1">// Len also works on string, map, slice or arrays
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Len</span><span class="p">(</span><span class="s">"foobar"</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Len</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">"a"</span><span class="p">,</span> <span class="s">"b"</span><span class="p">,</span> <span class="s">"c"</span><span class="p">},</span> <span class="mi">3</span><span class="p">))</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Len</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="s">"a"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s">"b"</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span> <span class="s">"c"</span><span class="p">:</span> <span class="mi">4</span><span class="p">},</span> <span class="mi">3</span><span class="p">))</span>
+
+<span class="c1">// Nil
+</span><span class="c1"></span><span class="kd">var</span> <span class="nx">foo</span> <span class="o">*</span><span class="nx">MyStruc</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Nil</span><span class="p">(</span><span class="nx">foo</span><span class="p">))</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">Nil</span><span class="p">(</span><span class="nf">bar</span><span class="p">()))</span></code></pre></div>
+<p>But let’s not waste more time and let’s see how to write our own <code>Comparison</code> !</p>
+
+<h3 id="write-your-own-comparison">Write your own <code>Comparison</code></h3>
+
+<p>One of the main aspect of <code>gotest.tools/assert</code> is to make it easy for developer to write as less boilerplate code as
+possible while writing tests. Writing your own <code>Comparison</code> allows you to write a well named function that will be easy
+to read and that can be re-used across your tests.</p>
+
+<p>Let’s look back at the <code>cmp.Comparison</code> and <code>cmp.Result</code> types.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Comparison</span> <span class="kd">func</span><span class="p">()</span> <span class="nx">Result</span>
+
+<span class="kd">type</span> <span class="nx">Result</span> <span class="kd">interface</span> <span class="p">{</span>
+ <span class="nf">Success</span><span class="p">()</span> <span class="kt">bool</span>
+<span class="p">}</span></code></pre></div>
+<p>A <code>Comparison</code> for <code>assert.Check</code> or <code>assert.Check</code> is a function that return a <code>Result</code>, it’s pretty straightforward to
+implement, especially with <code>cmp.ResultSuccess</code> and <code>cmp.ResultFailure(โฆ)</code> (as seen previously).</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">regexPattern</span><span class="p">(</span><span class="nx">value</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">pattern</span> <span class="kt">string</span><span class="p">)</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">Comparison</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="kd">func</span><span class="p">()</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">Result</span> <span class="p">{</span>
+ <span class="nx">re</span> <span class="o">:=</span> <span class="nx">regexp</span><span class="p">.</span><span class="nf">MustCompile</span><span class="p">(</span><span class="nx">pattern</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nx">re</span><span class="p">.</span><span class="nf">MatchString</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="nx">cmp</span><span class="p">.</span><span class="nx">ResultSuccess</span>
+ <span class="p">}</span>
+ <span class="k">return</span> <span class="nx">cmp</span><span class="p">.</span><span class="nf">ResultFailure</span><span class="p">(</span>
+ <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"%q did not match pattern %q"</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="nx">pattern</span><span class="p">))</span>
+ <span class="p">}</span>
+<span class="p">}</span>
+
+<span class="c1">// To use it
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nf">regexPattern</span><span class="p">(</span><span class="s">"12345.34"</span><span class="p">,</span> <span class="s">`\d+.\d\d`</span><span class="p">))</span></code></pre></div>
+<p>As you can see, it’s pretty easy to implement, and you can do quite a lot in there easily. If a function call returns an
+error inside of your <code>Comparison</code> function, you can use <code>cmp.ResultFromError</code> for example. Having something like
+<code>assert.Check(t, isMyServerUp(":8080"))</code> is way more readable than a 30-line of code to check it.</p>
+
+<h2 id="conclusion">Conclusionโฆ</h2>
+
+<p>โฆ and that’s a wrap. We only looked at the <code>assert</code> package of <a href="https://gotest.tools"><code>gotest.tools</code></a> so far, but it’s already quite a bit to process.</p>
+
+<p>We’ve seen :</p>
+
+<ul>
+<li>the main functions provided by this package : <code>assert.Assert</code> and <code>assert.Check</code></li>
+<li>some helper functions like <code>assert.NilError</code>, โฆ</li>
+<li>the <code>assert/cmp</code>, and <code>assert/opt</code> sub-package that allows you to write more custom <code>Comparison</code></li>
+</ul>
+
+<p>Next time, we’ll look at the <code>skip</code> package, that is a really simple wrapper on top of <code>testing.Skip</code> function.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2018-09-01-gotest-tools-skip/" title="Golang testing โ gotest.tools skip">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2018-07-28-gotest-tools-intro/" title="Golang testing โ gotest.tools introduction">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2018-09-01-gotest-tools-skip/index.html
@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2018-09-01-gotest-tools-skip/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ gotest.tools skip</h1><a href='https://vincent.demeester.fr/posts/2018-09-01-gotest-tools-skip/'></a>
+ <address class="signature">
+ <span class="date">Sat, 1 September, 2018</span>
+ <span class="words">(400 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-skip"><a href="/tags/#skip">skip<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+ <p>Let’s continue the <a href="https://gotest.tools"><code>gotest.tools</code></a> serie, this time with the <code>skip</code> package. This is a
+really simple one so this should be quick.</p>
+
+<blockquote>
+<p><code>skip</code> provides functions for skipping a test and printing the source code of the
+condition used to skip the test.</p>
+</blockquote>
+
+<p>The package consists of only one function : <code>If</code>. The idea comes mainly from
+<a href="https://github.com/docker/docker"><code>docker/docker</code></a> integration test suite, where we wanted to skip some test (or test suites)
+given different context. By context I mean things like the system we are running on
+(<code>Windows</code>, <code>Linux</code>, โฆ) or the capabilities of the running kernel or node (is <code>apparmor</code>
+available or not on the current machine).</p>
+
+<p>This <code>If</code> method takes a <code>testing.T</code> pointer and either a boolean, a function that
+returns a boolean, <strong>or</strong> an expression.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// boolean
+</span><span class="c1">// --- SKIP: TestName (0.00s)
+</span><span class="c1">// skip.go:19: MissingFeature
+</span><span class="c1"></span><span class="kd">var</span> <span class="nx">MissingFeature</span> <span class="kt">bool</span>
+<span class="nx">skip</span><span class="p">.</span><span class="nf">If</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">MissingFeature</span><span class="p">)</span>
+
+<span class="c1">// function
+</span><span class="c1">// --- SKIP: TestName (0.00s)
+</span><span class="c1">// skip.go:19: !IsExperimentalDaemon(dockerClient): daemon is not experimental
+</span><span class="c1"></span><span class="nx">skip</span><span class="p">.</span><span class="nf">If</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nf">IsExperimentalDaemon</span><span class="p">(</span><span class="nx">dockerClient</span><span class="p">),</span> <span class="s">"daemon is not experimental"</span><span class="p">)</span>
+
+<span class="c1">// expression
+</span><span class="c1">// --- SKIP: TestName (0.00s)
+</span><span class="c1">// skip.go:19: apiVersion < version("v1.24")
+</span><span class="c1"></span><span class="nx">skip</span><span class="p">.</span><span class="nf">If</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">apiVersion</span> <span class="p"><</span> <span class="nf">version</span><span class="p">(</span><span class="s">"v1.24"</span><span class="p">))</span></code></pre></div>
+<p>There is few elements to note though :</p>
+
+<ul>
+<li>This package (as other parts of the <code>gotest.tools</code> packages), will try to look at source
+files to display the expression used (same goes for <code>assert</code>). This is usually not a
+problem because you run tests where the source code is. <strong>However</strong>, in the cases you
+generate a test binary to be executed later (ร -la <code>kubernetes</code> or other projects), this
+can display a weird error message if the sources are not availableโฆ You shouldn’t be
+worried too much about it, but it’s better if you know :)</li>
+<li>The main reason to use <code>skip.If</code> is mainly for new contributors to get in quickly,
+<strong>reducing potential friction of them running the tests on their environment</strong>. The more
+the tests are written in a way they explicitely declare their requirements (and skipped
+if the environment does not meet those), the easier it makes contributors run your
+tests. <strong>But</strong>, this also means, you should try to measure the skipped tests on your
+continuous integration system to make sure you run all of them eventuallyโฆ otherwise
+it’s dead code. <em>But more on that in later posts ๐</em>.</li>
+</ul>
+
+<p>That’s all for today folks, told you that was going to be quick.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2018-09-06-gotest-tools-golden/" title="Golang testing โ gotest.tools golden">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2018-08-16-gotest-tools-assertions/" title="Golang testing โ gotest.tools assertions">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2018-09-06-gotest-tools-golden/index.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2018-09-06-gotest-tools-golden/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ gotest.tools golden</h1><a href='https://vincent.demeester.fr/posts/2018-09-06-gotest-tools-golden/'></a>
+ <address class="signature">
+ <span class="date">Thu, 6 September, 2018</span>
+ <span class="words">(500 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>Let’s continue the <a href="https://gotest.tools"><code>gotest.tools</code></a> serie, this time with the <code>golden</code> package. This is a
+<a href="/posts/2017-04-22-golang-testing-golden-file/"><em>quick follow-up</em> on a previous <code>golden</code> post</a>, but focused on the <code>gotest.tools</code>
+implementation. I’m gonna be quicker, please read that one if <code>golden</code> files is a new
+concept for you.</p>
+
+<blockquote>
+<p>Package <code>golden</code> provides tools for comparing large mutli-line strings.</p>
+
+<p>Golden files are files in the <code>./testdata/</code> sub-directory of the package under test.</p>
+</blockquote>
+
+<p>In the previous article, we described the problem, and how to fix it by writing a small
+helper. Well, that small helper is in <code>gotest.tools/golden</code> now, and it has a tiny bit
+more features.</p>
+
+<p>One of the difference between the <code>gotest.tools</code> implementation and the previous post is
+the flag name. In <code>gotest.tools/golden</code>, the flag is <code>-test.update-golden</code> (was just
+<code>-test.update</code> before). Just as before, if the <code>-test.update-golden</code> flag is set then the
+actual content is written to the golden file, before reading it and comparing.</p>
+
+<p>There is two ways to use the <code>golden</code> package:</p>
+
+<ul>
+<li>on it’s own, using <code>golden.Assert</code> or <code>golden.AssertBytes</code></li>
+<li>as a <code>cmp.Comparison</code>, with <code>golden.String</code> or <code>golden.Bytes</code></li>
+</ul>
+
+<h2 id="assert-and-assertbytes"><code>Assert</code> and <code>AssertBytes</code></h2>
+
+<p>Using <code>Assert</code> functions should be straightforward. Both <code>Assert</code> function compares the
+actual content to the expected content in the golden file and returns whether the
+assertion was successful (true) or not (false).</p>
+
+<ul>
+<li><code>Assert</code> uses string. Note that this one <strong>removes carriage return</strong> before comparing to
+depend as less as possible of the system (<code>\n</code> vs <code>\r\n</code> ๐
)</li>
+<li><code>AssertBytes</code> uses raw data (in the form of <code>[]byte</code>)</li>
+</ul>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">golden</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="s">"foo"</span><span class="p">,</span> <span class="s">"foo-content.golden"</span><span class="p">)</span>
+<span class="c1">// Could also be used to check some binary format
+</span><span class="c1"></span><span class="nx">golden</span><span class="p">.</span><span class="nf">AssertBytes</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">"foo"</span><span class="p">),</span> <span class="s">"foo-content.golden"</span><span class="p">)</span></code></pre></div>
+<h2 id="bytes-and-string"><code>Bytes</code> and <code>String</code></h2>
+
+<p>As written in a <a href="/posts/2018-08-16-gotest-tools-assertions/">previous post (about the <code>assert</code> package)</a>, I prefer to use <code>cmp.Comparison</code>.</p>
+
+<blockquote>
+<p>All those helper functions have a equivalent function in the <code>cmp</code> package that returns a
+<code>Comparison</code>. I, personally, prefer to use <code>assert.Check</code> or <code>assert.Assert</code> in
+combination with <code>cmp.Comparison</code> as it allows me to write all my assertions the same way,
+with built-ins comparison or with my own โ i.e. <code>assert.Assert(t, is.Equal(โฆ), "message"</code>
+or <code>assert.Assert(t, stackIsUp(c, timeโฆ), "another message")</code>.</p>
+</blockquote>
+
+<p>The <code>golden</code> package gives us that too, in the form of <code>Bytes</code> and <code>String</code>. Using the
+<code>assert.Check</code> or <code>assert.Assert</code> functions with those is equivalent to their <em>helper</em>
+counter-part <code>golden.Assert</code> and <code>golden.AssertBytes</code>.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">golden</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"foo"</span><span class="p">,</span> <span class="s">"foo-content.golden"</span><span class="p">))</span>
+<span class="c1">// Could also be used to check some binary format
+</span><span class="c1"></span><span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">golden</span><span class="p">.</span><span class="nf">Bytes</span><span class="p">([]</span><span class="nb">byte</span><span class="p">(</span><span class="s">"foo"</span><span class="p">),</span> <span class="s">"foo-content.golden"</span><span class="p">))</span></code></pre></div>
+<h2 id="conclusion">Conclusionโฆ</h2>
+
+<p>โฆ that’s a wrap. As for <a href="/posts/2018-09-01-gotest-tools-skip/"><code>skip</code></a>, this is a small package, so the post was going to be
+quick. <code>golden</code> package just solve a specific problem (read <a href="/posts/2017-04-22-golang-testing-golden-file/">Golang testing โ golden file</a>)
+in a simple way.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2018-09-14-gotest-tools-fs/" title="Golang testing โ gotest.tools fs">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2018-09-01-gotest-tools-skip/" title="Golang testing โ gotest.tools skip">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2018-09-14-gotest-tools-fs/index.html
@@ -0,0 +1,279 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2018-09-14-gotest-tools-fs/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ gotest.tools fs</h1><a href='https://vincent.demeester.fr/posts/2018-09-14-gotest-tools-fs/'></a>
+ <address class="signature">
+ <span class="date">Fri, 14 September, 2018</span>
+ <span class="words">(1100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-filesystem"><a href="/tags/#filesystem">filesystem<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>Let’s continue the <a href="https://gotest.tools"><code>gotest.tools</code></a> serie, this time with the <code>fs</code> package.</p>
+
+<blockquote>
+<p>Package fs provides tools for creating temporary files, and testing the contents and structure of a directory.</p>
+</blockquote>
+
+<p>This package is heavily using functional arguments (as we saw in <a href="/posts/2017-01-01-go-testing-functionnal-builders/">functional arguments for
+wonderful builders</a>). Functional arguments is, in a nutshell, a combinaison of two Go
+features : <em>variadic</em> functions (<code>...</code> operation in a function signature) and the fact
+that <code>func</code> are <em>first class citizen</em>. This looks more or less like that.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Config</span> <span class="kd">struct</span> <span class="p">{}</span>
+
+<span class="kd">func</span> <span class="nf">MyFn</span><span class="p">(</span><span class="nx">ops</span> <span class="o">...</span><span class="kd">func</span><span class="p">(</span><span class="o">*</span><span class="nx">Config</span><span class="p">))</span> <span class="o">*</span><span class="nx">Config</span> <span class="p">{</span>
+ <span class="nx">c</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">Config</span><span class="p">{}</span> <span class="c1">// with default values
+</span><span class="c1"></span> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">op</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">ops</span> <span class="p">{</span>
+ <span class="nf">op</span><span class="p">(</span><span class="nx">c</span><span class="p">)</span>
+ <span class="p">}</span>
+ <span class="k">return</span> <span class="nx">c</span>
+<span class="p">}</span>
+
+<span class="c1">// Calling it
+</span><span class="c1"></span><span class="nx">conf</span> <span class="o">:=</span> <span class="nf">MyFn</span><span class="p">(</span><span class="nx">withFoo</span><span class="p">,</span> <span class="nf">withBar</span><span class="p">(</span><span class="s">"baz"</span><span class="p">))</span></code></pre></div>
+<p>The <code>fs</code> package has too <strong>main</strong> purpose :</p>
+
+<ol>
+<li>create folders and files required for testing in a simple manner</li>
+<li>compare two folders structure (and content)</li>
+</ol>
+
+<h2 id="create-folder-structures">Create folder structures</h2>
+
+<p>Sometimes, you need to create folder structures (and files) in tests. Doing <code>i/o</code> work
+takes time so try to limit the number of tests that needs to do that, especially in unit
+tests. Doing it in tests adds a bit of boilerplate that could be avoid. As stated <a href="/posts/2017-01-01-go-testing-functionnal-builders/">before</a> :</p>
+
+<blockquote>
+<p>One of the most important characteristic of a unit test (and any type of test really) is
+<strong>readability</strong>. This means it should be easy to read but most importantly it should <strong>clearly
+show the intent</strong> of the test. The setup (and cleanup) of the tests should be as small as
+possible to avoid the noise.</p>
+</blockquote>
+
+<p>In a test you usually end up using <code>ioutil</code> function to create what you need. This looks
+somewhat like the following.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">path</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">ioutil</span><span class="p">.</span><span class="nf">TempDir</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">"bar"</span><span class="p">)</span>
+<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span> <span class="c1">// or using `assert.Assert`
+</span><span class="c1"></span> <span class="nx">t</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
+<span class="p">}</span>
+<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">os</span><span class="p">.</span><span class="nf">Mkdir</span><span class="p">(</span><span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">path</span><span class="p">,</span> <span class="s">"foo"</span><span class="p">),</span> <span class="nx">os</span><span class="p">.</span><span class="nf">FileMode</span><span class="p">(</span><span class="mo">0755</span><span class="p">));</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
+ <span class="nx">t</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
+<span class="p">}</span>
+<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">ioutil</span><span class="p">.</span><span class="nf">WriteFile</span><span class="p">(</span><span class="nx">filepath</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">path</span><span class="p">,</span> <span class="s">"foo"</span><span class="p">,</span> <span class="s">"bar"</span><span class="p">),</span> <span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">"content"</span><span class="p">),</span> <span class="nx">os</span><span class="p">.</span><span class="nf">FileMode</span><span class="p">(</span><span class="mo">0777</span><span class="p">));</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
+ <span class="nx">t</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
+<span class="p">}</span>
+<span class="k">defer</span> <span class="nx">os</span><span class="p">.</span><span class="nf">RemoveAll</span><span class="p">(</span><span class="nx">path</span><span class="p">)</span> <span class="o">//</span> <span class="nx">to</span> <span class="nx">clean</span> <span class="nx">up</span> <span class="nx">at</span> <span class="nx">the</span> <span class="nx">end</span> <span class="nx">of</span> <span class="nx">the</span> <span class="nx">test</span></code></pre></div>
+<p>The <code>fs</code> package intends to help reduce the noise and comes with a bunch function to create
+folder structure :</p>
+
+<ul>
+<li>two main function <code>NewFile</code> and <code>NewDir</code></li>
+<li>a bunch of <em>operators</em> : <code>WithFile</code>, <code>WithDir</code>, โฆ</li>
+</ul>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">NewDir</span><span class="p">(</span><span class="nx">t</span> <span class="nx">assert</span><span class="p">.</span><span class="nx">TestingT</span><span class="p">,</span> <span class="nx">prefix</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">ops</span> <span class="o">...</span><span class="nx">PathOp</span><span class="p">)</span> <span class="o">*</span><span class="nx">Dir</span> <span class="p">{</span>
+ <span class="c1">// โฆ
+</span><span class="c1"></span><span class="p">}</span>
+
+<span class="kd">func</span> <span class="nf">NewFile</span><span class="p">(</span><span class="nx">t</span> <span class="nx">assert</span><span class="p">.</span><span class="nx">TestingT</span><span class="p">,</span> <span class="nx">prefix</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">ops</span> <span class="o">...</span><span class="nx">PathOp</span><span class="p">)</span> <span class="o">*</span><span class="nx">File</span> <span class="p">{</span>
+ <span class="c1">// โฆ
+</span><span class="c1"></span><span class="p">}</span></code></pre></div>
+<p>The <code>With*</code> function are all satisfying the <code>PathOp</code> interface, making <code>NewFile</code> and
+<code>NewDir</code> extremely composable. Let’s first see how our above example would look like using
+the <code>fs</code> package, and then, we’ll look a bit more at the main <code>PathOp</code> functionโฆ</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">dir</span> <span class="o">:=</span> <span class="nx">fs</span><span class="p">.</span><span class="nf">NewDir</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="s">"bar"</span><span class="p">,</span> <span class="nx">fs</span><span class="p">.</span><span class="nf">WithDir</span><span class="p">(</span><span class="s">"foo"</span><span class="p">,</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nf">WithFile</span><span class="p">(</span><span class="s">"bar"</span><span class="p">,</span> <span class="nx">fs</span><span class="p">.</span><span class="nf">WithContent</span><span class="p">(</span><span class="s">"content"</span><span class="p">),</span> <span class="nx">fs</span><span class="p">.</span><span class="nf">WithMode</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nf">FileMode</span><span class="p">(</span><span class="mo">0777</span><span class="p">))),</span>
+<span class="p">))</span>
+<span class="k">defer</span> <span class="nx">dir</span><span class="p">.</span><span class="nf">Remove</span><span class="p">()</span></code></pre></div>
+<p>It’s clean and simple to read. The intent is well described and there is not that much of
+noise. <code>fs</code> functions tends to have <em>sane</em> and <em>safe</em> defaults value (for <code>os.FileMode</code>
+for example). Let’s list the main, useful, <code>PathOp</code> provided by <code>gotest.tools/fs</code>.</p>
+
+<ul>
+<li><code>WithDir</code> creates a sub-directory in the directory at path.</li>
+<li><code>WithFile</code> creates a file in the directory at path with content.</li>
+<li><code>WithSymlink</code> creates a symlink in the directory which links to target. Target must be a
+path relative to the directory.</li>
+<li><code>WithHardlink</code> creates a link in the directory which links to target. Target must be a
+path relative to the directory.</li>
+<li><code>WithContent</code> and <code>WWithBytes</code> write content to a file at Path (from a <code>string</code> or a
+<code>[]byte</code> slice).</li>
+<li><code>WithMode</code> sets the file mode on the directory or file at path.</li>
+<li><code>WithTimestamps</code> sets the access and modification times of the file system object at
+path.</li>
+<li><code>FromDir</code> copies the directory tree from the source path into the new Dir. This is
+pretty useful when you have a huge folder structure already present in you <code>testdata</code>
+folder or elsewhere.</li>
+<li><code>AsUser</code> changes ownership of the file system object at Path.</li>
+</ul>
+
+<p>Also, note that <code>PathOp</code> being an function type, you can provide your own implementation
+for specific use-cases. Your function just has to satisfy <code>PathOp</code> signature.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">PathOp</span> <span class="kd">func</span><span class="p">(</span><span class="nx">path</span> <span class="nx">Path</span><span class="p">)</span> <span class="kt">error</span></code></pre></div>
+<h2 id="compare-folder-structures">Compare folder structures</h2>
+
+<p>Sometimes, the code you’re testing is creating a folder structure, and you would like to
+be able to tests that, with the given arguments, it creates the specified structure. <code>fs</code>
+allows you to do that too.</p>
+
+<p>The package provides a <code>Equal</code> function, which returns a <code>Comparison</code>, that the <a href="/posts/2018-08-16-gotest-tools-assertions/"><code>assert</code></a>
+package understand. It works by comparing a <code>Manifest</code> type provided by the test and a
+<code>Manifest</code> representation of the specified folder.</p>
+
+<blockquote>
+<p>Equal compares a directory to the expected structured described by a manifest and returns
+success if they match. If they do not match the failure message will contain all the
+differences between the directory structure and the expected structure defined by the
+Manifest.</p>
+</blockquote>
+
+<p>A <code>Manifest</code> stores the expected structure and properties of files and directories in a
+file-system. You can create a <code>Manifest</code> using either the functions <code>Expected</code> or
+<code>ManifestFromDir</code>.</p>
+
+<p>We’re going to focus on the <code>Expected</code> function, as <code>ManifestFromDir</code> does pretty much
+what you would expected : it takes the specified path, and returns a <code>Manifest</code> that
+represent this folder.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">Expected</span><span class="p">(</span><span class="nx">t</span> <span class="nx">assert</span><span class="p">.</span><span class="nx">TestingT</span><span class="p">,</span> <span class="nx">ops</span> <span class="o">...</span><span class="nx">PathOp</span><span class="p">)</span> <span class="nx">Manifest</span></code></pre></div>
+<p><code>Expected</code> is close to <code>NewDir</code> function : it takes the same <code>PathOp</code> functional
+arguments. This makes creating a <code>Manifest</code> straightforward, as it’s working the same. Any
+function that satisfy <code>PathOp</code> can be used for <code>Manifest</code> the exact same way you’re using
+them on <code>fs.NewDir</code>.</p>
+
+<p>There is a few additional functions that are only useful with <code>Manifest</code> :</p>
+
+<ul>
+<li><code>MatchAnyFileContent</code> updates a Manifest so that the file at path may contain any content.</li>
+<li><code>MatchAnyFileMode</code> updates a Manifest so that the resource at path will match any file mode.</li>
+<li><code>MatchContentIgnoreCarriageReturn</code> ignores cariage return discrepancies.</li>
+<li><code>MatchExtraFiles</code> updates a Manifest to allow a directory to contain unspecified files.</li>
+</ul>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">path</span> <span class="o">:=</span> <span class="nf">operationWhichCreatesFiles</span><span class="p">()</span>
+<span class="nx">expected</span> <span class="o">:=</span> <span class="nx">fs</span><span class="p">.</span><span class="nf">Expected</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nf">WithFile</span><span class="p">(</span><span class="s">"one"</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nf">WithBytes</span><span class="p">(</span><span class="nx">golden</span><span class="p">.</span><span class="nf">Get</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="s">"one.golden"</span><span class="p">)),</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nf">WithMode</span><span class="p">(</span><span class="mo">0600</span><span class="p">)),</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nf">WithDir</span><span class="p">(</span><span class="s">"data"</span><span class="p">,</span>
+ <span class="nx">fs</span><span class="p">.</span><span class="nf">WithFile</span><span class="p">(</span><span class="s">"config"</span><span class="p">,</span> <span class="s">""</span><span class="p">,</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">MatchAnyFileContent</span><span class="p">)),</span>
+<span class="p">)</span>
+
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">fs</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="nx">path</span><span class="p">,</span> <span class="nx">expected</span><span class="p">))</span></code></pre></div>
+<p>The following example compares the result of <code>operationWhichCreatesFiles</code> to the expected
+<code>Manifest</code>. As you can see it also integrates well with other part of the <code>gotest.tools</code>
+library, with the <a href="/posts/2018-09-06-gotest-tools-golden/"><code>golden</code> package</a> in this example.</p>
+
+<h2 id="conclusion">Conclusionโฆ</h2>
+
+<p>โฆ that’s a wrap. In my opinion, this is one the most useful package provided by
+<code>gotest.tools</code> after <code>assert</code>. It allows to create simple or complex folder structure
+without the noise that usually comes with it.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2018-09-18-gotest-tools-icmd/" title="Golang testing โ gotest.tools icmd">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2018-09-06-gotest-tools-golden/" title="Golang testing โ gotest.tools golden">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2018-09-18-gotest-tools-icmd/index.html
@@ -0,0 +1,304 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2018-09-18-gotest-tools-icmd/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ gotest.tools icmd</h1><a href='https://vincent.demeester.fr/posts/2018-09-18-gotest-tools-icmd/'></a>
+ <address class="signature">
+ <span class="date">Tue, 18 September, 2018</span>
+ <span class="words">(1100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-exec"><a href="/tags/#exec">exec<span>1</span></a></li>
+
+
+ <li class="tag tag-command"><a href="/tags/#command">command<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>Let’s continue the <a href="https://gotest.tools"><code>gotest.tools</code></a> serie, this time with the <code>icmd</code> package.</p>
+
+<blockquote>
+<p>Package icmd executes binaries and provides convenient assertions for testing the results.</p>
+</blockquote>
+
+<p>After file-system operations (seen in <a href="/posts/2018-09-14-gotest-tools-fs/"><code>fs</code></a>), another common use-case in tests is to
+<strong>execute a command</strong>. The reasons can be you’re testing the <code>cli</code> you’re currently writing
+or you need to setup something using a command line. A classic execution in a test might
+lookup like the following.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">cmd</span> <span class="o">:=</span> <span class="nx">exec</span><span class="p">.</span><span class="nf">Command</span><span class="p">(</span><span class="s">"echo"</span><span class="p">,</span> <span class="s">"foo"</span><span class="p">)</span>
+<span class="nx">cmd</span><span class="p">.</span><span class="nx">Stout</span> <span class="p">=</span> <span class="o">&</span><span class="nx">stdout</span>
+<span class="nx">cmd</span><span class="p">.</span><span class="nx">Env</span> <span class="p">=</span> <span class="nx">env</span>
+<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">cmd</span><span class="p">.</span><span class="nf">Run</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
+ <span class="nx">t</span><span class="p">.</span><span class="nf">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
+<span class="p">}</span>
+<span class="k">if</span> <span class="nb">string</span><span class="p">(</span><span class="nx">stdout</span><span class="p">)</span> <span class="o">!=</span> <span class="s">"foo"</span> <span class="p">{</span>
+ <span class="nx">t</span><span class="p">.</span><span class="nf">Fatalf</span><span class="p">(</span><span class="s">"expected: foo, got %s"</span><span class="p">,</span> <span class="nb">string</span><span class="p">(</span><span class="nx">stdout</span><span class="p">))</span>
+<span class="p">}</span></code></pre></div>
+<p>The package <code>icmd</code> is there to ease your pain (as usual ๐) โ we used <em>the name <code>icmd</code></em>
+instead of <code>cmd</code> because it’s a pretty common identifier in Go source code, thus would be
+really easy to <em>shadow</em> โ and have some really weird problems going on.</p>
+
+<p>The usual <code>icmd</code> workflow is the following:</p>
+
+<ol>
+<li>Describe the command you want to execute using : type <code>Cmd</code>, function <code>Command</code> and
+<code>CmdOp</code> operators.</li>
+<li>Run it using : function <code>RunCmd</code> or <code>RunCommand</code> (that does 1. for you). You can also
+use <code>StartCmd</code> and <code>WaitOnCmd</code> if you want more control on the execution workflow.</li>
+<li>Check the result using the <code>Assert</code>, <code>Equal</code> or <code>Compare</code> methods attached to the
+<code>Result</code> struct that the command execution return.</li>
+</ol>
+
+<h2 id="create-and-run-a-command">Create and run a command</h2>
+
+<p>Let’s first dig how to create commands. In this part, the assumption here is that the
+command is successful, so we’ll have <code>.Assert(t, icmd.Success)</code> for now โ we’ll learn more
+about <code>Assert</code> in the next section ๐ผ.</p>
+
+<p>The simplest way to create and run a command is using <code>RunCommand</code>, it has the same
+signature as <code>os/exec.Command</code>. A simple command execution goes as below.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">icmd</span><span class="p">.</span><span class="nf">RunCommand</span><span class="p">(</span><span class="s">"echo"</span><span class="p">,</span> <span class="s">"foo"</span><span class="p">).</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">icmd</span><span class="p">.</span><span class="nx">Sucess</span><span class="p">)</span></code></pre></div>
+<p>Sometimes, you need to customize the command a bit more, like adding some environment
+variable. In those case, you are going to use <code>RunCmd</code>, it takes a <code>Cmd</code> and operators.
+Let’s look at those functions.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">RunCmd</span><span class="p">(</span><span class="nx">cmd</span> <span class="nx">Cmd</span><span class="p">,</span> <span class="nx">cmdOperators</span> <span class="o">...</span><span class="nx">CmdOp</span><span class="p">)</span> <span class="o">*</span><span class="nx">Result</span>
+
+<span class="kd">func</span> <span class="nf">Command</span><span class="p">(</span><span class="nx">command</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">args</span> <span class="o">...</span><span class="kt">string</span><span class="p">)</span> <span class="nx">Cmd</span>
+
+<span class="kd">type</span> <span class="nx">Cmd</span> <span class="kd">struct</span> <span class="p">{</span>
+ <span class="nx">Command</span> <span class="p">[]</span><span class="kt">string</span>
+ <span class="nx">Timeout</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Duration</span>
+ <span class="nx">Stdin</span> <span class="nx">io</span><span class="p">.</span><span class="nx">Reader</span>
+ <span class="nx">Stdout</span> <span class="nx">io</span><span class="p">.</span><span class="nx">Writer</span>
+ <span class="nx">Dir</span> <span class="kt">string</span>
+ <span class="nx">Env</span> <span class="p">[]</span><span class="kt">string</span>
+<span class="p">}</span></code></pre></div>
+<p>As we’ve seen <a href="/posts/2017-01-01-go-testing-functionnal-builders/">multiple</a> <a href="/posts/2018-08-16-gotest-tools-assertions/">times</a> <a href="/posts/2018-09-14-gotest-tools-fs/">before</a>, it uses the <em>powerful</em> functional arguments. At the
+time I wrote this post, the <code>icmd</code> package doesn’t contains too much <code>CmdOp</code> <sup class="footnote-ref" id="fnref:fn-1"><a href="#fn:fn-1">1</a></sup>, so I’ll
+propose two version for each example : one with <code>CmdOpt</code> present in <a href="https://github.com/gotestyourself/gotest.tools/pull/122">this PR</a> and one
+without them.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="c1">// With
+</span><span class="c1"></span><span class="nx">icmd</span><span class="p">.</span><span class="nf">RunCmd</span><span class="p">(</span><span class="nx">icmd</span><span class="p">.</span><span class="nf">Command</span><span class="p">(</span><span class="s">"sh"</span><span class="p">,</span> <span class="s">"-c"</span><span class="p">,</span> <span class="s">"echo $FOO"</span><span class="p">),</span>
+ <span class="nx">icmd</span><span class="p">.</span><span class="nf">WithEnv</span><span class="p">(</span><span class="s">"FOO=bar"</span><span class="p">,</span> <span class="s">"BAR=baz"</span><span class="p">),</span> <span class="nx">icmd</span><span class="p">.</span><span class="nf">Dir</span><span class="p">(</span><span class="s">"/tmp"</span><span class="p">),</span>
+ <span class="nx">icmd</span><span class="p">.</span><span class="nf">WithTimeout</span><span class="p">(</span><span class="mi">10</span><span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">),</span>
+<span class="p">).</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">icmd</span><span class="p">.</span><span class="nx">Success</span><span class="p">)</span>
+
+<span class="c1">// Without
+</span><span class="c1"></span><span class="nx">icmd</span><span class="p">.</span><span class="nf">RunCmd</span><span class="p">(</span><span class="nx">icmd</span><span class="p">.</span><span class="nx">Cmd</span><span class="p">{</span>
+ <span class="nx">Command</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">"sh"</span><span class="p">,</span> <span class="s">"-c"</span><span class="p">,</span> <span class="s">"echo $FOO"</span><span class="p">},</span>
+ <span class="nx">Env</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">"FOO=bar"</span><span class="p">,</span> <span class="s">"BAR=baz"</span><span class="p">},</span>
+ <span class="nx">Dir</span><span class="p">:</span> <span class="s">"/tmp"</span><span class="p">,</span>
+ <span class="nx">Timeout</span><span class="p">:</span> <span class="mi">10</span><span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">,</span>
+<span class="p">}).</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">icmd</span><span class="p">.</span><span class="nx">Success</span><span class="p">)</span></code></pre></div>
+<p>As usual, the intent is clear, it’s simple to read and composable (with <code>CmdOp</code>’s).</p>
+
+<h2 id="assertions">Assertions</h2>
+
+<p>Let’s dig into the assertion part of <code>icmd</code>. Running a command returns a struct
+<code>Result</code>. It has the following methods :</p>
+
+<ul>
+<li><code>Assert</code> compares the Result against the Expected struct, and fails the test if any of
+the expectations are not met.</li>
+<li><code>Compare</code> compares the result to Expected and return an error if they do not match.</li>
+<li><code>Equal</code> compares the result to Expected. If the result doesn’t match expected
+returns a formatted failure message with the command, stdout, stderr, exit code, and any
+failed expectations. It returns an <code>assert.Comparison</code> struct, that can be used by other
+<code>gotest.tools</code>.</li>
+<li><code>Combined</code> returns the stdout and stderr combined into a single string.</li>
+<li><code>Stderr</code> returns the stderr of the process as a string.</li>
+<li><code>Stdout</code> returns the stdout of the process as a string.</li>
+</ul>
+
+<p>When you have a result, you, most likely want to do two things :</p>
+
+<ul>
+<li><em>assert</em> that the command succeed or failed with some specific values (exit code,
+stderr, stdout)</li>
+<li>use the output โ most likely <code>stdout</code> but maybe <code>stderr</code> โ in the rest of the test.</li>
+</ul>
+
+<p>As seen above, <em>asserting</em> the command result is using the <code>Expected</code> struct.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Expected</span> <span class="kd">struct</span> <span class="p">{</span>
+ <span class="nx">ExitCode</span> <span class="kt">int</span> <span class="c1">// the exit code the command returned
+</span><span class="c1"></span> <span class="nx">Timeout</span> <span class="kt">bool</span> <span class="c1">// did it timeout ?
+</span><span class="c1"></span> <span class="nx">Error</span> <span class="kt">string</span> <span class="c1">// error returned by the execution (os/exe)
+</span><span class="c1"></span> <span class="nx">Out</span> <span class="kt">string</span> <span class="c1">// content of stdout
+</span><span class="c1"></span> <span class="nx">Err</span> <span class="kt">string</span> <span class="c1">// content of stderr
+</span><span class="c1"></span><span class="p">}</span></code></pre></div>
+<p><code>Success</code> is a constant that defines a success โ it’s an exit code of <code>0</code>, didn’t timeout,
+no error. There is also the <code>None</code> constant, that should be used for <code>Out</code> or <code>Err</code>, to
+specify that we don’t want any content for those standard outputs.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">icmd</span><span class="p">.</span><span class="nf">RunCmd</span><span class="p">(</span><span class="nx">icmd</span><span class="p">.</span><span class="nf">Command</span><span class="p">(</span><span class="s">"cat"</span><span class="p">,</span> <span class="s">"/does/not/exist"</span><span class="p">)).</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">icmd</span><span class="p">.</span><span class="nx">Expected</span><span class="p">{</span>
+ <span class="nx">ExitCode</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
+ <span class="nx">Err</span><span class="p">:</span> <span class="s">"cat: /does/not/exist: No such file or directory"</span><span class="p">,</span>
+<span class="p">})</span>
+
+<span class="c1">// In case of success, we may want to do something with the result
+</span><span class="c1"></span><span class="nx">result</span> <span class="o">:=</span> <span class="nx">icmd</span><span class="p">.</span><span class="nf">RunCommand</span><span class="p">(</span><span class="s">"cat"</span><span class="p">,</span> <span class="s">"/does/exist"</span><span class="p">)</span>
+<span class="nx">result</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">icmd</span><span class="p">.</span><span class="nx">Success</span><span class="p">)</span>
+<span class="c1">// Read the output line by line
+</span><span class="c1"></span><span class="nx">scanner</span> <span class="o">:=</span> <span class="nx">bufio</span><span class="p">.</span><span class="nf">NewScanner</span><span class="p">(</span><span class="nx">strings</span><span class="p">.</span><span class="nf">NewReader</span><span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nf">Stdout</span><span class="p">()))</span>
+<span class="k">for</span> <span class="nx">scanner</span><span class="p">.</span><span class="nf">Scan</span><span class="p">()</span> <span class="p">{</span>
+ <span class="c1">// Do something with it
+</span><span class="c1"></span><span class="p">}</span></code></pre></div>
+<p>If the <code>Result</code> doesn’t map the <code>Expected</code>, a test failure will happen with a useful
+message that will contains the executed command and what differs between the result and
+the expectation.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">result</span> <span class="o">:=</span> <span class="nx">icmd</span><span class="p">.</span><span class="nf">RunCommand</span><span class="p">(</span><span class="err">โฆ</span><span class="p">)</span>
+<span class="nx">result</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">icmd</span><span class="p">.</span><span class="nx">Expected</span><span class="p">{</span>
+ <span class="nx">ExitCode</span><span class="p">:</span> <span class="mi">101</span><span class="p">,</span>
+ <span class="nx">Out</span><span class="p">:</span> <span class="s">"Something else"</span><span class="p">,</span>
+ <span class="nx">Err</span><span class="p">:</span> <span class="nx">None</span><span class="p">,</span>
+<span class="p">})</span>
+<span class="c1">// Command: binary arg1
+</span><span class="c1">// ExitCode: 99 (timeout)
+</span><span class="c1">// Error: exit code 99
+</span><span class="c1">// Stdout: the output
+</span><span class="c1">// Stderr: the stderr
+</span><span class="c1">//
+</span><span class="c1">// Failures:
+</span><span class="c1">// ExitCode was 99 expected 101
+</span><span class="c1">// Expected command to finish, but it hit the timeout
+</span><span class="c1">// Expected stdout to contain "Something else"
+</span><span class="c1">// Expected stderr to contain "[NOTHING]"
+</span><span class="c1"></span><span class="err">โฆ</span></code></pre></div>
+<p>Finally, we listed <code>Equal</code> above, that returns a <code>Comparison</code> struct. This means we can
+use it easily with the <code>assert</code> package. As written in a <a href="/posts/2018-08-16-gotest-tools-assertions/">previous post (about the <code>assert</code>
+package)</a>, I tend prefer to use <code>cmp.Comparison</code>. Let’s convert the above examples using
+<code>assert</code>.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">result</span> <span class="o">:=</span> <span class="nx">icmd</span><span class="p">.</span><span class="nf">RunCmd</span><span class="p">(</span><span class="nx">icmd</span><span class="p">.</span><span class="nf">Command</span><span class="p">(</span><span class="s">"cat"</span><span class="p">,</span> <span class="s">"/does/not/exist"</span><span class="p">))</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Check</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">result</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="nx">icmd</span><span class="p">.</span><span class="nx">Expected</span><span class="p">{</span>
+ <span class="nx">ExitCode</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
+ <span class="nx">Err</span><span class="p">:</span> <span class="s">"cat: /does/not/exist: No such file or directory"</span><span class="p">,</span>
+<span class="p">}))</span>
+
+<span class="c1">// In case of success, we may want to do something with the result
+</span><span class="c1"></span><span class="nx">result</span> <span class="o">:=</span> <span class="nx">icmd</span><span class="p">.</span><span class="nf">RunCommand</span><span class="p">(</span><span class="s">"cat"</span><span class="p">,</span> <span class="s">"/does/exist"</span><span class="p">)</span>
+<span class="nx">assert</span><span class="p">.</span><span class="nf">Assert</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">result</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="nx">icmd</span><span class="p">.</span><span class="nx">Success</span><span class="p">))</span>
+<span class="c1">// Read the output line by line
+</span><span class="c1"></span><span class="nx">scanner</span> <span class="o">:=</span> <span class="nx">bufio</span><span class="p">.</span><span class="nf">NewScanner</span><span class="p">(</span><span class="nx">strings</span><span class="p">.</span><span class="nf">NewReader</span><span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nf">Stdout</span><span class="p">()))</span>
+<span class="k">for</span> <span class="nx">scanner</span><span class="p">.</span><span class="nf">Scan</span><span class="p">()</span> <span class="p">{</span>
+ <span class="c1">// Do something with it
+</span><span class="c1"></span><span class="p">}</span></code></pre></div>
+<h2 id="conclusion">Conclusionโฆ</h2>
+
+<p>โฆ that’s a wrap. The <code>icmd</code> package allows to easily run command and describe what result
+are expected of the execution, with the least noise possible. We <strong>use this package heavily</strong>
+on several <code>docker/*</code> projects (the engine, the cli)โฆ</p>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:fn-1">The <code>icmd</code> package is one of the oldest <code>gotest.tools</code> package, that comes from the <a href="https://github.com/docker/docker"><code>docker/docker</code></a> initially. We introduced these <code>CmdOp</code> but implementations were in <code>docker/docker</code> at first and we never really updated them.
+ <a class="footnote-return" href="#fnref:fn-1"><sup>[return]</sup></a></li>
+</ol>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2018-12-16-link/" title="Go testing style guide">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2018-09-14-gotest-tools-fs/" title="Golang testing โ gotest.tools fs">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2018-12-16-link/index.html
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2018-12-16-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Go testing style guide</h1><a href='https://vincent.demeester.fr/posts/2018-12-16-link/'></a>
+ <address class="signature">
+ <span class="date">Sun, 16 December, 2018</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>A small (opiniated) style guide for Writing Go tests.</p>
+ <p>๐ <a href="https://arp242.net/weblog/go-testing-style.html" class="link">https://arp242.net/weblog/go-testing-style.html</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-01-10-link/" title="log.Fatal vs log.Panic ยท Iskander Sharipov technical blog">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2018-09-18-gotest-tools-icmd/" title="Golang testing โ gotest.tools icmd">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-01-10-link/index.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-01-10-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">log.Fatal vs log.Panic ยท Iskander Sharipov technical blog</h1><a href='https://vincent.demeester.fr/posts/2019-01-10-link/'></a>
+ <address class="signature">
+ <span class="date">Thu, 10 January, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-log"><a href="/tags/#log">log<span>1</span></a></li>
+
+
+ <li class="tag tag-panic"><a href="/tags/#panic">panic<span>1</span></a></li>
+
+
+ <li class="tag tag-fatal"><a href="/tags/#fatal">fatal<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>Why you should prefer to use log.Panic instead of log.Fatal in go code</p>
+ <p>๐ <a href="https://quasilyte.github.io/blog/post/log-fatal-vs-log-panic/" class="link">https://quasilyte.github.io/blog/post/log-fatal-vs-log-panic/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-01-20-2018-year-review/" title="2018 year review">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2018-12-16-link/" title="Go testing style guide">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-01-20-2018-year-review/index.html
@@ -0,0 +1,284 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-01-20-2018-year-review/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">2018 year review</h1><a href='https://vincent.demeester.fr/posts/2019-01-20-2018-year-review/'></a>
+ <address class="signature">
+ <span class="date">Sun, 20 January, 2019</span>
+ <span class="words">(1500 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+
+
+
+
+ <li class="tag tag-review"><a href="/tags/#review">review<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>Here is my review of 2018, the first of its kind, hopefully not the last ๐ผ. I saw
+some<sup class="footnote-ref" id="fnref:fn-1"><a href="#fn:fn-1">1</a></sup> <em>2018<sup class="footnote-ref" id="fnref:fn-2"><a href="#fn:fn-2">2</a></sup> reviews</em><sup class="footnote-ref" id="fnref:fn-3"><a href="#fn:fn-3">3</a></sup> articles<sup class="footnote-ref" id="fnref:fn-4"><a href="#fn:fn-4">4</a></sup> in my Feedly feed and I thought it
+would be a good idea to write my own too.</p>
+
+<p>I’ll try in the next year โ maybe month if I ever want to do monthly reviews โ to automate
+some of it ; using the beloved <code>org-mode</code>.</p>
+
+<h2 id="work">Work</h2>
+
+<p>The big change this year is : I changed job ๐ผ. I went from Docker Inc. to Red Hat. I
+needed a change and 5 month in, I think it was the <strong>best choice I made in my life</strong> so far
+๐. I’m doing open-source for a living and best part, I am working remotely (more on that
+later).</p>
+
+<p>Before that, at Docker Inc., I continued the work I started years before,
+a.k.a. maintaining the Moby project and the docker engine, among other Docker project
+(both open-source and closed-source). I also helped the work on the compose side, from the
+root of <code>docker/compose-on-kubernetes</code> (before it got open-sourced), to the <code>docker/app</code>
+experiments.</p>
+
+<p>At Red Hat, I started to work upstream in the Kubernetes community, mainly on the Knative
+projects. I also work on the Openshift Cloud Function project (and thus team), and those
+fellows are awesome ! Digging more into Openshift, and other part of the Red Hat portfolio
+is a really good learning experience, and it’s just the start !</p>
+
+<p>As stated above, I am now working home, full-time. I could work from home from time to
+time when I was at Docker inc, but working home full-time is another kind of beast. So far
+it is really good, some adjustments were needed but it’s for the best. Here is a small
+take on “working from home”:</p>
+
+<ul>
+<li>It’s easy to have <strong>no distraction</strong>, thus having <strong>really productive</strong> piece of time</li>
+<li>It’s also <strong>really easy to work long day or really long period of time</strong>. It’s especially
+true if, like me, you work on a distributed team (across multiple timezones).
+
+<ul>
+<li>I ended up using the Pomodoro technique to make sure I move at least few times a day</li>
+<li>I try to make sure I don’t make an habits of checking out work code, email and other
+material after a certain hour in the evening. It’s ok to do it sometimes, but for your
+sanity, you need some rest time.</li>
+</ul></li>
+<li>It’s easy to adapt your day to circumstance. If you got to run errands in the middle of
+the day, it’s no big deal. You can take the time back later on.</li>
+<li>It’s so good to have <strong>no</strong> commmute time. That said I end up <em>walking or taking the bike</em>
+early morning to clear my head before work ๐.</li>
+</ul>
+
+<h2 id="personal">Personal</h2>
+
+<p>Health wise, it’s a mix of good and bad year. The first half was really good, the second
+way less. End of august, I felt something weird in the right knee, and well, turns out my
+internal meniscus is in a real bad shape. Just as before joining Docker, I’m gonna need a
+surgery, on the right knee that time. It’s gonna affect 2019 (the first half, I’m not
+gonna be able to move around much but.. meh, it’s life).</p>
+
+<p>Now that I work from home, I’m really glad I got a standing desk at the end of 2017. I
+tend to work standing most of the time – except when my knee hurts (and most likely for
+few months after the surgery ๐
). I invested on a ultrawide screen, to get the same
+experience I had at Docker. And oh boy those screens are good !</p>
+
+<p>I also try to clean my desk and it’s “neighboorhood”. As I get older, I want less messy
+stuuf (desk, flat, …). I’m leaning towards having less stuff, being commputer related or
+not. It’s not minimalism, but it feel good to have less stuff, but stuff that you actually
+use. I still have trouble throwing old computer away, mainly because I fell they can be
+useful in some way.</p>
+
+<figure>
+ <img src="/images/2019/01/desk1.jpg"/>
+</figure>
+
+
+<p>This year I migrate all of my “infrastructure” computer to NixOS. I learned a lot of Nix,
+reworked my configuration multiple time to end up with a <a href="https://github.com/vdemeester/nixos-configuration.git">system configuration repository</a>
+that uses modules, and a <a href="https://github.com/vdemeester/home.git"><em>home configuration repository</em></a> (for user configuration). The
+<a href="https://github.com/vdemeester/home.git">home</a> repository uses <a href="https://github.com/rycee/home-manager.git"><code>home-manager</code></a> and thus doesn’t make any assumption of running on top
+of NixOS. This allows me to have an <em>easy to get</em> setup on any system that <code>nixpkgs</code>
+supports (any Linux distribution, Mac OSX, Windows Subsystem Linux). The current
+configuration is not yet optimal but I’m pretty happy about what I got :</p>
+
+<ul>
+<li>Custom DNS server @home to make it easier to target local hosts.</li>
+<li>Local proxies and mirrors for docker images, nixpkgs binary package and go modules to
+eat less bandwidth.</li>
+<li>Easy to setup VPN using <a href="https://www.wireguard.com/">WireGuard</a>.</li>
+<li>File replication using <code>syncthing</code> and automatic backup on my local NAS.</li>
+<li>Automatic system upgrade, thanks to NixOS. I’ll probably write an article about that
+later on this year.</li>
+</ul>
+
+<p>I started to use <code>todoist</code> in 2017, and boy, oh boy, it helped me quite a lot ! I’m using
+it daily to organize my work and quickly get idea, and <em>todos</em> out of my head. The main
+problem with it is it’s not integrated with another tool I’m using daily : Emacs and
+<code>org-mode</code>. <code>org-mode</code> is a fantastic piece of software and is, on its own, the main
+reason for me to invest time in Emacs. I’m taking note in <code>org-mode</code>, I write my daily
+standup notes in there too. I end up going back and forth between <code>org-mode</code> and <code>todoist</code>
+for those daily standup. I am lazy, I want to automate that. And the best way to do it, is
+to also use <code>org-mode</code> for task management. I’m in a <em>transition</em> mode right now, but my
+goal for 2019 is to use todoist to take quick note/todo(s) on the move (aka on the phone)
+and use <code>org-mode</code> for the rest.</p>
+
+<h2 id="reading-and-writing">Reading & Writing</h2>
+
+<p>I used to like reading, but the past years, I didn’t really read that much, except some
+technical books. 2018 in, that respect, is not an exception, I didn’t read too much. Worse
+than that, I started some book and stopped at some point, for no apparent reason ; and
+now, I need to start back from the beginning, which, well, is not helping me want to read
+them again.</p>
+
+<p>I’m trying two thing to counter that and consume more books for the years to come.</p>
+
+<ol>
+<li>I now have a reading list on my <code>org-mode</code> files, where I track which one I read and
+when I read them ; and maybe notes too. I have a lot of book on my kindle, that only
+wait for one thing, being read..</li>
+<li>I subscribed to <a href="https://www.audible.fr">Audible</a> ๐ผ. Working from home, I tend to take a long break after lunch,
+where I’m going for a walk, for around an hour. I can’t read while walking but I
+definitely can listen - that make audio books perfect for these moments. I also
+alternate between audio books and non-musical podcasts.</li>
+</ol>
+
+<p>On the writing side, 2017 was a slow year in terms of writing (only 2 posts), 2018 was a
+bit better, 6 posts – it’s a bit cheating, as it was mainly between changing jobs, and
+on a series I still need to finish. I’m hoping to write more this year, hence the goals
+I’ve set to myself below.</p>
+
+<h2 id="2019-goals">2019 Goals</h2>
+
+<ul>
+<li><strong>Get back on my feet after knee surgery (exercices, โฆ)</strong> ๐</li>
+<li><strong>Read at least one book per month (be audible, ebook or paper)</strong> ๐</li>
+
+<li><p><strong>Giving at least a talk (on Knative, containers, nixos, ..)</strong> ๐</p>
+
+<p>I didn’t give too much talk in 2018 (at least less than 2017). I’m gonna try to get back
+at it this year. The surgery won’t help but it’s just few months.</p></li>
+
+<li><p><strong>At least 1 video per month</strong> ๐น</p>
+
+<p>I want to start recording some video, as I feel it’s an easier medium than writing and,
+well, I wanna try !</p></li>
+
+<li><p><strong>At least 1 post per month</strong> โ๏ธ</p></li>
+
+<li><p><strong>Enhance my emacs skills (aka don’t be afraid of the lisp)</strong> โจ๏ธ</p>
+
+<p>I’m using Emacs for almost anything that doesn’t happen in a web browser. But I still
+feel like a newbie. I want to learn more, to write more lisp that help me being even
+more lazier (aka achieve more doing less ๐)</p></li>
+
+<li><p><strong>Enhance my Nix(OS) skills</strong> ๐ง</p></li>
+
+<li><p><strong>Learn / master a new language</strong> ๐ฝ</p>
+
+<p>I’m working with Go 90% of my time. I want to master and learn more language. On my list
+are Emacs Lisp, Rust, Typescript and Haskell.</p></li>
+</ul>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:fn-1"><a href="https://punchagan.muse-amuse.in/blog/2018-in-review/">2018 in Review - Noetic Nought</a>
+ <a class="footnote-return" href="#fnref:fn-1"><sup>[return]</sup></a></li>
+<li id="fn:fn-2"><a href="https://medium.com/@buster/42-dig-deeper-e2278d1fe015">42 โ Dig deeper โ Buster Benson โ Medium</a>
+ <a class="footnote-return" href="#fnref:fn-2"><sup>[return]</sup></a></li>
+<li id="fn:fn-3"><a href="https://jvns.ca/blog/2018/12/23/2018--year-in-review/">2018: Year in review - Julia Evans</a>
+ <a class="footnote-return" href="#fnref:fn-3"><sup>[return]</sup></a></li>
+<li id="fn:fn-4"><a href="https://writing.natwelch.com/post/685">Nat? Nat. Nat! | #685 2018 Year in Review</a>
+ <a class="footnote-return" href="#fnref:fn-4"><sup>[return]</sup></a></li>
+</ol>
+</div>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-01-26-nix-run-alias/" title="nix run aliases">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-01-10-link/" title="log.Fatal vs log.Panic ยท Iskander Sharipov technical blog">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-01-26-nix-run-alias/index.html
@@ -0,0 +1,308 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-01-26-nix-run-alias/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">nix run aliases</h1><a href='https://vincent.demeester.fr/posts/2019-01-26-nix-run-alias/'></a>
+ <address class="signature">
+ <span class="date">Sat, 26 January, 2019</span>
+ <span class="words">(1300 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+
+
+
+
+ <li class="tag tag-nixos"><a href="/tags/#nixos">nixos<span>1</span></a></li>
+
+
+ <li class="tag tag-fish"><a href="/tags/#fish">fish<span>1</span></a></li>
+
+
+ <li class="tag tag-alias"><a href="/tags/#alias">alias<span>1</span></a></li>
+
+
+ <li class="tag tag-nix"><a href="/tags/#nix">nix<span>3</span></a></li>
+
+
+ <li class="tag tag-shell"><a href="/tags/#shell">shell<span>2</span></a></li>
+
+
+ <li class="tag tag-home"><a href="/tags/#home">home<span>1</span></a></li>
+
+
+ <li class="tag tag-manager"><a href="/tags/#manager">manager<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>I use <a href="https://nixos.org/"><code>NixOS</code></a> each and every day, everywhere. One really cool feature of <code>nix</code> is
+<code>nix-shell</code> and more recently (with <code>nix</code> >= <code>2.0.0</code>), <code>nix run</code>.</p>
+<div class="highlight"><pre class="chroma"><code class="language-man" data-lang="man">Usage: nix run <FLAGS>... <INSTALLABLES>...
+
+Summary: run a shell in which the specified packages are available.
+
+Flags:
+ --arg <NAME> <EXPR> argument to be passed to Nix functions
+ --argstr <NAME> <STRING> string-valued argument to be passed to Nix functions
+ -c, --command <COMMAND> <ARGS> command and arguments to be executed; defaults to 'bash'
+ -f, --file <FILE> evaluate FILE rather than the default
+ -i, --ignore-environment clear the entire environment (except those specified with --keep)
+ -I, --include <PATH> add a path to the list of locations used to look up <...> file names
+ -k, --keep <NAME> keep specified environment variable
+ -u, --unset <NAME> unset specified environment variable
+
+Examples:
+
+ To start a shell providing GNU Hello from NixOS 17.03:
+ $ nix run -f channel:nixos-17.03 hello
+
+ To start a shell providing youtube-dl from your 'nixpkgs' channel:
+ $ nix run nixpkgs.youtube-dl
+
+ To run GNU Hello:
+ $ nix run nixpkgs.hello -c hello --greeting 'Hi everybody!'
+
+ To run GNU Hello in a chroot store:
+ $ nix run --store ~/my-nix nixpkgs.hello -c hello
+
+Note: this program is EXPERIMENTAL and subject to change.</code></pre></div>
+<p>As you can see from the <code>-h</code> summary, it makes it really easy to run a shell or a command
+with some packages that are not in your main configuration. It will download the
+package(s) if there are not available in the Nix store (<code>/nix/store/</code>).</p>
+
+<p>A few month ago I decided it would be a perfect use-case for command I do not run
+often. My idea was, let’s define <code>aliases</code> (in the shell) that would make a simple command
+call, like <code>ncdu</code>, become <code>nix run nixpkgs.ncdu -c ndcu</code>. My <em>shell of choice</em> is <a href="https://fishshell.com/">fish</a>, so
+I decided to dig into the <em>language</em> in order to implement that.</p>
+
+<p>The use case is the following :</p>
+
+<ul>
+<li>When I type <code>foo</code>, I want the command <code>foo</code> in package <code>bar</code> to be executed.</li>
+<li>I want to be able to pin a channel for the package โ I’m using <a href="https://matthewbauer.us/">Matthew Bauer</a> <a href="https://matthewbauer.us/blog/channel-changing.html">Channel
+Changing with Nix</a> setup for pin-pointing a given channel.</li>
+</ul>
+
+<h2 id="fish-aliases-experimentation">Fish aliases experimentation</h2>
+
+<p>I had a feeling the built-in <code>alias</code> would not work so I ended up trying to define a
+<em>dynamic</em> function that would be the name of the command. That’s the beauty of the shell,
+everything is a command, even function appears as commands. If you define a function
+<code>foo()</code>, you will be able to run <code>foo</code> in your shell, <strong>and</strong> it will take precedence over
+the <code>foo</code> executable file that would be in your <code>PATH</code>.</p>
+
+<p>I ended up with two main helper function that would create those <em>alias</em> function.</p>
+<div class="highlight"><pre class="chroma"><code class="language-fish" data-lang="fish"><span class="k">function</span> _nix_run_package
+ <span class="k">set</span> -l s <span class="nv">$argv</span><span class="o">[</span>1<span class="o">]</span>
+ <span class="k">set</span> -l package <span class="o">(</span>string split <span class="s2">":"</span> <span class="nv">$s</span><span class="o">)</span>
+ <span class="k">switch</span> <span class="o">(</span><span class="k">count</span> <span class="nv">$package</span><span class="o">)</span>
+ <span class="k">case</span> 1
+ _nix_run <span class="nv">$s</span> <span class="nv">$s</span> <span class="nv">$argv</span><span class="o">[</span>2<span class="o">]</span> <span class="nv">$argv</span><span class="o">[</span>3<span class="o">]</span>
+ <span class="k">case</span> 2
+ _nix_run <span class="nv">$package</span><span class="o">[</span>1<span class="o">]</span> <span class="nv">$package</span><span class="o">[</span>2<span class="o">]</span> <span class="nv">$argv</span><span class="o">[</span>2<span class="o">]</span> <span class="nv">$argv</span><span class="o">[</span>3<span class="o">]</span>
+ <span class="k">end</span>
+<span class="k">end</span>
+
+<span class="k">function</span> _nix_run
+ <span class="k">set</span> -l c <span class="nv">$argv</span><span class="o">[</span>1<span class="o">]</span>
+ <span class="k">set</span> -l p <span class="nv">$argv</span><span class="o">[</span>2<span class="o">]</span>
+ <span class="k">set</span> -l channel <span class="nv">$argv</span><span class="o">[</span>3<span class="o">]</span>
+ <span class="k">set</span> -l channelsfile <span class="nv">$argv</span><span class="o">[</span>4<span class="o">]</span>
+ <span class="k">function</span> <span class="nv">$c</span> --inherit-variable c --inherit-variable p --inherit-variable channel --inherit-variable channelsfile
+ <span class="k">set</span> -l cmd nix run
+ <span class="k">if</span> <span class="k">test</span> -n <span class="s2">"</span><span class="nv">$channelsfile</span><span class="s2">"</span>
+ <span class="k">set</span> cmd <span class="nv">$cmd</span> -f <span class="nv">$channelsfile</span>
+ <span class="k">end</span>
+ <span class="nb">eval</span> <span class="nv">$cmd</span> <span class="nv">$channel</span>.<span class="nv">$p</span> -c <span class="nv">$c</span> <span class="nv">$argv</span>
+ <span class="k">end</span>
+<span class="k">end</span></code></pre></div>
+<p>In a nutshell, <code>_nix_run</code> is the function that create the alias function. There is so
+condition in there depending on whether we gave it a channel or not. So, a call like
+<code>_nix_run foo bar unstable channels.nix</code> would, in the end generate a function <code>foo</code> with
+the following call : <code>nix run -f channels.nix unstable.bar -c foo</code>.</p>
+
+<p>The other function, <code>_nix_run_package</code> is there to make me write less when I define those
+aliases โ aka if the command and the package share the same name, I don’t want to write it
+twice. So, a call like <code>_nix_run_package foo nixpkgs</code> would result in a <code>_nix_run foo foo
+nixpkgs</code>, whereas a call like <code>_nix_run_package foo:bar unstable channels.nix</code> would
+result in a <code>_nix_run foo bar unstable channels.nix</code>.</p>
+
+<p>An example is gonna be better than the above paragraphs. This is what I used to have in my
+fish configuration.</p>
+<div class="highlight"><pre class="chroma"><code class="language-fish" data-lang="fish"><span class="k">function</span> _def_nix_run_aliases
+ <span class="k">set</span> -l stable mr sshfs ncdu wakeonlan:python36Packages.wakeonlan lspci:pciutils lsusb:usbutils beet:beets gotop virt-manager:virtmanager pandoc nix-prefetch-git:nix-prefetch-scripts nix-prefetch-hg:nix-prefetch-scripts
+ <span class="k">set</span> -l unstable op:_1password update-desktop-database:desktop-file-utils lgogdownloader
+ <span class="k">for</span> s <span class="k">in</span> <span class="nv">$stable</span>
+ _nix_run_package <span class="nv">$s</span> nixpkgs
+ <span class="k">end</span>
+ <span class="k">for</span> s <span class="k">in</span> <span class="nv">$unstable</span>
+ _nix_run_package <span class="nv">$s</span> unstable ~/.config/nixpkgs/channels.nix
+ <span class="k">end</span>
+<span class="k">end</span>
+<span class="c"># Call the function to create the aliases
+</span><span class="c"></span>_def_nix_run_aliases</code></pre></div>
+<p>This works like a charm, and for a while, I was happy. But I soon realized something : I’m
+not always on my shell โ like, I tend to spend more and more time in <code>eshell</code>. This also
+doesn’t work with graphic tools like <a href="https://github.com/DaveDavenport/rofi"><code>rofi</code></a>. I needed actual command, so that external
+tools would benefit from that. I ended up writing a small tool, <a href="https://github.com/vdemeester/nr"><code>nr</code></a> that integrates
+nicely with <code>nix</code> and <a href="https://github.com/rycee/home-manager"><code>home-manager</code></a>.</p>
+
+<h2 id="a-proper-tool-nr">A proper tool : <code>nr</code></h2>
+
+<p>The gist for this tool is simple :</p>
+
+<ul>
+<li>create an executable script that will call <code>nix run ...</code> instead of the command</li>
+<li>as for the above fish script, support different channels</li>
+<li>make sure we don’t have conflicts โ if the command already exists, then don’t create the
+command</li>
+</ul>
+
+<p>The <code>nr</code> tool would have to be able to manage multiple <em>profile</em>, which really stands for
+multiple file. The main reason is really about how I manage my configuration ; To make it
+simple, depending on the computer my configurations are setup, I may not have <code>go</code>, thus I
+don’t want any <code>go</code>-related aliases for a computer that doesn’t have <code>go</code> (using <code>go</code> here
+but you can replace with anything).</p>
+<div class="highlight"><pre class="chroma"><code class="language-fish" data-lang="fish"><span class="nv">$ </span>nr default
+<span class="o">></span> nr generate default
+<span class="o">></span> virtmanager already exists
+<span class="nv">$ </span>nr git
+<span class="o">></span> nr generate git</code></pre></div>
+<p><code>nr</code> generates a bash script that does the <code>nr run โฆ</code> and mark it as executable. <code>nr</code>
+needs to be able to clean files it has generated (in case we removed it from
+aliases). Thus, I went for a really naive comment in the script. When generating a new set
+of commands, <code>nr</code> will first remove previously generated script for this profile, and for
+that, it uses the comment. Let’s look at what a generated script looks like, for the
+default profile.</p>
+<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash"><span class="cp">#!/usr/bin/env bash
+</span><span class="cp"></span><span class="c1"># Generated by nr default</span>
+nix run nixpkgs.nix-prefetch-scripts -c nix-prefetch-git <span class="nv">$@</span></code></pre></div>
+<p>The format used in <code>nr</code> is <code>json</code>. I’m not a <em>huge fan</em> of <code>json</code> but it really was the
+best format to use for this tool. The reason to use <code>json</code> are simple :</p>
+
+<ul>
+<li><p>Go has <code>encoding/json</code> built-in, so it’s really easy to <code>Marshall</code> and <code>Unmarshall</code>
+structure.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">alias</span> <span class="kd">struct</span> <span class="p">{</span>
+ <span class="nx">Command</span> <span class="kt">string</span> <span class="s">`json:"cmd"`</span>
+ <span class="nx">Package</span> <span class="kt">string</span> <span class="s">`json:"pkg"`</span>
+ <span class="nx">Channel</span> <span class="kt">string</span> <span class="s">`json:"chan"`</span>
+<span class="p">}</span></code></pre></div></li>
+
+<li><p>Nix also has built-in support for <code>json</code> : <code>builtins.toJSON</code> will marshall a <em>struct</em>
+into a json file.</p></li>
+</ul>
+
+<p>Finally, to avoid conflicts at <em>build time</em> (<code>home-manager switch</code>) I couldn’t use/define
+a nix package, but to execute command(s) at the end of the build. One way to achieve it is
+to use <code>file.?.onChange</code> script, which is executed after <a href="https://github.com/rycee/home-manager"><code>home-manager</code></a> has updated the
+environment, <strong>if</strong> the file has changed. That means it’s possible to check for executable
+files in <code>~/.nix-profile/bin/</code> for defined aliases and create those that are not there,
+with <code>nr</code>. My configuration then looks like the following.</p>
+<div class="highlight"><pre class="chroma"><code class="language-nix" data-lang="nix"><span class="n">xdg</span><span class="o">.</span><span class="n">configFile</span><span class="o">.</span><span class="s2">"nr/default"</span> <span class="err">=</span> <span class="p">{</span>
+ <span class="n">text</span> <span class="o">=</span> <span class="nb">builtins</span><span class="o">.</span><span class="n">toJSON</span> <span class="p">[</span>
+ <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"ncdu"</span><span class="p">;}</span> <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"sshfs"</span><span class="p">;}</span> <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"gotop"</span><span class="p">;}</span> <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"pandoc"</span><span class="p">;}</span>
+ <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"wakeonlan"</span><span class="p">;</span> <span class="n">pkg</span> <span class="o">=</span> <span class="s2">"python36Packages.wakeonlan"</span><span class="p">;}</span>
+ <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"beet"</span><span class="p">;</span> <span class="n">pkg</span> <span class="o">=</span> <span class="s2">"beets"</span><span class="p">;}</span>
+ <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"virt-manager"</span><span class="p">;</span> <span class="n">pkg</span> <span class="o">=</span> <span class="s2">"virtmanager"</span><span class="p">;}</span>
+ <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"nix-prefetch-git"</span><span class="p">;</span> <span class="n">pkg</span> <span class="o">=</span> <span class="s2">"nix-prefetch-scripts"</span><span class="p">;}</span>
+ <span class="p">{</span><span class="n">cmd</span> <span class="o">=</span> <span class="s2">"nix-prefetch-hg"</span><span class="p">;</span> <span class="n">pkg</span> <span class="o">=</span> <span class="s2">"nix-prefetch-scripts"</span><span class="p">;}</span>
+ <span class="p">];</span>
+ <span class="n">onChange</span> <span class="o">=</span> <span class="s2">"</span><span class="si">${</span><span class="n">pkgs</span><span class="o">.</span><span class="n">nur</span><span class="o">.</span><span class="n">repos</span><span class="o">.</span><span class="n">vdemeester</span><span class="o">.</span><span class="n">nr</span><span class="si">}</span><span class="s2">/bin/nr default"</span><span class="p">;</span>
+<span class="p">};</span></code></pre></div>
+<p>And there you are, now, each time I update my environment (<code>home-manager switch</code>), <code>nr</code>
+will regenerate my <code>nix run</code> aliases.</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-01-27-link/" title="Self-care tips for new developers">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-01-20-2018-year-review/" title="2018 year review">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-01-27-link/index.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-01-27-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Self-care tips for new developers</h1><a href='https://vincent.demeester.fr/posts/2019-01-27-link/'></a>
+ <address class="signature">
+ <span class="date">Sun, 27 January, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-productivity"><a href="/tags/#productivity">productivity<span>1</span></a></li>
+
+
+ <li class="tag tag-health"><a href="/tags/#health">health<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>Tips for developers to take care of themselves to work better (but less too ๐ผ)</p>
+ <p>๐ <a href="https://punchagan.muse-amuse.in/blog/self-care-tips-for-new-developers/" class="link">https://punchagan.muse-amuse.in/blog/self-care-tips-for-new-developers/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-02-15-link/" title="$ docker build -f Mockerfile.yaml .">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-01-26-nix-run-alias/" title="nix run aliases">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-02-15-link/index.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-02-15-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">$ docker build -f Mockerfile.yaml .</h1><a href='https://vincent.demeester.fr/posts/2019-02-15-link/'></a>
+ <address class="signature">
+ <span class="date">Fri, 15 February, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-docker"><a href="/tags/#docker">docker<span>3</span></a></li>
+
+
+ <li class="tag tag-buildkit"><a href="/tags/#buildkit">buildkit<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>how to write your own Dockerfile syntax that works out of the box with any existing Docker installation. </p>
+ <p>๐ <a href="https://matt-rickard.com/building-a-new-dockerfile-frontend/" class="link">https://matt-rickard.com/building-a-new-dockerfile-frontend/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-02-25-link/" title="Go Interfaces - fREW Schmidt's Foolish Manifesto">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-01-27-link/" title="Self-care tips for new developers">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-02-25-link/index.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-02-25-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Go Interfaces - fREW Schmidt's Foolish Manifesto</h1><a href='https://vincent.demeester.fr/posts/2019-02-25-link/'></a>
+ <address class="signature">
+ <span class="date">Mon, 25 February, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-go"><a href="/tags/#go">go<span>5</span></a></li>
+
+
+ <li class="tag tag-interfaces"><a href="/tags/#interfaces">interfaces<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>I did some work recently that depended on Go interfaces and I found it both straightforward and elegant.</p>
+ <p>๐ <a href="https://blog.afoolishmanifesto.com/posts/go-interfaces/" class="link">https://blog.afoolishmanifesto.com/posts/go-interfaces/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-03-12-link/" title="Go2 Contracts Go Too Far ยท npf.io">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-02-15-link/" title="$ docker build -f Mockerfile.yaml .">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-03-12-link/index.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-03-12-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Go2 Contracts Go Too Far ยท npf.io</h1><a href='https://vincent.demeester.fr/posts/2019-03-12-link/'></a>
+ <address class="signature">
+ <span class="date">Tue, 12 March, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-go"><a href="/tags/#go">go<span>5</span></a></li>
+
+
+ <li class="tag tag-contracts"><a href="/tags/#contracts">contracts<span>1</span></a></li>
+
+
+ <li class="tag tag-go2"><a href="/tags/#go2">go2<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>A take at the Go 2 contracts proposal and why it might not really do good</p>
+ <p>๐ <a href="https://npf.io/2018/09/go2-contracts-go-too-far/" class="link">https://npf.io/2018/09/go2-contracts-go-too-far/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-03-23-gotest-tools-poll/" title="Golang testing โ gotest.tools poll">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-02-25-link/" title="Go Interfaces - fREW Schmidt's Foolish Manifesto">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-03-23-gotest-tools-poll/index.html
@@ -0,0 +1,236 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-03-23-gotest-tools-poll/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Golang testing โ gotest.tools poll</h1><a href='https://vincent.demeester.fr/posts/2019-03-23-gotest-tools-poll/'></a>
+ <address class="signature">
+ <span class="date">Sat, 23 March, 2019</span>
+ <span class="words">(700 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#developement">developement</a></li>
+
+
+
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-golang"><a href="/tags/#golang">golang<span>12</span></a></li>
+
+
+ <li class="tag tag-poll"><a href="/tags/#poll">poll<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+
+
+
+
+<p>Let’s continue the <a href="https://gotest.tools"><code>gotest.tools</code></a> serie, this time with the <code>poll</code> package.</p>
+
+<blockquote>
+<p>Package poll provides tools for testing asynchronous code.</p>
+</blockquote>
+
+<p>When you write test, you may test a piece of code that work asynchronously, where the
+state you’re expecting is gonna take a bit of time to be achieved. This is especially true
+when you work on networking or file-system code. And this happens a lot when you write
+integration (or end-to-end) test, less for unit-tests.</p>
+
+<p>The package <code>poll</code> is trying to tackle those use cases. We’ll first take a look at the
+main function, <code>WaitOn</code>, then how to write a <code>Check</code>, using the <code>Result</code> type.</p>
+
+<h2 id="waiton"><code>WaitOn</code></h2>
+
+<p>Let’s look into the main <code>poll</code> function : `WaitOn`.</p>
+
+<blockquote>
+<p>WaitOn a condition or until a timeout. Poll by calling check and exit when check returns
+a done Result. To fail a test and exit polling with an error return a error result.</p>
+</blockquote>
+
+<p>In a gist, <code>WaitOn</code> will run a <em>condition</em> function until it either times out or
+succeed. It wait for a given time/delay between each run.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">func</span> <span class="nf">WaitOn</span><span class="p">(</span><span class="nx">t</span> <span class="nx">TestingT</span><span class="p">,</span> <span class="nx">check</span> <span class="nx">Check</span><span class="p">,</span> <span class="nx">pollOps</span> <span class="o">...</span><span class="nx">SettingOp</span><span class="p">)</span> <span class="p">{</span>
+ <span class="c1">// [โฆ]
+</span><span class="c1"></span><span class="p">}</span></code></pre></div>
+<p>As any <em>testing helper</em> function, the first argument is <code>*testing.T</code> (or, in this case,
+any thing that look like it, thanks to the <code>TestingT</code> interace). The two other arguments
+are way more interesting :</p>
+
+<ul>
+<li>The <code>Check</code> is the condition that will run multiple times until it either timeout, or succeed.</li>
+<li>The <code>SettingOp(s)</code> which are options to configure the function, things like the timeout,
+or the <em>delay</em> between each run.</li>
+</ul>
+
+<p>The settings are pretty straightforward :</p>
+
+<ul>
+<li><code>WithDelay</code> : sets the delay to wait between polls. The default delay is 100ms.</li>
+<li><code>WithTimeout</code> : sets the timeout. The default timeout is 10s.</li>
+</ul>
+
+<p>There is existing <code>Check</code> for common case:</p>
+
+<ul>
+<li><p><code>Connection</code> : try to open a connection to the address on the named network.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">poll</span><span class="p">.</span><span class="nf">WaitOn</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">poll</span><span class="p">.</span><span class="nf">Connection</span><span class="p">(</span><span class="s">"tcp"</span><span class="p">,</span> <span class="s">"foo.bar:55555"</span><span class="p">),</span> <span class="nx">poll</span><span class="p">.</span><span class="nf">WithTimeout</span><span class="p">(</span><span class="s">"5s"</span><span class="p">))</span></code></pre></div></li>
+
+<li><p><code>FileExists</code> : looks on filesystem and check that path exists.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">poll</span><span class="p">.</span><span class="nf">WaitOn</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">poll</span><span class="p">.</span><span class="nf">FileExists</span><span class="p">(</span><span class="s">"/should/be/created"</span><span class="p">),</span> <span class="nx">poll</span><span class="p">.</span><span class="nf">WithDelay</span><span class="p">(</span><span class="s">"1s"</span><span class="p">))</span></code></pre></div></li>
+</ul>
+
+<h2 id="check-and-result"><code>Check</code> and <code>Result</code></h2>
+
+<p><code>Connection</code> and <code>FileExists</code> are the only two <em>built-in</em> <code>Check</code> provided by
+<code>gotest.tools</code>. They are useful, but as usual, where <code>gotest.tools</code> shines is
+extensiblity. It is really easy to define your own <code>Check</code>.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Check</span> <span class="kd">func</span><span class="p">(</span><span class="nx">t</span> <span class="nx">LogT</span><span class="p">)</span> <span class="nx">Result</span></code></pre></div>
+<p>A <code>Check</code> is, thus, only a function that takes <code>LogT</code> โ which is anything that can log
+something, like <code>*testing.T</code> โ and return a <code>Result</code>. Let’s look at this intersting
+<code>Result</code> type.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="kd">type</span> <span class="nx">Result</span> <span class="kd">interface</span> <span class="p">{</span>
+ <span class="c1">// Error indicates that the check failed and polling should stop, and the
+</span><span class="c1"></span> <span class="c1">// the has failed
+</span><span class="c1"></span> <span class="nf">Error</span><span class="p">()</span> <span class="kt">error</span>
+ <span class="c1">// Done indicates that polling should stop, and the test should proceed
+</span><span class="c1"></span> <span class="nf">Done</span><span class="p">()</span> <span class="kt">bool</span>
+ <span class="c1">// Message provides the most recent state when polling has not completed
+</span><span class="c1"></span> <span class="nf">Message</span><span class="p">()</span> <span class="kt">string</span>
+<span class="p">}</span></code></pre></div>
+<p>Although it’s an interface, the <code>poll</code> package defines built-in <code>Result</code> so that it’s easy
+to write <code>Check</code> without having to define you <code>Result</code> type.</p>
+
+<ul>
+<li><code>Continue</code> returns a Result that indicates to WaitOn that it should continue
+polling. The message text will be used as the failure message if the timeout is reached.</li>
+<li><code>Success</code> returns a Result where Done() returns true, which indicates to WaitOn that it
+should stop polling and exit without an error.</li>
+<li><code>Error</code> returns a Result that indicates to WaitOn that it should fail the test and stop
+polling.</li>
+</ul>
+
+<p>The basic just to write a <code>Check</code> is then :</p>
+
+<ul>
+<li>if the state is not there yet, return <code>Continue</code>,</li>
+<li>if there is an error, unrelated to validating the state, return an <code>Error</code>,</li>
+<li>if the state is there, return <code>Success</code>.</li>
+</ul>
+
+<p>Let’s look at an example taken from the <code>moby/moby</code> source code.</p>
+<div class="highlight"><pre class="chroma"><code class="language-go" data-lang="go"><span class="nx">poll</span><span class="p">.</span><span class="nf">WaitOn</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span> <span class="nx">container</span><span class="p">.</span><span class="nf">IsInState</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">client</span><span class="p">,</span> <span class="nx">cID</span><span class="p">,</span> <span class="s">"running"</span><span class="p">),</span> <span class="nx">poll</span><span class="p">.</span><span class="nf">WithDelay</span><span class="p">(</span><span class="mi">100</span><span class="o">*</span><span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span><span class="p">))</span>
+
+<span class="kd">func</span> <span class="nf">IsInState</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span> <span class="nx">client</span> <span class="nx">client</span><span class="p">.</span><span class="nx">APIClient</span><span class="p">,</span> <span class="nx">containerID</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">state</span> <span class="o">...</span><span class="kt">string</span><span class="p">)</span> <span class="kd">func</span><span class="p">(</span><span class="nx">log</span> <span class="nx">poll</span><span class="p">.</span><span class="nx">LogT</span><span class="p">)</span> <span class="nx">poll</span><span class="p">.</span><span class="nx">Result</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="kd">func</span><span class="p">(</span><span class="nx">log</span> <span class="nx">poll</span><span class="p">.</span><span class="nx">LogT</span><span class="p">)</span> <span class="nx">poll</span><span class="p">.</span><span class="nx">Result</span> <span class="p">{</span>
+ <span class="nx">inspect</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">client</span><span class="p">.</span><span class="nf">ContainerInspect</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">containerID</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="nx">poll</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
+ <span class="p">}</span>
+ <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">state</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="nx">inspect</span><span class="p">.</span><span class="nx">State</span><span class="p">.</span><span class="nx">Status</span> <span class="o">==</span> <span class="nx">v</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="nx">poll</span><span class="p">.</span><span class="nf">Success</span><span class="p">()</span>
+ <span class="p">}</span>
+ <span class="p">}</span>
+ <span class="k">return</span> <span class="nx">poll</span><span class="p">.</span><span class="nf">Continue</span><span class="p">(</span><span class="s">"waiting for container to be one of (%s), currently %s"</span><span class="p">,</span> <span class="nx">strings</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="s">", "</span><span class="p">),</span> <span class="nx">inspect</span><span class="p">.</span><span class="nx">State</span><span class="p">.</span><span class="nx">Status</span><span class="p">)</span>
+ <span class="p">}</span>
+<span class="p">}</span></code></pre></div>
+<h2 id="conclusion">Conclusion</h2>
+
+<p>โฆ that’s a wrap. The <code>poll</code> package allows to easily wait for a condition to happen in a
+given time-frame โ with sane defaults. As for most of the <code>gotest.tools</code> package, we use
+this package heavily in <code>docker/*</code> projects tooโฆ</p>
+
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-03-24-link/" title="Building Blocks โ I.A.">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-03-12-link/" title="Go2 Contracts Go Too Far ยท npf.io">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-03-24-link/index.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-03-24-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Building Blocks โ I.A.</h1><a href='https://vincent.demeester.fr/posts/2019-03-24-link/'></a>
+ <address class="signature">
+ <span class="date">Sun, 24 March, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-functional"><a href="/tags/#functional">functional<span>1</span></a></li>
+
+
+ <li class="tag tag-programming"><a href="/tags/#programming">programming<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>A visual approach to the topic of purely-typed functional programming.</p>
+ <p>๐ <a href="https://icidasset.com/writings/building-blocks/" class="link">https://icidasset.com/writings/building-blocks/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-03-26-link/" title="Handle and Check - Let's Not ยท npf.io">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-03-23-gotest-tools-poll/" title="Golang testing โ gotest.tools poll">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-03-26-link/index.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-03-26-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Handle and Check - Let's Not ยท npf.io</h1><a href='https://vincent.demeester.fr/posts/2019-03-26-link/'></a>
+ <address class="signature">
+ <span class="date">Tue, 26 March, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-go"><a href="/tags/#go">go<span>5</span></a></li>
+
+
+ <li class="tag tag-proposal"><a href="/tags/#proposal">proposal<span>1</span></a></li>
+
+
+ <li class="tag tag-handle"><a href="/tags/#handle">handle<span>1</span></a></li>
+
+
+ <li class="tag tag-check"><a href="/tags/#check">check<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>Opinion (that I share) on the check/handle error proposal for Go 2</p>
+ <p>๐ <a href="https://npf.io/2018/09/check-and-handle/" class="link">https://npf.io/2018/09/check-and-handle/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-03-27-link/" title="Nicolas Mattia - The 5 Raisons d'รtre of Testing">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-03-24-link/" title="Building Blocks โ I.A.">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-03-27-link/index.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-03-27-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Nicolas Mattia - The 5 Raisons d'รtre of Testing</h1><a href='https://vincent.demeester.fr/posts/2019-03-27-link/'></a>
+ <address class="signature">
+ <span class="date">Wed, 27 March, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-testing"><a href="/tags/#testing">testing<span>11</span></a></li>
+
+
+ <li class="tag tag-craftmanship"><a href="/tags/#craftmanship">craftmanship<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>The author describes five of the reason why he thinks tests are important โ and I do agree !</p>
+ <p>๐ <a href="https://nmattia.com/posts/2019-01-22-the-5-raisons-detre-of-testing.html" class="link">https://nmattia.com/posts/2019-01-22-the-5-raisons-detre-of-testing.html</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-03-28-link/" title="Nix: A Reproducible Setup for Linux and macOS">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-03-26-link/" title="Handle and Check - Let's Not ยท npf.io">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-03-28-link/index.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-03-28-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Nix: A Reproducible Setup for Linux and macOS</h1><a href='https://vincent.demeester.fr/posts/2019-03-28-link/'></a>
+ <address class="signature">
+ <span class="date">Thu, 28 March, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-linux"><a href="/tags/#linux">linux<span>4</span></a></li>
+
+
+ <li class="tag tag-macos"><a href="/tags/#macos">macos<span>1</span></a></li>
+
+
+ <li class="tag tag-nix"><a href="/tags/#nix">nix<span>3</span></a></li>
+
+
+ <li class="tag tag-reproductible"><a href="/tags/#reproductible">reproductible<span>2</span></a></li>
+
+
+ <li class="tag tag-nixpkgs"><a href="/tags/#nixpkgs">nixpkgs<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>This post describes how I set up a reproducible development environment in a few seconds on any Linux distribution (and potentially macOS as well).</p>
+ <p>๐ <a href="https://nmattia.com/posts/2018-03-21-nix-reproducible-setup-linux-macos.html" class="link">https://nmattia.com/posts/2018-03-21-nix-reproducible-setup-linux-macos.html</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-03-31-link/" title="Six Years With a Distraction-Free iPhone">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-03-27-link/" title="Nicolas Mattia - The 5 Raisons d'รtre of Testing">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-03-31-link/index.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-03-31-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Six Years With a Distraction-Free iPhone</h1><a href='https://vincent.demeester.fr/posts/2019-03-31-link/'></a>
+ <address class="signature">
+ <span class="date">Sun, 31 March, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#productivity">productivity</a></li>
+
+
+
+
+
+ <li class="tag tag-iphone"><a href="/tags/#iphone">iphone<span>1</span></a></li>
+
+
+ <li class="tag tag-distration"><a href="/tags/#distration">distration<span>1</span></a></li>
+
+
+ <li class="tag tag-mobile"><a href="/tags/#mobile">mobile<span>1</span></a></li>
+
+
+ <li class="tag tag-free"><a href="/tags/#free">free<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>A very interesting medium story on why and how to try your own low-stress experiment. I went and did a few of what the author did, and it feels good ! Really !</p>
+ <p>๐ <a href="https://medium.com/s/story/six-years-with-a-distraction-free-iphone-8cf5eb4f97e3" class="link">https://medium.com/s/story/six-years-with-a-distraction-free-iphone-8cf5eb4f97e3</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-04-18-link/" title="Easy Peasy Nix Versions">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-03-28-link/" title="Nix: A Reproducible Setup for Linux and macOS">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-04-18-link/index.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-04-18-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Easy Peasy Nix Versions</h1><a href='https://vincent.demeester.fr/posts/2019-04-18-link/'></a>
+ <address class="signature">
+ <span class="date">Thu, 18 April, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-linux"><a href="/tags/#linux">linux<span>4</span></a></li>
+
+
+ <li class="tag tag-nix"><a href="/tags/#nix">nix<span>3</span></a></li>
+
+
+ <li class="tag tag-reproductible"><a href="/tags/#reproductible">reproductible<span>2</span></a></li>
+
+
+ <li class="tag tag-nixpkgs"><a href="/tags/#nixpkgs">nixpkgs<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>This is a convention for using third-party packages in Nix. It has a simple directory structure, makes using the packages straightforward and automatizes updates.</p>
+ <p>๐ <a href="https://www.nmattia.com/posts/2019-01-15-easy-peasy-nix-versions.html" class="link">https://www.nmattia.com/posts/2019-01-15-easy-peasy-nix-versions.html</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-04-19-link/" title="Stop writing broken Go libraries">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-03-31-link/" title="Six Years With a Distraction-Free iPhone">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-04-19-link/index.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-04-19-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Stop writing broken Go libraries</h1><a href='https://vincent.demeester.fr/posts/2019-04-19-link/'></a>
+ <address class="signature">
+ <span class="date">Fri, 19 April, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-go"><a href="/tags/#go">go<span>5</span></a></li>
+
+
+ <li class="tag tag-libraries"><a href="/tags/#libraries">libraries<span>1</span></a></li>
+
+
+ <li class="tag tag-broken"><a href="/tags/#broken">broken<span>1</span></a></li>
+
+
+ <li class="tag tag-tips"><a href="/tags/#tips">tips<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>Every single one of those libraries had some fundamental problems that made it unusable in any real world applications. Furthermore every single one of those libraries was written in a way which made fixing the issues impossible without altering the existing library APIs in a non backwards compatibile way. As the same problems unfortunately plague many other Go libraries I attempted to list most of the sins commited by their authors below.</p>
+ <p>๐ <a href="https://0x46.net/thoughts/2018/12/29/go-libraries/" class="link">https://0x46.net/thoughts/2018/12/29/go-libraries/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-04-23-link/" title="Trimming the fat from a Golang binary">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-04-18-link/" title="Easy Peasy Nix Versions">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-04-23-link/index.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-04-23-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">Trimming the fat from a Golang binary</h1><a href='https://vincent.demeester.fr/posts/2019-04-23-link/'></a>
+ <address class="signature">
+ <span class="date">Tue, 23 April, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-go"><a href="/tags/#go">go<span>5</span></a></li>
+
+
+ <li class="tag tag-binary"><a href="/tags/#binary">binary<span>1</span></a></li>
+
+
+ <li class="tag tag-size"><a href="/tags/#size">size<span>1</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>Some tips and tricks to reduce the size of a golang binary</p>
+ <p>๐ <a href="https://boyter.org/posts/trimming-golang-binary-fat/" class="link">https://boyter.org/posts/trimming-golang-binary-fat/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-05-11-link/" title="As We May Kube*">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-04-19-link/" title="Stop writing broken Go libraries">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-05-11-link/index.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-05-11-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">As We May Kube*</h1><a href='https://vincent.demeester.fr/posts/2019-05-11-link/'></a>
+ <address class="signature">
+ <span class="date">Sat, 11 May, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-orchestration"><a href="/tags/#orchestration">orchestration<span>2</span></a></li>
+
+
+ <li class="tag tag-kubernetes"><a href="/tags/#kubernetes">kubernetes<span>2</span></a></li>
+
+
+ <li class="tag tag-kube"><a href="/tags/#kube">kube<span>2</span></a></li>
+
+
+ <li class="tag tag-k8s"><a href="/tags/#k8s">k8s<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>We use different programming languages and development environments to write apps. Each language comes with a different flow and also we typically go through different phases, from prototyping to integration-level activities to incrementally adding features or fixing bugs once the app is in production. Now, the expectation of a developer coming from a โtraditionalโ environment to Kubernetes is in general that their natural and well-known workflow changes as little as possible. This article reviews where we stand in Kubernetes-land concerning developing apps and where we may be heading.</p>
+ <p>๐ <a href="https://itnext.io/as-we-may-kube-293b30c0a365" class="link">https://itnext.io/as-we-may-kube-293b30c0a365</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+ <a class="paging-link prev" href="/posts/2019-06-28-link/" title="boring is cool | advocacy site for boring technology">โ Previous post</a>
+
+
+
+ <a class="paging-link next" href="/posts/2019-04-23-link/" title="Trimming the fat from a Golang binary">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/legacy/posts/2019-06-28-link/index.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+
+<html lang="en">
+
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <link rel="start" href="https://vincent.demeester.fr" />
+
+ <title>Vincent Demeester</title>
+ <link rel="canonical" href="https://vincent.demeester.fr/posts/2019-06-28-link/">
+ <link href="https://vincent.demeester.fr/index.xml" rel="alternate" type="application/rss+xml" title="Vincent Demeester" />
+
+ <link rel="openid.server" href="https://indieauth.com/openid" />
+ <link rel="openid.delegate" href="http://vincent.demeester.fr/" />
+ <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
+
+ <link rel="stylesheet" href="/css/screen.css" type="text/css" />
+ <link rel="stylesheet" href="/css/sbrain.css" type="text/css" />
+ <link rel="stylesheet" href="/css/syntax.css" type="text/css" />
+
+ </head>
+
+ <body lang=""/>
+
+
+
+
+
+
+<div id="main-container">
+ <div id="page">
+ <article class="post">
+ <header>
+ <h1 class="emphnext">boring is cool | advocacy site for boring technology</h1><a href='https://vincent.demeester.fr/posts/2019-06-28-link/'></a>
+ <address class="signature">
+ <span class="date">Fri, 28 June, 2019</span>
+ <span class="words">(100 Words)</span>
+ </address>
+ <ul class="tag_box inline">
+
+ <li class="category"><a href="/categories/#development">development</a></li>
+
+
+
+
+
+ <li class="tag tag-development"><a href="/tags/#development">development<span>13</span></a></li>
+
+
+ <li class="tag tag-software"><a href="/tags/#software">software<span>13</span></a></li>
+
+
+ <li class="tag tag-orchestration"><a href="/tags/#orchestration">orchestration<span>2</span></a></li>
+
+
+ <li class="tag tag-kubernetes"><a href="/tags/#kubernetes">kubernetes<span>2</span></a></li>
+
+
+ <li class="tag tag-kube"><a href="/tags/#kube">kube<span>2</span></a></li>
+
+
+ <li class="tag tag-k8s"><a href="/tags/#k8s">k8s<span>2</span></a></li>
+
+ <br/>
+
+ </ul>
+ </header>
+
+ <p>ยซ Here, I share some thoughts and considerations around using cloud native technologies, including Kubernetes, observability tools such as Prometheus, service meshes, and serverless offerings. ยป</p>
+ <p>๐ <a href="http://boringis.cool/" class="link">http://boringis.cool/</a></p>
+
+ </article>
+ <hr />
+ <div class="prev-next">
+
+
+
+ <a class="paging-link next" href="/posts/2019-05-11-link/" title="As We May Kube*">Next post โ</a>
+
+ </div>
+
+ </div>
+</div>
+
+<footer>
+ <nav>
+
+ <a href="/">home</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/about">about</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/archive">archive</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/categories">categories</a>
+ <span class="text-muted"> | </span>
+
+ <a href="/tags">tags</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://twitter.com/vdemeest">twitter</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://github.com/vdemeester">github</a>
+ <span class="text-muted"> | </span>
+
+ <a href="https://vincent.demeester.fr/index.xml">rss</a>
+ </nav>
+ <br/>
+ <address>
+ <span class="copyright">
+ Content and design by Vincent Demeester
+ (<a rel="licence" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Some rights reserved</a>)
+ </span><br />
+ <span class="engine">
+ Powered by <a href="https://gohugo.io/">Hugo</a> and <a href="https://github.com/kaushalmodi/ox-hugo/">ox-hugo</a>
+ </span>
+ </address>
+</footer>
+</body>
+
www/vincent.demeester.fr/posts/2012-05-07-reinit-and-jekyll.org
@@ -0,0 +1,61 @@
+#+title: Reinit and Jekyll
+#+date: <2012-05-07 Mon>
+#+filetags: website jekyll
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+Two weeks ago, my /online/ personal server has been attacked and,
+somehow, died. I'm in the process of re-installation of it but I'm going
+to hardened a bit the security on it. Anyway, this crash meant that
+every piece of site I maintain has been down. That's why I moved this
+/identity site/ on the github pages, using a CNAME ; That way I can
+crash as much as I want my server(s), this page should still be up for a
+while.
+
+And I'm switching on Jekyll for this website as It is supported by
+Github page, easy to use and easy to deploy elsewhere (if one day I want
+to move from Github).
+
+The rest of the post is going to be used as a /sandbox/ post to test the
+site styles.
+
+#+BEGIN_QUOTE
+ This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+ consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+ Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+ id sem consectetuer libero luctus adipiscing.
+#+END_QUOTE
+
+** Highlight
+ :PROPERTIES:
+ :CUSTOM_ID: highlight
+ :ID: 6e1687a1-6898-4fe1-ac56-53b6e1e1f310
+ :END:
+
+#+begin_src ruby
+def foo puts 'foo' end
+#+end_src
+
+Some bash script...
+
+#+begin_src bash
+#!/bin/bash
+update_gems() {
+ echo "Update gems for all versions ? (y/N)"
+ read UPDATE_GEMS
+ test -z "${UPDATE_GEMS}" && UPDATE_GEMS="n"
+
+ if test "${UPDATE_GEMS}" = "y"; then
+ for version in =ls --color=never $HOME/.rbenv/versions=; do
+ echo "Updating ${version%/}"
+ RBENV_VERSION="${version%/}" rbenv exec gem update
+ RBENV_VERSION="${version%/}" rbenv exec gem install bundler
+ done
+ fi
+}
+
+update_gems
+#+end_src
www/vincent.demeester.fr/posts/2012-05-08-gitolite-quick-and-dirty-mirror.org
@@ -0,0 +1,126 @@
+#+title: Gitolite quick and dirty mirror
+#+date: <2012-05-08 Tue>
+#+filetags: gitolite git linux mirror github
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+I'm running a gitolite _instance_ on my personal server to manage my repositories
+(personnal, private or public) ; and I am quickly going to share with you how I setup a
+_quick and dirty_ mirror feature.
+
+First, I am using **gitolite 3**. The mirroring we are going to setup is not the
+_supported_ [[http://sitaramc.github.com/gitolite/mirroring.html][mirroring *built-in*]]. We are going to implement a simplier way to set mirror
+thing :
+
+1. Write a custom gitolite command ; the idea is to be able to write ~git-config~ stuff.
+2. Write a hook that take a specific ~git-config~ (let say ~mirror.url~) and do a simple
+ mirroring.
+
+* Gitolite commands
+
+Gitolite 3 has been rewritten to be more flexible : [[http://sitaramc.github.com/gitolite/g3why.html][Why a completely new version]]. The
+rewrite made it really easy to extend gitolite. +I've fork [[https://github.com/vdemeester/gitolite][gitolite]] on github+ I've
+created a [[http://github.com/vdemeester/vdemeester-gitolite-local-code][repository git]] to easily add commands to my gitolite instance via _local
+code_. The gitolite command I wrote is a quick and dirty script in shell to add ~git
+config~. The source should speek for itself ; It _should_ include some way to check if the
+given config is not already present in the ~gitolite-admin~ configuration file โ and so
+might be rewritten in ~Perl~.
+
+The command is ~write-git-config~ because a ~git-config~ command already exists
+in the built-in commands.
+
+#+begin_src bash
+#!/bin/sh
+
+# Usage: ssh git@host write-git-config <repo> <key> <value>
+#
+# Set git-config value for user-created ("wild") repo.
+
+die() { echo "$@" >&2; exit 1; }
+usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
+[ -z "$1" ] && [ -z "$2" ] && [ -z "$3" ] && usage
+[ "$1" = "-h" ] && usage
+[ -z "$GL_USER" ] && die GL_USER not set
+
+# ----------------------------------------------------------------------
+repo=$1; shift
+key=$1; shift
+value=$1; shift
+
+# this shell script takes arguments that are completely under the user's
+# control, so make sure you quote those suckers!
+
+if gitolite query-rc -q WRITER_CAN_UPDATE_DESC
+then
+ gitolite access -q "$repo" $GL_USER W any || die You are not authorised
+else
+ gitolite creator "$repo" $GL_USER || die You are not authorised
+fi
+
+# if it passes, $repo is a valid repo name so it is known to contain only sane
+# characters. This is because 'gitolite creator' return true only if there
+# *is* a repo of that name and it has a gl-creator file that contains the same
+# text as $GL_USER.
+
+configfile=`gitolite query-rc GL_REPO_BASE`/"$repo".git/config
+
+git config --file "$configfile" "$key" "$value"
+#+end_src
+
+* Gitolite hooks
+
+The next step is to write a quick ~post-receive~ hook that check if there is a
+certain ~git-config~ entry and run ~git push --mirror~. The file is in
+~$HOME/.gitolite/hooks/common/post-receive~ ; you could add a better system to
+hooks (to be able to add "dynamic" hooks, โฆ).
+
+#+begin_src bash
+
+#!/bin/sh
+
+# Simple gitolite mirroring
+
+# flush STDIN coming from git, because gitolite's own post-receive.mirrorpush
+# script does the same thing
+[ -t 0 ] || cat >/dev/null
+
+[ -z "$GL_REPO" ] && die GL_REPO not set
+
+target=`git config --get mirror.url`
+[ -z "$target" ] && exit 0
+
+# Support a REPO variable for wildcard mirrors
+gl_repo_escaped=$(echo $GL_REPO | sed 's/\//\\\//g')
+target=$(echo $target | sed -e "s/REPO/$gl_repo_escaped/g")
+
+# Do the mirror push
+git push --mirror $target
+#+end_src
+
+The next, and final step is to run `gitolite compile` to update links to hooks
+for every repositories.
+
+* For real
+
+And finaly, this is the final step you'll do.
+
+#+begin_src bash
+$ ssh git@host write-git-config vincent/vcsh-home mirror.url git@github.com:vdemeester/vcsh-home.git
+$ git push
+Counting objects: 5, done.
+Delta compression using up to 2 threads.
+Compressing objects: 100% (3/3), done.
+Writing objects: 100% (3/3), 294 bytes, done.
+Total 3 (delta 2), reused 0 (delta 0)
+remote: To git@github.com:vdemeester/vcsh-home.git
+remote: 65681a8..701c990 master -> master
+To git@host:vincent/vcsh-home.git
+ 65681a8..701c990 master -> master
+#+end_src
+
+
+And that should be it !
+
+_Update 2012/10/04_ : Moved from gitolite fork to _gitolite local code_
+repository.
www/vincent.demeester.fr/posts/2012-05-13-jekyll-foreman-guard-bundler.org
@@ -0,0 +1,90 @@
+#+title: Jekyll Forman Guard Bundler
+#+date: <2012-05-13 Sun>
+#+filetags: jekyll ruby bundler guard foreman
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+This post is a quick "How did I setup my Jekyll environnement ?". We are
+going all the tools that are quite awesome in Ruby.
+
+* Goal
+ :PROPERTIES:
+ :CUSTOM_ID: goal
+ :END:
+
+The goal is simple :
+
+1. I want to be able to install any dependent
+ [[http://rubygems.org][Gem]] with a /on-liner/ command
+2. I want to be able to run a /Jekyll server/ that auto updates.
+
+We are going to play with : [[http://gembundler.com/][Bundler]],
+[[https://github.com/guard/guard][Guard]] and
+[[https://github.com/ddollar/foreman][foreman]].
+
+* Bundler
+ :PROPERTIES:
+ :CUSTOM_ID: bundler
+ :END:
+
+Bundler let us run =bundle install= to get all Ruby Gems we will need ;
+It use a file name =Gemfile=. The gems we need are simple : =jekyll=,
+=guard= and some Guard extensions.
+
+#+begin_src ruby
+source "http://rubygems.org"
+
+gem 'jekyll'
+gem 'guard'
+gem 'guard-jekyll2'
+gem 'guard-shell'
+gem 'guard-bundler'
+#+end_src
+
+* Guard
+ :PROPERTIES:
+ :CUSTOM_ID: guard
+ :END:
+
+#+BEGIN_QUOTE
+ Guard is a command line tool to easily handle events on file system
+ modifications.
+#+END_QUOTE
+
+Guard will be watching file we told him and run action in consequence ;
+The file is name =Guardfile=.
+
+#+begin_src ruby
+guard 'jekyll2' do
+ watch %r{.*}
+end
+
+guard :bundler do
+ watch('Gemfile')
+end
+# vim:filetype=ruby
+#+end_src
+
+* Foreman
+ :PROPERTIES:
+ :CUSTOM_ID: foreman
+ :END:
+
+Finally, foreman will let us declare our processes and will handle the
+start, forward the output and handle the shutdown. It can then export
+its configuration into more /production-ready/ file (=init=, =upstard=,
+...) ; It uses a file named =Procfile=.
+
+We will tell foreman to run :
+
+- The jekyll build-in server : =jekyll --server=
+- Guard, to handle file changes /in background/.
+
+#+begin_src bash
+web: bundle exec jekyll --server
+guard: bundle exec guard
+#+end_src
+
+And that's all folk. Now, you just need to run foreman in the
+Jekyll-powered directory and edit your files.
www/vincent.demeester.fr/posts/2012-07-23-maven-release-gitflow.org
@@ -0,0 +1,99 @@
+#+title: Maven Release Gitflow
+#+date: <2012-07-23 Mon>
+#+filetags: maven java git gitflow release
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+I like a lot the [[http://nvie.com/posts/a-successful-git-branching-model/][gitflow]] way of managing project. When working on maven project, there is
+few great plugins that helps to get the work done. One of them is [[http://maven.apache.org/plugins/maven-release-plugin][maven-release-plugin]].
+
+Inspired on this [[https://gist.github.com/1043970][gist]], I've come
+with a cool way of doing things (let say we want to release a 0.1
+version of an artifact) :
+
+* Prepare the pom.xml.
+ :PROPERTIES:
+ :CUSTOM_ID: prepare-the-pom.xml.
+ :END:
+
+It needs =<scm>= entries, =<distributionManagement>= entries (to know
+where to deploy the release artifact) and few options for the
+maven-release-plugin :
+
+{{< highlight xml >}}
+#+begin_src xml
+<project>
+
+ <!-- [โฆ] -->
+ <build>
+ <plugins>
+ <!-- [โฆ] -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <tagNameFormat>v@{project.version}</tagNameFormat>
+ <pushChanges>false</pushChanges>
+ <localCheckout>true</localCheckout>
+ </configuration>
+ </plugin>
+ <!-- [โฆ] -->
+ </plugins>
+ </build>
+ <!-- [โฆ] -->
+
+</project>
+#+end_src
+
+Few explanation here :
+
+- =tagNameFormat= is here to change the default tag name (which is
+ =${project.artifactId}-${project.version}=) to a better one.
+- =pushChanges= set to =false= tells maven-release-plugin not to push
+ changes (this will become useful)
+- =localCheckout= set to =true= tells maven-release-plugin to clone from
+ local repository (not distant). This is especially useful here because
+ we didn't push anything (so not setting this option would result in a
+ failure).
+
+* The real stuff
+ :PROPERTIES:
+ :CUSTOM_ID: the-real-stuff
+ :END:
+
+First create a release branch from develop.
+
+#+begin_src bash
+$ git checkout -b release/v0.1 develop
+#+end_src
+
+Then run the maven release stuff.
+
+#+begin_src bash
+$ mvn release:prepare # change the pom, commit and tag version, and
+ # re-change pom (by incrementing SNAPSHOT version)
+$ mvn release:perform # get the tagged version, compile and deploy
+#+end_src
+
+And the real fun begins.
+
+#+begin_src bash
+$ git checkout develop # get back to the develop branch
+$ git merge --no-ff release/v0.1 # merge the version back into develop
+$ git checkout master # go to the master branch
+$ git merge --no-ff release/v0.1~1 # merge the version back into master but
+ # the tagged version instead of the release/v0.1 HEAD
+$ git branch -D release/v0.1 # Removing the release branch
+$ git push --all && git push --tags # Finally push everything
+#+end_src
+
+The real magic here is the =git merge --no-ff release/v0.1~1= which will
+merge into master the commit before the HEAD of the branch
+=release/v0.1=.
+
+The next step would be to create a helper script that automates this and
+verify that the =pom.xml= has the right configuration options.
+
+*Edit 17:58* : You can take a look [[https://github.com/vdemeester/java-config/blob/master/bin/mvn-release-flow][here]]
www/vincent.demeester.fr/posts/2012-12-16-gollum-comme-wiki-personnel.org
@@ -0,0 +1,84 @@
+#+title: Gollum comme Wiki personnel
+#+date: <2012-12-16 Sun>
+#+filetags: wiki golum github personnel
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+Il y a environ 4 mois j'ai eu un accident de vรฉlo ; un traumatisme
+crรขnien, des brulures sur la face, quelques points de sutures, un doigt
+cassรฉ et une hernie discale m'ont clouรฉ (et me clou encore) plus que
+d'habitude sur ma chaise de bureau. Le bon cรดtรฉ des choses, c'est que
+cela m'a permit de me poser et de rรฉflรฉchir une bonne faรงon d'รชtre
+efficace et organiser, au travail et ร la maison :-).
+
+Une des principales /action/ que j'ai pris est d'utiliser un wiki local
+et synchronisรฉ sur /tout/ mes PCs. Le /format/ wiki est assez adaptรฉ ร
+une prise de note et ร la crรฉation de contenu plus complet (comme des
+[[http://shortbrain.org][articles]] ou de la documentation pour des
+projets en cours). Les conditions รฉtaient les suivantes :
+
+- Facilitรฉ de mise en place.
+- Pas de base de donnรฉes.
+- /Merging/ facile ([[http://git-scm.com][git]] /rules my world/).
+- [[http://daringfireball.net/projects/markdown/][Markdown]] comme
+ syntaxe, car utilisรฉ ร peu prรจs partout (blogs, articles, READMEs,
+ documentations).
+- รditable ร partir d'une interface web ou de mon รฉditeur favoris.
+
+L'outil qui remplit presque toutes ces conditions s'appelle
+[[https://github.com/github/gollum][gollum]]. C'est un moteur wiki,
+รฉcris en ruby, qui se base sur un repository
+[[http://git-scm.com][git]]. Il est dรฉvelopper par l'รฉquipe de
+[[http://github.com][Github]] et c'est celui qui est utilisรฉ par les
+pages wiki lร -bas. Il permet d'utiliser ร peu prรจs n'importe quel
+syntaxe (dont
+[[https://github.com/github/github-flavored-markdown][github-markdown]]
+qui est assez proche de celle de
+[[http://johnmacfarlane.net/pandoc][pandoc]]). Par ailleurs, comme il se
+base sur [[http://git-scm.com][git]], les points /"pas de base de
+donnรฉes"/, /"merging facile"/ et /"รฉditable รฉgalement ร partir de mon
+รฉditeur favoris"/ sont toutes remplies.
+
+Avec [[https://github.com/github/gollum][Gollum]] vous avez un wiki
+markdown dรฉcentralisรฉ, รฉditable via une interface web ou via votre
+รฉditeur favoris.
+
+* Mise en place
+ :PROPERTIES:
+ :CUSTOM_ID: mise-en-place
+ :END:
+
+La mise en place est relativement simple ; aprรจs tout dรฉpend du besoin
+que vous avez. L'installation se fait par [[file:rubygems.org][RubyGem]]
+ou en clonant le repository.
+
+{{< highlight bash >}} # Installation de gollum et du format markdown de
+github $ gem install gollum gitub-markdown {{< /highlight >}}
+
+Si vous n'utilisez pas [[https://github.com/sstephenson/rbenv][rbenv]]
+ou [[https://rvm.io/][rvm]] il est probable qu'il faille lancer la
+commande en root ou utiliser sudo.
+
+Ensuite, il suffit de lancer
+[[https://github.com/github/gollum][Gollum]] dans un dossier qui est un
+repository git ; le tour est jouรฉ
+
+{{< highlight bash >}} # J'ulitise ~/desktop/wiki pour mon wiki $ cd
+~/desktop/wiki && gollum {{< /highlight >}}
+
+L'idรฉe finale est d'automatiser deux choses :
+
+1. Le dรฉmarrage de gollum
+2. La synchronisation du repository avec les diffรฉrents autres /remotes/
+
+Suivant le systรจme d'exploitation et/ou la distribution utilisรฉes, il y
+a รฉnormรฉment de possibilitรฉ d'effectuer cette automatisation. Dans mon
+cas, j'ai une [[http://debian.org][Debian]] assez light, avec surtout
+plein de scripts. Je dรฉmarre donc
+[[https://github.com/github/gollum][Gollum]] au dรฉmarrage de ma session
+grรขce ร une script qui est lancรฉ dans la foulรฉe du gestionnaire de
+fenรชtre. La synchronisation se fait grรขce ร une tรขche planifiรฉe /cron/
+qui est "distribuรฉ" sur chacune de mes machines.
+
+/C'est tout pour le moment/ ;-).
www/vincent.demeester.fr/posts/2013-09-08-maven-tmpfs.org
@@ -0,0 +1,158 @@
+#+title: Maven Tmpfs
+#+date: <2013-09-08 Sun>
+#+filetags: maven tmpfs ssd
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+Je suis un utilisateur convaincu de [[http://maven.apache.org/][maven]], malgrรฉ ces dรฉfauts, le
+moto *"Convention over configuration"* me va vraiment bien. Que ce soit
+au boulot ou ร la maison, j'ai plus d'ordinateurs รฉquipรฉs de ssd (ou de
+mรฉmoire flash) que de disque traditionnel (mรฉcanique ?). Pour augmenter
+un peu la durรฉe de vie de ces disques SSD, j'ai cherchรฉ ร savoir comment
+/dรฉporter/ le /build/ de maven (qui, pour rappel, se passe dans le
+dossier =target/=) hors du SSD ; ici ce sera dans le dossier =/tmp/= qui
+est montรฉ en mรฉmoire (merci =tmpfs=), mais on peut imaginer dรฉporter รงa
+sur un autre disque, etc.. Aprรจs quelques recherches j'ai trouvรฉs
+quelques inspirations.
+
+#+BEGIN_QUOTE
+ *Limitations*
+
+ Dans la solution prรฉsentรฉe ci-dessous les principales limitations sont
+ les suivantes (que j'essaierais de diminuer au fil du temp ;P) :
+
+ 1. Il est nรฉcessaire de modifier le pom.xml du projet ; cela ne
+ s'appliquera donc pas ร tous les projets maven sans modification du
+ pom.xml.
+ 2. Cela ne fonctionne que sur une plateforme qui support les liens
+ symboliques (Linux, Mac OS X, et autre UNIX).
+ 3. Cela ne fonctionne qu'avec Java 7 ou plus.
+ 4. Si vous utilisez m2e, il va gentillement gueuler et c'est moche ; pour rรฉsoudre le
+ problรจme, il faut faire un tour vers [[http://wiki.eclipse.org/M2E_plugin_execution_not_covered][M2E plugin execution not covered]].
+#+END_QUOTE
+
+Pour [[http://maven.apache.org/][maven]], le dossier =target/= vient de la propriรฉtรฉ
+=project.build.directory=. Dans la thรฉorie, il suffirait de modifier
+(dans =$HOME/.m2/settings.xml=) cette propriรฉtรฉ et le tour serait jouer.
+Malheuresement ce n'est pas possible, =project.build.directory= est une
+propriรฉtรฉ interne et n'est, ร priori, pas modifiable.
+
+Notre souhait est le suivant :
+
+1. Le build doit se faire dans =/tmp/m2/=, ce qui pour un projet se
+ traduit par =/tmp/m2/${groupId}:${artifactId}=.
+2. Le dossier =target/= dans les sources est un lien symbolique vers le
+ dossier dans =/tmp/m2/=
+3. On passe par un *profile* qui n'est *pas actif* par dรฉfaut (pour ne
+ pas faire chier le monde) mais *activable via une propriรฉtรฉ* (maven
+ nous permet de le faire et c'est cool =^_^=). La propriรฉtรฉ utilisรฉe
+ sera =external.build.root=.
+
+Le code ci-dessous est repris directement de mon inspiration[fn:1]. Il
+s'occupe de crรฉer le dossier =${groupId}:${artifactId}= dans
+=external.build.root= et de faire le lien dans le dossier courant.
+
+#+begin_src xml
+<project>
+ <!-- [โฆ] -->
+ <profiles>
+ <profile>
+ <id>external-build-dir</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>external.build.root</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.alexecollins.maven.plugin</groupId>
+ <artifactId>script-maven-plugin</artifactId>
+ <version>1.0.0</version>
+ <executions>
+ <execution>
+ <id>prep-work-tree</id>
+ <goals>
+ <goal>execute</goal>
+ </goals>
+ <phase>initialize</phase>
+ <configuration>
+ <script>
+ import java.nio.file.*
+ def dir =
+ "${external.build.root}/${project.groupId}:${project.artifactId}"
+ println "using Maven dir ${dir}"
+ def dirPath = Paths.get(dir)
+ if (!Files.exists(dirPath)) {
+ Files.createDirectories(dirPath)
+ }
+ def target = Paths.get("${project.build.directory}")
+ if (!Files.exists(target)) {
+ Files.createSymbolicLink(target, dirPath)
+ }</script>
+ </configuration>
+ </execution>
+ <execution>
+ <id>drop-symlink</id>
+ <goals>
+ <goal>execute</goal>
+ </goals>
+ <phase>clean</phase>
+ <configuration>
+ <script>
+ import java.nio.file.*
+ def target = Paths.get("${project.build.directory}")
+ if (Files.isSymbolicLink(target)) {
+ Files.delete(target)
+ }
+ </script>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy</artifactId>
+ <version>1.8.6</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <language>groovy</language>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+ <!-- [โฆ] -->
+</project>
+#+end_src
+
+Ainsi, il suffit ensuite d'avoir quelques choses du genre dans son
+=$HOME/.m2/settings.xml= pour que les builds qui ont ce profil se
+/build/ dans =/tmp/m2/=. On peut aussi ne rien avoir dans
+=$HOME/.m2/settings.xml= et utilise =-Dexternal.build.root=/tmp/m2/=
+avec la commande =mvn=.
+
+#+begin_src xml
+<settings>
+ <!-- [โฆ] -->
+ <profiles>
+ <profile>
+ <id>build-in-ramfs</id>
+ <properties>
+ <external.build.root>/tmp/m2/</external.build.root>
+ </properties>
+ </profile>
+ </profiles>
+ <activeProfiles>
+ <activeProfile>build-in-ramfs</activeProfile>
+ </activeProfiles>
+ <!-- [โฆ] -->
+</settings>
+#+end_src
+
+
+[fn:1] [[http://elehack.net/writings/programming/maven-target-in-tmpfs][PuttingMaven build directories out-of-tree]] par [[http://elehack.net/][Michal Ekstrand]]
www/vincent.demeester.fr/posts/2013-10-12-podcasts.org
@@ -0,0 +1,91 @@
+#+TITLE: Podcasts
+#+date: <2013-10-12 Sat>
+#+filetags: music podcast
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+#+BEGIN_QUOTE
+ Voici un petit billet prรฉsentant les diffรฉrents podcast que j'รฉcoute
+ plus ou moins rรฉguliรจrement.
+#+END_QUOTE
+
+J'รฉcoute รฉnormรฉment de musique et de podcast ; je passe beaucoup de
+temps avec des รฉcouteurs sur la tรชte ou la chaine hifi en route. Les
+podcasts ont une grande place. Voici une liste plus ou moins bien triรฉs
+de ceux auxquels je suis souscrit et/ou que j'รฉcoute en ce moment. Je
+tiendrais peut-รชtre ce post ร jour ou en crรฉerait un nouveau sinon :-).
+
+* Geek & co
+ :PROPERTIES:
+ :CUSTOM_ID: geek-co
+ :END:
+
+Je suis un developpeur, un geek et convaincu des logiciels libres, les
+podcasts qui suivent reflรจte assez cette partie lร de mon identitรฉ.
+
+- [[http://www.captainweb.net/][L'apรฉro de Captain (fr)]] : dans le
+ genre geeky, dรฉjantรฉ et sauvage, en franรงais, on ne fait pas mieux.
+ Pas vraiment safe for work, et pas tout ร fait "libriste" comme
+ j'aime, les tranches de rires sont garanties ; mรชme si parfois on est
+ un peu verreux d'avoir รฉcouter jusqu'ร la fin et le bien nommรฉ
+ "wazzuf".
+- [[http://www.agencetousgeeks.com/][Agence Tous Geeks (fr)]] : fils
+ cachรฉ de l'apรฉro du captain, on y retrouve des amis (et membres de ce
+ dernier), mais c'est un peu plus calme.
+- [[http://bazingcast.com/about/][Bazingcast (fr)]] : podcast geek, plus
+ posรฉ que les deux prรฉcรฉdents mais avec des dรฉbats, des trolls et tout
+ ce que l'on peut attendre de geeks.
+- [[http://www.captainposix.net/][Parole de Tux (fr-be)]] : podcast
+ venant de nos voisin belge, pas trop long et plutรดt sympa ; et si
+ comme moi vous adorez l'accent belge, c'est le top.
+- [[http://faif.us/][Free as in Freedom (en)]] : podcast parlant de
+ logiciel libre principalement cรดtรฉ license, truc lรฉgal, etc.. en
+ anglais, faut parfois s'accrocher.
+- [[http://episodes.gitminutes.com/][Git Minutes (en)]] : podcast ร
+ propos de Git et des outils de son รฉcosystรจme (vcsh, etc..).
+
+* Radio
+ :PROPERTIES:
+ :CUSTOM_ID: radio
+ :END:
+
+J'aime bien la radio, bien plus que la tรฉlรฉvision (que j'allume si peu
+qu'ร chaque fois la box se met ร jour =;-p=).
+
+- [[http://www.franceinter.fr/emission-laura-leishman-project][France
+ Inter - LLP (Laura leishman Project)]]
+- [[http://radiofrance-podcast.net/podcast09/rss_12265.xml][Le Mouv' -
+ Laura Leishman Project]]
+- [[http://www.franceinter.fr/emission-interception][France Inter -
+ Interception]]
+- [[http://www.la-bas.org/][France Inter - lร -bas si j'y suis]]
+- [[http://www.franceculture.fr/podcast/4689840][France Culture -
+ Pixel]]
+- [[http://www.franceculture.fr/podcast/4685228][France Culture - Place
+ de la toile]]
+- [[http://www.franceculture.fr/podcast/4689418][France Culture -
+ Philippe Meyer]]
+- [[http://radiofrance-podcast.net/podcast09/rss_12582.xml][Le Mouv' -
+ Glitch (sur le Mouv')]]
+- [[http://radiofrance-podcast.net/podcast09/rss_12691.xml][Le Mouv' -
+ Code Source]]
+- [[http://radiofrance-podcast.net/podcast09/rss_12190.xml][Le Mouv' -
+ Suivez le geek]]
+- [[http://www.divergence-fm.org/-http-www-divergence-fm-org-ecrire-exec-rubrique-id_rubrique-61-.html][Divergence
+ Numerique]]
+
+* Musique
+ :PROPERTIES:
+ :CUSTOM_ID: musique
+ :END:
+
+Les podcast suivant sont purement musique, tous musique techno ou trance
+(que j'aime bien).
+
+- [[http://podcasts.flaix.fr/corstencountdown][Ferry Corsten - Corsten
+ Countdown]]
+- [[http://www.galexmusic.com/podcast/gareth.xml][Gareth Emery Podcast]]
+- [[http://feedproxy.feedburner.com/Tiestos_club_life][Tiesto Club
+ Life]]
+- [[http://oakenfold.libsyn.com/rss][Oakenfold Perfecto Podcast]]
www/vincent.demeester.fr/posts/2014-03-24-redesign-et-rรฉsolutions.org
@@ -0,0 +1,76 @@
+#+title: Redesign et Rรฉsolutions
+#+date: <2014-03-24 Mon>
+#+filetags: jekyll design images redesign
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+Un /tout petit/ post pour parler rapidement, entre autre, du redesign de
+[[http://vincent.demeester.fr][vincent.demeester.fr]] et de mes
+rรฉsolutions.
+
+* Redesign
+ :PROPERTIES:
+ :CUSTOM_ID: redesign
+ :END:
+
+Les raisons de ce redesign sont assez simple : je change d'employeur et
+de ville (retour sur Paris =\o/=). Cela fait pas mal de changement, et
+en voulant mettre ร jour la page d'accueil (ce que je n'ai toujours pas
+fait =;-P=), j'avais envie de /dรฉmรฉnager/ le site en quelques sortes.
+
+Pour l'inspiration c'est assez facile ร trouver, regarder
+[[http://medium.com][medium]], le site de
+[[http://www.viksit.com/][Viksit Gaur]] ou encore celui de
+[[http://silent-strength.com/][Michael]] (coucou =:-P=). J'adore ce
+genre de site, assez รฉpurรฉ mais avec une partie fixe (ร gauche ou ร
+droite) et avec des images changeantes.
+
+Les images en fond de l'espace de gauche peuvent changer d'une page ร
+l'autre. Je suis en train de m'amuser un peu avec
+[[http://jekyllrb.com][Jekyll]]. Il faut que je trouve un moyen
+d'optimiser un peu les images que j'utilise parce que lร je joue un peu
+le bourrin.
+
+* Rรฉsolutions
+ :PROPERTIES:
+ :CUSTOM_ID: rรฉsolutions
+ :END:
+
+Nouvelle annรฉe, nouveau boulot, implique nouvelles rรฉsolutions. Il y a
+deux aspects ร ces /rรฉsolutions/ : sur un plan
+informatique/geek/travail/organisation, et sur un plan purement
+/physique/.
+
+Mon retour sur Paris devrait me permettre de participer ร un peu plus
+d'รฉvรจnements, notamment du cรดtรฉ des Java User Group, mais aussi FSFE, et
+j'en passe. Je compte รฉgalement continuรฉ ร jouer le /factotum/ en me
+gardant un peu de temps au niveau personnel pour travailler sur des
+aspects /geek/ que je n'aurais peut-รชtre pas l'occasion de pratiquer au
+travail. Au niveau de mes /points d'entrรฉes/ sur le web, je compte
+remettre un peu en route la partie blog de ce site et tourner
+shortbrain.org (ou autre) en un site plus "documentation" en me basant
+sur mes notes (powered by [[http://org-mode.org][org-mode]]). Je me suis
+รฉgalement remis ร [[https://www.gnu.org/software/emacs/][Gnu Emacs]] et
+/oh god/ qu'est-ce que c'est bon =:-D=.
+
+Au niveau phyisque, dans la continuitรฉ de la fin 2012, l'annรฉe 2013 a
+probablement รฉtรฉ la pire de ma vie. Les problรจmes de dos c'est pas
+facile tous les jours.. En fรฉvrier, j'avais peur de ne jamais remonter
+sur un vรฉlo ; en Mai je remontais pour la premiรจre fois sur le vรฉlo, en
+Septembre je faisais 40km par semaine et en dรฉcembre j'รฉtais presque
+capable de faire 30km en une journรฉe. Mรจme si l'annรฉe 2014 a mal
+commencรฉ (je me suis felรฉ un cรดte en Janvier), mes objectifs pour cette
+annรฉe et les futurs sont nettement plus positif. Le
+[[http://fitbit.com][fitbit]] que j'ai acquis en Fรฉvrier me permet
+d'avoir un objectif de marche (certes assez modeste) de 10000 pas et
+8,05 km par jour. Je compte bien me fixer d'autre objectifs : monter la
+barre plus haut (15000 voir plus), faire 50km de vรฉlo sur une journรฉe.
+
+Les objectifs physiques ร trรจs long termes sont รฉgalement assez simples
+: retrouver ma forme physique et ne plus รชtre gรฉnรฉ ร cause du dos. En
+gros c'est : รชtre capable de faire 120km de vรฉlo et monter des cols (Col
+du Sapenay, Mont Revard) et ร long terme, faire des courses de footing
+(i.e.ย 10km, Paris-Versaille, Semi-marathon, marathon :D).
+
+Sur ce, je vais retourner ร mes cartons :-P.
www/vincent.demeester.fr/posts/2018-07-28-gotest-tools-intro.org
@@ -0,0 +1,45 @@
+#+TITLE: Golang testing โ gotest.tools introduction
+#+date: <2018-07-28 Sat>
+#+filetags: feature go testing
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+I already wrote 2 previous posts about golang and testing. It's something I care deeply
+about and I wanted to continue writing about it. It took me a bit more time than I
+thought, but getting back to it. Since the [[http://vincent.demeester.fr/posts/2017-04-22-golang-testing-golden-file/][last post]], Daniel Nephin and I worked (but
+mainly Daniel ๐ค) on bootstrapping a testing helper library.
+
+Let me introduce it to you this library : [[https://gotest.tools][=gotest.tools=]]. As described in the [[https://godoc.org/gotest.tools][godoc]] package comment, =gotest.tools= is a
+collection of packages to augment =testing= and support common patterns. It's an enhanced and growing version of the
+initial helpers we (the docker/moby maintainers) wrote initially in [[https://github.com/docker/docker][=docker/docker=]] repository. We are using in quite some
+project here at [[https://github.com][Docker]].
+
+There is a bunch of packages that will all have their own post (linked here when available) :
+
+- [[file:2018-08-16-gotest-tools-assertions.org][=assert=]] (with =assert/cmp= and =assert/opt=) that provides assertions for comparing expected values to actual values.
+- =env= that provides functions to test code that read environment variable or the current working directory.
+- [[file:2018-09-14-gotest-tools-fs.org][=fs=]] that provides tools for creating temporary files, and testing the contents and structure of a directory.
+- [[file:2018-09-06-gotest-tools-golden.org][=golden=]] that provides tools for comparing large multi-line strings.
+- [[file:2018-09-18-gotest-tools-icmd.org][=icmd=]] that executes binaries and provides convenient assertions for testing the results.
+- [[file:2019-03-23-gotest-tools-poll.org][=poll=]] that provides tools for testing asynchronous code.
+- [[file:2018-09-01-gotest-tools-skip.org][=skip=]] that provides functions for skipping a test and printing the source code of the condition used to skip the test.
+
+There is also experimental package, using the =x= notation (as the golang team uses, for example with =golang.org/x/sync=) :
+
+- =x/subtest= that provides a =TestContext= to subtests which handles cleanup and provides a =testing.TB= and =context.Context=.
+
+There is already some good =testing= helpers in the Go ecosystem : [[https://github.com/stretchr/testify][=testify=]], [[http://labix.org/gocheck][=gocheck=]], [[https://github.com/onsi/ginkgo][=ginkgo=]] and a lot more โ so
+why create a new one ? There is multiple reason for it, most of them can be seen in the following [[https://github.com/gotestyourself/gotest.tools/issues/49#issuecomment-362436026][GitHub issue]].
+
+[[https://github.com/dnephin/][Daniel]] also wrote a very useful converter if your code base is currently using =testify= : =gty-migrate-from-testify=.
+
+#+BEGIN_SRC sh
+$ go get -u gotest.tools/assert/cmd/gty-migrate-from-testify
+# [โฆ]
+$ go list \
+ -f '{{.ImportPath}} {{if .XTestGoFiles}}{{"\n"}}{{.ImportPath}}_test{{end}}' \
+ ./... | xargs gty-migrate-from-testify
+#+END_SRC
+
+In the next post, let's dig into the assertion part of the library, package =assert= ๐ผ.
www/vincent.demeester.fr/posts/2018-08-16-gotest-tools-assertions.org
@@ -0,0 +1,340 @@
+#+title: Golang testing โ gotest.tools assertions
+#+date: <2018-08-16 Thu>
+#+filetags: go testing assert
+#+setupfile: ../templates/post.org
+
+#+TOC: headlines 2
+
+* Introduction
+
+Let's take a closer look at [[https://gotest.tools][=gotest.tools=]] assertions packages. This is mainly about =assert=, =assert/cmp= and
+=assert/opt=.
+
+#+BEGIN_QUOTE
+Package assert provides assertions for comparing expected values to actual values. When assertion fails a helpful error
+message is printed.
+#+END_QUOTE
+
+There is two main functions (=Assert= and =Check=) and some helpers (like =NilError=, โฆ). They all take a =*testing.T= as
+a first argument, pretty common across testing Go libraries. Let's dive into those !
+
+* =Assert= and =Check=
+
+Both those functions accept a =Comparison= (we'll check what it is later on) and fail the test when that comparison
+fails. The one difference is that =Assert= will end the test execution at immediately whereas =Check= will fail the test
+and proceed with the rest of the test case. This is similar to =FailNow= and =Fail= from the standard library
+=testing=. Both have their use cases.
+
+We'll Use =Assert= for the rest of the section but any example here would work with =Check= too. When we said
+=Comparison= above, it's mainly the [[https://godoc.org/gotest.tools/assert#BoolOrComparison][BoolOrComparison]] interface โ it can either be a boolean expression, or a
+[[https://godoc.org/gotest.tools/assert/cmp#Comparison][cmp.Comparison]] type. =Assert= and =Check= code will be /smart/ enough to detect which one it is.
+
+#+BEGIN_SRC go
+ assert.Assert(t, ok)
+ assert.Assert(t, err != nil)
+ assert.Assert(t, foo.IsBar())
+#+END_SRC
+
+So far not anything extra-ordinary. Let's first look at some more /helper/ functions in the =assert= package and quickly
+dive a bit deeper with =Comparison=.
+
+* More =assert= helpers
+
+The additional helper functions are the following
+
+- =Equal= uses the ==== operator to assert two values are equal.
+- =DeepEqual= uses =google/go-cmp= to assert two values are equal (it's /close/ to =reflect.DeepEqual= but not
+ quite). We'll detail a bit more the /options/ part of this function with =cmp.DeepEqual=.
+- =Error= fails if the error is =nil= *or* the error message is not the expected one.
+- =ErrorContains= fails if the error is =nil= *or* the error message does not contain the expected substring.
+- =ErrorType= fails if the error is =nil= *or* the error type is not the expected type.
+- =NilError= fails if the error is not =nil=.
+
+All those helper functions have a equivalent function in the =cmp= package that returns a =Comparison=. I, personally,
+prefer to use =assert.Check= or =assert.Assert= in combination with =cmp.Comparison= as it allows me to write all my
+assertions the same way, with built-ins comparison or with my own โ i.e. =assert.Assert(t, is.Equal(โฆ), "message"= or
+=assert.Assert(t, stackIsUp(c, timeโฆ), "another message")=.
+
+* =cmp.Comparison=
+
+This is where it get really interesting, =gotest.tools= tries to make it as easy as possible for you to create
+appropriate comparison โ making you test readable as much as possible.
+
+Let's look a bit at the =cmp.Comparison= type.
+
+#+BEGIN_SRC go
+type Comparison func() Result
+#+END_SRC
+
+It's just a function that returns a =cmp.Result=, so let's look at =cmp.Result= definition.
+
+#+BEGIN_SRC go
+type Result interface {
+ Success() bool
+}
+#+END_SRC
+
+Result is an =interface=, thus any /struct/ that provide a function =Success= that returns a =bool= can be used as a
+comparison result, making it really easy to use in your code. There is also existing type of result to make it even
+quicker to write your own comparison.
+
+- =ResultSuccess= is a constant which is returned to indicate success.
+- =ResultFailure= and =ResultFailureTemplate= return a failed Result with a failure message.
+- =ResultFromError= returns =ResultSuccess= if =err= is nil. Otherwise =ResultFailure= is returned with the error
+ message as the failure message. It works a bit like the =errors.Wrap= function of the [[https://github.com/pkg/errors][=github.com/pkgs/errors=]]
+ package.
+
+The =cmp= package comes with a few defined comparison that, we think, should cover a high number of use-cases. Let's
+look at them.
+
+** Equality with =Equal= and =DeepEqual=
+
+#+BEGIN_QUOTE
+Equal uses the == operator to assert two values are equal and fails the test if they are not equal.
+
+If the comparison fails Equal will use the variable names for x and y as part of the failure message to identify the
+actual and expected values.
+
+If either x or y are a multi-line string the failure message will include a unified diff of the two values. If the
+values only differ by whitespace the unified diff will be augmented by replacing whitespace characters with visible
+characters to identify the whitespace difference.
+#+END_QUOTE
+
+On the other handโฆ
+
+#+BEGIN_QUOTE
+DeepEqual uses google/go-cmp (http://bit.do/go-cmp) to assert two values are equal and fails the test if they are not
+equal.
+
+Package https://godoc.org/gotest.tools/assert/opt provides some additional commonly used Options.
+#+END_QUOTE
+
+Using one or the other is as simple as : if you wrote your =if= with ==== then use =Equal=, otherwise use =DeepEqual=.
+=DeepEqual= (and usually =reflect.DeepEqual=) is used when you want to compare anything more complex than primitive
+types. One advantage of using =cmp.DeepEqual= over =reflect.DeepEqual= (in an if), is that you get a well crafted
+message that shows the diff between the expected and the actual structs compared โ and you can pass options to it.
+
+#+BEGIN_SRC go
+assert.Assert(t, cmp.DeepEqual([]string{"a", "b"}, []string{"b", "a"}))
+// Will print something like
+// --- result
+// +++ exp
+// {[]string}[0]:
+// -: "a"
+// +: "b"
+// {[]string}[1]:
+// -: "b"
+// +: "a"
+foo := &someType(a: "with", b: "value")
+bar := &someType(a: "with", b: "value")
+// the following will succeed as foo and bar are _DeepEqual_
+assert.Assert(t, cmp.DeepEqual(foo, bar))
+#+END_SRC
+
+When using =DeepEqual=, you may end up with really weird behavior(s). You may want to ignore some fields, or consider
+=nil= slice or map the same as empty ones ; or more common, your /struct/ contains some unexported fields that you
+cannot use when comparing (as they are not exported ๐). In those case, you can use =go-cmp= options.
+
+Some existing one are :
+- [[https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#EquateEmpty][=EquateEmpty=]] returns a Comparer option that determines all maps and slices with a length of zero to be equal,
+ regardless of whether they are nil.
+- [[https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#IgnoreFields][=IgnoreFields=]] returns an Option that ignores exported fields of the given names on a single struct type. The struct
+ type is specified by passing in a value of that type.
+- [[https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#IgnoreUnexported][=IgnoreUnexported=]] returns an Option that only ignores the immediate unexported fields of a struct, including anonymous
+ fields of unexported types.
+- [[https://godoc.org/github.com/google/go-cmp/cmp/cmpopts#SortSlices][=SortSlices=]] returns a Transformer option that sorts all =[]V=
+- โฆ and [[https://godoc.org/github.com/google/go-cmp/cmp/cmpopts][more]] ๐ผ
+
+=gotest.tools= also defines some *and* you can define yours ! As an example, =gotest.tools= defines =TimeWithThreshold=
+and =DurationWithThreshold= that allows to not fails if the time (or duration) is not exactly the same but in the
+specified threshold we specified. Here is the code for =DurationWithThreshold= for inspiration.
+
+#+BEGIN_SRC go
+// DurationWithThreshold returns a gocmp.Comparer for comparing time.Duration. The
+// Comparer returns true if the difference between the two Duration values is
+// within the threshold and neither value is zero.
+func DurationWithThreshold(threshold time.Duration) gocmp.Option {
+ return gocmp.Comparer(cmpDuration(threshold))
+}
+
+func cmpDuration(threshold time.Duration) func(x, y time.Duration) bool {
+ return func(x, y time.Duration) bool {
+ if x == 0 || y == 0 {
+ return false
+ }
+ delta := x - y
+ return delta <= threshold && delta >= -threshold
+ }
+}
+#+END_SRC
+
+Another good example for those options is when you want to skip some field. In [[https://github.com/docker/docker][=docker/docker=]] we want to be able to
+easily check for equality between two service specs, but those might have different =CreatedAt= and =UpdatedAt= values
+that we usually don't care about โ what we want is to make sure it happens in the past 20 seconds. You can easily define
+an option for that.
+
+#+BEGIN_SRC go
+ func cmpServiceOpts() cmp.Option {
+ const threshold = 20 * time.Second
+
+ // Apply withinThreshold only for the following fields
+ metaTimeFields := func(path cmp.Path)bool {
+ switch path.String() {
+ case "Meta.CreatedAt", "Meta.UpdatedAt":
+ return true
+ }
+ return false
+ }
+ // have a 20s threshold for the time value that will be passed
+ withinThreshold := cmp.Comparer(func(x, y time.Time) bool {
+ delta := x.Sub(y)
+ return delta < threshold && delta > -threshold
+ })
+
+ return cmp.FilterPath(metaTimeFields, withinThreshold)
+ }
+#+END_SRC
+
+I recommend you look at the [[https://godoc.org/gotest.tools/assert/opt][gotest.tools/assert/opt]] documentation to see which one are defined and how to use them.
+
+** Errors with =Error=, =ErrorContains= and =ErrorType=
+
+Checking for errors is *very common* in Go, having =Comparison= function for it was a requirement.
+
+- =Error= fails if the error is =nil= *or* the error message is not the expected one.
+- =ErrorContains= fails if the error is =nil= *or* the error message does not contain the expected substring.
+- =ErrorType= fails if the error is =nil= *or* the error type is not the expected type.
+
+Let's first look at the most used : =Error= and =ErrorContains=.
+
+#+BEGIN_SRC go
+ var err error
+ // will fail with : expected an error, got nil
+ assert.Check(t, cmp.Error(err, "message in a bottle"))
+ err = errors.Wrap(errors.New("other"), "wrapped")
+ // will fail with : expected error "other", got "wrapped: other"
+ assert.Check(t, cmp.Error(err, "other"))
+ // will succeed
+ assert.Check(t, cmp.ErrorContains(err, "other"))
+#+END_SRC
+
+As you can see =ErrorContains= is especially useful when working with /wrapped/ errors.
+Now let's look at =ErrorType=.
+
+#+BEGIN_SRC go
+ var err error
+ // will fail with : error is nil, not StubError
+ assert.Check(t, cmp.ErrorType(err, StubError{}))
+
+ err := StubError{"foo"}
+ // will succeed
+ assert.Check(t, cmp.ErrorType(err, StubError{}))
+
+ // Note that it also work with a function returning an error
+ func foo() error {}
+ assert.Check(t, cmp.ErrorType(foo, StubError{}))
+#+END_SRC
+
+** Bonus with =Panics=
+
+Sometimes, a code is supposed to /panic/, see [[https://golang.org/doc/effective_go.html#panic][Effective Go (#Panic)]] for more information. And thus, you may want to make
+sure you're code panics in such cases. It's always a bit tricky to test a code that panic as you have to use a deferred
+function to recover the panic โ but then if the panic doesn't happen how do you fail the test ?
+
+This is where =Panics= comes handy.
+
+#+BEGIN_SRC go
+ func foo(shouldPanic bool) {
+ if shouldPanic {
+ panic("booooooooooh")
+ }
+ // don't worry, be happy
+ }
+ // will fail with : did not panic
+ assert.Check(t, cmp.Panics(foo(false)))
+ // will succeed
+ assert.Check(t, cmp.Panics(foo(true)))
+#+END_SRC
+
+** Miscellaneous with =Contains=, =Len= and =Nil=
+
+Those last three /built-in/ =Comparison= are pretty straightforward.
+
+- =Contains= succeeds if item is in collection. Collection may be a string, map, slice, or array.
+
+ If collection is a string, item must also be a string, and is compared using =strings.Contains()=. If collection is a
+ Map, contains will succeed if item is a key in the map. If collection is a slice or array, item is compared to each
+ item in the sequence using ==reflect.DeepEqual()==.
+- =Len= succeeds if the sequence has the expected length.
+- =Nil= succeeds if obj is a nil interface, pointer, or function.
+
+#+BEGIN_SRC go
+ // Contains works on string, map, slice or arrays
+ assert.Check(t, cmp.Contains("foobar", "foo"))
+ assert.Check(t, cmp.Contains([]string{"a", "b", "c"}, "b"))
+ assert.Check(t, cmp.Contains(map[string]int{"a": 1, "b": 2, "c": 4}, "b"))
+
+ // Len also works on string, map, slice or arrays
+ assert.Check(t, cmp.Len("foobar", 6))
+ assert.Check(t, cmp.Len([]string{"a", "b", "c"}, 3))
+ assert.Check(t, cmp.Len(map[string]int{"a": 1, "b": 2, "c": 4}, 3))
+
+ // Nil
+ var foo *MyStruc
+ assert.Check(t, cmp.Nil(foo))
+ assert.Check(t, cmp.Nil(bar()))
+#+END_SRC
+
+But let's not waste more time and let's see how to write our own =Comparison= !
+
+** Write your own =Comparison=
+
+One of the main aspect of =gotest.tools/assert= is to make it easy for developer to write as less boilerplate code as
+possible while writing tests. Writing your own =Comparison= allows you to write a well named function that will be easy
+to read and that can be re-used across your tests.
+
+Let's look back at the =cmp.Comparison= and =cmp.Result= types.
+
+#+BEGIN_SRC go
+type Comparison func() Result
+
+type Result interface {
+ Success() bool
+}
+#+END_SRC
+
+A =Comparison= for =assert.Check= or =assert.Check= is a function that return a =Result=, it's pretty straightforward to
+implement, especially with =cmp.ResultSuccess= and =cmp.ResultFailure(โฆ)= (as seen previously).
+
+#+BEGIN_SRC go
+ func regexPattern(value string, pattern string) cmp.Comparison {
+ return func() cmp.Result {
+ re := regexp.MustCompile(pattern)
+ if re.MatchString(value) {
+ return cmp.ResultSuccess
+ }
+ return cmp.ResultFailure(
+ fmt.Sprintf("%q did not match pattern %q", value, pattern))
+ }
+ }
+
+ // To use it
+ assert.Check(t, regexPattern("12345.34", `\d+.\d\d`))
+#+END_SRC
+
+As you can see, it's pretty easy to implement, and you can do quite a lot in there easily. If a function call returns an
+error inside of your =Comparison= function, you can use =cmp.ResultFromError= for example. Having something like
+=assert.Check(t, isMyServerUp(":8080"))= is way more readable than a 30-line of code to check it.
+
+* Conclusionโฆ
+
+โฆ and that's a wrap. We only looked at the =assert= package of [[https://gotest.tools][=gotest.tools=]] so far, but it's already quite a bit to process.
+
+We've seen :
+- the main functions provided by this package : =assert.Assert= and =assert.Check=
+- some helper functions like =assert.NilError=, โฆ
+- the =assert/cmp=, and =assert/opt= sub-package that allows you to write more custom =Comparison=
+
+Next time, we'll look at the =skip= package, that is a really simple wrapper on top of =testing.Skip= function.
+
+**
www/vincent.demeester.fr/posts/2018-09-01-gotest-tools-skip.org
@@ -0,0 +1,59 @@
+#+title: Golang testing โ gotest.tools skip
+#+date: <2018-09-01 Sat>
+#+filetags: go testing skip
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+Let's continue the [[https://gotest.tools][=gotest.tools=]] serie, this time with the =skip= package. This is a
+really simple one so this should be quick.
+
+#+BEGIN_QUOTE
+=skip= provides functions for skipping a test and printing the source code of the
+condition used to skip the test.
+#+END_QUOTE
+
+The package consists of only one function : =If=. The idea comes mainly from
+[[https://github.com/docker/docker][=docker/docker=]] integration test suite, where we wanted to skip some test (or test suites)
+given different context. By context I mean things like the system we are running on
+(=Windows=, =Linux=, โฆ) or the capabilities of the running kernel or node (is =apparmor=
+available or not on the current machine).
+
+This =If= method takes a =testing.T= pointer and either a boolean, a function that
+returns a boolean, *or* an expression.
+
+#+BEGIN_SRC go
+ // boolean
+ // --- SKIP: TestName (0.00s)
+ // skip.go:19: MissingFeature
+ var MissingFeature bool
+ skip.If(t, MissingFeature)
+
+ // function
+ // --- SKIP: TestName (0.00s)
+ // skip.go:19: !IsExperimentalDaemon(dockerClient): daemon is not experimental
+ skip.If(t, IsExperimentalDaemon(dockerClient), "daemon is not experimental")
+
+ // expression
+ // --- SKIP: TestName (0.00s)
+ // skip.go:19: apiVersion < version("v1.24")
+ skip.If(t, apiVersion < version("v1.24"))
+#+END_SRC
+
+There is few elements to note though :
+
+- This package (as other parts of the =gotest.tools= packages), will try to look at source
+ files to display the expression used (same goes for =assert=). This is usually not a
+ problem because you run tests where the source code is. *However*, in the cases you
+ generate a test binary to be executed later (ร -la =kubernetes= or other projects), this
+ can display a weird error message if the sources are not availableโฆ You shouldn't be
+ worried too much about it, but it's better if you know :)
+- The main reason to use =skip.If= is mainly for new contributors to get in quickly,
+ *reducing potential friction of them running the tests on their environment*. The more
+ the tests are written in a way they explicitely declare their requirements (and skipped
+ if the environment does not meet those), the easier it makes contributors run your
+ tests. *But*, this also means, you should try to measure the skipped tests on your
+ continuous integration system to make sure you run all of them eventuallyโฆ otherwise
+ it's dead code. /But more on that in later posts ๐/.
+
+That's all for today folks, told you that was going to be quick.
www/vincent.demeester.fr/posts/2018-09-06-gotest-tools-golden.org
@@ -0,0 +1,75 @@
+#+TITLE: Golang testing โ gotest.tools golden
+#+date: <2018-09-06 Thu>
+#+filetags: go testing golden
+#+setupfile: ../templates/post.org
+
+#+TOC: headlines 2
+
+* Introduction
+Let's continue the [[https://gotest.tools][=gotest.tools=]] serie, this time with the =golden= package. This is a
+[[/posts/2017-04-22-golang-testing-golden-file/][/quick follow-up/ on a previous =golden= post]], but focused on the =gotest.tools=
+implementation. I'm gonna be quicker, please read that one if =golden= files is a new
+concept for you.
+
+#+BEGIN_QUOTE
+Package =golden= provides tools for comparing large mutli-line strings.
+
+Golden files are files in the =./testdata/= sub-directory of the package under test.
+#+END_QUOTE
+
+In the previous article, we described the problem, and how to fix it by writing a small
+helper. Well, that small helper is in =gotest.tools/golden= now, and it has a tiny bit
+more features.
+
+One of the difference between the =gotest.tools= implementation and the previous post is
+the flag name. In =gotest.tools/golden=, the flag is =-test.update-golden= (was just
+=-test.update= before). Just as before, if the =-test.update-golden= flag is set then the
+actual content is written to the golden file, before reading it and comparing.
+
+There is two ways to use the =golden= package:
+- on it's own, using =golden.Assert= or =golden.AssertBytes=
+- as a =cmp.Comparison=, with =golden.String= or =golden.Bytes=
+
+* =Assert= and =AssertBytes=
+
+Using =Assert= functions should be straightforward. Both =Assert= function compares the
+actual content to the expected content in the golden file and returns whether the
+assertion was successful (true) or not (false).
+
+- =Assert= uses string. Note that this one *removes carriage return* before comparing to
+ depend as less as possible of the system (=\n= vs =\r\n= ๐
)
+- =AssertBytes= uses raw data (in the form of =[]byte=)
+
+#+BEGIN_SRC go
+ golden.Assert(t, "foo", "foo-content.golden")
+ // Could also be used to check some binary format
+ golden.AssertBytes(t, []byte("foo"), "foo-content.golden")
+#+END_SRC
+
+* =Bytes= and =String=
+
+As written in a [[/posts/2018-08-16-gotest-tools-assertions/][previous post (about the =assert= package)]], I prefer to use =cmp.Comparison=.
+
+#+BEGIN_QUOTE
+All those helper functions have a equivalent function in the =cmp= package that returns a
+=Comparison=. I, personally, prefer to use =assert.Check= or =assert.Assert= in
+combination with =cmp.Comparison= as it allows me to write all my assertions the same way,
+with built-ins comparison or with my own โ i.e. =assert.Assert(t, is.Equal(โฆ), "message"=
+or =assert.Assert(t, stackIsUp(c, timeโฆ), "another message")=.
+#+END_QUOTE
+
+The =golden= package gives us that too, in the form of =Bytes= and =String=. Using the
+=assert.Check= or =assert.Assert= functions with those is equivalent to their /helper/
+counter-part =golden.Assert= and =golden.AssertBytes=.
+
+#+BEGIN_SRC go
+ assert.Assert(t, golden.String("foo", "foo-content.golden"))
+ // Could also be used to check some binary format
+ assert.Assert(t, golden.Bytes([]byte("foo"), "foo-content.golden"))
+#+END_SRC
+
+* Conclusionโฆ
+
+โฆ that's a wrap. As for [[/posts/2018-09-01-gotest-tools-skip/][=skip=]], this is a small package, so the post was going to be
+quick. =golden= package just solve a specific problem (read [[/posts/2017--04-22-golang-testing-golden-file/][Golang testing โ golden file]])
+in a simple way.
www/vincent.demeester.fr/posts/2018-09-14-gotest-tools-fs.org
@@ -0,0 +1,187 @@
+#+TITLE: Golang testing โ gotest.tools fs
+#+date: <2018-09-14 Fri>
+#+filetags: go testing fs
+#+setupfile: ../templates/post.org
+
+#+TOC: headlines 2
+
+* Introduction
+
+Let's continue the [[https://gotest.tools][=gotest.tools=]] serie, this time with the =fs= package.
+
+#+BEGIN_QUOTE
+Package fs provides tools for creating temporary files, and testing the contents and structure of a directory.
+#+END_QUOTE
+
+This package is heavily using functional arguments (as we saw in [[/posts/2017-01-01-go-testing-functionnal-builders/][functional arguments for
+wonderful builders]]). Functional arguments is, in a nutshell, a combinaison of two Go
+features : /variadic/ functions (=...= operation in a function signature) and the fact
+that =func= are /first class citizen/. This looks more or less like that.
+
+#+BEGIN_SRC go
+ type Config struct {}
+
+ func MyFn(ops ...func(*Config)) *Config {
+ c := &Config{} // with default values
+ for _, op := range ops {
+ op(c)
+ }
+ return c
+ }
+
+ // Calling it
+ conf := MyFn(withFoo, withBar("baz"))
+#+END_SRC
+
+The =fs= package has too *main* purpose :
+
+1. create folders and files required for testing in a simple manner
+2. compare two folders structure (and content)
+
+* Create folder structures
+
+Sometimes, you need to create folder structures (and files) in tests. Doing =i/o= work
+takes time so try to limit the number of tests that needs to do that, especially in unit
+tests. Doing it in tests adds a bit of boilerplate that could be avoid. As stated [[/posts/2017-01-01-go-testing-functionnal-builders/][before]] :
+
+#+BEGIN_QUOTE
+One of the most important characteristic of a unit test (and any type of test really) is
+*readability*. This means it should be easy to read but most importantly it should *clearly
+show the intent* of the test. The setup (and cleanup) of the tests should be as small as
+possible to avoid the noise.
+#+END_QUOTE
+
+In a test you usually end up using =ioutil= function to create what you need. This looks
+somewhat like the following.
+
+#+BEGIN_SRC go
+ path, err := ioutil.TempDir("", "bar")
+ if err != nil { // or using `assert.Assert`
+ t.Fatal(err)
+ }
+ if err := os.Mkdir(filepath.Join(path, "foo"), os.FileMode(0755)); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(path, "foo", "bar"), []byte("content"), os.FileMode(0777)); err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(path) // to clean up at the end of the test
+#+END_SRC
+
+The =fs= package intends to help reduce the noise and comes with a bunch function to create
+folder structure :
+
+- two main function =NewFile= and =NewDir=
+- a bunch of /operators/ : =WithFile=, =WithDir=, โฆ
+
+#+BEGIN_SRC go
+ func NewDir(t assert.TestingT, prefix string, ops ...PathOp) *Dir {
+ // โฆ
+ }
+
+ func NewFile(t assert.TestingT, prefix string, ops ...PathOp) *File {
+ // โฆ
+ }
+#+END_SRC
+
+The =With*= function are all satisfying the =PathOp= interface, making =NewFile= and
+=NewDir= extremely composable. Let's first see how our above example would look like using
+the =fs= package, and then, we'll look a bit more at the main =PathOp= functionโฆ
+
+#+BEGIN_SRC go
+ dir := fs.NewDir(t, "bar", fs.WithDir("foo",
+ fs.WithFile("bar", fs.WithContent("content"), fs.WithMode(os.FileMode(0777))),
+ ))
+ defer dir.Remove()
+#+END_SRC
+
+It's clean and simple to read. The intent is well described and there is not that much of
+noise. =fs= functions tends to have /sane/ and /safe/ defaults value (for =os.FileMode=
+for example). Let's list the main, useful, =PathOp= provided by =gotest.tools/fs=.
+
+- =WithDir= creates a sub-directory in the directory at path.
+- =WithFile= creates a file in the directory at path with content.
+- =WithSymlink= creates a symlink in the directory which links to target. Target must be a
+ path relative to the directory.
+- =WithHardlink= creates a link in the directory which links to target. Target must be a
+ path relative to the directory.
+- =WithContent= and =WWithBytes= write content to a file at Path (from a =string= or a
+ =[]byte= slice).
+- =WithMode= sets the file mode on the directory or file at path.
+- =WithTimestamps= sets the access and modification times of the file system object at
+ path.
+- =FromDir= copies the directory tree from the source path into the new Dir. This is
+ pretty useful when you have a huge folder structure already present in you =testdata=
+ folder or elsewhere.
+- =AsUser= changes ownership of the file system object at Path.
+
+Also, note that =PathOp= being an function type, you can provide your own implementation
+for specific use-cases. Your function just has to satisfy =PathOp= signature.
+
+#+BEGIN_SRC go
+ type PathOp func(path Path) error
+#+END_SRC
+
+* Compare folder structures
+
+Sometimes, the code you're testing is creating a folder structure, and you would like to
+be able to tests that, with the given arguments, it creates the specified structure. =fs=
+allows you to do that too.
+
+The package provides a =Equal= function, which returns a =Comparison=, that the [[/posts/2018-08-16-gotest-tools-assertions/][=assert=]]
+package understand. It works by comparing a =Manifest= type provided by the test and a
+=Manifest= representation of the specified folder.
+
+#+BEGIN_QUOTE
+ Equal compares a directory to the expected structured described by a manifest and returns
+ success if they match. If they do not match the failure message will contain all the
+ differences between the directory structure and the expected structure defined by the
+ Manifest.
+#+END_QUOTE
+
+A =Manifest= stores the expected structure and properties of files and directories in a
+file-system. You can create a =Manifest= using either the functions =Expected= or
+=ManifestFromDir=.
+
+We're going to focus on the =Expected= function, as =ManifestFromDir= does pretty much
+what you would expected : it takes the specified path, and returns a =Manifest= that
+represent this folder.
+
+#+BEGIN_SRC go
+ func Expected(t assert.TestingT, ops ...PathOp) Manifest
+#+END_SRC
+
+=Expected= is close to =NewDir= function : it takes the same =PathOp= functional
+arguments. This makes creating a =Manifest= straightforward, as it's working the same. Any
+function that satisfy =PathOp= can be used for =Manifest= the exact same way you're using
+them on =fs.NewDir=.
+
+There is a few additional functions that are only useful with =Manifest= :
+
+- =MatchAnyFileContent= updates a Manifest so that the file at path may contain any content.
+- =MatchAnyFileMode= updates a Manifest so that the resource at path will match any file mode.
+- =MatchContentIgnoreCarriageReturn= ignores cariage return discrepancies.
+- =MatchExtraFiles= updates a Manifest to allow a directory to contain unspecified files.
+
+#+BEGIN_SRC go
+ path := operationWhichCreatesFiles()
+ expected := fs.Expected(t,
+ fs.WithFile("one", "",
+ fs.WithBytes(golden.Get(t, "one.golden")),
+ fs.WithMode(0600)),
+ fs.WithDir("data",
+ fs.WithFile("config", "", fs.MatchAnyFileContent)),
+ )
+
+ assert.Assert(t, fs.Equal(path, expected))
+#+END_SRC
+
+The following example compares the result of =operationWhichCreatesFiles= to the expected
+=Manifest=. As you can see it also integrates well with other part of the =gotest.tools=
+library, with the [[/posts/2018-09-06-gotest-tools-golden/][=golden= package]] in this example.
+
+* Conclusionโฆ
+
+โฆ that's a wrap. In my opinion, this is one the most useful package provided by
+=gotest.tools= after =assert=. It allows to create simple or complex folder structure
+without the noise that usually comes with it.
www/vincent.demeester.fr/posts/2018-09-18-gotest-tools-icmd.org
@@ -0,0 +1,209 @@
+#+TITLE: Golang testing โ gotest.tools icmd
+#+date: <2018-09-18 Tue>
+#+filetags: go testing cmd
+#+setupfile: ../templates/post.org
+
+#+TOC: headlines 2
+
+* Introduction
+Let's continue the [[https://gotest.tools][=gotest.tools=]] serie, this time with the =icmd= package.
+
+#+BEGIN_QUOTE
+Package icmd executes binaries and provides convenient assertions for testing the results.
+#+END_QUOTE
+
+After file-system operations (seen in [[/posts/2018-09-14-gotest-tools-fs/][=fs=]]), another common use-case in tests is to
+*execute a command*. The reasons can be you're testing the =cli= you're currently writing
+or you need to setup something using a command line. A classic execution in a test might
+lookup like the following.
+
+#+BEGIN_SRC go
+ cmd := exec.Command("echo", "foo")
+ cmd.Stout = &stdout
+ cmd.Env = env
+ if err := cmd.Run(); err != nil {
+ t.Fatal(err)
+ }
+ if string(stdout) != "foo" {
+ t.Fatalf("expected: foo, got %s", string(stdout))
+ }
+#+END_SRC
+
+The package =icmd= is there to ease your pain (as usual ๐) โ we used /the name =icmd=/
+instead of =cmd= because it's a pretty common identifier in Go source code, thus would be
+really easy to /shadow/ โ and have some really weird problems going on.
+
+The usual =icmd= workflow is the following:
+
+1. Describe the command you want to execute using : type =Cmd=, function =Command= and
+ =CmdOp= operators.
+2. Run it using : function =RunCmd= or =RunCommand= (that does 1. for you). You can also
+ use =StartCmd= and =WaitOnCmd= if you want more control on the execution workflow.
+3. Check the result using the =Assert=, =Equal= or =Compare= methods attached to the
+ =Result= struct that the command execution return.
+
+* Create and run a command
+
+Let's first dig how to create commands. In this part, the assumption here is that the
+command is successful, so we'll have =.Assert(t, icmd.Success)= for now โ we'll learn more
+about =Assert= in the next section ๐ผ.
+
+The simplest way to create and run a command is using =RunCommand=, it has the same
+signature as =os/exec.Command=. A simple command execution goes as below.
+
+#+BEGIN_SRC go
+ icmd.RunCommand("echo", "foo").Assert(t, icmd.Sucess)
+#+END_SRC
+
+Sometimes, you need to customize the command a bit more, like adding some environment
+variable. In those case, you are going to use =RunCmd=, it takes a =Cmd= and operators.
+Let's look at those functions.
+
+#+BEGIN_SRC go
+ func RunCmd(cmd Cmd, cmdOperators ...CmdOp) *Result
+
+ func Command(command string, args ...string) Cmd
+
+ type Cmd struct {
+ Command []string
+ Timeout time.Duration
+ Stdin io.Reader
+ Stdout io.Writer
+ Dir string
+ Env []string
+ }
+#+END_SRC
+
+As we've seen [[/posts/2017-01-01-go-testing-functionnal-builders/][multiple]] [[/posts/2018-08-16-gotest-tools-assertions/][times]] [[/posts/2018-09-14-gotest-tools-fs/][before]], it uses the /powerful/ functional arguments. At the
+time I wrote this post, the =icmd= package doesn't contains too much =CmdOp= [fn:1], so I'll
+propose two version for each example : one with =CmdOpt= present in [[https://github.com/gotestyourself/gotest.tools/pull/122][this PR]] and one
+without them.
+
+#+BEGIN_SRC go
+ // With
+ icmd.RunCmd(icmd.Command("sh", "-c", "echo $FOO"),
+ icmd.WithEnv("FOO=bar", "BAR=baz"), icmd.Dir("/tmp"),
+ icmd.WithTimeout(10*time.Second),
+ ).Assert(t, icmd.Success)
+
+ // Without
+ icmd.RunCmd(icmd.Cmd{
+ Command: []string{"sh", "-c", "echo $FOO"},
+ Env: []string{"FOO=bar", "BAR=baz"},
+ Dir: "/tmp",
+ Timeout: 10*time.Second,
+ }).Assert(t, icmd.Success)
+#+END_SRC
+
+As usual, the intent is clear, it's simple to read and composable (with =CmdOp='s).
+
+[fn:1] The =icmd= package is one of the oldest =gotest.tools= package, that comes from the
+[[https://github.com/docker/docker][=docker/docker=]] initially. We introduced these =CmdOp= but implementations were in
+=docker/docker= at first and we never really updated them.
+
+* Assertions
+
+Let's dig into the assertion part of =icmd=. Running a command returns a struct
+=Result=. It has the following methods :
+
+- =Assert= compares the Result against the Expected struct, and fails the test if any of
+ the expectations are not met.
+- =Compare= compares the result to Expected and return an error if they do not match.
+- =Equal= compares the result to Expected. If the result doesn't match expected
+ returns a formatted failure message with the command, stdout, stderr, exit code, and any
+ failed expectations. It returns an =assert.Comparison= struct, that can be used by other
+ =gotest.tools=.
+- =Combined= returns the stdout and stderr combined into a single string.
+- =Stderr= returns the stderr of the process as a string.
+- =Stdout= returns the stdout of the process as a string.
+
+When you have a result, you, most likely want to do two things :
+
+- /assert/ that the command succeed or failed with some specific values (exit code,
+ stderr, stdout)
+- use the output โ most likely =stdout= but maybe =stderr= โ in the rest of the test.
+
+As seen above, /asserting/ the command result is using the =Expected= struct.
+
+#+BEGIN_SRC go
+ type Expected struct {
+ ExitCode int // the exit code the command returned
+ Timeout bool // did it timeout ?
+ Error string // error returned by the execution (os/exe)
+ Out string // content of stdout
+ Err string // content of stderr
+ }
+#+END_SRC
+
+=Success= is a constant that defines a success โ it's an exit code of =0=, didn't timeout,
+no error. There is also the =None= constant, that should be used for =Out= or =Err=, to
+specify that we don't want any content for those standard outputs.
+
+#+BEGIN_SRC go
+ icmd.RunCmd(icmd.Command("cat", "/does/not/exist")).Assert(t, icmd.Expected{
+ ExitCode: 1,
+ Err: "cat: /does/not/exist: No such file or directory",
+ })
+
+ // In case of success, we may want to do something with the result
+ result := icmd.RunCommand("cat", "/does/exist")
+ result.Assert(t, icmd.Success)
+ // Read the output line by line
+ scanner := bufio.NewScanner(strings.NewReader(result.Stdout()))
+ for scanner.Scan() {
+ // Do something with it
+ }
+#+END_SRC
+
+If the =Result= doesn't map the =Expected=, a test failure will happen with a useful
+message that will contains the executed command and what differs between the result and
+the expectation.
+
+#+BEGIN_SRC go
+ result := icmd.RunCommand(โฆ)
+ result.Assert(t, icmd.Expected{
+ ExitCode: 101,
+ Out: "Something else",
+ Err: None,
+ })
+ // Command: binary arg1
+ // ExitCode: 99 (timeout)
+ // Error: exit code 99
+ // Stdout: the output
+ // Stderr: the stderr
+ //
+ // Failures:
+ // ExitCode was 99 expected 101
+ // Expected command to finish, but it hit the timeout
+ // Expected stdout to contain "Something else"
+ // Expected stderr to contain "[NOTHING]"
+ โฆ
+#+END_SRC
+
+Finally, we listed =Equal= above, that returns a =Comparison= struct. This means we can
+use it easily with the =assert= package. As written in a [[/posts/2018-08-16-gotest-tools-assertions/][previous post (about the =assert=
+package)]], I tend prefer to use =cmp.Comparison=. Let's convert the above examples using
+=assert=.
+
+#+BEGIN_SRC go
+ result := icmd.RunCmd(icmd.Command("cat", "/does/not/exist"))
+ assert.Check(t, result.Equal(icmd.Expected{
+ ExitCode: 1,
+ Err: "cat: /does/not/exist: No such file or directory",
+ }))
+
+ // In case of success, we may want to do something with the result
+ result := icmd.RunCommand("cat", "/does/exist")
+ assert.Assert(t, result.Equal(icmd.Success))
+ // Read the output line by line
+ scanner := bufio.NewScanner(strings.NewReader(result.Stdout()))
+ for scanner.Scan() {
+ // Do something with it
+ }
+#+END_SRC
+
+* Conclusionโฆ
+
+โฆ that's a wrap. The =icmd= package allows to easily run command and describe what result
+are expected of the execution, with the least noise possible. We *use this package heavily*
+on several =docker/*= projects (the engine, the cli)โฆ
www/vincent.demeester.fr/posts/2019-01-20-2018-year-review.org
@@ -0,0 +1,151 @@
+#+title: 2018 year review
+#+date: <2019-01-20 Sun>
+#+filetags: review
+
+* Introduction
+
+Here is my review of 2018, the first of its kind, hopefully not the last ๐ผ. I saw
+some[fn:1] /2018[fn:2] reviews/[fn:3] articles[fn:4] in my Feedly feed and I thought it
+would be a good idea to write my own too.
+
+I'll try in the next year โ maybe month if I ever want to do monthly reviews โ to automate
+some of it ; using the beloved =org-mode=.
+
+[fn:1] [[https://punchagan.muse-amuse.in/blog/2018-in-review/][2018 in Review - Noetic Nought]]
+[fn:2] [[https://medium.com/@buster/42-dig-deeper-e2278d1fe015][42 โ Dig deeper โ Buster Benson โ Medium]]
+[fn:3] [[https://jvns.ca/blog/2018/12/23/2018--year-in-review/][2018: Year in review - Julia Evans]]
+[fn:4] [[https://writing.natwelch.com/post/685][Nat? Nat. Nat! | #685 2018 Year in Review]]
+
+* Work
+
+The big change this year is : I changed job ๐ผ. I went from Docker Inc. to Red Hat. I
+needed a change and 5 month in, I think it was the *best choice I made in my life* so far
+๐. I'm doing open-source for a living and best part, I am working remotely (more on that
+later).
+
+Before that, at Docker Inc., I continued the work I started years before,
+a.k.a. maintaining the Moby project and the docker engine, among other Docker project
+(both open-source and closed-source). I also helped the work on the compose side, from the
+root of =docker/compose-on-kubernetes= (before it got open-sourced), to the =docker/app=
+experiments.
+
+At Red Hat, I started to work upstream in the Kubernetes community, mainly on the Knative
+projects. I also work on the Openshift Cloud Function project (and thus team), and those
+fellows are awesome ! Digging more into Openshift, and other part of the Red Hat portfolio
+is a really good learning experience, and it's just the start !
+
+As stated above, I am now working home, full-time. I could work from home from time to
+time when I was at Docker inc, but working home full-time is another kind of beast. So far
+it is really good, some adjustments were needed but it's for the best. Here is a small
+take on "working from home":
+
+- It's easy to have *no distraction*, thus having *really productive* piece of time
+- It's also *really easy to work long day or really long period of time*. It's especially
+ true if, like me, you work on a distributed team (across multiple timezones).
+ - I ended up using the Pomodoro technique to make sure I move at least few times a day
+ - I try to make sure I don't make an habits of checking out work code, email and other
+ material after a certain hour in the evening. It's ok to do it sometimes, but for your
+ sanity, you need some rest time.
+- It's easy to adapt your day to circumstance. If you got to run errands in the middle of
+ the day, it's no big deal. You can take the time back later on.
+- It's so good to have *no* commmute time. That said I end up /walking or taking the bike/
+ early morning to clear my head before work ๐.
+
+* Personal
+
+Health wise, it's a mix of good and bad year. The first half was really good, the second
+way less. End of august, I felt something weird in the right knee, and well, turns out my
+internal meniscus is in a real bad shape. Just as before joining Docker, I'm gonna need a
+surgery, on the right knee that time. It's gonna affect 2019 (the first half, I'm not
+gonna be able to move around much but.. meh, it's life).
+
+Now that I work from home, I'm really glad I got a standing desk at the end of 2017. I
+tend to work standing most of the time -- except when my knee hurts (and most likely for
+few months after the surgery ๐
). I invested on a ultrawide screen, to get the same
+experience I had at Docker. And oh boy those screens are good !
+
+I also try to clean my desk and it's "neighboorhood". As I get older, I want less messy
+stuuf (desk, flat, ...). I'm leaning towards having less stuff, being commputer related or
+not. It's not minimalism, but it feel good to have less stuff, but stuff that you actually
+use. I still have trouble throwing old computer away, mainly because I fell they can be
+useful in some way.
+
+[[/images/2019/01/desk1.jpg]]
+
+This year I migrate all of my "infrastructure" computer to NixOS. I learned a lot of Nix,
+reworked my configuration multiple time to end up with a [[https://github.com/vdemeester/nixos-configuration.git][system configuration repository]]
+that uses modules, and a [[https://github.com/vdemeester/home.git][/home configuration repository/]] (for user configuration). The
+[[https://github.com/vdemeester/home.git][home]] repository uses [[https://github.com/rycee/home-manager.git][=home-manager=]] and thus doesn't make any assumption of running on top
+of NixOS. This allows me to have an /easy to get/ setup on any system that =nixpkgs=
+supports (any Linux distribution, Mac OSX, Windows Subsystem Linux). The current
+configuration is not yet optimal but I'm pretty happy about what I got :
+
+- Custom DNS server @home to make it easier to target local hosts.
+- Local proxies and mirrors for docker images, nixpkgs binary package and go modules to
+ eat less bandwidth.
+- Easy to setup VPN using [[https://www.wireguard.com/][WireGuard]].
+- File replication using =syncthing= and automatic backup on my local NAS.
+- Automatic system upgrade, thanks to NixOS. I'll probably write an article about that
+ later on this year.
+
+I started to use =todoist= in 2017, and boy, oh boy, it helped me quite a lot ! I'm using
+it daily to organize my work and quickly get idea, and /todos/ out of my head. The main
+problem with it is it's not integrated with another tool I'm using daily : Emacs and
+=org-mode=. =org-mode= is a fantastic piece of software and is, on its own, the main
+reason for me to invest time in Emacs. I'm taking note in =org-mode=, I write my daily
+standup notes in there too. I end up going back and forth between =org-mode= and =todoist=
+for those daily standup. I am lazy, I want to automate that. And the best way to do it, is
+to also use =org-mode= for task management. I'm in a /transition/ mode right now, but my
+goal for 2019 is to use todoist to take quick note/todo(s) on the move (aka on the phone)
+and use =org-mode= for the rest.
+
+
+* Reading & Writing
+
+I used to like reading, but the past years, I didn't really read that much, except some
+technical books. 2018 in, that respect, is not an exception, I didn't read too much. Worse
+than that, I started some book and stopped at some point, for no apparent reason ; and
+now, I need to start back from the beginning, which, well, is not helping me want to read
+them again.
+
+I'm trying two thing to counter that and consume more books for the years to come.
+
+1. I now have a reading list on my =org-mode= files, where I track which one I read and
+ when I read them ; and maybe notes too. I have a lot of book on my kindle, that only
+ wait for one thing, being read..
+2. I subscribed to [[https://www.audible.fr][Audible]] ๐ผ. Working from home, I tend to take a long break after lunch,
+ where I'm going for a walk, for around an hour. I can't read while walking but I
+ definitely can listen - that make audio books perfect for these moments. I also
+ alternate between audio books and non-musical podcasts.
+
+On the writing side, 2017 was a slow year in terms of writing (only 2 posts), 2018 was a
+bit better, 6 posts -- it's a bit cheating, as it was mainly between changing jobs, and
+on a series I still need to finish. I'm hoping to write more this year, hence the goals
+I've set to myself below.
+
+* 2019 Goals
+
+- *Get back on my feet after knee surgery (exercices, โฆ)* ๐
+- *Read at least one book per month (be audible, ebook or paper)* ๐
+- *Giving at least a talk (on Knative, containers, nixos, ..)* ๐
+
+ I didn't give too much talk in 2018 (at least less than 2017). I'm gonna try to get back
+ at it this year. The surgery won't help but it's just few months.
+
+- *At least 1 video per month* ๐น
+
+ I want to start recording some video, as I feel it's an easier medium than writing and,
+ well, I wanna try !
+
+- *At least 1 post per month* โ๏ธ
+- *Enhance my emacs skills (aka don't be afraid of the lisp)* โจ๏ธ
+
+ I'm using Emacs for almost anything that doesn't happen in a web browser. But I still
+ feel like a newbie. I want to learn more, to write more lisp that help me being even
+ more lazier (aka achieve more doing less ๐)
+
+- *Enhance my Nix(OS) skills* ๐ง
+- *Learn / master a new language* ๐ฝ
+
+ I'm working with Go 90% of my time. I want to master and learn more language. On my list
+ are Emacs Lisp, Rust, Typescript and Haskell.
www/vincent.demeester.fr/posts/2019-01-26-nix-run-alias.org
@@ -0,0 +1,200 @@
+#+title: Nix run aliases
+#+date: <2019-01-26 Sat>
+#+filetags: nixos fish alias nix shell home manager
+
+* Introduction
+
+I use [[https://nixos.org/][=NixOS=]] each and every day, everywhere. One really cool feature of =nix= is
+=nix-shell= and more recently (with =nix= >= =2.0.0=), =nix run=.
+
+#+begin_src man
+Usage: nix run <FLAGS>... <INSTALLABLES>...
+
+Summary: run a shell in which the specified packages are available.
+
+Flags:
+ --arg <NAME> <EXPR> argument to be passed to Nix functions
+ --argstr <NAME> <STRING> string-valued argument to be passed to Nix functions
+ -c, --command <COMMAND> <ARGS> command and arguments to be executed; defaults to 'bash'
+ -f, --file <FILE> evaluate FILE rather than the default
+ -i, --ignore-environment clear the entire environment (except those specified with --keep)
+ -I, --include <PATH> add a path to the list of locations used to look up <...> file names
+ -k, --keep <NAME> keep specified environment variable
+ -u, --unset <NAME> unset specified environment variable
+
+Examples:
+
+ To start a shell providing GNU Hello from NixOS 17.03:
+ $ nix run -f channel:nixos-17.03 hello
+
+ To start a shell providing youtube-dl from your 'nixpkgs' channel:
+ $ nix run nixpkgs.youtube-dl
+
+ To run GNU Hello:
+ $ nix run nixpkgs.hello -c hello --greeting 'Hi everybody!'
+
+ To run GNU Hello in a chroot store:
+ $ nix run --store ~/my-nix nixpkgs.hello -c hello
+
+Note: this program is EXPERIMENTAL and subject to change.
+#+end_src
+
+As you can see from the =-h= summary, it makes it really easy to run a shell or a command
+with some packages that are not in your main configuration. It will download the
+package(s) if there are not available in the Nix store (=/nix/store/=).
+
+A few month ago I decided it would be a perfect use-case for command I do not run
+often. My idea was, let's define =aliases= (in the shell) that would make a simple command
+call, like =ncdu=, become =nix run nixpkgs.ncdu -c ndcu=. My /shell of choice/ is [[https://fishshell.com/][fish]], so
+I decided to dig into the /language/ in order to implement that.
+
+The use case is the following :
+- When I type =foo=, I want the command =foo= in package =bar= to be executed.
+- I want to be able to pin a channel for the package โ I'm using [[https://matthewbauer.us/][Matthew Bauer]] [[https://matthewbauer.us/blog/channel-changing.html][Channel
+ Changing with Nix]] setup for pin-pointing a given channel.
+
+* Fish aliases experimentation
+
+I had a feeling the built-in =alias= would not work so I ended up trying to define a
+/dynamic/ function that would be the name of the command. That's the beauty of the shell,
+everything is a command, even function appears as commands. If you define a function
+=foo()=, you will be able to run =foo= in your shell, *and* it will take precedence over
+the =foo= executable file that would be in your =PATH=.
+
+I ended up with two main helper function that would create those /alias/ function.
+
+#+begin_src fish
+ function _nix_run_package
+ set -l s $argv[1]
+ set -l package (string split ":" $s)
+ switch (count $package)
+ case 1
+ _nix_run $s $s $argv[2] $argv[3]
+ case 2
+ _nix_run $package[1] $package[2] $argv[2] $argv[3]
+ end
+ end
+
+ function _nix_run
+ set -l c $argv[1]
+ set -l p $argv[2]
+ set -l channel $argv[3]
+ set -l channelsfile $argv[4]
+ function $c --inherit-variable c --inherit-variable p --inherit-variable channel --inherit-variable channelsfile
+ set -l cmd nix run
+ if test -n "$channelsfile"
+ set cmd $cmd -f $channelsfile
+ end
+ eval $cmd $channel.$p -c $c $argv
+ end
+ end
+#+end_src
+
+In a nutshell, =_nix_run= is the function that create the alias function. There is so
+condition in there depending on whether we gave it a channel or not. So, a call like
+=_nix_run foo bar unstable channels.nix= would, in the end generate a function =foo= with
+the following call : =nix run -f channels.nix unstable.bar -c foo=.
+
+The other function, =_nix_run_package= is there to make me write less when I define those
+aliases โ aka if the command and the package share the same name, I don't want to write it
+twice. So, a call like =_nix_run_package foo nixpkgs= would result in a =_nix_run foo foo
+nixpkgs=, whereas a call like =_nix_run_package foo:bar unstable channels.nix= would
+result in a =_nix_run foo bar unstable channels.nix=.
+
+An example is gonna be better than the above paragraphs. This is what I used to have in my
+fish configuration.
+
+#+begin_src fish
+ function _def_nix_run_aliases
+ set -l stable mr sshfs ncdu wakeonlan:python36Packages.wakeonlan lspci:pciutils lsusb:usbutils beet:beets gotop virt-manager:virtmanager pandoc nix-prefetch-git:nix-prefetch-scripts nix-prefetch-hg:nix-prefetch-scripts
+ set -l unstable op:_1password update-desktop-database:desktop-file-utils lgogdownloader
+ for s in $stable
+ _nix_run_package $s nixpkgs
+ end
+ for s in $unstable
+ _nix_run_package $s unstable ~/.config/nixpkgs/channels.nix
+ end
+ end
+ # Call the function to create the aliases
+ _def_nix_run_aliases
+#+end_src
+
+This works like a charm, and for a while, I was happy. But I soon realized something : I'm
+not always on my shell โ like, I tend to spend more and more time in =eshell=. This also
+doesn't work with graphic tools like [[https://github.com/DaveDavenport/rofi][=rofi=]]. I needed actual command, so that external
+tools would benefit from that. I ended up writing a small tool, [[https://github.com/vdemeester/nr][=nr=]] that integrates
+nicely with =nix= and [[https://github.com/rycee/home-manager][=home-manager=]].
+
+* A proper tool : =nr=
+
+The gist for this tool is simple :
+- create an executable script that will call =nix run ...= instead of the command
+- as for the above fish script, support different channels
+- make sure we don't have conflicts โ if the command already exists, then don't create the
+ command
+
+The =nr= tool would have to be able to manage multiple /profile/, which really stands for
+multiple file. The main reason is really about how I manage my configuration ; To make it
+simple, depending on the computer my configurations are setup, I may not have =go=, thus I
+don't want any =go=-related aliases for a computer that doesn't have =go= (using =go= here
+but you can replace with anything).
+
+#+begin_src fish
+$ nr default
+> nr generate default
+> virtmanager already exists
+$ nr git
+> nr generate git
+#+end_src
+
+=nr= generates a bash script that does the =nr run โฆ= and mark it as executable. =nr=
+needs to be able to clean files it has generated (in case we removed it from
+aliases). Thus, I went for a really naive comment in the script. When generating a new set
+of commands, =nr= will first remove previously generated script for this profile, and for
+that, it uses the comment. Let's look at what a generated script looks like, for the
+default profile.
+
+#+begin_src bash
+#!/usr/bin/env bash
+# Generated by nr default
+nix run nixpkgs.nix-prefetch-scripts -c nix-prefetch-git $@
+#+end_src
+
+The format used in =nr= is =json=. I'm not a /huge fan/ of =json= but it really was the
+best format to use for this tool. The reason to use =json= are simple :
+
+- Go has =encoding/json= built-in, so it's really easy to =Marshall= and =Unmarshall=
+ structure.
+ #+begin_src go
+ type alias struct {
+ Command string `json:"cmd"`
+ Package string `json:"pkg"`
+ Channel string `json:"chan"`
+ }
+ #+end_src
+- Nix also has built-in support for =json= : =builtins.toJSON= will marshall a /struct/
+ into a json file.
+
+Finally, to avoid conflicts at /build time/ (=home-manager switch=) I couldn't use/define
+a nix package, but to execute command(s) at the end of the build. One way to achieve it is
+to use =file.?.onChange= script, which is executed after [[https://github.com/rycee/home-manager][=home-manager=]] has updated the
+environment, *if* the file has changed. That means it's possible to check for executable
+files in =~/.nix-profile/bin/= for defined aliases and create those that are not there,
+with =nr=. My configuration then looks like the following.
+
+#+BEGIN_SRC nix
+ xdg.configFile."nr/default" = {
+ text = builtins.toJSON [
+ {cmd = "ncdu";} {cmd = "sshfs";} {cmd = "gotop";} {cmd = "pandoc";}
+ {cmd = "wakeonlan"; pkg = "python36Packages.wakeonlan";}
+ {cmd = "beet"; pkg = "beets";}
+ {cmd = "virt-manager"; pkg = "virtmanager";}
+ {cmd = "nix-prefetch-git"; pkg = "nix-prefetch-scripts";}
+ {cmd = "nix-prefetch-hg"; pkg = "nix-prefetch-scripts";}
+ ];
+ onChange = "${pkgs.nur.repos.vdemeester.nr}/bin/nr default";
+ };
+#+END_SRC
+
+And there you are, now, each time I update my environment (=home-manager switch=), =nr=
+will regenerate my =nix run= aliases.
www/vincent.demeester.fr/posts/2019-03-23-gotest-tools-poll.org
@@ -0,0 +1,136 @@
+#+TITLE: Golang testing โ gotest.tools poll
+#+date: <2019-03-23 Sat>
+#+filetags: go testing poll
+
+#+TOC: headlines 2
+
+* Introduction
+Let's continue the [[https://gotest.tools][=gotest.tools=]] serie, this time with the =poll= package.
+
+#+BEGIN_QUOTE
+Package poll provides tools for testing asynchronous code.
+#+END_QUOTE
+
+When you write test, you may test a piece of code that work asynchronously, where the
+state you're expecting is gonna take a bit of time to be achieved. This is especially true
+when you work on networking or file-system code. And this happens a lot when you write
+integration (or end-to-end) test, less for unit-tests.
+
+The package =poll= is trying to tackle those use cases. We'll first take a look at the
+main function, =WaitOn=, then how to write a ~Check~, using the ~Result~ type.
+
+* ~WaitOn~
+
+Let's look into the main ~poll~ function : `WaitOn`.
+
+#+begin_quote
+ WaitOn a condition or until a timeout. Poll by calling check and exit when check returns
+ a done Result. To fail a test and exit polling with an error return a error result.
+#+end_quote
+
+In a gist, ~WaitOn~ will run a /condition/ function until it either times out or
+succeed. It wait for a given time/delay between each run.
+
+#+begin_src go
+ func WaitOn(t TestingT, check Check, pollOps ...SettingOp) {
+ // [โฆ]
+ }
+#+end_src
+
+As any /testing helper/ function, the first argument is ~*testing.T~ (or, in this case,
+any thing that look like it, thanks to the ~TestingT~ interace). The two other arguments
+are way more interesting :
+
+- The ~Check~ is the condition that will run multiple times until it either timeout, or succeed.
+- The ~SettingOp(s)~ which are options to configure the function, things like the timeout,
+ or the /delay/ between each run.
+
+The settings are pretty straightforward :
+
+- ~WithDelay~ : sets the delay to wait between polls. The default delay is 100ms.
+- ~WithTimeout~ : sets the timeout. The default timeout is 10s.
+
+There is existing ~Check~ for common case:
+
+- ~Connection~ : try to open a connection to the address on the named network.
+
+ #+begin_src go
+ poll.WaitOn(t, poll.Connection("tcp", "foo.bar:55555"), poll.WithTimeout("5s"))
+ #+end_src
+
+- ~FileExists~ : looks on filesystem and check that path exists.
+
+ #+begin_src go
+ poll.WaitOn(t, poll.FileExists("/should/be/created"), poll.WithDelay("1s"))
+ #+end_src
+
+
+* ~Check~ and ~Result~
+
+~Connection~ and ~FileExists~ are the only two /built-in/ ~Check~ provided by
+~gotest.tools~. They are useful, but as usual, where ~gotest.tools~ shines is
+extensiblity. It is really easy to define your own ~Check~.
+
+#+begin_src go
+ type Check func(t LogT) Result
+#+end_src
+
+A ~Check~ is, thus, only a function that takes ~LogT~ โ which is anything that can log
+something, like ~*testing.T~ โ and return a ~Result~. Let's look at this intersting
+~Result~ type.
+
+#+begin_src go
+ type Result interface {
+ // Error indicates that the check failed and polling should stop, and the
+ // the has failed
+ Error() error
+ // Done indicates that polling should stop, and the test should proceed
+ Done() bool
+ // Message provides the most recent state when polling has not completed
+ Message() string
+ }
+#+end_src
+
+Although it's an interface, the ~poll~ package defines built-in ~Result~ so that it's easy
+to write ~Check~ without having to define you ~Result~ type.
+
+- ~Continue~ returns a Result that indicates to WaitOn that it should continue
+ polling. The message text will be used as the failure message if the timeout is reached.
+- ~Success~ returns a Result where Done() returns true, which indicates to WaitOn that it
+ should stop polling and exit without an error.
+- ~Error~ returns a Result that indicates to WaitOn that it should fail the test and stop
+ polling.
+
+The basic just to write a ~Check~ is then :
+
+- if the state is not there yet, return ~Continue~,
+- if there is an error, unrelated to validating the state, return an ~Error~,
+- if the state is there, return ~Success~.
+
+Let's look at an example taken from the ~moby/moby~ source code.
+
+#+begin_src go
+ poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
+
+ func IsInState(ctx context.Context, client client.APIClient, containerID string, state ...string) func(log poll.LogT) poll.Result {
+ return func(log poll.LogT) poll.Result {
+ inspect, err := client.ContainerInspect(ctx, containerID)
+ if err != nil {
+ return poll.Error(err)
+ }
+ for _, v := range state {
+ if inspect.State.Status == v {
+ return poll.Success()
+ }
+ }
+ return poll.Continue("waiting for container to be one of (%s), currently %s", strings.Join(state, ", "), inspect.State.Status)
+ }
+ }
+#+end_src
+
+
+* Conclusion
+
+โฆ that's a wrap. The =poll= package allows to easily wait for a condition to happen in a
+given time-frame โ with sane defaults. As for most of the ~gotest.tools~ package, we use
+this package heavily in =docker/*= projects tooโฆ
www/vincent.demeester.fr/posts/2020-02-22-digital-minimalism.org
@@ -0,0 +1,130 @@
+#+title: On digital minimalism, Linux, NixOS and Emacs
+#+date:
+#+filetags: minimalism digital emacs linux nixos
+#+setupfile: ../templates/post.org/
+
+* Introduction
+
+I've been reading and listening about Minimalism and Digital Minimalism for a little while
+now. I've watch some [[https://www.youtube.com/channel/UCJ24N4O0bP7LGLBDvye7oCA][Matt D'Avella]] youtube video (and documentary), read [[https://www.goodreads.com/book/show/40672036-digital-minimalism][Digital
+Minimalism]] from [[https://www.goodreads.com/author/show/147891.Cal_Newport][Cal Newport]], and read a bunch of [[Links][articles and blog posts]].
+
+I wouldn't say I am a minimalist, neither am I a digital minimalist *but* it is something
+that is a bit appealing and I feel I am slowly taking inspiration from those. I've started
+reducing to a minimun what my /smart/-phone does, I've reduced the number of /gadgets/
+I've add over time. But in this posts, I am going to focus on my systems and tools โ this
+means Linux distributions, Emacs and other tools.
+
+* A little bit of history (or context)
+
+I've been using GNU/Linux for ages now. It has been around 22 years now that I discovered
+Red Hat[fn:1] Linux, 5.2 at the time. I've use it as my primary operating system almost
+ever sync. During that time, I've tried so many distribution: from [[https://en.wikipedia.org/wiki/Mandriva_Linux][Mandrake]] (later
+Mandriva), to [[https://www.debian.org/][Debian]] (3.0 -> 9.0 on some servers) and [[https://www.ubuntu.com][Ubuntu]] (on the first ever public
+release), with a long time on [[https://gentoo.org/][Gentoo]] and later [[https://www.archlinux.org/][Archlinux]]. I've used Gnome, KDE, wmii,
+XMonad, awesome-vm. I've used bash, zsh, fish, switching from one to another multiple
+times. I've used Emacs, vim, IntelliJ, Eclipse, VSCodeโฆ My gentoo/archlinux days made me
+try and /use/ a lot of tools (screen, tmux, โฆ) and customization.
+
+I had the habit to customize everything, down to the theme and icons I use. There was a
+time where I would patch and re-package some GTK themes and icons set. *I had to
+customize everything*, that was my learning experience. I would often break things and
+have to re-install the system โ and *it was fun* ๐.
+
+But the more I /grew/, the more I worked for different companies, the less time I had to
+do this. I was also learning a lot about tests, reproducibility at that time. My /will/ to
+customization and /instability/ slowly faded, I wanted to be able to focus on what
+mattered, and not loose time on silly things that I would break soon after making it.
+
+* Minimalism and Digital Mininalism
+
+Let's try to define really quick what is minimalism and digital minimalism about.Digital
+minimalism is Minimalism in the digital world, and [[https://www.theminimalists.com/minimalism/][minimalism]] can be seen as [[https://jamesstuber.com/minimalism-as-a-framework/][a Framework
+for Decision Making]].
+
+#+begin_quote
+Every decision we make is constrained by limited resources. Money, materials, energy. Even
+the richest man in the world is limited by time, and has to make decisions accordingly.
+
+Here are some factors that make minimalism well suited for decision making:
+
+- Practicing minimalism helps develop an improved ability to discern whatโs important and
+ whatโs not
+- It becomes easier to let go of โsort of importantโ things
+- What you choose to keep is a reflection of your values
+#+end_quote
+
+In a gist, Digital Minimalism is about making conscious choice of what you use and what
+you do in the digital world, a world of abundance (information, software, โฆ).
+
+Let's take two examples: our desktops and our phones.
+
+On desktop, digital minimalism can be something like the follow blog post : [[http://neugierig.org/software/blog/2014/07/anti-dashboard-manifesto.html][Tech Notes:
+The Anti-Dashboard Manifesto]].
+
+#+begin_quote
+Now take that reasoning further: It's not useful to reserve a portion of my screen for
+displaying which applications are running, as the things that are running are visible and
+the things that aren't visible can be found when necessary. There's no need for an icon
+displaying wifi status; if I'm connected it's uninteresting and if I'm not connected I'll
+surely discover it if I attempt to use the internet.
+
+I took this reasoning to its conclusion. I run my computers with the screen blank except
+for the apps I run, and the apps I run I configure to display a minimal amount of
+information. I think of this as being anti-dashboard: against the cognitive clutter of
+extraneous information. My computer is not a cockpit and I am at my best when I'm only
+thinking about the single task at hand.
+#+end_quote
+
+This is taking things a little bit too far for me *but* it does resonate with me, and as
+you'll see in the following articles (and on my configuration), I share some of Evan's
+belief. By default, my desktop do only show a background (be an image or a color) and
+anything related to time, battery and other status is a keybinding away (the =Win= key).
+
+And on the phone: [[https://robertheaton.com/2020/03/18/yourself-happier-iphone-worse/][How to make yourself happier by making your iPhone worse | Robert Heaton]]
+โ which I followed almost word for word, but this isn't the subject of this post.
+
+* Emacs, Nix, NixOS, =home-manager= and other tools
+
+How a GNU/Linux distribution like NixOS comes into this. First, let's see what I want :
+
+- A system that is tailored to my needs, that makes me efficient.
+- A system that is customizable, to answer the previous item. I want to be able to modify
+ the default behavior if it doesn't suit me.
+- A system that is reproductible and easy to replicate. If I change my hardware, or if I
+ need to re-install my system for /any reason/.
+- A way to share configuration on my infra. This is probably the developer speaking, but I
+ want to write something once and re-use it several times.
+- A developer environment that is reproductible, on-demand and /safe/.
+- Use defaults of the software I use as much as possible. This one is tricky to achiev for
+ several reasons:
+ + I am used to customize everything (/easy to fix/)
+ + I use a custom keyboard layout ([[https://bepo.fr][bepo]]), so if I go with default keybinding, I will have
+ the wrong /muscle memory/ (and they could be not optimized either)
+- Hackable tools that I can manipulate as I want.
+- Use the right tool at the right time, trying not to reinvent the wheel.
+
+As it turns out Nix and NixOS are giving all the components required for my /almost/ ideal
+setup.
+
+If you complete that with a /not really minimalist/ editor, called [[https://www.gnu.org/software/emacs/][GNU Emacs]], you've got a
+pretty composable system without leaving Emacs. I'll dig more into my Emacs configuration
+and my NixOS setup in different posts โ and on the [[https://vincent.demeester.fr/configurations/][=configurations=]] pages โ but my take
+lately is to try to do with what is available (as built-in, in Emacs for example). After
+reading the docs, if it's not sufficient, I may look for an external module or tool.
+
+* Conclusion
+
+This was a weird post that mixes up tooling, minimalism and thoughts. It's definitely not
+what I initially envisioned. But I'm hoping it introduce a bit my take on things.
+
+* Links
+
+- [[http://neugierig.org/software/blog/2014/07/anti-dashboard-manifesto.html][Tech Notes: The Anti-Dashboard Manifesto]]
+- [[https://blog.zdsmith.com/posts/digital-minimalism-for-the-working-hacker.html][Subset Park: Digital Minimalism for the Working Hacker]]
+- [[https://jamesstuber.com/minimalism-as-a-framework/][Minimalism as a Framework for Decision Making | JamesStuber.com]]
+- [[https://robertheaton.com/2020/03/18/yourself-happier-iphone-worse/][How to make yourself happier by making your iPhone worse | Robert Heaton]]
+
+* Footnotes
+
+[fn:1] And I now work for Red Hat Inc., what a journey ๐
www/vincent.demeester.fr/posts/2020-03-22-org-mode-website.org
@@ -0,0 +1,562 @@
+#+title: Migrating to an org-mode website
+#+date: <2020-03-22 Sun>
+#+filetags: orgmode website emacs
+#+setupfile: ../templates/post.org
+
+* Introduction
+:PROPERTIES:
+:ID: 24a765bd-a0ed-42cf-b96c-db667f7d37e2
+:END:
+
+This is a storyโฆ a story of me changing the way I code and publish my website. In the
+past, I've switch from [[https://vincent.demeester.fr/posts/2012-05-07-reinit-and-jekyll/][Jekyll]] to [[https://vincent.demeester.fr/posts/2015-05-01-orgmode-et-jekyll/]["=orgmode= and Jekyll"]] to [[https://vincent.demeester.fr/posts/2015-05-09-migration-to-hugo/][Hugo]] (sorry those are written
+in french). The past year, I've written and documented myself a little bit about
+[[https://www.theminimalists.com/minimalism/][minimalism]] and [[https://www.goodreads.com/book/show/40672036-digital-minimalism][digital minimalism]]. Although I don't see myself as a minimalist, it helped
+me realize some issues I had.
+
+I also realized if I want to write more, I need to lower the barrier between writing and
+publishing my content ; /if I want it to be published, of course/. This /post/ is about
+what I'm putting in place for this, with a premise : I spend my life in [[https://www.gnu.org/software/emacs/][Emacs]] and thus in
+[[https://orgmode.org/][=orgmode=]]. And [[https://orgmode.org/][=orgmode=]] is feature-full and has this badass feature : =org-publish=.
+
+To build and publish this website, we will /try/ to rely on a reproducible setup, meaning
+[[https://www.gnu.org/software/emacs/][Emacs]] and [[https://orgmode.org/][=orgmode=]] of course, [[https://www.gnu.org/software/make/][GNU Make]] of course *but* most importantly, [[https://nixos.org/nix/][Nix]] (in the near
+future ๐ผ).
+
+:update:
+There is now an article about it, that uses literate programming: [[../articles/meta_publishing_this_website.org][publishing this
+website]]. The content of the post might no be up-to-date at some point.
+:end:
+
+
+* Requirements
+:PROPERTIES:
+:ID: 09991f8e-4257-443c-a3a3-40f449df4597
+:END:
+
+Let's list the requirements I feel I have for my website:
+
+- Full control over the URL of the published posts. ::
+ This is a golden rule of the web: should I change the publishing system, I want to be
+ able to stick to the same URLs or else all external references would be broken. This is
+ a big no-no and in my opinion it makes most blogging systems unacceptable.
+- Top-notch Org support. ::
+ I believe generators like Jekyll and Hugo only have partial Org support. You end up
+ requiring some conversion tooling to get the job done.
+- Simple publishing pipeline. ::
+ I want the generation process to be as simple as possible. This is important for
+ maintenance. Should I someday switch host, I want to be sure that I can set up the same
+ pipeline.
+- Full control over the publishing system. ::
+ I want maximum control over the generation process. I donโt want to be restricted by a
+ non-Turing-complete configuration file or a dumb programming language.
+- Ease of use. ::
+ The process as a whole must be as immediate and friction-less as possible, or else I
+ take the risk of feeling too lazy to publish new posts and update the content.
+- Hackability. ::
+ Last but not least, and this probably supersedes all other requirements: The system must
+ be hackable. Lisp-based systems are prime contenders in that area.
+
+* DONE Organizing
+CLOSED: [2020-03-21 Sat 17:57]
+:PROPERTIES:
+:ID: 78251967-c48a-476d-bc39-c748fc412927
+:END:
+:LOGBOOK:
+- State "DONE" from "TODO" [2020-03-21 Sat 17:57]
+:END:
+
+Let's describe what I do want to publish here:
+
+- Posts :: this is what we call /blog/ these days : short to medium article that are valid
+ at a point of time, as may contain /deprecated/ content, or content that do not reflect
+ my views at a later point in time.
+- Articles :: medium to long article about a topic. Those should be up-to-date or
+ explicitly mark as deprecated or invalid. /In a ideal world this is my *ready for the
+ public* knowledge database, a bit like [[https://braindump.jethro.dev/][Jethro's Braindump]]/.
+- Configurations :: medium to long article about my configurations. Those are base on my
+ ~home~ /configuration/ mono-repository, and usually follow literate programming
+ principles.
+- About :: an about page about the author of the website (aka [[https://vincent.demeester.fr][me]]), linking external
+ contributions (GitHub/Gitlab/โฆ profiles, Talks, โฆ).
+
+* DONE Publishing
+CLOSED: [2020-03-25 Wed 15:54]
+:PROPERTIES:
+:ID: da542763-78b9-46c0-bcf7-d8d2a2b18677
+:END:
+:LOGBOOK:
+- State "DONE" from "TODO" [2020-03-25 Wed 15:54]
+:END:
+
+As said above, the goal is to publish everything using only [[https://www.gnu.org/software/emacs/][Emacs]] and [[https://orgmode.org/][=orgmode=]] (with the
+help of some standard GNU tools).
+
+The [[file:~/src/sbr/publish.el][~publish.el~]] file is where all the magic happens:
+
+- I want to generate something that is ~html5~ (almost?). The /preamble/, /content/ and
+ /postamble/ ~div~ can be customized using ~org-html-div~. Same goes for the /container/
+ element that is used for "wrapping top level sections", it is customized using
+ ~org-html-container-helement~ (we want ~<section>~). There is a few additional variable
+ that I might document one day ๐.
+
+ #+begin_src emacs-lisp
+ (setq org-export-use-babel nil)
+ (setq org-link-abbrev-alist '(("att" . org-attach-expand-link)))
+
+ ;; setting to nil, avoids "Author: x" at the bottom
+ (setq org-export-with-section-numbers nil
+ org-export-with-smart-quotes t
+ org-export-with-toc nil)
+
+ (defvar sbr-date-format "%b %d, %Y")
+
+ (setq org-html-divs '((preamble "header" "top")
+ (content "main" "content")
+ (postamble "footer" "postamble"))
+ org-html-container-element "section"
+ org-html-metadata-timestamp-format sbr-date-format
+ org-html-checkbox-type 'unicode
+ org-html-html5-fancy t
+ org-html-doctype "html5"
+ org-html-htmlize-output-type 'css
+ org-html-htmlize-font-prefix "org-"
+ org-src-fontify-natively t
+ org-html-coding-system 'utf-8-unix)
+ #+end_src
+
+- Part of the ~<head>~, preamble and postamble are customized for the website.
+ + ~head~ ::
+ #+begin_src emacs-lisp
+ (defvar sbr-website-html-head
+ "<link rel='icon' type='image/x-icon' href='/images/favicon.ico'/>
+ <meta name='viewport' content='width=device-width, initial-scale=1'>
+ <link rel='stylesheet' href='/css/new.css' type='text/css'/>
+ <link rel='stylesheet' href='/css/syntax.css' type='text/css'/>
+ <link href='/index.xml' rel='alternate' type='application/rss+xml' title='Vincent Demeester' />")
+ #+end_src
+ + premable ::
+ #+begin_src emacs-lisp
+ (defun sbr-website-html-preamble (plist)
+ "PLIST: An entry."
+ ;; Skip adding subtitle to the post if :KEYWORDS don't have 'post' has a
+ ;; keyword
+ (when (string-match-p "post" (format "%s" (plist-get plist :keywords)))
+ (plist-put plist
+ :subtitle (format "Published on %s by %s."
+ (org-export-get-date plist sbr-date-format)
+ (car (plist-get plist :author)))))
+
+ ;; Below content will be added anyways
+ "<nav>
+ <img src=\"/images/favicon.ico\" id=\"sitelogo\"/> <a href='/'>home</a> /
+ <a href='/posts/'>posts</a> (<a href='/index.xml'>rss</a>) /
+ <a href='/articles/'>articles</a> /
+ <a href='/configurations/'>configurations</a> /
+ <a href='https://dl.sbr.pm/'>files</a> /
+ <a href='/about/'>about</a></li>
+ </nav>")
+ #+end_src
+ + postamble ::
+ #+begin_src emacs-lisp
+ (defvar sbr-website-html-postamble
+ "<footer>
+ <span class='questions'>Questions, comments ? Please use my <a href=\"https://lists.sr.ht/~vdemeester/public-inbox\">public inbox</a> by sending a plain-text email to <a href=\"mailto:~vdemeester/public-inbox@lists.sr.ht\">~vdemeester/public-inbox@lists.sr.ht</a>.</span>
+ <span class='opinions'>Opinions stated here are my own and do not express the views of my employer, spouse, children, pets, neighbors, secret crushes, favorite authors, or anyone else who is not me. And maybe not even me, depending on how old this is.</span>
+ <span class='copyright'>
+ Content and design by Vincent Demeester
+ (<a rel='licence' href='http://creativecommons.org/licenses/by-nc-sa/3.0/'>Some rights reserved</a>)
+ </span><br />
+ <span class='engine'>
+ Powered by <a href='https://www.gnu.org/software/emacs/'>Gnu Emacs</a> and <a href='https://orgmode.org'>orgmode</a>
+ </span>
+ </footer>")
+ #+end_src
+- =orgmode= is able to generate a site-map. This is what we are going to use to generate
+ the index files for ~posts/~ and ~articles~ mainly.
+ #+begin_src emacs-lisp
+ (defun sbr/org-sitemap-format-entry (entry style project)
+ "Format posts with author and published data in the index page.
+
+ ENTRY: file-name
+ STYLE:
+ PROJECT: `posts in this case."
+ (cond ((not (directory-name-p entry))
+ (format "%s โ [[file:%s][%s]]
+ :PROPERTIES:
+ :PUBDATE: [%s]
+ :END:"
+ (format-time-string "%Y-%m-%d"
+ (org-publish-find-date entry project))
+ entry
+ (org-publish-find-title entry project)
+ (format-time-string "%Y-%m-%d"
+ (org-publish-find-date entry project))))
+ ((eq style 'tree) (file-name-nondirectory (directory-file-name entry)))
+ (t entry)))
+
+ (defun sbr/org-publish-sitemap (title list)
+ ""
+ (concat "#+TITLE: " title "\n\n"
+ (org-list-to-subtree list)))
+ #+end_src
+- =orgmode= is able to generate a rss, with =ox-rss=. This is what we are going to use to
+ generate the rss files for ~posts~ and ~articles~. This is _heavily_ customized.
+ #+begin_src emacs-lisp
+ (defun sbr/org-get-first-paragraph (file)
+ "Get string content of first paragraph of file."
+ (ignore-errors
+ (with-temp-buffer
+ (insert-file-contents file)
+ (goto-char (point-min))
+ (show-all)
+ (let ((first-begin (progn
+ (org-forward-heading-same-level 1)
+ (next-line)
+ (point)))
+ (first-end (progn
+ (org-next-visible-heading 1)
+ (point))))
+ (buffer-substring first-begin first-end)))))
+
+ (defun sbr/org-rss-publish-to-rss (plist filename pub-dir)
+ "Prepare rss.org file before exporting."
+ (let* ((postsdir (plist-get plist :base-directory)))
+ (with-current-buffer (find-file filename)
+ (erase-buffer)
+ (insert "#+TITLE: Posts\n")
+ (insert "#+AUTHOR: Vincent Demeester\n")
+ (insert "#+OPTIONS: toc:nil\n")
+ (let* ((files-all
+ (reverse (directory-files "." nil
+ "[0-9-]+.*\\.org$")))
+ (files (subseq files-all 0 (min (length files-all) 30))))
+ (message (format "foo: %s" filename))
+ (dolist (post files)
+ (let* ((post-file post)
+ (post-title (org-publish-find-title post-file plist))
+ (preview-str (sbr/org-get-first-paragraph post-file))
+ (date (replace-regexp-in-string
+ "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-.*"
+ "\\1" post)))
+ (insert (concat "* [[file:" postsdir "/" post "][" post-title "]]\n\n"))
+ (org-set-property "ID" post)
+ (org-set-property "RSS_TITLE" post-title)
+ ;; ox-rss prepends html-link-home to permalink
+ (org-set-property "RSS_PERMALINK"
+ (concat postsdir "/"
+ (file-name-sans-extension post)
+ ".html"))
+ (org-set-property
+ "PUBDATE"
+ (format-time-string
+ "<%Y-%m-%d %a %H:%M>"
+ (org-time-string-to-time
+ (replace-regexp-in-string
+ "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-.*"
+ "\\1" post))))
+ (insert preview-str)
+ (newline 1)
+ (insert (concat "[[file:" postsdir "/" post "][(Read more)]]\n\n"))))
+ (save-buffer))))
+ (let ((user-mail-address "t")
+ (org-export-with-broken-links t)
+ (org-rss-use-entry-url-as-guid nil))
+ (org-rss-publish-to-rss plist filename pub-dir)))
+ #+end_src
+- Finally let's set the ~org-publish-project-alist~ to publish our projects
+ #+begin_src emacs-lisp
+ (setq org-publish-project-alist
+ `(("posts"
+ :base-directory "posts"
+ :base-extension "org"
+ :recursive t
+ :publishing-function org-html-publish-to-html
+ :publishing-directory "./public/posts"
+ :exclude ,(regexp-opt '("README.org" "draft"))
+ :auto-sitemap t
+ :with-footnotes t
+ :with-toc nil
+ :with-drawers t
+ :sitemap-filename "index.org"
+ :sitemap-title "Posts"
+ :sitemap-format-entry sbr/org-sitemap-format-entry
+ :sitemap-style list
+ :sitemap-sort-files anti-chronologically
+ :sitemap-function sbr/org-publish-sitemap
+ :html-head-include-scripts nil
+ :html-head-include-default-style nil
+ :html-head ,sbr-website-html-head
+ :html-preamble sbr-website-html-preamble
+ :html-postamble ,sbr-website-html-postamble)
+ ("posts-rss"
+ :base-directory "posts"
+ :base-extension "org"
+ :recursive t
+ :html-link-home "https://vincent.demeester.fr/"
+ :rss-link-home "https://vincent.demeester.fr/posts/"
+ :html-link-use-abs-url t
+ :rss-extension "xml"
+ :publishing-directory "./public"
+ :publishing-function (sbr/org-rss-publish-to-rss)
+ :section-number nil
+ :exclude ".*"
+ :include ("index.org"))
+ ("articles"
+ :base-directory "articles"
+ :base-extension "org"
+ :recursive t
+ :publishing-function org-html-publish-to-html
+ :publishing-directory "./public/articles"
+ :exclude ,(regexp-opt '("README.org" "draft"))
+ :auto-sitemap t
+ :with-footnotes t
+ :with-toc nil
+ :with-drawers t
+ :sitemap-filename "sitemap.org"
+ :sitemap-title "Articles"
+ :sitemap-style tree
+ :sitemap-sort-files anti-chronologically
+ ;;:sitemap-format-entry sbr/org-sitemap-format-entry
+ ;;:sitemap-function sbr/org-publish-sitemap
+ :html-head-include-scripts nil
+ :html-head-include-default-style nil
+ :html-head ,sbr-website-html-head
+ :html-preamble sbr-website-html-preamble
+ :html-postamble ,sbr-website-html-postamble)
+ ("articles-assets"
+ :exclude ,(regexp-opt '("*.org"))
+ :base-directory "articles"
+ :base-extension ,site-attachments
+ :publishing-directory "./public/articles"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("about"
+ :base-directory "about"
+ :base-extension "org"
+ :exclude ,(regexp-opt '("README.org" "draft"))
+ :index-filename "index.org"
+ :recursive nil
+ :with-footnotes t
+ :with-toc nil
+ :with-drawers t
+ :publishing-function org-html-publish-to-html
+ :publishing-directory "./public/about"
+ :html-head-include-scripts nil
+ :html-head-include-default-style nil
+ :html-head ,sbr-website-html-head
+ :html-preamble sbr-website-html-preamble
+ :html-postamble ,sbr-website-html-postamble)
+ ("index"
+ :base-directory ""
+ :base-extension "org"
+ :exclude ,(regexp-opt '("README.org" "draft"))
+ :index-filename "index.org"
+ :recursive nil
+ :with-footnotes t
+ :with-toc nil
+ :with-drawers t
+ :with-title nil
+ :publishing-function org-html-publish-to-html
+ :publishing-directory "./public"
+ :html-head-include-scripts nil
+ :html-head-include-default-style nil
+ :html-head ,sbr-website-html-head
+ :html-preamble sbr-website-html-preamble
+ :html-postamble ,sbr-website-html-postamble)
+ ("css"
+ :base-directory "./css"
+ :base-extension ,site-attachments
+ :recursive t
+ :publishing-directory "./public/css"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("images"
+ :base-directory "./images"
+ :base-extension ,site-attachments
+ :publishing-directory "./public/images"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("assets"
+ :base-directory "./assets"
+ :base-extension ,site-attachments
+ :publishing-directory "./public/assets"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("legacy"
+ :base-directory "./legacy"
+ :base-extension ,site-attachments
+ :publishing-directory "./public/"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("all" :components ("posts" "about" "index" "articles" "articles-assets" "css" "images" "assets" "legacy" "posts-rss"))))
+ #+end_src
+
+Here are some /inspiration/ I took for this publishing code:
+
+- [[https://thibaultmarin.github.io/blog/posts/2016-11-13-Personal_website_in_org.html][Personal website in org]]
+- [[https://vicarie.in/posts/blogging-with-org.html][Blogging with Org publishing]]
+- [[https://ambrevar.xyz/blog-architecture/][A blog in pure Org/Lisp]]
+- [[https://zngguvnf.org/2017-07-13--blogging-with-org-static-blog.html][Blogging with org-static-blog]]
+- [[https://bastibe.de/2013-11-13-blogging-with-emacs.html][Blogging with Emacs]]
+- [[https://gjhenrique.com/meta.html][Blogging with org-mode and Gitlab Pages]]
+
+
+* DONE Styling
+CLOSED: [2020-03-23 Mon 19:02]
+:PROPERTIES:
+:ID: 052e297f-01b2-41d3-9689-cd2946b56cfb
+:END:
+:LOGBOOK:
+- State "DONE" from "STARTED" [2020-03-23 Mon 19:02]
+:END:
+
+The style of the website has be as simple as possible, and also really light. This means:
+- use default system font as much as possible
+- have a small stylesheet, rely on the default as much as we can
+
+In addition, I want support for:
+- side notes
+- code syntax highlight
+- table of content
+
+The inspiration for this website, in term of style are the following:
+- [[https://vincent.demeester.fr/posts/2018-08-16-gotest-tools-assertions/][Vincent Demeester]]
+- [[https://braindump.jethro.dev/zettels/zettelkasten/][Jethro's Braindump]]
+- [[https://hamberg.no/gtd/][GTD in 15 minutes โ A Pragmatic Guide to Getting Things Done]]
+- [[https://www.inkandswitch.com/local-first.html][Local-first software: You own your data, in spite of the cloud]]
+- [[https://archive.casouri.cat/note/2018/blog-in-org-mode-revisited/index.html][Blog in Org Mode, Revisited]]
+- [[https://kind.sigs.k8s.io/][kind]]
+- [[http://willcrichton.net/notes/idioms-of-dynamic-languages/][Idioms of Dynamic Languages | Will Crichton]]
+- [[https://peter.bourgon.org/blog/2019/09/11/programming-with-errors.html][Peter Bourgon ยท Programming with errors]]
+- [[https://johv.dk/blog/bare-metal-assembly-tutorial.html][Getting started with bare-metal assembly โ Jonas Hvid]]
+
+To be able to define the style a bit, let's try some things below. From this point on,
+this is random content just to try my style out. ๐ผ
+
+There is more in [[../articles/sandbox.org][the sandbox]].
+
+------
+
+#+begin_abstract
+Let's dig into how I setup my development environment when working on ~tektoncd/pipeline~
+#+end_abstract
+
+#+TOC: headlines 2
+
+** sub-heading 1
+
+Checking for errors is *very common* in Go, having =Comparison= function for it was a requirement.
+
+#+BEGIN_aside
+This is a side note. If collection is a string, item must also be a string, and is
+compared using =strings.Contains()=. If collection is a Map, contains will succeed if item
+is a key in the map.
+#+END_aside
+
+- =Error= fails if the error is =nil= *or* the error message is not the expected one.
+- =ErrorContains= fails if the error is =nil= *or* the error message does not contain the expected substring.
+- =ErrorType= fails if the error is =nil= *or* the error type is not the expected type.
+
+Let's first look at the most used : =Error= and =ErrorContains=.
+When you're working on ~pipeline~, usually you want :
+
+1. make sure it compiles : ~go build -v ./..~
+2. Running unit tests : ~go test ./...~ (bonus use [[https://github.com/vdemeester/ram][~ram~]] for continuous testing)
+3. End-to-end tests : ~go test -tags e2e ./...~ (or simply using `./test/` package)
+
+ *Make sure you re-deploy before running the e2e tests* using ~ko apply -f ./config~,
+ otherwise you're testing the wrong code.
+
+#+BEGIN_SRC go
+ var err error
+ // will fail with : expected an error, got nil
+ assert.Check(t, cmp.Error(err, "message in a bottle"))
+ err = errors.Wrap(errors.New("other"), "wrapped")
+ // will fail with : expected error "other", got "wrapped: other"
+ assert.Check(t, cmp.Error(err, "other"))
+ // will succeed
+ assert.Check(t, cmp.ErrorContains(err, "other"))
+#+END_SRC
+
+#+CAPTION: This is the caption for the next figure link (or table)
+#+NAME: fig:SED-HR4049
+#+ATTR_ORG: :width 400/600
+#+ATTR_HTML: :width 100%
+[[../images/emacs/2020-02-29-13-46-08.png]]
+
+If this is the case, then what makes dynamic languages feel easy? Can we take what we learn in answering this question and improve the ergonomics of our static languages? For example, in 2018, I donโt think thereโs as strong an argument for โyou donโt have to write out the types,โ since modern type inference eliminates most of the keystrokes required (even though many major languages still lack such facilities). Plus, saving a few keystrokes does not seem like a critical bottleneck in the programming process.
+
+#+NAME: fig:tektoncd-logo
+[[../images/emacs/2020-02-29-14-41-59.png]]
+
+
+** sub-heading 2
+
+Some content from my other org-mode files.
+
+#+begin_description
+I already wrote 2 previous posts about golang and testing. It's something I care deeply about and I wanted to continue
+writing about it. It took me a bit more time than I thought, but getting back to it. Since the [[http://vincent.demeester.fr/posts/2017-04-22-golang-testing-golden-file/][last post]], Daniel
+Nephin
+and I worked (but mainly Daniel ๐ค) on bootstrapping a testing helper library.
+#+end_description
+
+#+BEGIN_QUOTE
+Package assert provides assertions for comparing expected values to actual values. When
+assertion fails a helpful error message is printed.
+#+END_QUOTE
+
+There is already some good =testing= helpers in the Go ecosystem : [[https://github.com/stretchr/testify][=testify=]], [[http://labix.org/gocheck][=gocheck=]],
+[[https://github.com/onsi/ginkgo][=ginkgo=]] and a lot more โ so why create a new one ? There is multiple reason for it, most
+of them can be seen in the following [[https://github.com/gotestyourself/gotest.tools/issues/49#issuecomment-362436026][GitHub issue]].
+
+[[https://github.com/dnephin/][Daniel]] also wrote a very useful [fn:1]converter if your code base is currently using =testify= :
+=gty-migrate-from-testify=.
+
+#+BEGIN_SRC sh
+$ go get -u gotest.tools/assert/cmd/gty-migrate-from-testify
+# [โฆ]
+$ go list \
+ -f '{{.ImportPath}} {{if .XTestGoFiles}}{{"\n"}}{{.ImportPath}}_test{{end}}' \
+ ./... | xargs gty-migrate-from-testify
+#+END_SRC
+
+We'll Use =Assert= for the rest of the section but any example here would work with
+=Check= too. When we said =Comparison= above, it's mainly the [[https://godoc.org/gotest.tools/assert#BoolOrComparison][BoolOrComparison]] interface โ
+it can either be a boolean expression, or a [[https://godoc.org/gotest.tools/assert/cmp#Comparison][cmp.Comparison]] type. =Assert= and =Check= code
+will be /smart/ enough to detect which one it is.
+
+#+BEGIN_SRC go
+ assert.Assert(t, ok)
+ assert.Assert(t, err != nil)
+ assert.Assert(t, foo.IsBar())
+#+END_SRC
+
+
+* What's next ?
+:PROPERTIES:
+:ID: 678bf6cb-68e7-4fc9-af50-23d283293ab1
+:END:
+
+One thing is to import old blog posts from [[https://vincent.demeester.fr][vincent.demeester.fr]]. This is easily done with
+[[https://pandoc.org/][Pandoc]] and a small bash loop โ and some manual adjusting later on ๐.
+
+#+begin_src bash
+for post in ~/src/github.com/vdemeester/blog/content/posts/*.md; do
+ pandoc -f markdown -t org -o posts/$(basename -s .md ${post}).org ${post}
+done
+#+end_src
+
+
+What is still /to do/ after this initial take.
+
+- [ ] List =FILETAGS= for taximony
+- [ ] Maybe use [[https://css-tricks.com/snippets/css/complete-guide-grid/][css grid]] for the UI
+
+* Footnotes
+:PROPERTIES:
+:ID: 220a0cce-39c3-4b5f-aaa0-66e3a2450f04
+:END:
+
+[fn:1] foo is bar, bar is baz
www/vincent.demeester.fr/posts/2020-04-15-emacs-bankruptcy-is-fun.org
@@ -0,0 +1,108 @@
+#+title: Emacs bankruptcy is fun
+#+date: <2020-04-15 Wed>
+#+filetags: emacs configuration optimization
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+Since go 1.14 go released, I've had a broken =go-mode= setup on my Emacs. I was using
+=lsp-mode= and =gopls= and well, the update broke everything. I initally try to fix it but
+I made it worse. At the same time, I started to get fed up with some performance issue of
+my configuration and how slow my Emacs starts, about 6s.
+
+I, thus, declared my third Emacs bankruptcy, =:disabled= everything and slowly started
+from scratch, with the following goal:
+
+- Have it start quick, as less than a second, not too much more than =emacs -Q= would
+- Disable anything that I don't use often initially
+- Try to use as much built-in as possible (example: using =icomplete= instead of
+ =ivy=/=counsel=)
+
+* Do I really need this feature
+
+Following [[https://protesilaos.com/][Protesilaos Stavrou]]'s emacs videos (and [[https://protesilaos.com/dotemacs/][=dotemacs=]]) for a while now, I have a
+tendency to try to use built-in feature as much as possible. The most obvious example is
+using =icomplete= instead of =ivy=/=counsel=.
+
+When I started my /bankruptcy/, I disabled every single customization I had, either using
+=:disabled= when using =use-package= *or* the =(when nil)= /hack/. I then started Emacs
+and acted on what was missing :
+
+1. Do I really miss it ? An example would be, at least initially, the completion in a =go=
+ file. I do miss it, but I miss it *way less* than having Emacs lagging because of
+ =lsp-mode= and showing me wrong completion.
+2. Is there a built-in option to what I previously used ? Here, the =icomplete= example
+ fits well, or =isearch= instead of =swiper=.
+3. Do I need it at startup or /on-demand/ ?
+
+* Looking into what takes time
+
+In "Advanced Techniques for Reducing Emacs Startup Time"[fn:1], I discovered the [[https://github.com/jschaf/esup][=esup=]]
+emacs library. In a gist, this is a profiler for Emacs. It starts a new Emacs instance and
+look at the loading time.
+
+#+CAPTION: esup "result" view
+[[../images/2020-04-15-16-12-54.png]]
+
+Then, you can do a simple loop:
+
+- Run =esup=
+- Look at the top result
+- Fix it (lazy load, removing the feature, โฆ)
+- Re-iterate
+
+* Loading on-demand
+
+Once you have the setup to know what takes time and what not, it's time to look into how
+to load the most thing on demand.
+
+For this, [[https://github.com/jwiegley/use-package][=use-package=]] is amazing, it tremendously help autoloading modules on-demand. If
+you are not using =use-package=, usually you are using =require=, which loads the
+underlying source file (all of it).
+
+With =use-package=, there is multiple ways to load on demand:
+
+- =:commands= to add callable that will trigger loading the package
+- =:bind=, =:bind*=, =:bind-keymap= and =:bind-keymap*= to bind key sequences to the
+ global keymap or a specific keymap.
+- =:mode= and =:interpreter= establish a deferred binding with the =auto-mode-alist= and
+ =interpreter-mode-alist=.
+- =:hook= allows adding functions onto the package hook
+- =:defer= is the most generic one, all the previous keyword imply =:defer=. You can
+ specify a number of second of idle to load the package.
+
+#+BEGIN_aside
+In a gist for =org-babel=, use =use-package ob-python= and never call =org-babel-do-languages=.
+#+END_aside
+Once this is done, you are left with edge cases, like =org-babel-do-languages=. Those are
+to be handle case by case. The good thing about those cases is that you'll learn what
+those function do and this will give you an even better understanding of what is
+happening.
+
+Doing this exercise also forces you to make you see if you really use that feature or
+not. I ended up removing entire feature from my configuration because they were taking
+quite some time to load, and was used almost never. Instead I am forcing myself to learn
+more what I can do with the built-in features first.
+
+* Conclusion
+
+All in all, this /bankruptcy/ was the most fun I had to do. I consider myself still in the
+process but the base is there.
+
+1. I learned a lot !
+2. My Emacs starts in 0.6s against previously in 5s โ =emacs -q= starts in about 0.3s so
+ there is still a little bit of room for improvement.
+3. I discovered / re-discovered a lot of built-in feature
+4. I started documenting my configuration, see [[../configurations/emacs.org][here]].
+
+๐
+
+:update:
+Well, I've look into the /portable dump/ feature of Emacs, thanks to [[https://archive.casouri.cat/note/2020/painless-transition-to-portable-dumper/index.html][Painless Transition
+to Portable Dumper]]. And I am now down to =0.091s= for the startup. There is a few gotchas
+with /portable dump/, I'll try to write about it later.
+:end:
+
+* Footnotes
+
+[fn:1]: [[https://blog.d46.us/advanced-emacs-startup/][Advanced Techniques for Reducing Emacs Startup Time]]
www/vincent.demeester.fr/posts/2020-06-21-website-update.org
@@ -0,0 +1,16 @@
+#+title: website update
+#+date: <2020-06-08 Mon>
+#+filetags: website css new simple
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+A really small article to talk about small updates on the website (/well, maybe not that
+small/). In a gist: a new css and articles changes.
+
+- Updating the style of the website to something really similar to [[https://newcss.net/][new.css]]. It is way
+ simpler and /pleasing/ (at least for me).
+- My [[../articles][=/articles=]] are now exporting from my [[../articles/personal_knowledge_base.org][personal knowledge base]], powered by
+ [[../articles/org_roam.org][=org-roam=]].
+- A new [[https://dl.sbr.pm/][=/files=]] part is available, where I share some random file. See for example the
+ [[https://dl.sbr.pm/wallpapers/dynamics/][dynamic wallpaper]] part.
www/vincent.demeester.fr/posts/2020-07-08-june-status-update.org
@@ -0,0 +1,109 @@
+#+title: Status update, June 2020
+#+date: <2020-07-08 Wed>
+#+filetags: status update
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+Time for the first new monthly status update! I do like those updates from [[https://drewdevault.com/2020/06/15/Status-update.html][Drew DeVault]]
+and [[https://emersion.fr/blog/2020/status-update-19/][Simon Ser]], so I figured, why not trying myself ๐. I am not sure where to start and
+where to end, but I guess I'll figure things out as I go.
+
+* Tekton & OpenShift Pipelines
+
+As you know, /or may not/, I am working on the [[https://github.com/tektoncd/][TektonCD]] project and also on our [[https://redhat.com][RedHat]]
+product [[https://www.openshift.com/learn/topics/pipelines][OpenShift Pipelines]]. As far as the month of June went :
+
+- We release [[https://github.com/tektoncd/pipeline/releases/tag/v0.13.0][v0.13.0]] "Bobtail Bishop" and a bunch of fixes ([[https://github.com/tektoncd/pipeline/releases/tag/v0.13.2][v0.13.2]])
+ + It's the second release after the =v1beta1= bump, and we start to stabilise things.
+ + [[https://github.com/tektoncd/pipeline/releases/tag/v0.14.0][v0.14.0]] will (and actually is already) a more feature-packed release because there is
+ now the =finally= field support and cloud-events opt-in.
+- But the *most important* contributions I tried to make during that month is the TEP
+ process. *TEP* stands for *Tekton Enhancement proposals*.
+
+ #+begin_src markdown
+ # Tekton Enhancement Proposals (TEPs)
+
+ A Tekton Enhancement Proposal (TEP) is a way to propose, communicate
+ and coordinate on new efforts for the Tekton project. You can read
+ the full details of the project in
+ [TEP-1](https://github.com/tektoncd/community/blob/master/teps/0001-tekton-enhancement-proposal-process.md).
+
+ ## What is a TEP
+
+ A standardized development process for Tekton is proposed in order to
+
+ - provide a common structure and clear checkpoints for proposing
+ changes to Tekton
+ - ensure that the motivation for a change is clear
+ - allow for the enumeration stability milestones and stability
+ graduation criteria
+ - persist project information in a Version Control System (VCS) for
+ future Tekton users and contributors
+ - support the creation of _high value user facing_ information such
+ as:
+ - an overall project development roadmap
+ - motivation for impactful user facing changes
+ - ensure community participants are successfully able to drive changes
+ to completion across one or more releases while stakeholders are
+ adequately represented throughout the process
+
+ This process is supported by a unit of work called a Tekton
+ Enhancement Proposal (TEP). A TEP attempts to combine aspects of the
+ following:
+
+ - feature, and effort tracking document
+ - a product requirements document
+ - design document
+
+ into one file which is created incrementally in collaboration with one
+ or more [Working
+ Groups](https://github.com/tektoncd/community/blob/master/working-groups.md)
+ (WGs).
+
+ This process does not block authors from doing early design docs using
+ any means. It does not block authors from sharing those design docs
+ with the community (during Working groups, on Slack, GitHub, โฆ.
+
+ ,**This process acts as a requirement when a design docs is ready to be
+ implemented or integrated in the `tektoncd` projects**. In other words,
+ a change that impact other `tektoncd` projects or users cannot be
+ merged if there is no `TEP` associated with it.
+
+ This TEP process is related to
+ - the generation of an architectural roadmap
+ - the fact that the what constitutes a feature is still undefined
+ - issue management
+ - the difference between an accepted design and a proposal
+ - the organization of design proposals
+
+ This proposal attempts to place these concerns within a general
+ framework.
+
+
+ See [TEP-1](https://github.com/tektoncd/community/blob/master/teps/0001-tekton-enhancement-proposal-process.md) for more details.
+ #+end_src
+
+* =home=, Nixos and the rest of thing
+
+I did some big changes in my [[https://git.sr.ht/~vdemeester/home][=home=]] repository, it's still much a work-in-progress but it
+is in a way better state than before.
+
+- It is more reproductible. All dependencies are managed by [[https://github.com/nmattia/niv][niv]] and all machines are using
+ a pinned version of channels from there. That way I can test the configuration (on the
+ CI) and cache the packages for all channels that my machines uses. I also can decide
+ when I want to upgrade a particular channel (nixos, unstable, โฆ).
+- I am slowly experimenting on simplifying things more and more. This is a bit related to
+ the [[file:2020-02-22-digital-minimalism.org][previous post]]. I am trying to use Gnome3 everywhere. Well configured, managed by
+ NixOS, it's enough for my test and reduce the configuration cruft I need to do.
+
+An ongoing work is my knowledge base and how it is published as part of this website :
+[[https://vincent.demeester.fr/articles/][articles]]. I am trying to make all those publishable (for the one that do not hold any
+secret). I'll document this a bit more at some point butโฆ
+- Configurations are now part of that knowledge base, the =docs= folder of [[https://git.sr.ht/~vdemeester/home][=home=]] is going
+ away.
+- I am trying to use litterate configuration as much as possible. So slowly, the content
+ from [[https://git.sr.ht/~vdemeester/home][=home=]] will be a tangled version of my knowledge base. At least that is the goal as
+ of today.
+
+And I feel that's all /for June/.
www/vincent.demeester.fr/posts/2020-12-01-nixify-www.org
@@ -0,0 +1,8 @@
+#+title: Nixifying this website
+#+date: <2020-12-01 Fri>
+#+filetags: website nix
+#+setupfile: ../templates/post.org
+
+* Introduction
+
+โฆ
www/vincent.demeester.fr/posts/diving-into-nix.org.draft
@@ -0,0 +1,8 @@
+#+TITLE: Diving into Nix(OS) โ introduction
+#+SUBTITLE: Series about nixos
+#+SETUPFILE: ../templates/post.org
+
+* TODO Introduction
+
+This will be the start of a serie of blog post around Nix, Nixpkgs and NixOS. The goal is
+to present the pros and cons of Nix and how it benefits to use it in different use cases.
www/vincent.demeester.fr/posts/quick-kubernetes-provisionning.org.draft
@@ -0,0 +1,5 @@
+#+TITLE: Quickly provision Kubernetes
+#+SUBTITLE: Experiment with different tools to see what is the most efficient way to provision a multi-node kubernetes cluster
+#+SETUPFILE: ../templates/post.org
+
+* TODO Introduction
www/vincent.demeester.fr/templates/articles.org
@@ -0,0 +1,4 @@
+#+AUTHOR: Vincent Demeester
+#+KEYWORDS: article
+#+OPTIONS: toc:nil d:(not "LOGBOOK")
+#+EXCLUDE_TAGS: noexport
www/vincent.demeester.fr/templates/post.org
@@ -0,0 +1,4 @@
+#+AUTHOR: Vincent Demeester
+#+KEYWORDS: post
+#+OPTIONS: toc:nil pri:nil todo:nil d:(not "LOGBOOK")
+#+EXCLUDE_TAGS: noexport
www/vincent.demeester.fr/.gitignore
@@ -0,0 +1,3 @@
+articles/*
+public/*
+posts/index.org
\ No newline at end of file
www/vincent.demeester.fr/index.org
@@ -0,0 +1,14 @@
+#+TITLE: Vincent Demeester
+#+FILETAGS: home index
+#+LINK: monorepo https://git.sr.ht/~vdemeester/home
+
+#+BEGIN_EXPORT html
+<header>
+<h1>Hi, I'm Vincent Demeester</h1>
+<p>I'm a <em>french</em> developer ๐ป, Gopher ๐น, sysadmin ๐บ, <abbr title="who does all kinds of work"> factotum</abbr> ๐ฆ, <span class="fan"><abbr title="as in free speek">free</abbr>-software <abbr title="You could say Evangelist">fan</abbr></span> ๐ผ and unicode lover ๐ธ. I'm working <a href="https://www.redhat.com">RedHat</a> ๐ฉ as a principal software engineer, previously at <a href="https://www.docker.com">Docker</a> ๐ณ and <a href="http://www.zenika.com/">Zenika</a> ๐ฏ. I am a maintainer of the <a href="https://docker.com">docker project (<a href="https://github.com/moby/moby"><code>moby/moby</code></a>, <a href="https://github.com/docker/cli"><code>docker/cli</code></a>, โฆ), the <a href="https://github.com/tektoncd">TektonCD</a> project (<code>tektoncd/*</code>) and a tiny bit of <a href="https://github.com/NixOS/nixpkgs">NixOS</a>.</p>
+</header>
+#+END_EXPORT
+
+#+BEGIN_COMMENT
+{{{title}}}
+#+END_COMMENT
www/vincent.demeester.fr/Makefile
@@ -0,0 +1,116 @@
+# /Make/ it happen
+# :PROPERTIES:
+# :header-args: :tangle ~/src/home/www/vincent.demeester.fr/Makefile
+# :header-args+: :comments org
+# :ID: 6191455e-95bc-4abc-a5f5-a62606ab2ea7
+# :END:
+#
+# In order to publish this website, I am using [[file:make.org][make]]. In a nutshell, I am going to define a
+# few target to get the content from my notes, export org files into html and copy more or
+# less everything to the =public= folder. I will also define a clean and a publish target.
+#
+# The first part of my =Makefile= will be to define some constants that I want to use later
+# on. Those are mainly to easily change where to look for the notes or where the emacs
+# configuration is.
+
+
+EMACS =
+ifndef EMACS
+EMACS = "emacs"
+endif
+
+DOTEMACS =
+ifndef DOTEMACS
+DOTEMACS = "~/.config/emacs"
+endif
+
+PUBLISH =
+ifndef PUBLISH
+PUBLISH = vincent.demeester.fr
+endif
+
+NOTES = ~/desktop/org/notes
+
+
+
+# The default target will be name =build=.
+
+
+all: build
+
+# Building =public/= and publishing it
+# :PROPERTIES:
+# :ID: 853f3d6b-f385-4091-9f9e-b04d17794e5c
+# :END:
+#
+# To build the website, we will be using [[file:emacs.org][Emacs]] in batch mode, with some shared library *and*
+# the actual [[id:631ced7a-f3f7-4a77-81a8-4a1884a6c4d4][publish]] script.
+
+
+.PHONY: build
+build: publish.el publish-common.el build-articles
+ @echo "Publishing... with current Emacs configurations."
+ ${EMACS} --debug-init --batch --directory $(DOTEMACS)/lisp/ --directory $(DOTEMACS)/lisp/vorg/ \
+ --load publish-common.el --load publish.el \
+ --funcall org-publish-all
+
+.PHONY: build-articles
+build-articles: $(NOTES)
+ rsync -arv --delete --copy-links --exclude='*.private.org' --exclude='*.db' $(NOTES)/ articles/
+
+$(NOTES):
+ $(error $(NOTES) doesn't existsโฆ)
+
+
+
+# The =publish= target is gonna be really simple: I just need to copy the content to
+# =~/desktop/sites= on the current machine, and the rest is automated.
+
+
+.PHONY: publish
+publish: build
+ rsync -a --progress --copy-links --delete public/assets/.fancyindex/ ~/desktop/sites/dl.sbr.pm/.fancyindex/
+ rsync -a --progress --copy-links --delete public/ ~/desktop/sites/${PUBLISH}/
+
+# Local server
+# :PROPERTIES:
+# :ID: 0e26a52e-5f66-42c6-934d-b45cfc9745b2
+# :END:
+#
+# Let's use =miniserve= (using [[file:nix.org][Nix]] with =nix-shell=) to serve the static website locally to
+# validate my changes.
+
+
+.PHONY: serve
+serve:
+ nix-shell -p miniserve --command "miniserve --port=8181 --index=index.html public/"
+
+# Final nits of the =Makefile=
+# :PROPERTIES:
+# :ID: 5bec22c8-491b-4e03-855a-4b5f859473cf
+# :END:
+#
+# One of the final step is to install the git hooks if any. I tend to have this target in all my
+# personal =Makefile= at least. Let's also define a =pre-commit= target that will hold
+# anything we need to do at =pre-commit=.
+
+
+.PHONY: install-hooks
+install-hooks:
+ if [ -e .git ]; then nix-shell -p git --run 'git config core.hooksPath .githooks'; fi
+
+.PHONY: pre-commit
+pre-commit: README.md
+
+
+
+# And the final target is the =clean= one. This will remove any compile emacs-lisp file
+# (=*.elc=), the =public= folder, and some org-mode metadata.
+
+
+.PHONY: clean
+clean:
+ @echo "Cleaning up.."
+ @-rm -rvf *.elc
+ @-rm -rvf public
+ @-rm -rv ~/.org-timestamps/*
www/vincent.demeester.fr/publish-common.el
@@ -0,0 +1,277 @@
+;;; publish-common.el --- Commons code for www publishing projects -*- lexical-binding: t; -*-
+;; Author: Vincent Demeester <vincent@sbr.pm>
+
+;;; Commentary:
+;;
+;;; Code:
+;; load org
+(require 'org)
+(require 'dash)
+;; load org export functions
+(require 'ox-publish)
+(require 'ox-rss)
+(require 'ox-html)
+;; load org link functions
+(require 'ol-man)
+(require 'ol-git-link)
+;; Those are mine
+(require 'ol-github)
+(require 'ol-gitlab)
+(require 'org-attach)
+;; load additional libraries
+(require 'go-mode)
+(require 'css-mode)
+(require 'yaml-mode)
+(require 'nix-mode)
+
+(require 's)
+
+(setq org-export-use-babel nil)
+(setq org-link-abbrev-alist '(("att" . org-attach-expand-link)))
+
+;; setting to nil, avoids "Author: x" at the bottom
+(setq org-export-with-section-numbers nil
+ org-export-with-smart-quotes t
+ org-export-with-toc nil)
+
+(defvar sbr-date-format "%b %d, %Y")
+
+(setq org-html-divs '((preamble "header" "top")
+ (content "main" "content")
+ (postamble "footer" "postamble"))
+ org-html-container-element "section"
+ org-html-metadata-timestamp-format sbr-date-format
+ org-html-checkbox-type 'unicode
+ org-html-html5-fancy t
+ org-html-doctype "html5"
+ org-html-htmlize-output-type 'css
+ org-html-htmlize-font-prefix "org-"
+ org-src-fontify-natively t
+ org-html-coding-system 'utf-8-unix)
+
+(defun sbr/org-export-format-drawer (name content)
+ "HTML export of drawer with NAME and CONTENT.
+name is the name of the drawer, that will be used as class.
+content is the content of the drawer"
+ (format "<div class='drawer %s'>\n<h6>%s</h6>\n%s</div>"
+ (downcase name)
+ (capitalize name)
+ content))
+(setq org-html-format-drawer-function 'sbr/org-export-format-drawer)
+
+(defun read-file (filePath)
+ "Return FILEPATH's file content."
+ (with-temp-buffer
+ (insert-file-contents filePath)
+ (buffer-string)))
+
+(defvar sbr-website-html-head
+ "<link rel='icon' type='image/x-icon' href='/images/favicon.ico'/>
+<meta name='viewport' content='width=device-width, initial-scale=1'>
+<link rel='stylesheet' href='/css/new.css' type='text/css'/>
+<link rel='stylesheet' href='/css/syntax.css' type='text/css'/>
+<link href='/index.xml' rel='alternate' type='application/rss+xml' title='Vincent Demeester' />")
+
+(defun sbr-website-html-preamble (plist)
+ "PLIST: An entry."
+ ;; Skip adding subtitle to the post if :KEYWORDS don't have 'post' has a
+ ;; keyword
+ (when (string-match-p "post" (format "%s" (plist-get plist :keywords)))
+ (plist-put plist
+ :subtitle (format "Published on %s by %s."
+ (org-export-get-date plist sbr-date-format)
+ (car (plist-get plist :author)))))
+
+ ;; Below content will be added anyways
+ "<nav>
+<img src=\"/images/favicon.ico\" id=\"sitelogo\"/> <a href='/'>home</a> /
+<a href='/posts/'>posts</a> (<a href='/index.xml'>rss</a>) /
+<a href='/articles/'>articles</a> /
+<a href='https://dl.sbr.pm/'>files</a> /
+<a href='/about/'>about</a></li>
+</nav>")
+
+(defvar sbr-website-html-postamble
+ "<footer>
+ <span class='questions'>Questions, comments ? Please use my <a href=\"https://lists.sr.ht/~vdemeester/public-inbox\">public inbox</a> by sending a plain-text email to <a href=\"mailto:~vdemeester/public-inbox@lists.sr.ht\">~vdemeester/public-inbox@lists.sr.ht</a>.</span>
+ <span class='opinions'>Opinions stated here are my own and do not express the views of my employer, spouse, children, pets, neighbors, secret crushes, favorite authors, or anyone else who is not me. And maybe not even me, depending on how old this is.</span>
+ <span class='copyright'>
+ Content and design by Vincent Demeester
+ (<a rel='licence' href='http://creativecommons.org/licenses/by-nc-sa/3.0/'>Some rights reserved</a>)
+ </span><br />
+ <span class='engine'>
+ Powered by <a href='https://www.gnu.org/software/emacs/'>Gnu Emacs</a> and <a href='https://orgmode.org'>orgmode</a>
+ </span>
+</footer>")
+(defvar site-attachments
+ (regexp-opt '("jpg" "jpeg" "gif" "png" "svg"
+ "ico" "cur" "css" "js" "woff" "html" "pdf" "otf"))
+ "File types that are published as static files.")
+
+(defun sbr/org-sitemap-format-entry (entry style project)
+ "Format posts with author and published data in the index page.
+
+ENTRY: file-name
+STYLE:
+PROJECT: `posts in this case."
+ (cond ((not (directory-name-p entry))
+ (format "%s โ [[file:%s][%s]]
+ :PROPERTIES:
+ :PUBDATE: [%s]
+ :END:"
+ (format-time-string "%Y-%m-%d"
+ (org-publish-find-date entry project))
+ entry
+ (org-publish-find-title entry project)
+ (format-time-string "%Y-%m-%d"
+ (org-publish-find-date entry project))))
+ ((eq style 'tree) (file-name-nondirectory (directory-file-name entry)))
+ (t entry)))
+
+(defun sbr/org-publish-sitemap (title list)
+ ""
+ (concat "#+TITLE: " title "\n\n"
+ (org-list-to-subtree list)))
+
+(defun sbr/org-get-first-paragraph (file)
+ "Get string content of first paragraph of file."
+ (ignore-errors
+ (with-temp-buffer
+ (insert-file-contents file)
+ (goto-char (point-min))
+ (show-all)
+ (let ((first-begin (progn
+ (org-forward-heading-same-level 1)
+ (next-line)
+ (point)))
+ (first-end (progn
+ (org-next-visible-heading 1)
+ (point))))
+ (buffer-substring first-begin first-end)))))
+
+(defun sbr/org-rss-publish-to-rss (plist filename pub-dir)
+ "Prepare rss.org file before exporting."
+ (let* ((postsdir (plist-get plist :base-directory)))
+ (with-current-buffer (find-file filename)
+ (erase-buffer)
+ (insert "#+TITLE: Posts\n")
+ (insert "#+AUTHOR: Vincent Demeester\n")
+ (insert "#+OPTIONS: toc:nil\n")
+ (let* ((files-all
+ (reverse (directory-files "." nil
+ "[0-9-]+.*\\.org$")))
+ (files (seq-subseq files-all 0 (min (length files-all) 30))))
+ (message (format "foo: %s" filename))
+ (dolist (post files)
+ (let* ((post-file post)
+ (post-title (org-publish-find-title post-file plist))
+ (preview-str (sbr/org-get-first-paragraph post-file))
+ (date (replace-regexp-in-string
+ "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-.*"
+ "\\1" post)))
+ (insert (concat "* [[file:" postsdir "/" post "][" post-title "]]\n\n"))
+ (org-set-property "ID" post)
+ (org-set-property "RSS_TITLE" post-title)
+ ;; ox-rss prepends html-link-home to permalink
+ (org-set-property "RSS_PERMALINK"
+ (concat postsdir "/"
+ (file-name-sans-extension post)
+ ".html"))
+ (org-set-property
+ "PUBDATE"
+ (format-time-string
+ "<%Y-%m-%d %a %H:%M>"
+ (org-time-string-to-time
+ (replace-regexp-in-string
+ "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)-.*"
+ "\\1" post))))
+ (insert preview-str)
+ (newline 1)
+ (insert (concat "[[file:" postsdir "/" post "][(Read more)]]\n\n"))))
+ (save-buffer))))
+ (let ((user-mail-address "t")
+ (org-export-with-broken-links t)
+ (org-rss-use-entry-url-as-guid nil))
+ (org-rss-publish-to-rss plist filename pub-dir)))
+
+(advice-add #'org-export-get-reference :override #'unpackaged/org-export-get-reference)
+
+(defun unpackaged/org-export-get-reference (datum info)
+ "Like `org-export-get-reference', except uses heading titles instead of random numbers."
+ (let ((cache (plist-get info :internal-references)))
+ (or (car (rassq datum cache))
+ (let* ((crossrefs (plist-get info :crossrefs))
+ (cells (org-export-search-cells datum))
+ ;; Preserve any pre-existing association between
+ ;; a search cell and a reference, i.e., when some
+ ;; previously published document referenced a location
+ ;; within current file (see
+ ;; `org-publish-resolve-external-link').
+ ;;
+ ;; However, there is no guarantee that search cells are
+ ;; unique, e.g., there might be duplicate custom ID or
+ ;; two headings with the same title in the file.
+ ;;
+ ;; As a consequence, before re-using any reference to
+ ;; an element or object, we check that it doesn't refer
+ ;; to a previous element or object.
+ (new (or (cl-some
+ (lambda (cell)
+ (let ((stored (cdr (assoc cell crossrefs))))
+ (when stored
+ (let ((old (org-export-format-reference stored)))
+ (and (not (assoc old cache)) stored)))))
+ cells)
+ (when (org-element-property :raw-value datum)
+ ;; Heading with a title
+ (unpackaged/org-export-new-title-reference datum cache))
+ ;; NOTE: This probably breaks some Org Export
+ ;; feature, but if it does what I need, fine.
+ (org-export-format-reference
+ (org-export-new-reference cache))))
+ (reference-string new))
+ ;; Cache contains both data already associated to
+ ;; a reference and in-use internal references, so as to make
+ ;; unique references.
+ (dolist (cell cells) (push (cons cell new) cache))
+ ;; Retain a direct association between reference string and
+ ;; DATUM since (1) not every object or element can be given
+ ;; a search cell (2) it permits quick lookup.
+ (push (cons reference-string datum) cache)
+ (plist-put info :internal-references cache)
+ reference-string))))
+
+(defun unpackaged/org-export-new-title-reference (datum cache)
+ "Return new reference for DATUM that is unique in CACHE."
+ (cl-macrolet ((inc-suffixf (place)
+ `(progn
+ (string-match (rx bos
+ (minimal-match (group (1+ anything)))
+ (optional "--" (group (1+ digit)))
+ eos)
+ ,place)
+ ;; HACK: `s1' instead of a gensym.
+ (-let* (((s1 suffix) (list (match-string 1 ,place)
+ (match-string 2 ,place)))
+ (suffix (if suffix
+ (string-to-number suffix)
+ 0)))
+ (setf ,place (format "%s--%s" s1 (cl-incf suffix)))))))
+ (let* ((title (org-element-property :raw-value datum))
+ (ref (url-hexify-string (substring-no-properties title)))
+ (parent (org-element-property :parent datum)))
+ (while (--any (equal ref (car it))
+ cache)
+ ;; Title not unique: make it so.
+ (if parent
+ ;; Append ancestor title.
+ (setf title (concat (org-element-property :raw-value parent)
+ "--" title)
+ ref (url-hexify-string (substring-no-properties title))
+ parent (org-element-property :parent parent))
+ ;; No more ancestors: add and increment a number.
+ (inc-suffixf ref)))
+ ref)))
+
+(provide 'publish-common)
+;;; publish-common.el ends here
www/vincent.demeester.fr/publish.el
@@ -0,0 +1,138 @@
+;;; publish.el --- Publish www project -*- lexical-binding: t; -*-
+;; Author: Vincent Demeester <vincent@sbr.pm>
+
+;;; Commentary:
+;; This script will convert the org-mode files in this directory into
+;; html.
+
+;;; Code:
+(require 'package)
+(require 'publish-common)
+
+(setq org-publish-project-alist
+ `(("posts"
+ :base-directory "posts"
+ :base-extension "org"
+ :recursive t
+ :publishing-function org-html-publish-to-html
+ :publishing-directory "./public/posts"
+ :exclude ,(regexp-opt '("README.org" "draft"))
+ :auto-sitemap t
+ :with-footnotes t
+ :with-toc nil
+ :with-drawers t
+ :sitemap-filename "index.org"
+ :sitemap-title "Posts"
+ :sitemap-format-entry sbr/org-sitemap-format-entry
+ :sitemap-style list
+ :sitemap-sort-files anti-chronologically
+ :sitemap-function sbr/org-publish-sitemap
+ :html-head-include-scripts nil
+ :html-head-include-default-style nil
+ :html-head ,sbr-website-html-head
+ :html-preamble sbr-website-html-preamble
+ :html-postamble ,sbr-website-html-postamble)
+ ("posts-rss"
+ :base-directory "posts"
+ :base-extension "org"
+ :recursive t
+ :html-link-home "https://vincent.demeester.fr/"
+ :rss-link-home "https://vincent.demeester.fr/posts/"
+ :html-link-use-abs-url t
+ :rss-extension "xml"
+ :publishing-directory "./public"
+ :publishing-function (sbr/org-rss-publish-to-rss)
+ :section-number nil
+ :exclude ".*"
+ :include ("index.org"))
+ ("articles"
+ :base-directory "articles"
+ :base-extension "org"
+ :recursive t
+ :publishing-function org-html-publish-to-html
+ :publishing-directory "./public/articles"
+ :exclude ,(regexp-opt '("README.org" "draft"))
+ :auto-sitemap t
+ :with-footnotes t
+ :with-toc nil
+ :with-drawers t
+ :sitemap-filename "sitemap.org"
+ :sitemap-title "Articles"
+ :sitemap-style tree
+ :sitemap-sort-files anti-chronologically
+ ;;:sitemap-format-entry sbr/org-sitemap-format-entry
+ ;;:sitemap-function sbr/org-publish-sitemap
+ :html-head-include-scripts nil
+ :html-head-include-default-style nil
+ :html-head ,sbr-website-html-head
+ :html-preamble sbr-website-html-preamble
+ :html-postamble ,sbr-website-html-postamble)
+ ("articles-assets"
+ :exclude ,(regexp-opt '("*.org"))
+ :base-directory "articles"
+ :base-extension ,site-attachments
+ :publishing-directory "./public/articles"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("about"
+ :base-directory "about"
+ :base-extension "org"
+ :exclude ,(regexp-opt '("README.org" "draft"))
+ :index-filename "index.org"
+ :recursive nil
+ :with-footnotes t
+ :with-toc nil
+ :with-drawers t
+ :publishing-function org-html-publish-to-html
+ :publishing-directory "./public/about"
+ :html-head-include-scripts nil
+ :html-head-include-default-style nil
+ :html-head ,sbr-website-html-head
+ :html-preamble sbr-website-html-preamble
+ :html-postamble ,sbr-website-html-postamble)
+ ("index"
+ :base-directory ""
+ :base-extension "org"
+ :exclude ,(regexp-opt '("README.org" "draft"))
+ :index-filename "index.org"
+ :recursive nil
+ :with-footnotes t
+ :with-toc nil
+ :with-drawers t
+ :with-title nil
+ :publishing-function org-html-publish-to-html
+ :publishing-directory "./public"
+ :html-head-include-scripts nil
+ :html-head-include-default-style nil
+ :html-head ,sbr-website-html-head
+ :html-preamble sbr-website-html-preamble
+ :html-postamble ,sbr-website-html-postamble)
+ ("css"
+ :base-directory "./css"
+ :base-extension ,site-attachments
+ :recursive t
+ :publishing-directory "./public/css"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("images"
+ :base-directory "./images"
+ :base-extension ,site-attachments
+ :publishing-directory "./public/images"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("assets"
+ :base-directory "./assets"
+ :base-extension ,site-attachments
+ :publishing-directory "./public/assets"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("legacy"
+ :base-directory "./legacy"
+ :base-extension ,site-attachments
+ :publishing-directory "./public/"
+ :publishing-function org-publish-attachment
+ :recursive t)
+ ("all" :components ("posts" "about" "index" "articles" "articles-assets" "css" "images" "assets" "legacy" "posts-rss"))))
+
+(provide 'publish)
+;;; publish.el ends here
www/vincent.demeester.fr/tasks.org
@@ -0,0 +1,84 @@
+#+TITLE: tasks
+
+* TODO Should the publish/export code be in =src/home=
+
+A nice side effect would be that it can be used directly from emacs (no need to call =make=
+from emacs). Otherwise, [[https://tecosaur.github.io/emacs-config/config.html#nicer-generated-heading][this]] will need to be adapted.
+
+* TODO nixify publishing
+
+See https://github.com/etu/etu.github.io/
+
+* TODO [[https://abhinavsarkar.net/about/][About Me | abhinavsarkar.net]]
+
+[2020-05-07 Thu 16:25]
+
+Good automation setup.
+
+* TODO Simplify home again
+[2020-06-11 Thu 10:49]
+
+Like [[https://ahuth.github.io/][Andrew Huth]]
+- Subtitle is "Hi, โฆ"
+- List of /featured/ content (posts)
+- Little explanation for articles
+- List of some projects (docker, tekton, โฆ)
+
+* TODO Add support for org-roam in publish
+
+- [ ] On reference, add the link
+- [ ] Add a reference /aside/ or entry for references on the page
+
+* TODO New blog post capture template/snippet
+
+- Ask for date
+- Ask for title
+- Put in the right place
+
+Use skeleton, โฆ
+* TODO Have a "series" page ?
+:PROPERTIES:
+:CREATED:[2020-06-28 Sun 14:05]
+:END:
+
+For series of article or posts ?
+
+
+From: [[git:~/src/home/README.org::master@{2020-06-28}::1][git:~/src/home/README.org::master@{2020-06-28}::1]]
+* DONE Simplify the home
+CLOSED: [2020-06-06 Sat 15:50]
+:LOGBOOK:
+- State "DONE" from "TODO" [2020-06-06 Sat 15:50]
+:END:
+[2020-04-30 Thu 12:55]
+
+to sthg like [[https://filippo.io/][Filippo Valsorda]]
+also https://duan.ca/articles/
+
+Also look at http://git.foldling.org/ and
+https://emacsninja.com/posts/farewell-github.html for a ~git.sbr.pm~
+(with gitlab.com/vdemeester header as header)
+
+https://www.garron.blog/en/
+https://yarmo.eu/
+
+Could take https://newcss.net/ and go with it :D [[https://newcss.net/][new.css]]
+Base on top of new.css but:
+- a bit larger
+- remove some nonsense
+- support main > header
+- add customs (org related)
+
+* DONE Article listing instead of sitemap
+CLOSED: [2020-05-17 Sun 13:48]
+:LOGBOOK:
+- State "DONE" from "TODO" [2020-05-17 Sun 13:48]
+:END:
+
+Manual listing of articles, linking to the sitemap (like ~configuration~)
+
+* DONE Add support for small screen like iPhone
+CLOSED: [2020-06-06 Sat 15:50]
+:LOGBOOK:
+- State "DONE" from "TODO" [2020-06-06 Sat 15:50]
+:END:
www/README.org
@@ -0,0 +1,2 @@
+#+TITLE: www
+#+SUBTITLE: my website(s)