{"tag":"javascript","articles":{"projects\/tinyfingerprint":{"key":"projects\/tinyfingerprint","type":"article","published":true,"meta":{"createdAt":"2023-05-17T17:52:37+02:00","publishedAt":"2023-05-17T17:52:37+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/tinyfingerprint.avris.it\/","displayUrl":null}],"category":"projects","subcategory":null,"slug":"tinyfingerprint"},"content":{"en":{"slug":"tinyfingerprint","title":"tinyfingerprint","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/tinyfingerprint_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022252.51048532055\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACBklEQVRIia1Wy27jMAwcUi87SFMgQY655P+\/aU89FdtukMJwHElkD10T6WLbqEEIGLAkShqNZmiTqiquxPn4Cy9DQikCZgYzQ1WxXC6xWq2uTW8OEQE3ZXKPvuvgnIOqYhiGj25um\/6ToBaGDuMEzhNEBEQEIkKtFc45y6m1GnMPDw+fxlpDRNoA5SoI7v5s\/A+Qb0n88\/Ib4zhCVe0hImNkPhMzo5SCGKOxKfKhu91uByK6ulcTIGaG994AzBsBsHcigqoixmigACDnDO89xnHEYrG4DyARMQClFHjvUUqBcw61Vhub2wCsX1UNcEs0AVJVTNOEEAJyziilGCO1VnsvpWC73RqTImLO7Pv+foCYGSEEc45zDo+Pj3Z9s45mvcxtZjb25ty7AWJms7yI4PX1Fc45Y+FSRwCsLDjnEEKwvLsA6vseMcZPevDem7YumZidRkQ31aMmQMfjEcMwYL\/f\/2hxAMZYq6jbKvXhgNPpZMKNMZqYa61m95TSl2vEGK\/avrkwqiqen5\/tikII6PseXdehlIJpmjCOI7qu+zjlX61dnnW5XN6vDnnvsdlskFK66RtFRFYor+U1Aco5g4hwPp\/hvW9a\/DJSSt9e502A3t7eEELAer1uov7faJAqAMCLCHLOZtuvAOWcoao4HA54enpCSumT\/ReLxbf\/R9dET0QIIeAdmqdWoOSD4fwAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/tinyfingerprint_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022252.51048532055\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic, privacy-friendly library for browser fingerprinting in nodejs\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/tinyfingerprint_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022505.0209706411\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACBklEQVRIia1Wy27jMAwcUi87SFMgQY655P+\/aU89FdtukMJwHElkD10T6WLbqEEIGLAkShqNZmiTqiquxPn4Cy9DQikCZgYzQ1WxXC6xWq2uTW8OEQE3ZXKPvuvgnIOqYhiGj25um\/6ToBaGDuMEzhNEBEQEIkKtFc45y6m1GnMPDw+fxlpDRNoA5SoI7v5s\/A+Qb0n88\/Ib4zhCVe0hImNkPhMzo5SCGKOxKfKhu91uByK6ulcTIGaG994AzBsBsHcigqoixmigACDnDO89xnHEYrG4DyARMQClFHjvUUqBcw61Vhub2wCsX1UNcEs0AVJVTNOEEAJyziilGCO1VnsvpWC73RqTImLO7Pv+foCYGSEEc45zDo+Pj3Z9s45mvcxtZjb25ty7AWJms7yI4PX1Fc45Y+FSRwCsLDjnEEKwvLsA6vseMcZPevDem7YumZidRkQ31aMmQMfjEcMwYL\/f\/2hxAMZYq6jbKvXhgNPpZMKNMZqYa61m95TSl2vEGK\/avrkwqiqen5\/tikII6PseXdehlIJpmjCOI7qu+zjlX61dnnW5XN6vDnnvsdlskFK66RtFRFYor+U1Aco5g4hwPp\/hvW9a\/DJSSt9e502A3t7eEELAer1uov7faJAqAMCLCHLOZtuvAOWcoao4HA54enpCSumT\/ReLxbf\/R9dET0QIIeAdmqdWoOSD4fwAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/tinyfingerprint_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022505.0209706411\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic, privacy-friendly library for browser fingerprinting in nodejs\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["fingerprint","server-side","javascript","nodejs","library","minimalistic"],"hasMore":false,"image":"https:\/\/avris.it\/image\/tinyfingerprint_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/tinyfingerprint_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/tinyfingerprint_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022126.25524266028\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic, privacy-friendly library for browser fingerprinting in nodejs\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/tinyfingerprint_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/tinyfingerprint_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022126.25524266028\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic, privacy-friendly library for browser fingerprinting in nodejs\u003C\/p\u003E","words":9,"readTime":null,"lang":"en"}}},"projects\/tinytranslator":{"key":"projects\/tinytranslator","type":"article","published":true,"meta":{"createdAt":"2023-05-16T17:52:22+02:00","publishedAt":"2023-05-16T17:52:22+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/tinytranslator.avris.it\/","displayUrl":null}],"category":"projects","subcategory":null,"slug":"tinytranslator"},"content":{"en":{"slug":"tinytranslator","title":"tinytranslator","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/tinytranslator_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022252.38895558223\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABiklEQVRIicWVwY7iMBBEX9uJnUTsICRu\/P9ncdrlhIRAgV0mibv3FLSH2aFBjKbObbu6ulwtZmbcweHnL\/4ITKVQ1zWqipmx2WwIIdw7\/hAqT9GP5ZIK43K5ICJM04SIvJwMgHgUOv5+J0zvmBlzedM0NE3zPYRGVeovUOMjuF457Pdst9uv5gI4FTqdTkzTRCmFGCOqSlVVpJRIKbkeCiEQY7xb5zK1mbHb7RARcs6sVitEhHEcGcfRRSilRNd1d+tcI0spsV6vSSnRNA1V5erjKbidOncoIjim\/DTcrZZSaNsWVWUYhhs5L7y1bkI5Z97e3h4i8QwhXzAej+z3e8yMnDOLxcL1Y\/7Fy00dQsDMGIYBVX2IzCNwj6zrOoZhAOB6vQIQY\/ye5SoitG1L13U3debl6iXkHbE7GM0MVUVEUFVCCNR17U7ql5r6cDjQ9z2llFsozsdijJgZKSVyzv+9w2vqSlUZx\/HTsCulcLlc6Pue5XLJ+Xy+7bM5wc3s5q2PMKv6GVJK\/AW+Ibv2Kw7IKwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/tinytranslator_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022252.38895558223\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic translator library\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/tinytranslator_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022504.77791116447\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABiklEQVRIicWVwY7iMBBEX9uJnUTsICRu\/P9ncdrlhIRAgV0mibv3FLSH2aFBjKbObbu6ulwtZmbcweHnL\/4ITKVQ1zWqipmx2WwIIdw7\/hAqT9GP5ZIK43K5ICJM04SIvJwMgHgUOv5+J0zvmBlzedM0NE3zPYRGVeovUOMjuF457Pdst9uv5gI4FTqdTkzTRCmFGCOqSlVVpJRIKbkeCiEQY7xb5zK1mbHb7RARcs6sVitEhHEcGcfRRSilRNd1d+tcI0spsV6vSSnRNA1V5erjKbidOncoIjim\/DTcrZZSaNsWVWUYhhs5L7y1bkI5Z97e3h4i8QwhXzAej+z3e8yMnDOLxcL1Y\/7Fy00dQsDMGIYBVX2IzCNwj6zrOoZhAOB6vQIQY\/ye5SoitG1L13U3debl6iXkHbE7GM0MVUVEUFVCCNR17U7ql5r6cDjQ9z2llFsozsdijJgZKSVyzv+9w2vqSlUZx\/HTsCulcLlc6Pue5XLJ+Xy+7bM5wc3s5q2PMKv6GVJK\/AW+Ibv2Kw7IKwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/tinytranslator_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022504.77791116447\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic translator library\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["translator","javascript","library","minimalistic"],"hasMore":false,"image":"https:\/\/avris.it\/image\/tinytranslator_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/tinytranslator_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/tinytranslator_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022126.19447779112\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic translator library\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/tinytranslator_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/tinytranslator_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022126.19447779112\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic translator library\u003C\/p\u003E","words":4,"readTime":null,"lang":"en"}}},"projects\/tinymarkdown":{"key":"projects\/tinymarkdown","type":"article","published":true,"meta":{"createdAt":"2023-05-16T16:52:28+02:00","publishedAt":"2023-05-16T16:52:28+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/tinymarkdown.avris.it\/","displayUrl":null}],"category":"projects","subcategory":null,"slug":"tinymarkdown"},"content":{"en":{"slug":"tinymarkdown","title":"tinymarkdown","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/tinymarkdown_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022251.53846153846\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB2UlEQVRIia2VXW+bMBSGH3+AATWNIrW9aO\/y\/3\/XtGiL0iwdxGDO2UUHWqZucVReCSEdsP34PcfHRlWVK\/ry7ZWh+4GKoKqICCEEHh4eqKrq2vCb5LP+UmF9f0\/XdQCICNZanHOLwgCYHIde24gZzqgqxhiMMagqqoq19n2iokEUjAHtf6KqlGVJ0zTLAw2iFNZcxCa4v\/WveK6yUvZ995W2bfHeIyIAjONIURSoKiEEhmHAe09KaXbOWov8rruXl5esFGc51LbtvHMRmd93d3efcuMjZTm03+\/puo7tdnsRH8cxeyFjzHIO7XY7TqcTfd9T1zXOOYqimNNU1\/VVp3ILPMuhpmlIKbFarS5c8f59+J\/twDk3n8AJchxHNptNzlJ5QDFGzuczxhhijDjnEBG893NxT6B1Xc+wU0Fba7PTmwUUQmC9XmdN+NHYqqrmfrUI0OFwoO97np+fb250tyoLuyxLvPfEGAHmGpmeJZV1yt7e3kgpAVAUBSklUkpzAdd1vdglm5Wy4\/FI13WICE9PT4QQKMsS5xxlWS4CchNQ0zTz7T51aWvt4unKBkopISKM44i1lpTSRSMMISwHpKoMw\/Df3cYYiTFireXx8fHD75+VMQbvPb8AVxwPhTUnZx0AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/tinymarkdown_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022251.53846153846\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic library for inline markdown: 9 features \u2013 10 lines of code \u2013 0 dependencies\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/tinymarkdown_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022503.07692307692\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB2UlEQVRIia2VXW+bMBSGH3+AATWNIrW9aO\/y\/3\/XtGiL0iwdxGDO2UUHWqZucVReCSEdsP34PcfHRlWVK\/ry7ZWh+4GKoKqICCEEHh4eqKrq2vCb5LP+UmF9f0\/XdQCICNZanHOLwgCYHIde24gZzqgqxhiMMagqqoq19n2iokEUjAHtf6KqlGVJ0zTLAw2iFNZcxCa4v\/WveK6yUvZ995W2bfHeIyIAjONIURSoKiEEhmHAe09KaXbOWov8rruXl5esFGc51LbtvHMRmd93d3efcuMjZTm03+\/puo7tdnsRH8cxeyFjzHIO7XY7TqcTfd9T1zXOOYqimNNU1\/VVp3ILPMuhpmlIKbFarS5c8f59+J\/twDk3n8AJchxHNptNzlJ5QDFGzuczxhhijDjnEBG893NxT6B1Xc+wU0Fba7PTmwUUQmC9XmdN+NHYqqrmfrUI0OFwoO97np+fb250tyoLuyxLvPfEGAHmGpmeJZV1yt7e3kgpAVAUBSklUkpzAdd1vdglm5Wy4\/FI13WICE9PT4QQKMsS5xxlWS4CchNQ0zTz7T51aWvt4unKBkopISKM44i1lpTSRSMMISwHpKoMw\/Df3cYYiTFireXx8fHD75+VMQbvPb8AVxwPhTUnZx0AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/tinymarkdown_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022503.07692307692\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic library for inline markdown: 9 features \u2013 10 lines of code \u2013 0 dependencies\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["markdown","inline","javascript","library","minimalistic"],"hasMore":false,"image":"https:\/\/avris.it\/image\/tinymarkdown_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/tinymarkdown_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/tinymarkdown_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022125.76923076923\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic library for inline markdown: 9 features \u2013 10 lines of code \u2013 0 dependencies\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/tinymarkdown_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/tinymarkdown_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022125.76923076923\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003Ea minimalistic library for inline markdown: 9 features \u2013 10 lines of code \u2013 0 dependencies\u003C\/p\u003E","words":11,"readTime":null,"lang":"en"}}},"projects\/code-doodle-gradient-progress-bar":{"key":"projects\/code-doodle-gradient-progress-bar","type":"article","published":true,"meta":{"createdAt":"2022-01-02T15:32:29+01:00","publishedAt":"2022-01-02T15:32:29+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/progressbar.avris.it","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/ProgressBar","displayUrl":null}],"category":"projects","subcategory":null,"slug":"code-doodle-gradient-progress-bar"},"content":{"en":{"slug":"code-doodle-gradient-progress-bar","title":"Code Doodle: a gradient progress bar","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-progress-bar_small.png\u0022 alt=\u0022Screenshot of the visual effect: a number of progress bar with increasing values, and their colour gradually changes from red to yellow to green\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022240\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADJklEQVRIibWWT0\/jVhTFf++P7SR2SJygiSGtVFBQqDKbqhJSRSWWVN1WfEU+Aiu6oGqrqk0W1QCaVIzIVChlqoY2JE3s2Im7YPCQIZPJMNOzee8+nWefe8+7zxbh6ZM4On\/GojC\/+BLpFhfmvyt091kTfv4OQ4jFNtQeI90icRwjXu6J4xhgKhZCPIij09UqflpjabWQIJl3k4ffjre4Gz+Uo4cvzvn76Q\/4WpGz3i5Kbz5G5goLiX8IdLr8MfA5AMKQKDnfOmFn72X9QQWNgg793jkAQykoOBo57zxN\/MTzg4MDtNaMRiOKxSKNRoONjQ22trbY39\/HdV0ymQwrKysANBoNrq6u2N3dJQgCarUarutOCzJzeexyOVmItCQ9zzrTBG58V+qGd3p6yng8xvM8Dg8PqVQqaK1RSnF8fEyr1aJQKNButymVShwdHbG2tkatVps67HEcI3ovfoz\/vXoy9c6sbWAacqYeVfgKjEdvFgxEUUS\/3yefzwMQhiGGYczdcwstLYV0psm+FFhZg5nOKZlkc3JyQq\/XI5vN0ul0CIKAbreLaZqkUikuLi5YX1\/n7OyMvb09crnc29s+Nk3ijD2dIdCLJZm0vp+BkAhuSuw4Do7jMBgM8H2farVKt9slDEOKxSKe51EqlVhdXQVe3UF356+viT+vv487vV9nli\/nmpjWtHVL4msM4QHQ7\/cJggApJVEUEUURmUwG3\/exLIswDAEYDAY4jsNwOMS27aRSMyskjTyG\/dFMQcORAGu6SjFWchDr9TqXl5dorbFtm1arhed5jMdjBoMBUkrK5TKpVIput0u9XmdnZ4ft7e1EwN0RQPz2z7fx79f1mYIAzLTCcc0k3pDf4IgbC9rtNsvLy0nrN5tNNjc3kVIymUySzJVSRFHEeDzGsqykO2dB\/DFsxn8Fz99IADBSCvWy68riM1IszeW\/D3Q7OOfp9U9zSaIvsJctpBIUVIW0yP1\/gh5Z60yy97vpdchQYGiFRRbg3oX2oea6HTzn5PqXhdRbSwZerkImfmXZrK\/3+8y1q0p8Yn+6kCDGYEQWwlg843f9H\/oPQE+Gnfb7BO8AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-progress-bar_small.png\u0022 alt=\u0022Screenshot of the visual effect: a number of progress bar with increasing values, and their colour gradually changes from red to yellow to green\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022240\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA simple doodling project \u2013 probably not that useful, but I enjoyed creating it \ud83e\udd37\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-progress-bar_big.png\u0022 alt=\u0022Screenshot of the visual effect: a number of progress bar with increasing values, and their colour gradually changes from red to yellow to green\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022480\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADJklEQVRIibWWT0\/jVhTFf++P7SR2SJygiSGtVFBQqDKbqhJSRSWWVN1WfEU+Aiu6oGqrqk0W1QCaVIzIVChlqoY2JE3s2Im7YPCQIZPJMNOzee8+nWefe8+7zxbh6ZM4On\/GojC\/+BLpFhfmvyt091kTfv4OQ4jFNtQeI90icRwjXu6J4xhgKhZCPIij09UqflpjabWQIJl3k4ffjre4Gz+Uo4cvzvn76Q\/4WpGz3i5Kbz5G5goLiX8IdLr8MfA5AMKQKDnfOmFn72X9QQWNgg793jkAQykoOBo57zxN\/MTzg4MDtNaMRiOKxSKNRoONjQ22trbY39\/HdV0ymQwrKysANBoNrq6u2N3dJQgCarUarutOCzJzeexyOVmItCQ9zzrTBG58V+qGd3p6yng8xvM8Dg8PqVQqaK1RSnF8fEyr1aJQKNButymVShwdHbG2tkatVps67HEcI3ovfoz\/vXoy9c6sbWAacqYeVfgKjEdvFgxEUUS\/3yefzwMQhiGGYczdcwstLYV0psm+FFhZg5nOKZlkc3JyQq\/XI5vN0ul0CIKAbreLaZqkUikuLi5YX1\/n7OyMvb09crnc29s+Nk3ijD2dIdCLJZm0vp+BkAhuSuw4Do7jMBgM8H2farVKt9slDEOKxSKe51EqlVhdXQVe3UF356+viT+vv487vV9nli\/nmpjWtHVL4msM4QHQ7\/cJggApJVEUEUURmUwG3\/exLIswDAEYDAY4jsNwOMS27aRSMyskjTyG\/dFMQcORAGu6SjFWchDr9TqXl5dorbFtm1arhed5jMdjBoMBUkrK5TKpVIput0u9XmdnZ4ft7e1EwN0RQPz2z7fx79f1mYIAzLTCcc0k3pDf4IgbC9rtNsvLy0nrN5tNNjc3kVIymUySzJVSRFHEeDzGsqykO2dB\/DFsxn8Fz99IADBSCvWy68riM1IszeW\/D3Q7OOfp9U9zSaIvsJctpBIUVIW0yP1\/gh5Z60yy97vpdchQYGiFRRbg3oX2oea6HTzn5PqXhdRbSwZerkImfmXZrK\/3+8y1q0p8Yn+6kCDGYEQWwlg843f9H\/oPQE+Gnfb7BO8AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-progress-bar_big.png\u0022 alt=\u0022Screenshot of the visual effect: a number of progress bar with increasing values, and their colour gradually changes from red to yellow to green\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022480\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA simple doodling project \u2013 probably not that useful, but I enjoyed creating it \ud83e\udd37\u003C\/p\u003E\n\u003Cp\u003EI liked the way Wendover Productions displayed the HDI score in their video\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=W3qZIPiWKc4\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E \u201eThe News You Missed in 2021\u201d\u003C\/a\u003E,\nso of course I decided to create a widget like this for VueJS \ud83d\ude05\u003C\/p\u003E\n\u003Cp\u003EHere\u0027s a demo:\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/progressbar.avris.it\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022 class=\u0022btn btn-primary btn-lg d-block\u0022\u003E\nDemo\n\u003C\/a\u003E\u003C\/p\u003E\n\u003Cp\u003EAnd here\u0027s how I made it:\u003C\/p\u003E\n\u003Cp\u003ETo minimise the initial bootsrapping, I picked a framework I already know and absolutely love:\n\u003Ca href=\u0022https:\/\/v3.nuxtjs.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Nuxt\u003C\/a\u003E.\nIts upcoming version, v3, cuts all the bootstrapping crap to the minimum, while remaining highly flexible.\nAll I had to do to start working were those commands:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs bash border\u0022\u003Enpx nuxi init ProgressBar\n\u003Cspan class=\u0022hljs-built_in\u0022\u003Ecd\u003C\/span\u003E ProgressBar\nyarn\nyarn dev -o\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWhat they do is fetch a project template, install dependencies, start a development server\nand open \u003Ccode\u003Ehttp:\/\/localhost:3000\/\u003C\/code\u003E in the browser.\u003C\/p\u003E\n\u003Cdiv class=\u0022alert alert-warning\u0022\u003E\n    Watch out: it\u0027s not the best idea to use v3 yet, this version is not stable!\n    I did, because I like experimenting and I want to see where the project is going,\n    but I had to pay the price (in this case: inability to generate a static website on production,\n    and a weird issue with including stylesheets that I made \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/ProgressBar\/-\/blob\/main\/app.vue#L117\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E an ugly workaround for\u003C\/a\u003E).\n\u003C\/div\u003E\n\u003Cp\u003EBootrapping done; now I can focus on work. It\u0027s a simple project, so only two files will be relevant:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003Eapp.vue\u003C\/code\u003E is the main entrypoint, the homepage.\nIt contains what you see in the demo: just some introduction and lots of \u003Ccode\u003E\u0026lt;AvrisProgressBar\/\u0026gt;\u003C\/code\u003E components\nembedded to showcase their usage.\nI won\u0027t focus here on the \u003Ccode\u003Eapp.vue\u003C\/code\u003E code, because it\u0027s really straightforward \u2013\nyou can check it out \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/ProgressBar\/-\/blob\/main\/app.vue\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E here\u003C\/a\u003E.\nSidenote: if I ever need to add multiple pages, I\u0027ll just create a \u003Ccode\u003Eroutes\u003C\/code\u003E directory\nand move \u003Ccode\u003Eapp.vue\u003C\/code\u003E to the appropriate structure inside of that folder, it\u0027s as simple as that! \u2013\nand for the simplest case it\u0027s all already preconfigured and working!\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003Ecomponents\/AvrisProgressBar.vue\u003C\/code\u003E is the actual component I\u0027ll be working on.\nNuxt automatically configures everything so that throughout the application\nyou can simply use the \u003Ccode\u003E\u0026lt;AvrisProgressBar\/\u0026gt;\u003C\/code\u003E tag.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EThe template is really simple:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Etemplate\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ediv\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022outer\u0022\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003E:style\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022`background-color: ${colourOuter}`\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n        \u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ediv\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022inner\u0022\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003E:style\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022`width: ${percent}%; background-color: ${colourInner}`\u0022\u003C\/span\u003E\n             \u003Cspan class=\u0022hljs-attr\u0022\u003Erole\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022progressbar\u0022\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003E:aria-valuenow\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022percent\u0022\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Earia-valuemin\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u00220\u0022\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Earia-valuemax\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022100\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ediv\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ediv\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Etemplate\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EAll we need is two divs:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ethe outer one, taking a full width of the container\nand coloured with the \u201emain\u201d colour depending on the value of the progress bar,\u003C\/li\u003E\n\u003Cli\u003Ethe inner one, taking a fraction of the outer div\u0027s width proportional to the progress bar\u0027s value\nand coloured with a shade slightly darker than the \u201emain\u201d colour.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EAnd here\u0027s how I styled them:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs css border\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-selector-tag\u0022\u003Estyle\u003C\/span\u003E \u003Cspan class=\u0022hljs-selector-tag\u0022\u003Escoped\u003C\/span\u003E\u0026gt;\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.outer\u003C\/span\u003E {\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003E--apb-height\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E16px\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003E--apb-border-width\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E0px\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003E--apb-border-color\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E#aaa\u003C\/span\u003E;\n}\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.outer\u003C\/span\u003E {\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E100%\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Eborder-radius\u003C\/span\u003E: \u003Cspan class=\u0022hljs-built_in\u0022\u003Ecalc\u003C\/span\u003E(var(--apb-height) \/ \u003Cspan class=\u0022hljs-number\u0022\u003E2\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Eheight\u003C\/span\u003E: \u003Cspan class=\u0022hljs-built_in\u0022\u003Evar\u003C\/span\u003E(--apb-height);\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Emargin\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E4px\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Epadding\u003C\/span\u003E: \u003Cspan class=\u0022hljs-built_in\u0022\u003Ecalc\u003C\/span\u003E(var(--apb-height) \/ \u003Cspan class=\u0022hljs-number\u0022\u003E4\u003C\/span\u003E - \u003Cspan class=\u0022hljs-built_in\u0022\u003Evar\u003C\/span\u003E(--apb-border-width));\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Edisplay\u003C\/span\u003E: inline-block;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Eborder\u003C\/span\u003E: \u003Cspan class=\u0022hljs-built_in\u0022\u003Evar\u003C\/span\u003E(--apb-border-width) solid \u003Cspan class=\u0022hljs-built_in\u0022\u003Evar\u003C\/span\u003E(--apb-border-color);\n}\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.outer\u003C\/span\u003E \u003Cspan class=\u0022hljs-selector-class\u0022\u003E.inner\u003C\/span\u003E {\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Eheight\u003C\/span\u003E: \u003Cspan class=\u0022hljs-built_in\u0022\u003Ecalc\u003C\/span\u003E(var(--apb-height) \/ \u003Cspan class=\u0022hljs-number\u0022\u003E2\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Eborder-radius\u003C\/span\u003E: \u003Cspan class=\u0022hljs-built_in\u0022\u003Ecalc\u003C\/span\u003E(var(--apb-height) \/ \u003Cspan class=\u0022hljs-number\u0022\u003E2\u003C\/span\u003E);\n}\n\u0026lt;\/\u003Cspan class=\u0022hljs-selector-tag\u0022\u003Estyle\u003C\/span\u003E\u0026gt;\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EI used CSS variables so that each usage of this widget can override the default height and border.\u003C\/p\u003E\n\u003Cp\u003ENow all we need to do is calculate \u003Ccode\u003Epercent\u003C\/code\u003E, \u003Ccode\u003EcolourOuter\u003C\/code\u003E and \u003Ccode\u003EcolourInner\u003C\/code\u003E. Easy!\u003C\/p\u003E\n\u003Cp\u003ELet\u0027s start with declaring \u003Ccode\u003Eprops\u003C\/code\u003E of our component:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Escript\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\u003Cspan class=\u0022javascript\u0022\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eexport\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Edefault\u003C\/span\u003E {\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Eprops\u003C\/span\u003E: {\n        \u003Cspan class=\u0022hljs-attr\u0022\u003Evalue\u003C\/span\u003E: { \u003Cspan class=\u0022hljs-attr\u0022\u003Erequired\u003C\/span\u003E: \u003Cspan class=\u0022hljs-literal\u0022\u003Etrue\u003C\/span\u003E },\n        \u003Cspan class=\u0022hljs-attr\u0022\u003Emin\u003C\/span\u003E: { \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027default\u0027\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E },\n        \u003Cspan class=\u0022hljs-attr\u0022\u003Emax\u003C\/span\u003E: { \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027default\u0027\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E1000\u003C\/span\u003E },\n        \u003Cspan class=\u0022hljs-attr\u0022\u003Ecolours\u003C\/span\u003E: { \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027default\u0027\u003C\/span\u003E: \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E =\u0026gt;\u003C\/span\u003E {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E [\n                \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027#ff0000\u0027\u003C\/span\u003E,\n                \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027#ffff00\u0027\u003C\/span\u003E,\n                \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027#00ff00\u0027\u003C\/span\u003E,\n            ];\n        }}\n    },\n};\n\u003C\/span\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Escript\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWe expect the user of our widget to provide a value (eg. \u003Ccode\u003E\u0026lt;AvrisProgressBar :value=\u0022123\u0022\/\u0026gt;\u003C\/code\u003E)\nand we allow them to overwrite the default values of \u003Ccode\u003Emin\u003C\/code\u003E (0), \u003Ccode\u003Emax\u003C\/code\u003E (1000) and \u003Ccode\u003Ecolours\u003C\/code\u003E (red, yellow, green)\nwith their own (eg. \u003Ccode\u003E\u0026lt;AvrisProgressBar :value=\u002269\u0022 :min=\u002224\u0022 :max=\u0022169\u0022\/\u0026gt;\u003C\/code\u003E).\u003C\/p\u003E\n\u003Cp\u003ENow let\u0027s calculate the \u003Ccode\u003Epercent\u003C\/code\u003E.\nIt\u0027s pretty simple: we divide the current progress by the full range, and multiply by 100%.\nIf \u003Ccode\u003Emin == 0\u003C\/code\u003E, the formula is trivial: \u003Ccode\u003E100% * value \/ max\u003C\/code\u003E.\nBut in any other case we should add the \u003Ccode\u003Emin\u003C\/code\u003E to the formula:\n\u003Ccode\u003E100% * (value - min) \/ (max - min)\u003C\/code\u003E.\nPlus let\u0027s cut it at no less than 0 and no more than 100, just in case the user provides some weird input.\nHere\u0027s a Vue code that implements that:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Ecomputed: {\n    percent() {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Elet\u003C\/span\u003E percent = \u003Cspan class=\u0022hljs-number\u0022\u003E100\u003C\/span\u003E * (\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.value - \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.min) \/ (\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.range);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (percent \u0026lt; \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E) { \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E; }\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (percent \u0026gt; \u003Cspan class=\u0022hljs-number\u0022\u003E100\u003C\/span\u003E) { \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-number\u0022\u003E100\u003C\/span\u003E; }\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E percent;\n    },\n    range() {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.max - \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.min;\n    },\n},\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EAnd for the remaining two properties that we need, let\u0027s first mock their values to simply be green and black respectively,\njust so that we can validate that \u003Ccode\u003Epercent\u003C\/code\u003E works well without worrying about the colours.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Ecomputed: {\n    colourOuter() {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027#00ff00\u0027\u003C\/span\u003E;\n    },\n    colourInner() {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027#000000\u0027\u003C\/span\u003E;\n    },\n},\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EOf course, in a full-blown, production-ready library, we should cover a lot more ground than in my simple doodle:\nsupporting multiple colour models, implementing colour mixing algorythms that adjust for human perception, etc.\nBut here I wanted to keep it simple:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ewe only support RGB,\u003C\/li\u003E\n\u003Cli\u003Ewe only support the HTML colour syntax with six digits (eg. \u003Ccode\u003E#C71585\u003C\/code\u003E),\u003C\/li\u003E\n\u003Cli\u003Ewe darken the colour by simply decreesing all of its RGB components by the same percent,\u003C\/li\u003E\n\u003Cli\u003Ewe mix the colours to create the gradient by simply calculating a weighted average for each RGB component.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EActually, that\u0027s my main purpose for creating this widget \u2013\nI\u0027m curious whether such a simple setup would give a visually pleasant effect.\nSpoiler alert: it\u0027s not perfect, but it works well enough indeed!\u003C\/p\u003E\n\u003Cp\u003ESo now, let\u0027s compute two more values that will help us in further calculations.\n\u003Ccode\u003EcoloursHighpoints\u003C\/code\u003E will be a map between the primary colours and the values where they should appear.\nIn the default case, we have \u003Ccode\u003En = 3\u003C\/code\u003E colours (red, yellow, green) and a range from 0 to 1000,\nso to spread them out evenly we\u0027d need red to be at 0, yellow at 500 and green at 1000.\nThe code below splits the available range into \u003Ccode\u003En - 1\u003C\/code\u003E sections (so in this case sections have a width of 500)\nand then produces points at: \u003Ccode\u003Emin\u003C\/code\u003E, \u003Ccode\u003Emin + range\u003C\/code\u003E, \u003Ccode\u003Emin + 2*range\u003C\/code\u003E, \u2026\nSo in our case the methods retuns a map like this: \u003Ccode\u003E{0: \u0022#ff0000\u0022, 500: \u0022#ffff00\u0022, 1000: \u0022#00ff00\u0022}\u003C\/code\u003E:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003EcoloursHighpoints() {\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E highpoints = {};\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E sectionRange = \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.range \/ (\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.colours.length - \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Efor\u003C\/span\u003E (\u003Cspan class=\u0022hljs-keyword\u0022\u003Elet\u003C\/span\u003E i \u003Cspan class=\u0022hljs-keyword\u0022\u003Ein\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.colours) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E point = \u003Cspan class=\u0022hljs-built_in\u0022\u003EparseInt\u003C\/span\u003E(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.min + i * sectionRange, \u003Cspan class=\u0022hljs-number\u0022\u003E10\u003C\/span\u003E);\n        highpoints[point] = \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.colours[i];\n    }\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E highpoints;\n},\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EThe next step would be to figure out which colours to mix for a given value.\nLet\u0027s say our \u003Ccode\u003Evalue = 400\u003C\/code\u003E. We know it\u0027s between 0 \/ red and 500 \/ yellow,\nso we expect it be an orange-ish yellow.\nBut how do we put that into code?\u003C\/p\u003E\n\u003Cp\u003EWe need a method that will return an object telling us what\u0027s the closest highpoint\nbefore our value, and what\u0027s the closest one after our value.\nLet\u0027s iterate over the highpoints and keep assigning their values to the variable \u003Ccode\u003Eleft\u003C\/code\u003E as long as it\u0027s smaller than \u003Ccode\u003Ethis.value\u003C\/code\u003E.\nAs soon as a highpoint appears that\u0027s higher than \u003Ccode\u003Ethis.value\u003C\/code\u003E, we assign it to the \u003Ccode\u003Eright\u003C\/code\u003E variable.\nAnd then let\u0027s handle the edge case of \u003Ccode\u003Evalue \u0026gt;= max\u003C\/code\u003E.\nHere\u0027s the code for that, and it produces the following output for our parameters: \u003Ccode\u003E{left: 0, right: 500}\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003EcoloursBetween() {\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Elet\u003C\/span\u003E left = \u003Cspan class=\u0022hljs-literal\u0022\u003Enull\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Elet\u003C\/span\u003E right = \u003Cspan class=\u0022hljs-literal\u0022\u003Enull\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Efor\u003C\/span\u003E (\u003Cspan class=\u0022hljs-keyword\u0022\u003Elet\u003C\/span\u003E val \u003Cspan class=\u0022hljs-keyword\u0022\u003Eof\u003C\/span\u003E \u003Cspan class=\u0022hljs-built_in\u0022\u003EObject\u003C\/span\u003E.keys(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.coloursHighpoints)) {\n        val = \u003Cspan class=\u0022hljs-built_in\u0022\u003EparseInt\u003C\/span\u003E(val);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (val \u0026lt;= \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.value) {\n            left = val;\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Econtinue\u003C\/span\u003E;\n        }\n        right = val;\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ebreak\u003C\/span\u003E;\n    }\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!right) {\n        right = left;\n    }\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E {left, right};\n},\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EBefore we actually calculate our colours, let\u0027s prepare some helpers that we\u0027ll need:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003EhexToDec\u003C\/code\u003E and \u003Ccode\u003EdecToHex\u003C\/code\u003E \u2013 simply converting the number base and adding some hex-colour specific padding,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EsplitColour\u003C\/code\u003E: turns \u003Ccode\u003E#C71585\u003C\/code\u003E into \u003Ccode\u003E[199, 21, 133]\u003C\/code\u003E,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EmergeColour\u003C\/code\u003E: turns \u003Ccode\u003E[199, 21, 133]\u003C\/code\u003E into \u003Ccode\u003E#C71585\u003C\/code\u003E,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EadjustValue\u003C\/code\u003E: takes an RGB component and increases it by a given \u003Ccode\u003Epercent\u003C\/code\u003E,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EshadeColour\u003C\/code\u003E: splits a colour into components, adjusts their value and merges them back into a colour,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EmixColours\u003C\/code\u003E: takes two colours and a ratio in which they should be mixed, splits them into components,\nfor each of them calculates a weighted average, and then merges them back into a colour.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Emethods: {\n    hexToDec(hex) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-built_in\u0022\u003EparseInt\u003C\/span\u003E(hex, \u003Cspan class=\u0022hljs-number\u0022\u003E16\u003C\/span\u003E);\n    },\n    decToHex(dec) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-built_in\u0022\u003EparseInt\u003C\/span\u003E(dec, \u003Cspan class=\u0022hljs-number\u0022\u003E10\u003C\/span\u003E).toString(\u003Cspan class=\u0022hljs-number\u0022\u003E16\u003C\/span\u003E).padStart(\u003Cspan class=\u0022hljs-number\u0022\u003E2\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u00270\u0027\u003C\/span\u003E);\n    },\n    splitColour(colour) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E [\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.hexToDec(colour.substring(\u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E, \u003Cspan class=\u0022hljs-number\u0022\u003E3\u003C\/span\u003E)),\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.hexToDec(colour.substring(\u003Cspan class=\u0022hljs-number\u0022\u003E3\u003C\/span\u003E, \u003Cspan class=\u0022hljs-number\u0022\u003E5\u003C\/span\u003E)),\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.hexToDec(colour.substring(\u003Cspan class=\u0022hljs-number\u0022\u003E5\u003C\/span\u003E, \u003Cspan class=\u0022hljs-number\u0022\u003E7\u003C\/span\u003E)),\n        ];\n    },\n    mergeColour(r, g, b) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E`#\u003Cspan class=\u0022hljs-subst\u0022\u003E${\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.decToHex(r)}\u003C\/span\u003E\u003Cspan class=\u0022hljs-subst\u0022\u003E${\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.decToHex(g)}\u003C\/span\u003E\u003Cspan class=\u0022hljs-subst\u0022\u003E${\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.decToHex(b)}\u003C\/span\u003E`\u003C\/span\u003E;\n    },\n    adjustValue(val, percent) {\n        val = \u003Cspan class=\u0022hljs-built_in\u0022\u003EparseInt\u003C\/span\u003E(val * (\u003Cspan class=\u0022hljs-number\u0022\u003E100\u003C\/span\u003E + percent) \/ \u003Cspan class=\u0022hljs-number\u0022\u003E100\u003C\/span\u003E);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (val \u0026gt; \u003Cspan class=\u0022hljs-number\u0022\u003E255\u003C\/span\u003E) { val = \u003Cspan class=\u0022hljs-number\u0022\u003E255\u003C\/span\u003E; }\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (val \u0026lt; \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E) { val = \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E; }\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E val;\n    },\n    shadeColour(colour, percent) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E [r, g, b] = \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.splitColour(colour);\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.mergeColour(\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.adjustValue(r, percent),\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.adjustValue(g, percent),\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.adjustValue(b, percent),\n        );\n    },\n    mixColours(colour1, colour2, ratio) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E [r1, g1, b1] = \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.splitColour(colour1);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E [r2, g2, b2] = \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.splitColour(colour2);\n\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.mergeColour(\n            r1 * ratio + r2 * (\u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E - ratio),\n            g1 * ratio + g2 * (\u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E - ratio),\n            b1 * ratio + b2 * (\u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E - ratio),\n        );\n    },\n},\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EAnd now it\u0027s finally time to put it all together.\u003C\/p\u003E\n\u003Cp\u003ETo calculate \u003Ccode\u003EcolourOuter\u003C\/code\u003E we take the \u003Ccode\u003EcoloursBetween\u003C\/code\u003E and we calculate\nhow far away from \u003Ccode\u003Eleft\u003C\/code\u003E is our value.\nIn our case that\u0027s \u003Ccode\u003E(value - left) \/ (right - left) = (400 - 0) \/ (500 - 0) = 400 \/ 500 = 0.8\u003C\/code\u003E.\nWe will use that value as our weight when calculating the weighted average\nbetween the colour in the \u003Ccode\u003Eleft\u003C\/code\u003E highpoint and the colour in the \u003Ccode\u003Eright\u003C\/code\u003E highpoint.\u003C\/p\u003E\n\u003Cp\u003EAnd \u003Ccode\u003EcolourInner\u003C\/code\u003E will just be just \u003Ccode\u003EcolourOuter\u003C\/code\u003E darkened by 30%.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003EcolourOuter() {\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E {left, right} = \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.coloursBetween;\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E ratio = (\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.value - left) \/ ((right - left) || \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E);\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.mixColours(\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.coloursHighpoints[left],\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.coloursHighpoints[right],\n        \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E - ratio,\n    );\n},\ncolourInner() {\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.shadeColour(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E.colourOuter, \u003Cspan class=\u0022hljs-number\u0022\u003E-30\u003C\/span\u003E);\n},\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EAnd that\u0027s it, we\u0027re done!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["vue","nuxt","javascript","widget","progress bar","colours","gradient"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avris-progress-bar_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-progress-bar_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-progress-bar_mini.png\u0022 alt=\u0022Screenshot of the visual effect: a number of progress bar with increasing values, and their colour gradually changes from red to yellow to green\u0022 width=\u0022240\u0022 height=\u0022120\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA simple doodling project \u2013 probably not that useful, but I enjoyed creating it \ud83e\udd37\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-progress-bar_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-progress-bar_mini.png\u0022 alt=\u0022Screenshot of the visual effect: a number of progress bar with increasing values, and their colour gradually changes from red to yellow to green\u0022 width=\u0022240\u0022 height=\u0022120\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA simple doodling project \u2013 probably not that useful, but I enjoyed creating it \ud83e\udd37\u003C\/p\u003E\n\u003Cp\u003EI liked the way Wendover Productions displayed the HDI score in their video\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=W3qZIPiWKc4\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E \u201eThe News You Missed in 2021\u201d\u003C\/a\u003E,\nso of course I decided to create a widget like this for VueJS \ud83d\ude05\u003C\/p\u003E\n\u003Cp\u003EHere\u0027s a demo:\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/progressbar.avris.it\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022 class=\u0022btn btn-primary btn-lg d-block\u0022\u003E\nDemo\n\u003C\/a\u003E\u003C\/p\u003E\n\u003Cp\u003EAnd here\u0027s how I made it:\u003C\/p\u003E\n\u003Cp\u003ETo minimise the initial bootsrapping, I picked a framework I already know and absolutely love:\n\u003Ca href=\u0022https:\/\/v3.nuxtjs.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Nuxt\u003C\/a\u003E.\nIts upcoming version, v3, cuts all the bootstrapping crap to the minimum, while remaining highly flexible.\nAll I had to do to start working were those commands:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-bash\u0022\u003Enpx nuxi init ProgressBar\ncd ProgressBar\nyarn\nyarn dev -o\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWhat they do is fetch a project template, install dependencies, start a development server\nand open \u003Ccode\u003Ehttp:\/\/localhost:3000\/\u003C\/code\u003E in the browser.\u003C\/p\u003E\n\u003Cdiv class=\u0022alert alert-warning\u0022\u003E\n    Watch out: it\u0027s not the best idea to use v3 yet, this version is not stable!\n    I did, because I like experimenting and I want to see where the project is going,\n    but I had to pay the price (in this case: inability to generate a static website on production,\n    and a weird issue with including stylesheets that I made \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/ProgressBar\/-\/blob\/main\/app.vue#L117\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E an ugly workaround for\u003C\/a\u003E).\n\u003C\/div\u003E\n\u003Cp\u003EBootrapping done; now I can focus on work. It\u0027s a simple project, so only two files will be relevant:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003Eapp.vue\u003C\/code\u003E is the main entrypoint, the homepage.\nIt contains what you see in the demo: just some introduction and lots of \u003Ccode\u003E\u0026lt;AvrisProgressBar\/\u0026gt;\u003C\/code\u003E components\nembedded to showcase their usage.\nI won\u0027t focus here on the \u003Ccode\u003Eapp.vue\u003C\/code\u003E code, because it\u0027s really straightforward \u2013\nyou can check it out \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/ProgressBar\/-\/blob\/main\/app.vue\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E here\u003C\/a\u003E.\nSidenote: if I ever need to add multiple pages, I\u0027ll just create a \u003Ccode\u003Eroutes\u003C\/code\u003E directory\nand move \u003Ccode\u003Eapp.vue\u003C\/code\u003E to the appropriate structure inside of that folder, it\u0027s as simple as that! \u2013\nand for the simplest case it\u0027s all already preconfigured and working!\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003Ecomponents\/AvrisProgressBar.vue\u003C\/code\u003E is the actual component I\u0027ll be working on.\nNuxt automatically configures everything so that throughout the application\nyou can simply use the \u003Ccode\u003E\u0026lt;AvrisProgressBar\/\u0026gt;\u003C\/code\u003E tag.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EThe template is really simple:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-html\u0022\u003E\u0026lt;template\u0026gt;\n    \u0026lt;div class=\u0022outer\u0022 :style=\u0022`background-color: ${colourOuter}`\u0022\u0026gt;\n        \u0026lt;div class=\u0022inner\u0022 :style=\u0022`width: ${percent}%; background-color: ${colourInner}`\u0022\n             role=\u0022progressbar\u0022 :aria-valuenow=\u0022percent\u0022 aria-valuemin=\u00220\u0022 aria-valuemax=\u0022100\u0022\u0026gt;\u0026lt;\/div\u0026gt;\n    \u0026lt;\/div\u0026gt;\n\u0026lt;\/template\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EAll we need is two divs:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ethe outer one, taking a full width of the container\nand coloured with the \u201emain\u201d colour depending on the value of the progress bar,\u003C\/li\u003E\n\u003Cli\u003Ethe inner one, taking a fraction of the outer div\u0027s width proportional to the progress bar\u0027s value\nand coloured with a shade slightly darker than the \u201emain\u201d colour.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EAnd here\u0027s how I styled them:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-css\u0022\u003E\u0026lt;style scoped\u0026gt;\n.outer {\n    --apb-height: 16px;\n    --apb-border-width: 0px;\n    --apb-border-color: #aaa;\n}\n\n.outer {\n    width: 100%;\n    border-radius: calc(var(--apb-height) \/ 2);\n    height: var(--apb-height);\n    margin: 4px;\n    padding: calc(var(--apb-height) \/ 4 - var(--apb-border-width));\n    display: inline-block;\n    border: var(--apb-border-width) solid var(--apb-border-color);\n}\n.outer .inner {\n    height: calc(var(--apb-height) \/ 2);\n    border-radius: calc(var(--apb-height) \/ 2);\n}\n\u0026lt;\/style\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EI used CSS variables so that each usage of this widget can override the default height and border.\u003C\/p\u003E\n\u003Cp\u003ENow all we need to do is calculate \u003Ccode\u003Epercent\u003C\/code\u003E, \u003Ccode\u003EcolourOuter\u003C\/code\u003E and \u003Ccode\u003EcolourInner\u003C\/code\u003E. Easy!\u003C\/p\u003E\n\u003Cp\u003ELet\u0027s start with declaring \u003Ccode\u003Eprops\u003C\/code\u003E of our component:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;script\u0026gt;\nexport default {\n    props: {\n        value: { required: true },\n        min: { \u0027default\u0027: 0 },\n        max: { \u0027default\u0027: 1000 },\n        colours: { \u0027default\u0027: () =\u0026gt; {\n            return [\n                \u0027#ff0000\u0027,\n                \u0027#ffff00\u0027,\n                \u0027#00ff00\u0027,\n            ];\n        }}\n    },\n};\n\u0026lt;\/script\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWe expect the user of our widget to provide a value (eg. \u003Ccode\u003E\u0026lt;AvrisProgressBar :value=\u0022123\u0022\/\u0026gt;\u003C\/code\u003E)\nand we allow them to overwrite the default values of \u003Ccode\u003Emin\u003C\/code\u003E (0), \u003Ccode\u003Emax\u003C\/code\u003E (1000) and \u003Ccode\u003Ecolours\u003C\/code\u003E (red, yellow, green)\nwith their own (eg. \u003Ccode\u003E\u0026lt;AvrisProgressBar :value=\u002269\u0022 :min=\u002224\u0022 :max=\u0022169\u0022\/\u0026gt;\u003C\/code\u003E).\u003C\/p\u003E\n\u003Cp\u003ENow let\u0027s calculate the \u003Ccode\u003Epercent\u003C\/code\u003E.\nIt\u0027s pretty simple: we divide the current progress by the full range, and multiply by 100%.\nIf \u003Ccode\u003Emin == 0\u003C\/code\u003E, the formula is trivial: \u003Ccode\u003E100% * value \/ max\u003C\/code\u003E.\nBut in any other case we should add the \u003Ccode\u003Emin\u003C\/code\u003E to the formula:\n\u003Ccode\u003E100% * (value - min) \/ (max - min)\u003C\/code\u003E.\nPlus let\u0027s cut it at no less than 0 and no more than 100, just in case the user provides some weird input.\nHere\u0027s a Vue code that implements that:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Ecomputed: {\n    percent() {\n        let percent = 100 * (this.value - this.min) \/ (this.range);\n        if (percent \u0026lt; 0) { return 0; }\n        if (percent \u0026gt; 100) { return 100; }\n        return percent;\n    },\n    range() {\n        return this.max - this.min;\n    },\n},\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EAnd for the remaining two properties that we need, let\u0027s first mock their values to simply be green and black respectively,\njust so that we can validate that \u003Ccode\u003Epercent\u003C\/code\u003E works well without worrying about the colours.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Ecomputed: {\n    colourOuter() {\n        return \u0027#00ff00\u0027;\n    },\n    colourInner() {\n        return \u0027#000000\u0027;\n    },\n},\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EOf course, in a full-blown, production-ready library, we should cover a lot more ground than in my simple doodle:\nsupporting multiple colour models, implementing colour mixing algorythms that adjust for human perception, etc.\nBut here I wanted to keep it simple:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ewe only support RGB,\u003C\/li\u003E\n\u003Cli\u003Ewe only support the HTML colour syntax with six digits (eg. \u003Ccode\u003E#C71585\u003C\/code\u003E),\u003C\/li\u003E\n\u003Cli\u003Ewe darken the colour by simply decreesing all of its RGB components by the same percent,\u003C\/li\u003E\n\u003Cli\u003Ewe mix the colours to create the gradient by simply calculating a weighted average for each RGB component.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EActually, that\u0027s my main purpose for creating this widget \u2013\nI\u0027m curious whether such a simple setup would give a visually pleasant effect.\nSpoiler alert: it\u0027s not perfect, but it works well enough indeed!\u003C\/p\u003E\n\u003Cp\u003ESo now, let\u0027s compute two more values that will help us in further calculations.\n\u003Ccode\u003EcoloursHighpoints\u003C\/code\u003E will be a map between the primary colours and the values where they should appear.\nIn the default case, we have \u003Ccode\u003En = 3\u003C\/code\u003E colours (red, yellow, green) and a range from 0 to 1000,\nso to spread them out evenly we\u0027d need red to be at 0, yellow at 500 and green at 1000.\nThe code below splits the available range into \u003Ccode\u003En - 1\u003C\/code\u003E sections (so in this case sections have a width of 500)\nand then produces points at: \u003Ccode\u003Emin\u003C\/code\u003E, \u003Ccode\u003Emin + range\u003C\/code\u003E, \u003Ccode\u003Emin + 2*range\u003C\/code\u003E, \u2026\nSo in our case the methods retuns a map like this: \u003Ccode\u003E{0: \u0022#ff0000\u0022, 500: \u0022#ffff00\u0022, 1000: \u0022#00ff00\u0022}\u003C\/code\u003E:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003EcoloursHighpoints() {\n    const highpoints = {};\n    const sectionRange = this.range \/ (this.colours.length - 1);\n    for (let i in this.colours) {\n        const point = parseInt(this.min + i * sectionRange, 10);\n        highpoints[point] = this.colours[i];\n    }\n    return highpoints;\n},\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EThe next step would be to figure out which colours to mix for a given value.\nLet\u0027s say our \u003Ccode\u003Evalue = 400\u003C\/code\u003E. We know it\u0027s between 0 \/ red and 500 \/ yellow,\nso we expect it be an orange-ish yellow.\nBut how do we put that into code?\u003C\/p\u003E\n\u003Cp\u003EWe need a method that will return an object telling us what\u0027s the closest highpoint\nbefore our value, and what\u0027s the closest one after our value.\nLet\u0027s iterate over the highpoints and keep assigning their values to the variable \u003Ccode\u003Eleft\u003C\/code\u003E as long as it\u0027s smaller than \u003Ccode\u003Ethis.value\u003C\/code\u003E.\nAs soon as a highpoint appears that\u0027s higher than \u003Ccode\u003Ethis.value\u003C\/code\u003E, we assign it to the \u003Ccode\u003Eright\u003C\/code\u003E variable.\nAnd then let\u0027s handle the edge case of \u003Ccode\u003Evalue \u0026gt;= max\u003C\/code\u003E.\nHere\u0027s the code for that, and it produces the following output for our parameters: \u003Ccode\u003E{left: 0, right: 500}\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003EcoloursBetween() {\n    let left = null;\n    let right = null;\n    for (let val of Object.keys(this.coloursHighpoints)) {\n        val = parseInt(val);\n        if (val \u0026lt;= this.value) {\n            left = val;\n            continue;\n        }\n        right = val;\n        break;\n    }\n    if (!right) {\n        right = left;\n    }\n    return {left, right};\n},\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EBefore we actually calculate our colours, let\u0027s prepare some helpers that we\u0027ll need:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003EhexToDec\u003C\/code\u003E and \u003Ccode\u003EdecToHex\u003C\/code\u003E \u2013 simply converting the number base and adding some hex-colour specific padding,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EsplitColour\u003C\/code\u003E: turns \u003Ccode\u003E#C71585\u003C\/code\u003E into \u003Ccode\u003E[199, 21, 133]\u003C\/code\u003E,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EmergeColour\u003C\/code\u003E: turns \u003Ccode\u003E[199, 21, 133]\u003C\/code\u003E into \u003Ccode\u003E#C71585\u003C\/code\u003E,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EadjustValue\u003C\/code\u003E: takes an RGB component and increases it by a given \u003Ccode\u003Epercent\u003C\/code\u003E,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EshadeColour\u003C\/code\u003E: splits a colour into components, adjusts their value and merges them back into a colour,\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EmixColours\u003C\/code\u003E: takes two colours and a ratio in which they should be mixed, splits them into components,\nfor each of them calculates a weighted average, and then merges them back into a colour.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Emethods: {\n    hexToDec(hex) {\n        return parseInt(hex, 16);\n    },\n    decToHex(dec) {\n        return parseInt(dec, 10).toString(16).padStart(2, \u00270\u0027);\n    },\n    splitColour(colour) {\n        return [\n            this.hexToDec(colour.substring(1, 3)),\n            this.hexToDec(colour.substring(3, 5)),\n            this.hexToDec(colour.substring(5, 7)),\n        ];\n    },\n    mergeColour(r, g, b) {\n        return `#${this.decToHex(r)}${this.decToHex(g)}${this.decToHex(b)}`;\n    },\n    adjustValue(val, percent) {\n        val = parseInt(val * (100 + percent) \/ 100);\n        if (val \u0026gt; 255) { val = 255; }\n        if (val \u0026lt; 0) { val = 0; }\n        return val;\n    },\n    shadeColour(colour, percent) {\n        const [r, g, b] = this.splitColour(colour);\n\n        return this.mergeColour(\n            this.adjustValue(r, percent),\n            this.adjustValue(g, percent),\n            this.adjustValue(b, percent),\n        );\n    },\n    mixColours(colour1, colour2, ratio) {\n        const [r1, g1, b1] = this.splitColour(colour1);\n        const [r2, g2, b2] = this.splitColour(colour2);\n\n        return this.mergeColour(\n            r1 * ratio + r2 * (1 - ratio),\n            g1 * ratio + g2 * (1 - ratio),\n            b1 * ratio + b2 * (1 - ratio),\n        );\n    },\n},\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EAnd now it\u0027s finally time to put it all together.\u003C\/p\u003E\n\u003Cp\u003ETo calculate \u003Ccode\u003EcolourOuter\u003C\/code\u003E we take the \u003Ccode\u003EcoloursBetween\u003C\/code\u003E and we calculate\nhow far away from \u003Ccode\u003Eleft\u003C\/code\u003E is our value.\nIn our case that\u0027s \u003Ccode\u003E(value - left) \/ (right - left) = (400 - 0) \/ (500 - 0) = 400 \/ 500 = 0.8\u003C\/code\u003E.\nWe will use that value as our weight when calculating the weighted average\nbetween the colour in the \u003Ccode\u003Eleft\u003C\/code\u003E highpoint and the colour in the \u003Ccode\u003Eright\u003C\/code\u003E highpoint.\u003C\/p\u003E\n\u003Cp\u003EAnd \u003Ccode\u003EcolourInner\u003C\/code\u003E will just be just \u003Ccode\u003EcolourOuter\u003C\/code\u003E darkened by 30%.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003EcolourOuter() {\n    const {left, right} = this.coloursBetween;\n    const ratio = (this.value - left) \/ ((right - left) || 1);\n\n    return this.mixColours(\n        this.coloursHighpoints[left],\n        this.coloursHighpoints[right],\n        1 - ratio,\n    );\n},\ncolourInner() {\n    return this.shadeColour(this.colourOuter, -30);\n},\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EAnd that\u0027s it, we\u0027re done!\u003C\/p\u003E","words":1514,"readTime":7,"lang":"en"}}},"projects\/avris-counter":{"key":"projects\/avris-counter","type":"article","published":true,"meta":{"createdAt":"2020-10-04T20:50:17+02:00","publishedAt":"2020-10-04T20:50:17+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/counter.avris.it\/","displayUrl":"Website"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Counter","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-counter"},"content":{"en":{"slug":"avris-counter","title":"Avris Counter","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-counter_small.png\u0022 alt=\u0022Avris Counter screenshot\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022279.58165728077\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACwklEQVRIia2WwW7bRhCGv+UuuSQtwXZsA\/att16bUx6gfYM+RZ6wb9B7kwAFesrFrePGkpWEokXuzvQgS5Elam24\/gGCAGcx83Hm54BGRJSEuq6jKIrUkReVM8bsDYoIf7x7z9npKc18Tuk9fd+jKE0z5\/Xrn3DWviiQ2e6QMQZVXQPdzmagijHmPgard4gi5M4hIvQh4L0nxohEwVpLiAGbZRiTMR6PsPfwmzW262arQqtrFVwXxyCirLhFZR3PjOHj7x8JbcBZR+h7RIQsM4DirEMVVAURGayx80yXWhNu3mOM3EwmFHlOCHH9hs45xuPRg\/OrhCsN5dw8s69DOyPbVIzC1fVnokRiFNz9GHKXo6oURYFz7nFjsBxzXXrK0ifPJU0NShRZeiKz9GHpiUXXkTtH13XM2xZrLSJCkecUeQHLiX2\/A8YajHnYxUHwlKkB+hCTCZ4sVUxmcNYmTT3Yoc05\/315SV1XLLoOFaWqKs7OTv833766SVOLKN+aBlQRVfLcoaKUZflsEOeWH8azTK2qdH1IFmhuvjG9nAJw\/uMFzu83uQGKIk8Dp0y26lQSaNLw6a8rQhc5+eGUvEwUfEK+pKlVIcQXMvW9cpc2tdHtyIb6vufT9TVFXqAor46P18txO9l0OuXw8JAsy5JAj3XIwfBWNcZgrePmz8\/MrmbJJG9+fUNZVnz58pXRaLQ27rY2LfAsU4cYmd3eogonJ6\/2AhljaNuWu7sFdV3h\/fA2foonk6a2WUbta1SU9mu795w\/8KgutzrAYtGR525wfI8C7WsdLH8\/5os5dV1TVVUy0YffPjD5Z0Jz26BR8b7YASrHJT+\/\/eX5mzrLMg4ORnhf7CTYlh979F84ujiiKofhi6p48KsxVHdnU8N3w4UQmEyna7iu67g4Px9M1LZ3zNsWY+D46Ggv+CbINpyq8h88n7nO5mY7EAAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-counter_small.png\u0022 alt=\u0022Avris Counter screenshot\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022279.58165728077\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EIt\u0027s the simplest way to show a counter of visitors on your website \u2013 just copy-paste this simple HTML code!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-counter_big.png\u0022 alt=\u0022Avris Counter screenshot\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022559.16331456154\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACwklEQVRIia2WwW7bRhCGv+UuuSQtwXZsA\/att16bUx6gfYM+RZ6wb9B7kwAFesrFrePGkpWEokXuzvQgS5Elam24\/gGCAGcx83Hm54BGRJSEuq6jKIrUkReVM8bsDYoIf7x7z9npKc18Tuk9fd+jKE0z5\/Xrn3DWviiQ2e6QMQZVXQPdzmagijHmPgard4gi5M4hIvQh4L0nxohEwVpLiAGbZRiTMR6PsPfwmzW262arQqtrFVwXxyCirLhFZR3PjOHj7x8JbcBZR+h7RIQsM4DirEMVVAURGayx80yXWhNu3mOM3EwmFHlOCHH9hs45xuPRg\/OrhCsN5dw8s69DOyPbVIzC1fVnokRiFNz9GHKXo6oURYFz7nFjsBxzXXrK0ifPJU0NShRZeiKz9GHpiUXXkTtH13XM2xZrLSJCkecUeQHLiX2\/A8YajHnYxUHwlKkB+hCTCZ4sVUxmcNYmTT3Yoc05\/315SV1XLLoOFaWqKs7OTv833766SVOLKN+aBlQRVfLcoaKUZflsEOeWH8azTK2qdH1IFmhuvjG9nAJw\/uMFzu83uQGKIk8Dp0y26lQSaNLw6a8rQhc5+eGUvEwUfEK+pKlVIcQXMvW9cpc2tdHtyIb6vufT9TVFXqAor46P18txO9l0OuXw8JAsy5JAj3XIwfBWNcZgrePmz8\/MrmbJJG9+fUNZVnz58pXRaLQ27rY2LfAsU4cYmd3eogonJ6\/2AhljaNuWu7sFdV3h\/fA2foonk6a2WUbta1SU9mu795w\/8KgutzrAYtGR525wfI8C7WsdLH8\/5os5dV1TVVUy0YffPjD5Z0Jz26BR8b7YASrHJT+\/\/eX5mzrLMg4ORnhf7CTYlh979F84ujiiKofhi6p48KsxVHdnU8N3w4UQmEyna7iu67g4Px9M1LZ3zNsWY+D46Ggv+CbINpyq8h88n7nO5mY7EAAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-counter_big.png\u0022 alt=\u0022Avris Counter screenshot\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022559.16331456154\u0022\u003E\u003C\/span\u003E\n                \u003Cfigcaption\u003E\n                    \u003Ca href=\u0022https:\/\/counter.avris.it\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\n                        \u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E\n                        counter.avris.it\n                    \u003C\/a\u003E\n                \u003C\/figcaption\u003E\n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EIt\u0027s the simplest way to show a counter of visitors on your website \u2013 just copy-paste this simple HTML code!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["counter","visits","visitors","stats","image","html","nuxt","vue","javascript"],"hasMore":false,"image":"https:\/\/avris.it\/image\/avris-counter_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-counter_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-counter_mini.png\u0022 alt=\u0022Avris Counter screenshot\u0022 width=\u0022240\u0022 height=\u0022139.79082864039\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EIt\u0027s the simplest way to show a counter of visitors on your website \u2013 just copy-paste this simple HTML code!\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-counter_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-counter_mini.png\u0022 alt=\u0022Avris Counter screenshot\u0022 width=\u0022240\u0022 height=\u0022139.79082864039\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003Cfigcaption\u003E\n                    \u003Ca href=\u0022https:\/\/counter.avris.it\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csmall\u003Ecounter.avris.it\u003C\/small\u003E\u003C\/a\u003E\n                \u003C\/figcaption\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EIt\u0027s the simplest way to show a counter of visitors on your website \u2013 just copy-paste this simple HTML code!\u003C\/p\u003E","words":22,"readTime":null,"lang":"en"}}},"projects\/zaimki":{"key":"projects\/zaimki","type":"article","published":true,"meta":{"createdAt":"2020-07-25T12:32:20+02:00","publishedAt":"2020-07-25T12:32:20+02:00","group":"nonbinary","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/zaimki.pl\/","displayUrl":null},{"icon":"globe-europe","colour":"primary","url":"https:\/\/pronouns.page\/","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Zaimki","displayUrl":null}],"category":"projects","subcategory":null,"slug":"zaimki"},"content":{"pl":{"slug":"zaimki","title":"Zaimki.pl","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/zaimki_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022362.08219178082\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEZ0lEQVRIiZ2Xy3bbRgyGP8yFFCnZObFPe3rd9P0fprsu2nVzYiVpLFKiKM4MuqAoUyRlp8VqNMJgfgA\/MKAcDo0yEWMNMt0ERAQRA+h5vaQFMUYAQggw0rHG3DwziJv+v\/9ri1153MqToiKmVxBrcLkje7+GM9wlUCmly54xZtGptm2JMZFjMblD7IuemRrMHtfYMkOcRQTcJkeMoF3EeDe7QFWv1imlF+MTQIOutRaYJaY\/M93IHtaY3OEfSlY\/vsNtcj6HivKX97hNDsDT0xOqiqpS13WfGqBtW9r2dLH18ePTZb0\/HGiaBlXFOYdC77i9hmDGHg5etNuKeOwA+PLlH6qqZrv9hKoSY+R5t6Pe7wE4HA6EEFBVnp62bLdboOfPbrejbVsAqt2O3a5CVanqmg9\/f6BpmlmE5Ng0V5C6fw5o6nf8uwLj7SIXLgbOPEopMXUOek6lpCP9IWXDbzPmPQ4RGBn61O4oVitOXYevOsqy4Ni2aFK8dzjnuLu7m4FS1QuZx7zsAacr\/dccdFOvNus13ntAqPc1eZ6B9q3AGHMp6WkUbslSmY\/Bz\/SPx6OOQXWfX\/IqgBmF95ZoSlf9Zun\/sdvjduHucuzqpXpnddx9al7QK1w65MI6hsCfv\/9BXq447huss7z\/\/pHvfv7hzbPDWoxcA1oiol6tblttmyM\/\/fYrMUT0UclWOZoS4dRhvfs2RBNxAyEH8Y8r4LoDC8tcyB5XLzZFXstaX2lj50UwItjSXwOaHvwcKsqywFpLSglrLdbal7yfW793nqJYj+zLm+\/bNBt2gZ+zlDnv8D7j6\/NXsiwjNA3eObouUBQFRgQUAh2wuoCBN6pnkolbMovQu\/t76romxUToAnVdU5YlIUYy78l8zvp+g55byfT6W6C+tfzNvImZCy1iOodZAJTC52zuNmBHRt4YJ65tX+suRewqZSKCMYI1BkWJXWSz2aCqWGN5PlSoQFkUiLf\/vemN0jY8zuNzqooTzoU48sBaS+Y9yWr\/9jiHMYbS5ZTrcvZCvwZqCmB4iAcxk6HNITIraxFBjEFImHN5GhGOsWPVhn5suBGd4bIhGkvTxC3wcE7ZNL8xpouysZYQI4SIc47t7gt2bzl1HQ\/lPfl9uXjxrQd0Wm2zcz1vrg+L6UvbGNP3IARrLVVVEUKkbU9k3mOMuTl23Crxt2ZqadtWx+Htuo663rPf7\/HekZISY0AVnLPEmHDO9p0ZOQ\/ycJeXlPebywx+K0rDkHcVlRGP3LSDxpRQTZxOJ4qioKp2FEXB8djiJefh4e7NoW18+TQiAz2mabt8GCyFNsZIlmcc2yPG2svEV7cHvlbPhLq9TJX\/R17rR0sxJSXldOqHdUGoqqrnSkrU9Z66OZAWBrW5qbd5NHDYGINzbv50pJTw3uOdI4RACIEuBKzryZ15j4pSHw5Yayj9CpPPP4\/GoKYP71LaBplZyrK+xzjv+vcsBB4eLOZsYDzGWmsRN6nQyaW3JoBb5f8voc2F\/xkJVV0AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/zaimki_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022362.08219178082\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EPolska gramatyka jest skomplikowana i silnie zgenderyzowana. Nie oznacza to jednak, \u017ce niemo\u017cliwe jest u\u017cywanie innych form ni\u017c \u201eon\u201d i \u201eona\u201d.\u003C\/p\u003E\n\u003Cp\u003ETo narz\u0119dzie udost\u0119pnia linki do przyk\u0142ad\u00f3w u\u017cycia (w prostych zdaniach oraz w literaturze, prasie, filmach i serialach) zaimk\u00f3w i innych form p\u0142ciowych \u2013 nie tylko normatywnych \u201eon\u201d i \u201eona\u201d, lecz tak\u017ce form niebinarnych.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/zaimki_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022724.16438356164\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEZ0lEQVRIiZ2Xy3bbRgyGP8yFFCnZObFPe3rd9P0fprsu2nVzYiVpLFKiKM4MuqAoUyRlp8VqNMJgfgA\/MKAcDo0yEWMNMt0ERAQRA+h5vaQFMUYAQggw0rHG3DwziJv+v\/9ri1153MqToiKmVxBrcLkje7+GM9wlUCmly54xZtGptm2JMZFjMblD7IuemRrMHtfYMkOcRQTcJkeMoF3EeDe7QFWv1imlF+MTQIOutRaYJaY\/M93IHtaY3OEfSlY\/vsNtcj6HivKX97hNDsDT0xOqiqpS13WfGqBtW9r2dLH18ePTZb0\/HGiaBlXFOYdC77i9hmDGHg5etNuKeOwA+PLlH6qqZrv9hKoSY+R5t6Pe7wE4HA6EEFBVnp62bLdboOfPbrejbVsAqt2O3a5CVanqmg9\/f6BpmlmE5Ng0V5C6fw5o6nf8uwLj7SIXLgbOPEopMXUOek6lpCP9IWXDbzPmPQ4RGBn61O4oVitOXYevOsqy4Ni2aFK8dzjnuLu7m4FS1QuZx7zsAacr\/dccdFOvNus13ntAqPc1eZ6B9q3AGHMp6WkUbslSmY\/Bz\/SPx6OOQXWfX\/IqgBmF95ZoSlf9Zun\/sdvjduHucuzqpXpnddx9al7QK1w65MI6hsCfv\/9BXq447huss7z\/\/pHvfv7hzbPDWoxcA1oiol6tblttmyM\/\/fYrMUT0UclWOZoS4dRhvfs2RBNxAyEH8Y8r4LoDC8tcyB5XLzZFXstaX2lj50UwItjSXwOaHvwcKsqywFpLSglrLdbal7yfW793nqJYj+zLm+\/bNBt2gZ+zlDnv8D7j6\/NXsiwjNA3eObouUBQFRgQUAh2wuoCBN6pnkolbMovQu\/t76romxUToAnVdU5YlIUYy78l8zvp+g55byfT6W6C+tfzNvImZCy1iOodZAJTC52zuNmBHRt4YJ65tX+suRewqZSKCMYI1BkWJXWSz2aCqWGN5PlSoQFkUiLf\/vemN0jY8zuNzqooTzoU48sBaS+Y9yWr\/9jiHMYbS5ZTrcvZCvwZqCmB4iAcxk6HNITIraxFBjEFImHN5GhGOsWPVhn5suBGd4bIhGkvTxC3wcE7ZNL8xpouysZYQI4SIc47t7gt2bzl1HQ\/lPfl9uXjxrQd0Wm2zcz1vrg+L6UvbGNP3IARrLVVVEUKkbU9k3mOMuTl23Crxt2ZqadtWx+Htuo663rPf7\/HekZISY0AVnLPEmHDO9p0ZOQ\/ycJeXlPebywx+K0rDkHcVlRGP3LSDxpRQTZxOJ4qioKp2FEXB8djiJefh4e7NoW18+TQiAz2mabt8GCyFNsZIlmcc2yPG2svEV7cHvlbPhLq9TJX\/R17rR0sxJSXldOqHdUGoqqrnSkrU9Z66OZAWBrW5qbd5NHDYGINzbv50pJTw3uOdI4RACIEuBKzryZ15j4pSHw5Yayj9CpPPP4\/GoKYP71LaBplZyrK+xzjv+vcsBB4eLOZsYDzGWmsRN6nQyaW3JoBb5f8voc2F\/xkJVV0AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/zaimki_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022724.16438356164\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EPolska gramatyka jest skomplikowana i silnie zgenderyzowana. Nie oznacza to jednak, \u017ce niemo\u017cliwe jest u\u017cywanie innych form ni\u017c \u201eon\u201d i \u201eona\u201d.\u003C\/p\u003E\n\u003Cp\u003ETo narz\u0119dzie udost\u0119pnia linki do przyk\u0142ad\u00f3w u\u017cycia (w prostych zdaniach oraz w literaturze, prasie, filmach i serialach) zaimk\u00f3w i innych form p\u0142ciowych \u2013 nie tylko normatywnych \u201eon\u201d i \u201eona\u201d, lecz tak\u017ce form niebinarnych.\u003C\/p\u003E\n\u003Cp\u003EDlaczego nale\u017cy je respektowa\u0107? Bo zwracanie si\u0119 do kogo\u015b tak, jak sobie \u017cyczy, jest podstaw\u0105 relacji spo\u0142ecznych. Nie powiesz do Ani \u201cFranku\u201d, nie powiesz \u201cna ty\u201d do osoby, z kt\u00f3r\u0105 jeste\u015b \u201cna pan\u201d, itp. A s\u0105 osoby, kt\u00f3re nie chc\u0105, by im m\u00f3wi\u0107 \u201con\u201d ani \u201cona\u201d. Czy to uszanujesz, \u015bwiadczy wy\u0142\u0105cznie o Tobie.\u003C\/p\u003E\n\u003Cp\u003EWarto wrzuci\u0107 link do swoich zaimk\u00f3w na swoje profile na portalach spo\u0142eczno\u015bciowych \u2013 nawet je\u015bli jeste\u015b cis i u\u017cywasz \u201eon\u201d lub \u201eona\u201d \u2013 poniewa\u017c dzi\u0119ki temu pokazujesz wsparcie dla spo\u0142eczno\u015bci trans i normalizujesz podawanie zaimk\u00f3w przez osoby, kt\u00f3rych zaimki nie s\u0105 oczywiste \u003Ca href=\u0022\/blog\/why-everyone-should-have-pronouns-in-their-bio\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-people-carry\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E (wi\u0119cej powod\u00f3w tutaj)\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["zaimki","pronouns","gender","p\u0142e\u0107","javascript","nuxt","vue"],"hasMore":true,"image":"https:\/\/avris.it\/image\/zaimki_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/zaimki_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/zaimki_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022181.04109589041\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EPolska gramatyka jest skomplikowana i silnie zgenderyzowana. Nie oznacza to jednak, \u017ce niemo\u017cliwe jest u\u017cywanie innych form ni\u017c \u201eon\u201d i \u201eona\u201d.\u003C\/p\u003E\n\u003Cp\u003ETo narz\u0119dzie udost\u0119pnia linki do przyk\u0142ad\u00f3w u\u017cycia (w prostych zdaniach oraz w literaturze, prasie, filmach i serialach) zaimk\u00f3w i innych form p\u0142ciowych \u2013 nie tylko normatywnych \u201eon\u201d i \u201eona\u201d, lecz tak\u017ce form niebinarnych.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/zaimki_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/zaimki_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022181.04109589041\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EPolska gramatyka jest skomplikowana i silnie zgenderyzowana. Nie oznacza to jednak, \u017ce niemo\u017cliwe jest u\u017cywanie innych form ni\u017c \u201eon\u201d i \u201eona\u201d.\u003C\/p\u003E\n\u003Cp\u003ETo narz\u0119dzie udost\u0119pnia linki do przyk\u0142ad\u00f3w u\u017cycia (w prostych zdaniach oraz w literaturze, prasie, filmach i serialach) zaimk\u00f3w i innych form p\u0142ciowych \u2013 nie tylko normatywnych \u201eon\u201d i \u201eona\u201d, lecz tak\u017ce form niebinarnych.\u003C\/p\u003E\n\u003Cp\u003EDlaczego nale\u017cy je respektowa\u0107? Bo zwracanie si\u0119 do kogo\u015b tak, jak sobie \u017cyczy, jest podstaw\u0105 relacji spo\u0142ecznych. Nie powiesz do Ani \u201cFranku\u201d, nie powiesz \u201cna ty\u201d do osoby, z kt\u00f3r\u0105 jeste\u015b \u201cna pan\u201d, itp. A s\u0105 osoby, kt\u00f3re nie chc\u0105, by im m\u00f3wi\u0107 \u201con\u201d ani \u201cona\u201d. Czy to uszanujesz, \u015bwiadczy wy\u0142\u0105cznie o Tobie.\u003C\/p\u003E\n\u003Cp\u003EWarto wrzuci\u0107 link do swoich zaimk\u00f3w na swoje profile na portalach spo\u0142eczno\u015bciowych \u2013 nawet je\u015bli jeste\u015b cis i u\u017cywasz \u201eon\u201d lub \u201eona\u201d \u2013 poniewa\u017c dzi\u0119ki temu pokazujesz wsparcie dla spo\u0142eczno\u015bci trans i normalizujesz podawanie zaimk\u00f3w przez osoby, kt\u00f3rych zaimki nie s\u0105 oczywiste \u003Ca href=\u0022\/blog\/why-everyone-should-have-pronouns-in-their-bio.lite\u0022\u003E (wi\u0119cej powod\u00f3w tutaj)\u003C\/a\u003E.\u003C\/p\u003E","words":177,"readTime":null,"lang":"pl"},"en":{"slug":"pronouns","title":"Pronouns.page","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/pronouns_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022360.10899182561\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEuUlEQVRIiY2XyXLjRhKGv8wqrJLIVtty2OOJ6YMPfv93mNPc5iUc0SORrYUEiKWq5gCgBJAQ5YxgBIDKyvxzT0pd10FECCEAICKoKmukqohI5DsnEcF7v\/jN+Ywxq3LnZIEIpt0daXdH0i8lofeoVcQqYhTfOGyREnpHcB4xSvnbl4WwEALe+whuDTTAjx\/P5ElKqhZTpkujAaZr6X2JvclINjn5rxvEKppYggsktxnu1IIIru4wZRoNmQOae+ucJrBJmpBkKWIvI6EAUYwKxe9bwigre7gj+VLQFVDRUv5+T\/7LHbd\/PPB0eF4A2e9\/RIV1XeOci6CedrsF4OA9NrFoatcBLaz0gXZ\/pHup47eqrnl9e4vvLy+vVHVFXQ88zjnqulqcd12PiNC2LcfjkaZpAGiahu\/\/e+RwOFyAAZC6roOMXgqdo3s9DQcIqoK9L1GznuSMPAHwzq1y9P3yuxpFYziH+3Maknp8qbuGo68AIc8znHPoa4+oIECaptSnE1mastlsBpFjZc0rc54\/53l2rYrhLGRFUZBmGdvthqqq8N5jjCKjYOccRnVRvt77q8l8\/n4O8JykruvI4RuHe2tmwubuXacQwnuZcskbQiAEv\/imoiAgRkl\/KhdndhITAH\/q6ffNewyngw+e\/\/vv\/5BkGTebW54f9yDwzz++8dOvv3x6F0CsXABaeKh\/aWi\/VzC5VeTT59f9M653ZEVGVuQYa\/\/2XbXK7Z8\/XwKKHmoc7tAiyML7k4vnNITieiOcMePPckdVESOkX1dCNlEnjld\/JE1TRMB5T1EUuL4DBGMNXdsBA5jtdrsYER9Vz1QQF4BWjFh26hAoioKmaajqGu88p\/rE29TEek+eZ1iboMZcHR1zWlP8Ee9iluV5TpZleO9xveNpt6PtWlSUqqrouo6mafDekWmCXhmgn4G6CigWgAhqBuUAN2UJAbquw3vHqWt4fHzi7fUN8QwJeqbkQ0Ur4VzjjVxTLkwd2SZ2tCpgrcUYgxrDdrul6Tr+2n9n97TD1d0qgM9oWlW89zjn6Pueruvey\/6jJPvIqmu8c29MXpsS+7yzny9tdhIuIpxOJ56fXzgcDyQ24du3fy2YnXNXK+kcwFrSfzY6IiAAay0IPDw8sLm74+lph6pyf\/+Fx8cnQgjYxNI2LWqUPMu5uSmjot1+j4xWex8QEb5+vY\/Kdrs9Tduw3WzI8zyCnHvbzvtIYGiCiU3ijFLVcdkaLqgoaZaOOaU49z6nEpvgvSdNM7x3gCw8kqQJCDjnCRCH9gWgiBSw1pCmSZzs1prY1MqyjAm+RqpKmiYURbG6Uxs1OHX0fReH9sV6UlVVuBbX+eI+V\/x3CuCjUj\/v2nMD7RzMoXP8dagXF6a\/SGH+HMK7hRAbZD\/em95FJBZCP3pcVKOR27LgH0USFzwRWc6yABxPJ9q2o24a7m5KnPf0vYuxttbQ9w4BfAjDChsGsM57GMEnxoAMO7rzfkx0jzUGRLgtC8K4PQ5yBygXa39iLSEMbrzzFtMH0BRUwXsIwqHwbDcbRiTEXj+P\/PnKsbocrWyYx+MxnnY+UE1Vs8gduVg\/5FzY2OVFJD6vKZzIeY8Cd8mQP8YYRIT\/A4gozUxo6rCGAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/pronouns_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022360.10899182561\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWe all have pronouns. They\u0027re those words that we use instead of calling someone by their name every time we mention them. Most people use \u201che\/him\u201d and \u201cshe\/her\u201d, so we automatically assume which one to call them based on someone\u0027s looks. But it\u0027s actually not that simple\u2026\u003C\/p\u003E\n\u003Cp\u003EGender is complicated. Some people \u201cdon\u0027t look like\u201d their gender. Some prefer being called in a different way from what you\u0027d assume. Some people don\u0027t fit into the boxes of \u201cmale\u201d or \u201cfemale\u201d and prefer more neutral language.\u003C\/p\u003E\n\u003Cp\u003EThis tool lets you share a link to your pronouns, with example sentences, so that you can show people how you like to be called.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/pronouns_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022720.21798365123\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEuUlEQVRIiY2XyXLjRhKGv8wqrJLIVtty2OOJ6YMPfv93mNPc5iUc0SORrYUEiKWq5gCgBJAQ5YxgBIDKyvxzT0pd10FECCEAICKoKmukqohI5DsnEcF7v\/jN+Ywxq3LnZIEIpt0daXdH0i8lofeoVcQqYhTfOGyREnpHcB4xSvnbl4WwEALe+whuDTTAjx\/P5ElKqhZTpkujAaZr6X2JvclINjn5rxvEKppYggsktxnu1IIIru4wZRoNmQOae+ucJrBJmpBkKWIvI6EAUYwKxe9bwigre7gj+VLQFVDRUv5+T\/7LHbd\/PPB0eF4A2e9\/RIV1XeOci6CedrsF4OA9NrFoatcBLaz0gXZ\/pHup47eqrnl9e4vvLy+vVHVFXQ88zjnqulqcd12PiNC2LcfjkaZpAGiahu\/\/e+RwOFyAAZC6roOMXgqdo3s9DQcIqoK9L1GznuSMPAHwzq1y9P3yuxpFYziH+3Maknp8qbuGo68AIc8znHPoa4+oIECaptSnE1mastlsBpFjZc0rc54\/53l2rYrhLGRFUZBmGdvthqqq8N5jjCKjYOccRnVRvt77q8l8\/n4O8JykruvI4RuHe2tmwubuXacQwnuZcskbQiAEv\/imoiAgRkl\/KhdndhITAH\/q6ffNewyngw+e\/\/vv\/5BkGTebW54f9yDwzz++8dOvv3x6F0CsXABaeKh\/aWi\/VzC5VeTT59f9M653ZEVGVuQYa\/\/2XbXK7Z8\/XwKKHmoc7tAiyML7k4vnNITieiOcMePPckdVESOkX1dCNlEnjld\/JE1TRMB5T1EUuL4DBGMNXdsBA5jtdrsYER9Vz1QQF4BWjFh26hAoioKmaajqGu88p\/rE29TEek+eZ1iboMZcHR1zWlP8Ee9iluV5TpZleO9xveNpt6PtWlSUqqrouo6mafDekWmCXhmgn4G6CigWgAhqBuUAN2UJAbquw3vHqWt4fHzi7fUN8QwJeqbkQ0Ur4VzjjVxTLkwd2SZ2tCpgrcUYgxrDdrul6Tr+2n9n97TD1d0qgM9oWlW89zjn6Pueruvey\/6jJPvIqmu8c29MXpsS+7yzny9tdhIuIpxOJ56fXzgcDyQ24du3fy2YnXNXK+kcwFrSfzY6IiAAay0IPDw8sLm74+lph6pyf\/+Fx8cnQgjYxNI2LWqUPMu5uSmjot1+j4xWex8QEb5+vY\/Kdrs9Tduw3WzI8zyCnHvbzvtIYGiCiU3ijFLVcdkaLqgoaZaOOaU49z6nEpvgvSdNM7x3gCw8kqQJCDjnCRCH9gWgiBSw1pCmSZzs1prY1MqyjAm+RqpKmiYURbG6Uxs1OHX0fReH9sV6UlVVuBbX+eI+V\/x3CuCjUj\/v2nMD7RzMoXP8dagXF6a\/SGH+HMK7hRAbZD\/em95FJBZCP3pcVKOR27LgH0USFzwRWc6yABxPJ9q2o24a7m5KnPf0vYuxttbQ9w4BfAjDChsGsM57GMEnxoAMO7rzfkx0jzUGRLgtC8K4PQ5yBygXa39iLSEMbrzzFtMH0BRUwXsIwqHwbDcbRiTEXj+P\/PnKsbocrWyYx+MxnnY+UE1Vs8gduVg\/5FzY2OVFJD6vKZzIeY8Cd8mQP8YYRIT\/A4gozUxo6rCGAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/pronouns_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022720.21798365123\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWe all have pronouns. They\u0027re those words that we use instead of calling someone by their name every time we mention them. Most people use \u201che\/him\u201d and \u201cshe\/her\u201d, so we automatically assume which one to call them based on someone\u0027s looks. But it\u0027s actually not that simple\u2026\u003C\/p\u003E\n\u003Cp\u003EGender is complicated. Some people \u201cdon\u0027t look like\u201d their gender. Some prefer being called in a different way from what you\u0027d assume. Some people don\u0027t fit into the boxes of \u201cmale\u201d or \u201cfemale\u201d and prefer more neutral language.\u003C\/p\u003E\n\u003Cp\u003EThis tool lets you share a link to your pronouns, with example sentences, so that you can show people how you like to be called.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["pronouns","gender","javascript","nuxt","vue"],"hasMore":false,"image":"https:\/\/avris.it\/image\/pronouns_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/pronouns_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/pronouns_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022180.05449591281\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWe all have pronouns. They\u0027re those words that we use instead of calling someone by their name every time we mention them. Most people use \u201che\/him\u201d and \u201cshe\/her\u201d, so we automatically assume which one to call them based on someone\u0027s looks. But it\u0027s actually not that simple\u2026\u003C\/p\u003E\n\u003Cp\u003EGender is complicated. Some people \u201cdon\u0027t look like\u201d their gender. Some prefer being called in a different way from what you\u0027d assume. Some people don\u0027t fit into the boxes of \u201cmale\u201d or \u201cfemale\u201d and prefer more neutral language.\u003C\/p\u003E\n\u003Cp\u003EThis tool lets you share a link to your pronouns, with example sentences, so that you can show people how you like to be called.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/pronouns_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/pronouns_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022180.05449591281\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWe all have pronouns. They\u0027re those words that we use instead of calling someone by their name every time we mention them. Most people use \u201che\/him\u201d and \u201cshe\/her\u201d, so we automatically assume which one to call them based on someone\u0027s looks. But it\u0027s actually not that simple\u2026\u003C\/p\u003E\n\u003Cp\u003EGender is complicated. Some people \u201cdon\u0027t look like\u201d their gender. Some prefer being called in a different way from what you\u0027d assume. Some people don\u0027t fit into the boxes of \u201cmale\u201d or \u201cfemale\u201d and prefer more neutral language.\u003C\/p\u003E\n\u003Cp\u003EThis tool lets you share a link to your pronouns, with example sentences, so that you can show people how you like to be called.\u003C\/p\u003E","words":112,"readTime":null,"lang":"en"}}},"projects\/sumup":{"key":"projects\/sumup","type":"article","published":true,"meta":{"createdAt":"2020-06-16T14:48:41+02:00","publishedAt":"2020-06-16T14:48:41+02:00","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/sumup.avris.it","displayUrl":null}],"category":"projects","subcategory":null,"slug":"sumup"},"content":{"en":{"slug":"sumup","title":"SumUp","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/sumup_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022330.36077705828\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADgElEQVRIicWWzW4cRRDHf9UfM7O7idf22gE7ENsCiQtcIiEU5Rl4Aq48CScehMfgyAkJjpEiIQUJE8XGMpbxfk13V3OY3bWd7K690SL+0kgzrerpX3dVdZXkRogIb+vi9Rm+9HR6XW7aLHsHEJHZ+M2x+9i4dygmCqOaH779Hld6nn\/3DXVdoznjrKUOgaOjQx7t7i6a\/t5aCORKzxdfP6fqtDg4eIKqUlUtxuMx\/UGfrc3NtcMAyCKXqSonJyeIMRTek1Sp6xrnHCJCDBERwRgBEVJKWGshg2ZFk1IUBSKQUiLn5p\/OOYqiYHOzO9dlZhFpVmV00SePI+ev\/0JDoixKqrJEk1JVJWVZIGJw1iKAEYP3jqyZVqsCAURQzRgjbHa7dGxBt7ux+gnlnAnjcG1oBOPsezhhvqwxqwV1zpmgifF4TAgR5yzGGGKMgGCMQTVRFAVlWZFSZDAYYK0lhNC4byJjDIgggPce5xy2LOauuxDoprx3qOokFprjh2Z3zTO1bHbrnJttyhqD5owBQozkzC3YlYCstXQ3rv191b+i3x\/iHLTbLVpVC2iCGKCsSgrv8ROgq36fB53ObH6IgfE4kFQXrrk0y676Ay4vL\/HiMEExzqJJySlhvEOTYr2l1X2A8Q5yBpoTu44PgMzsGCfxUpXFajEEUBQFOzs7pBDRkEAgJ0VsExNoBgExC5N1ZS0FqvtDXv74CyJgnKW99ZB\/Tv9m4+ARnY96XLw4pvfJY7YeP1ob0FKX1TFClqkl5NvuIEOejCP89y4bD0dAxntPHQLWNNkRU7wV7OvUUqBpCRAxkDOqTdpnvU756S5jjJydnTEcjdjf25uUjcXVfmUgYwzHP72gu9\/jydPPFrYcsx85x+nPv9E73KM8LO9ceGUgaNye0+I746ZSSmw\/PcI6x\/Hxn4gI+\/t76wXKOXP+xykPP9hm6+PlmWSt5fzXV2hMIIKvCq5evsFXnqNnn68HaKp53eTbSimx++Wn1HVNu91mNBrRarXo9bbvDXMnkLEW65tW5C5Za2m9+p0Pn301tz29rxbeQwAaJ8V0cjP\/rz01gFiDuWe6rktL+6G6rhERbKhRbxBpepg8yT4jgvHuHdjpd4qxqX3GoDFgvZ9e1Dg\/f+mlQIPhEEFoS6ZfK5WHqAnNmcI6YlKqJV2kqqKT3lvTiBR0VjrsRmfunH8Bdwwal0oloW0AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/sumup_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022330.36077705828\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ESumUp is a simple tool that shows all possible combinations of numbers that add up to a given sum.\nIt\u0027s useful for certain types of puzzles, like for example\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=hOAB65KFl6I\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E this killer sudoku\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/sumup_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022660.72155411656\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADgElEQVRIicWWzW4cRRDHf9UfM7O7idf22gE7ENsCiQtcIiEU5Rl4Aq48CScehMfgyAkJjpEiIQUJE8XGMpbxfk13V3OY3bWd7K690SL+0kgzrerpX3dVdZXkRogIb+vi9Rm+9HR6XW7aLHsHEJHZ+M2x+9i4dygmCqOaH779Hld6nn\/3DXVdoznjrKUOgaOjQx7t7i6a\/t5aCORKzxdfP6fqtDg4eIKqUlUtxuMx\/UGfrc3NtcMAyCKXqSonJyeIMRTek1Sp6xrnHCJCDBERwRgBEVJKWGshg2ZFk1IUBSKQUiLn5p\/OOYqiYHOzO9dlZhFpVmV00SePI+ev\/0JDoixKqrJEk1JVJWVZIGJw1iKAEYP3jqyZVqsCAURQzRgjbHa7dGxBt7ux+gnlnAnjcG1oBOPsezhhvqwxqwV1zpmgifF4TAgR5yzGGGKMgGCMQTVRFAVlWZFSZDAYYK0lhNC4byJjDIgggPce5xy2LOauuxDoprx3qOokFprjh2Z3zTO1bHbrnJttyhqD5owBQozkzC3YlYCstXQ3rv191b+i3x\/iHLTbLVpVC2iCGKCsSgrv8ROgq36fB53ObH6IgfE4kFQXrrk0y676Ay4vL\/HiMEExzqJJySlhvEOTYr2l1X2A8Q5yBpoTu44PgMzsGCfxUpXFajEEUBQFOzs7pBDRkEAgJ0VsExNoBgExC5N1ZS0FqvtDXv74CyJgnKW99ZB\/Tv9m4+ARnY96XLw4pvfJY7YeP1ob0FKX1TFClqkl5NvuIEOejCP89y4bD0dAxntPHQLWNNkRU7wV7OvUUqBpCRAxkDOqTdpnvU756S5jjJydnTEcjdjf25uUjcXVfmUgYwzHP72gu9\/jydPPFrYcsx85x+nPv9E73KM8LO9ceGUgaNye0+I746ZSSmw\/PcI6x\/Hxn4gI+\/t76wXKOXP+xykPP9hm6+PlmWSt5fzXV2hMIIKvCq5evsFXnqNnn68HaKp53eTbSimx++Wn1HVNu91mNBrRarXo9bbvDXMnkLEW65tW5C5Za2m9+p0Pn301tz29rxbeQwAaJ8V0cjP\/rz01gFiDuWe6rktL+6G6rhERbKhRbxBpepg8yT4jgvHuHdjpd4qxqX3GoDFgvZ9e1Dg\/f+mlQIPhEEFoS6ZfK5WHqAnNmcI6YlKqJV2kqqKT3lvTiBR0VjrsRmfunH8Bdwwal0oloW0AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/sumup_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022660.72155411656\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ESumUp is a simple tool that shows all possible combinations of numbers that add up to a given sum.\nIt\u0027s useful for certain types of puzzles, like for example\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=hOAB65KFl6I\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E this killer sudoku\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["sudoku","numbers","puzzle","logic","svelte","javascript","js","nodejs"],"hasMore":false,"image":"https:\/\/avris.it\/image\/sumup_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/sumup_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/sumup_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022165.18038852914\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ESumUp is a simple tool that shows all possible combinations of numbers that add up to a given sum.\nIt\u0027s useful for certain types of puzzles, like for example\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=hOAB65KFl6I\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E this killer sudoku\u003C\/a\u003E.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/sumup_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/sumup_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022165.18038852914\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ESumUp is a simple tool that shows all possible combinations of numbers that add up to a given sum.\nIt\u0027s useful for certain types of puzzles, like for example\n\u003Ca href=\u0022https:\/\/www.youtube.com\/watch?v=hOAB65KFl6I\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E this killer sudoku\u003C\/a\u003E.\u003C\/p\u003E","words":32,"readTime":null,"lang":"en"}}},"blog\/technology\/redesigning-a-website-naked-adventure":{"key":"blog\/technology\/redesigning-a-website-naked-adventure","type":"article","published":true,"meta":{"createdAt":"2020-05-23T22:45:46+02:00","publishedAt":"2020-05-23T22:45:46+02:00","group":"redesign","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/naked-adventure.eu","displayUrl":null}],"category":"blog","subcategory":"technology","slug":"redesigning-a-website-naked-adventure"},"content":{"en":{"slug":"redesigning-a-website-naked-adventure","title":"Redesigning a website: Naked Adventure","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-revamp_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022323.41488807913\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHx0lEQVRIiaWWy48cVxnFf\/dRr65+THfPjD0zHj\/iJI5IFAnHJBHEioJAiCAkImUHiC0LFglISKxZwJ+AEiGxgA0SAgmxCAvEBhZBCQ85ColfsROPZzzueXV3dT3uvR+L9kxiQjbkbKpUdUvn3O+c77ulnvre7yUxiuVehtYah8EYTTuP0FqDUhSVwzshBEGUIo00mTRMVMysFuqm5trlEf1ejgTHeFzwQPdPRHrKv29qVpd63L57gFKKOI5JEnhoeAenh+RmG60bnAp02zn2hfWGTEM3DmSxJWl3aecxJ9f6LK\/1McYQghBCYFY0RGlMUQtRrHFBcVB4alfzzZ9ucTCpsKoheIfWnuVOwWihw82NEdpoEGGx3+LFL18Ev81b\/3qNPAZvLAZHXY2xiYZWZGillsgo2rail0bgS+5sbaAjTfAeazRLx1aIs4yWKKomUNZCP7aUpRBZTZxoZqVClGah1XBr3zJzFqUcwXlEhGJaMZ3cQIdAJ824vG1Z6lSs5AmJK7HPPnkGAgQfGB8UaF+jfAWNZlrOyAdtRAnGRKR5glcG8UISG6wVahfwQROphtnU0W1pGkru7jVcvgF1s4PWljhNcFXN8UGLWzc3ePv9PTA91lq7dIPgSkuoNXby3l\/oL51gcXWV9OQQBFCgECYzodaC7fbJshwdR2gJWB2Q4BEViJXHuBkqlCy0EopZgW9K9sISSbRNEkVEcYr3jrzT4sK6ZWD3OPeYZTytmLkeeewZFYrltePYevsm195\/j+23Y9bWThBFhlZnAZN1GAwHxMMhujtABPzuNlUjNEFRV55JUVFUnp29A8QVBO0wUlOWE37245fp9hZ4b3NKEOHJR\/pEBowxfBKUUtjW8mk6CJGG0sMsCAfS0DWgixLTqRBREAJeBKUEowJWO1qxYEQwHUtV7INL0MqDmwKBwSBGZQLATl0D9wxQIAJxZI\/EZMbQSyLs09\/6LlVVsbm5yfr6+rzVPwGm1fufz6uqQurf4aWiqEqapgQJJAi5r8mzjCRN+cUfb\/C3d3fwrqBtJhw\/cZrNvZpqb4Ozi56Xvv08FkBrTavVYjweA9DpdJh5zdZ+gUIxDjEdtpk0W+yFFbQfYXTFQpLwwOJZACazBt0o2mZGCCUi866K4xhjLd57lswGZ5vXWe8I7WOr\/Py1PzDZuc1J\/S7m\/JPA81ilQJmIie6jyymdyANQOMWbey1SDqiC4BtNphWTsqITrpC0YqYzODM8AyjGdy6D0qSLXaqiQEIghMBkPKGpa7rdLmsLUC136VrIO22+9NmEY9lpHlh9GpcM5xkSAQXksUbbBGsC3ntAIwLVdJM33tljtR+wMuWJczOKKiFKDJE1KKUQwNdjlNJUBYhvUAijSeDGSKNNQG7v8tDpR1hZPUOn1yXLMh5+fBejNL2FeRREZG6ZiOBcg7UxThqKsgYbgVL47AwPr7zBqeGEK9cnSK1pRwlJlDKMM6zSNAR8PUEpDT5iNp0ymYy5M9vizSt3CQEiHAfnVtmcBJSu6aYGWxZs71WU02ucOtbi4hNrWKUUu7PA9397wDDX1E4oauGFJww6i2nKESoIt\/aHdAddtkZjuoMVboc1VLjLksy7aPXzP0CZmGP9iOmkIO2uYPxfCfUrCOCA6p1naa5ewhpF1V3mN3++wgcf3CSKIr7w7HN85eJPsCJClo754jOvkpkcEGa+4NHlr7OefobgcqL4PE7FGAJN3RCbeQMrtYI1Md5V82kKFKVHmM+bB9e\/yHLvUbIkJUkTXn\/tV2SxIwRoRY5zJ4+zNIhZWBhiIosxZm5ZIi2+ln+Hfr9PnufIvV0rpRDpsLGxQZ7ndHo9iO7l5iNr5rY7CBqrYeYaQEjjnGFvlSzLUEox7C\/yfujTHyRESZ9HL5wh67SoixnLaycB5pYZY8jzHGMMInJEckio4pzSQVQ7Yq3QWn1s4gZXo3QgNAZXzxAJxHFMHMdHa85e+AanHv8q\/cEQrTWTyQSjIMvbR1xWRAgCe9OGSelYHiiiKLpPVKwcdV2zvzNDHVVOiKKI4XA4F9QUKG1pKoOSCpCjKh5iey9QNpqbox12Nt7iqc+dJ05beO9pmoYsy+aWKQV5q4XWCo8lvifmkHi\/STDeEqeBNI7QzHefpimHultqRukNo50KcRXB+\/uqLCJcvT3m+t2CNLUcXLnGr3\/5KosLbbwIKycf5KWXfzi37N5X+CD44FHq0I65fScX06M5cX\/15CjMYTYikOLrCvE1BP8x60c3\/sHW1esUtePO+29x8cFF9rc3cM5xqvvwh5YZrVnII6y19wX2kNRay0fx3+8B6mqG6BpflQRfHx0dH8Vzz5znwmOnSbMWcfQiabuLNZq83TniPWISZWkCOC9oBVqDD2DvXfX8DxQFBEADRivMvbNY3D6VA1fXiG+Q8HHL+oMhvYU+aTqvuHMOrfV9HWsvXbrEp0Vd17jpPsZGVGWBiONHr\/yT5eMjklhRlnORVVnQ1AWprimLA6rigLMnemxtbrKzcxfxDXZ3d\/dTC2qahtBMqGqFb+b5ufrBPptFG60E39SEpkLCjGKyTyQzivEOrtynHa\/z90vvMrq7jfgafViqQ\/y\/92VVIL4iuA8zFLxHiQfxKOWJjNBKFHVdg3hEPJev32Jvb8xhFv8DbBYDPiGD0eUAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-revamp_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022323.41488807913\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EYet another one of my projects, \u003Ca href=\u0022\/projects\/naked-adventure-de\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Naked Adventure\u003C\/a\u003E,\ngrew too outdated to support it. I had to rewrite it from scratch.\u003C\/p\u003E\n\u003Cp\u003EI took the opportunity to redesign it as well. (screenshots before \u0026amp; after at the bottom)\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-revamp_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022646.82977615825\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHx0lEQVRIiaWWy48cVxnFf\/dRr65+THfPjD0zHj\/iJI5IFAnHJBHEioJAiCAkImUHiC0LFglISKxZwJ+AEiGxgA0SAgmxCAvEBhZBCQ85ColfsROPZzzueXV3dT3uvR+L9kxiQjbkbKpUdUvn3O+c77ulnvre7yUxiuVehtYah8EYTTuP0FqDUhSVwzshBEGUIo00mTRMVMysFuqm5trlEf1ejgTHeFzwQPdPRHrKv29qVpd63L57gFKKOI5JEnhoeAenh+RmG60bnAp02zn2hfWGTEM3DmSxJWl3aecxJ9f6LK\/1McYQghBCYFY0RGlMUQtRrHFBcVB4alfzzZ9ucTCpsKoheIfWnuVOwWihw82NEdpoEGGx3+LFL18Ev81b\/3qNPAZvLAZHXY2xiYZWZGillsgo2rail0bgS+5sbaAjTfAeazRLx1aIs4yWKKomUNZCP7aUpRBZTZxoZqVClGah1XBr3zJzFqUcwXlEhGJaMZ3cQIdAJ824vG1Z6lSs5AmJK7HPPnkGAgQfGB8UaF+jfAWNZlrOyAdtRAnGRKR5glcG8UISG6wVahfwQROphtnU0W1pGkru7jVcvgF1s4PWljhNcFXN8UGLWzc3ePv9PTA91lq7dIPgSkuoNXby3l\/oL51gcXWV9OQQBFCgECYzodaC7fbJshwdR2gJWB2Q4BEViJXHuBkqlCy0EopZgW9K9sISSbRNEkVEcYr3jrzT4sK6ZWD3OPeYZTytmLkeeewZFYrltePYevsm195\/j+23Y9bWThBFhlZnAZN1GAwHxMMhujtABPzuNlUjNEFRV55JUVFUnp29A8QVBO0wUlOWE37245fp9hZ4b3NKEOHJR\/pEBowxfBKUUtjW8mk6CJGG0sMsCAfS0DWgixLTqRBREAJeBKUEowJWO1qxYEQwHUtV7INL0MqDmwKBwSBGZQLATl0D9wxQIAJxZI\/EZMbQSyLs09\/6LlVVsbm5yfr6+rzVPwGm1fufz6uqQurf4aWiqEqapgQJJAi5r8mzjCRN+cUfb\/C3d3fwrqBtJhw\/cZrNvZpqb4Ozi56Xvv08FkBrTavVYjweA9DpdJh5zdZ+gUIxDjEdtpk0W+yFFbQfYXTFQpLwwOJZACazBt0o2mZGCCUi866K4xhjLd57lswGZ5vXWe8I7WOr\/Py1PzDZuc1J\/S7m\/JPA81ilQJmIie6jyymdyANQOMWbey1SDqiC4BtNphWTsqITrpC0YqYzODM8AyjGdy6D0qSLXaqiQEIghMBkPKGpa7rdLmsLUC136VrIO22+9NmEY9lpHlh9GpcM5xkSAQXksUbbBGsC3ntAIwLVdJM33tljtR+wMuWJczOKKiFKDJE1KKUQwNdjlNJUBYhvUAijSeDGSKNNQG7v8tDpR1hZPUOn1yXLMh5+fBejNL2FeRREZG6ZiOBcg7UxThqKsgYbgVL47AwPr7zBqeGEK9cnSK1pRwlJlDKMM6zSNAR8PUEpDT5iNp0ymYy5M9vizSt3CQEiHAfnVtmcBJSu6aYGWxZs71WU02ucOtbi4hNrWKUUu7PA9397wDDX1E4oauGFJww6i2nKESoIt\/aHdAddtkZjuoMVboc1VLjLksy7aPXzP0CZmGP9iOmkIO2uYPxfCfUrCOCA6p1naa5ewhpF1V3mN3++wgcf3CSKIr7w7HN85eJPsCJClo754jOvkpkcEGa+4NHlr7OefobgcqL4PE7FGAJN3RCbeQMrtYI1Md5V82kKFKVHmM+bB9e\/yHLvUbIkJUkTXn\/tV2SxIwRoRY5zJ4+zNIhZWBhiIosxZm5ZIi2+ln+Hfr9PnufIvV0rpRDpsLGxQZ7ndHo9iO7l5iNr5rY7CBqrYeYaQEjjnGFvlSzLUEox7C\/yfujTHyRESZ9HL5wh67SoixnLaycB5pYZY8jzHGMMInJEckio4pzSQVQ7Yq3QWn1s4gZXo3QgNAZXzxAJxHFMHMdHa85e+AanHv8q\/cEQrTWTyQSjIMvbR1xWRAgCe9OGSelYHiiiKLpPVKwcdV2zvzNDHVVOiKKI4XA4F9QUKG1pKoOSCpCjKh5iey9QNpqbox12Nt7iqc+dJ05beO9pmoYsy+aWKQV5q4XWCo8lvifmkHi\/STDeEqeBNI7QzHefpimHultqRukNo50KcRXB+\/uqLCJcvT3m+t2CNLUcXLnGr3\/5KosLbbwIKycf5KWXfzi37N5X+CD44FHq0I65fScX06M5cX\/15CjMYTYikOLrCvE1BP8x60c3\/sHW1esUtePO+29x8cFF9rc3cM5xqvvwh5YZrVnII6y19wX2kNRay0fx3+8B6mqG6BpflQRfHx0dH8Vzz5znwmOnSbMWcfQiabuLNZq83TniPWISZWkCOC9oBVqDD2DvXfX8DxQFBEADRivMvbNY3D6VA1fXiG+Q8HHL+oMhvYU+aTqvuHMOrfV9HWsvXbrEp0Vd17jpPsZGVGWBiONHr\/yT5eMjklhRlnORVVnQ1AWprimLA6rigLMnemxtbrKzcxfxDXZ3d\/dTC2qahtBMqGqFb+b5ufrBPptFG60E39SEpkLCjGKyTyQzivEOrtynHa\/z90vvMrq7jfgafViqQ\/y\/92VVIL4iuA8zFLxHiQfxKOWJjNBKFHVdg3hEPJev32Jvb8xhFv8DbBYDPiGD0eUAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-revamp_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022646.82977615825\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EYet another one of my projects, \u003Ca href=\u0022\/projects\/naked-adventure-de\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Naked Adventure\u003C\/a\u003E,\ngrew too outdated to support it. I had to rewrite it from scratch.\u003C\/p\u003E\n\u003Cp\u003EI took the opportunity to redesign it as well. (screenshots before \u0026amp; after at the bottom)\u003C\/p\u003E\n\u003Cp\u003EHere\u0027s an overview of what I did:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ereplaced my abandoned framework \u003Ca href=\u0022\/projects\/micrus-v4\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus v4 \u2022 Beauty of simplicity\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/symfony.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Symfony 5\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Ebased the project on \u003Ca href=\u0022\/projects\/avris-booster-quick-start-of-new-projects\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avris Booster: Quick start of new projects\u003C\/a\u003E, to take advantage of built-in features:\nuser management (including a passwordless approach to authentication \u2013 \u003Ca href=\u0022\/blog\/passwords-are-pass%C3%A9\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Passwords are pass\u00e9\u003C\/a\u003E), push notifications, etc.\u003C\/li\u003E\n\u003Cli\u003Ereplaced \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Micrus-Assetic\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E custom Assetic setup\u003C\/a\u003E\nwith \u003Ca href=\u0022https:\/\/symfony.com\/doc\/current\/frontend\/encore\/installation.html\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Webpack Encore\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Eupdated \u003Ca href=\u0022https:\/\/getbootstrap.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Bootstrap\u003C\/a\u003E from 3.0 to 4.4,\u003C\/li\u003E\n\u003Cli\u003Eadded more contrast to the design, filled the excess of white spaces with content, making filters and maps more prominent,\u003C\/li\u003E\n\u003Cli\u003Ereplaced Google Maps with Apple Maps, because of privacy concerns (see: \u003Ca href=\u0022\/blog\/ungoogling\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Ungoogling\u003C\/a\u003E, \u003Ca href=\u0022\/blog\/log-out-for-privacy\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Log out for privacy\u003C\/a\u003E) \u2013 the website is now officially Google-free,\u003C\/li\u003E\n\u003Cli\u003Eremoved a couple of unnecessary and unused features:\n\u003Cul\u003E\n\u003Cli\u003Ethe homepage (now the user is shown the map right away \u2013 after all, the map is the whole point of the project),\u003C\/li\u003E\n\u003Cli\u003Ethe \u201dgeographic\u201d links (there\u0027s no separate map of e.g. German nude beaches anymore, it got integrated into the main map),\u003C\/li\u003E\n\u003Cli\u003Eseparate events section (now they show up together with places on the same map),\u003C\/li\u003E\n\u003Cli\u003Eforum (it wasn\u0027t used at all),\u003C\/li\u003E\n\u003Cli\u003Eadmin panel (now the buttons for admins are just integrated across the website),\u003C\/li\u003E\n\u003C\/ul\u003E\u003C\/li\u003E\n\u003Cli\u003Eimproved filters (for instance added filtering by name and location),\u003C\/li\u003E\n\u003Cli\u003Ethe process of submission of new steps isn\u0027t split into steps anymore: place info, review and description are finally just one single form,\u003C\/li\u003E\n\u003Cli\u003Eincluded some more \u003Ca href=\u0022\/blog\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E optimisations\u003C\/a\u003E.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Ch3\u003EBefore:\u003C\/h3\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-before-home_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221147.3333333333\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAkCAYAAACe0YppAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHV0lEQVRYhc2XS48dVxWFv30e9bhV97offsUPHJLYMpFQeCTioUiIARIC8Q9QxvwAxvyijBig8AMACSkSgQFECbZjE8duu93dt\/s+quqcvRlcu7svcRIYEFjDe+4+66y99llVJaO33jGe4tr5BlQBmPcZL8L+fGBSB6aLxJlRYNZl2jKwNxvokvJZEOBbX6nYvfuYT8KEunDsz9PxevjljSMcUAoUYUFdlBQxEooCQkGMYzYnkbObNXVTYghlFXDOkfpEVmXoMvN5QoJHRMgIQzYyjhheQg2cd8w7YzFAXTpCHR1RhNIZUYTK9ZRO8SKE4CkjxKyEFDk3aambipSUsozo0+44JxxN5yQVmrbicJ4YFGJ0eC+YCcmMo4WBgHMQNCXMe0wcMQZidIAS6aljoCodo5GnKozoFeeUGAQfBDGH5Yw4aNqI4YlVpBqXmK36rQqH88x8kYnFitQ7CG0ViSLUwVEXEINDEGJwBAacCYGI08TdO\/eQwmFOQQTnhGG+wATOn7\/I+YuXwDnEOfpB6QYjqeG8Y9IKApgZ3WCEN75+FTEFNQQYktL1inYLggePYqlHkzCuW3Zne5RtBCekviMGY9SM2dyY4KOQbNVaNaGMwsgLqsaQjT4pGXBBCOOREIoWyxnvQFXoFksWc8NpxovhJCPWYcNALYnaFdSbEwgR74Sh7wltg68qyEZWoxRBBLIaiBH8ahbMwDDCw7+\/y9a5S9R1RdOOGZ1pkLMtpg3Oe8Q5ADQNdMsF3d4MrOfwcErRjjEXERfJGGaKE0PciswwnBjmDGy1bqqYGaF99Ece38087iqIFW+8dp1z117FO4\/zHmTlmQuB5kxke\/sqyUcO+wFXNEy2zhG8QE6Qe7IqlpWcVwSalKxKSpmUMzkrqkbYyRcgwAvjEi\/Cw7u7HDz4A2V0mCnjjS2qUYvFiqKuaTY38KOW7XELVYE4sOUUm89Iy4F+gCyOrELKRt9nll3PvOvpE3TLnsNlTxhXBajiyThTvBna9XQDmDjSkz047Gm3ztKIEKf7jJxCXUBKoAnSQF7MyUNGTPDicQCaUVUKG5hs1PSDktqASUM4\/43vIRgOwTtwrIZiFXqQcYgviUWBRM8QPV1dEXyDxBFQQLUFocWp4syOffSqFKrkIdMte4wBCSsrRFWPs\/rLRJCVPADefvttbt68yfXr1ynL8lN\/7jOcHPNpNAE6zBHAR49SgHZoVnz0wCoJRYTCF8d7rSm+ffs2dV0jIgzDAEDbtmxsbABw50mHLQ9XbRfHnUXF+VoZ2RP6dMTt6S325fs09meyFSABZ\/s0Qfjqxktc2b56ovi0oo0L11ADzYlJvUREGI\/Hx+sfLUp25iXMYOQWdCbcXxa0aZ+MUriGIQl\/u1dy44UnhCIjElgk5db+h2vE7jTx7kyZLpXpbMHuYccwDMxms+d6FPNDdHGfnJR7R5dx6nl0UBBD4JXxfbz1CIZ0iWBGGYq1+jWPt5vVOaweYwZeF6SUGIaBolgVikAxPODegwfcvn+EazMXNpVFPOCv7z\/mR9\/5C\/WlMft7M6oYkRK8c5TBcZprrdVPZkpSw1uHt4EmQhnXmrI6WKzZvnyDOzt\/osqf0C4esHso\/PT1CVsjZaCkn2SqGDEyRSjYCqPTO5wmNrYat3pbkBFJofCrKV4sjo4VYzBwhpQXbG5O+OaVGU29wXsfHPHBrUNeeTFjAUo8osJ43FBJyUROa5TTxMKv330EcbTWkhUcL59bQlk9u0GEWLPZjrn1jx0uTHo+uJu5erGmCRX7yxnjdsK8uMbjTrk62sMV59Y9NjvJj99+6HgwnfG1C5Gdo0xwwnIwDpbKj1+t+e7NiFPl\/Y8e8YOXdykvZX7zu4ILL77Om9\/eQXzLO+99yJs3PHv5LI9mm4Dj4HDJa9sLxpMTLrFTzL\/4\/U94tPyEcdzA4UBglg5JOvDDiz\/j5y\/+ij4r89khk1IpYmDGGMQjopSy4PHU2K4zmKx8AcQ5vBPa5uRq\/s8ic21kP\/74Y7quY7lc\/lvFBwcHHB0d0XXdf0y8do+HYWBnZ4e6rqnr+guLp9Mp3ntUlStXrjxnKJ\/hJNePiU8PV1VViAgigqp+zkYrLKyin\/d4J9zf3WVjvIUnYZoJIRDC6Su07uh6gMyNIWWcDCy7h1y+dPFziTdroQ+CqZEWC\/aW9wEQEcwMM8M5h6oyGo3Y2to6IV6pWrXi8nZDCP64uO97gOc+IgE6qVEfMWcIhi8AdQTJ5LSKWe89ZVlSVdXzFK9a2kvFfIDgQJzHJ2Gr8Z+h12gKIQ1GcI6UFdWBUVkBDovhWECM8bjmGdeaxz4dUYZAzhlLRtO2mH06q59hUFgmqMUwgxDcsULv1w98wvP0bp8OkHuPjhBxGEJwSigqthuH+4Ih+2J8eqrXAmS5XGJmx978N\/H\/kVxfJsK\/\/vBkrtRRGDKoGe7px9coCtOl4p1QxdVTy8yoC0c3GKNS2JspmyPHwUKZ1I7pQinC6n29juse\/xPzaJzjyI4XIAAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-before-home_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221147.3333333333\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-before-map_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022911.20234604106\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAiCAYAAAA3WXuFAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAKPElEQVRYhcWYSYwk2VnHf++9eLFkZORamZWV1bX1NnTPdGMPHgwDshjbhznYt\/FyQliIAyfEhSPiAAIhS3O1sBC++MAiGYQBGazB7WHG46Vtpj0zraarl6qacm1dWVlZWZEZ6+OQldGT08NIRkh8Uii2F+998f\/+3\/\/7IgQv\/a0Bw5ULbZw8IUoyhBDkxrB9OGJ5rsR\/7ZzQbXiEUUZuDFpJjsOElVaJQZhwdJowijLAAIKJffDxfM1hoWZj0ojSuzv8QDV5rh3xw32HLAPxlX9dN\/x\/mTEgxOM9IIwxBmA4HOL7PkKID53jw+c3xfP\/22M5PXn55Ze5ceMGN2\/enFng5zn+vzCR57nJsow3dr5HmqcfOGipvEwq19jZvMfqyipHR0cIKdgTdc7pEVprtNaQDrl753t0a13ssuZOVGKQ12hmrzEOU3K3hZQ5ILFMD0FO2Qk4FyzRrrYJ3ABr+pZ\/9tYfE+cxLbdFmIZIIUnzlH58xJcu\/g7X5lYR1QV2x4JUV5BCMBjB3dRFjMBgUFlC4Odsm0OssQVpzJjn6ZnzGFfi8TNMHqGJSI0EkzKKQx4ND2hVW5OwGWNMkiREUfQ\/wygEr\/dcHg7PzpnkjStSmnKXvaxNho00EaV8i0w6+OYeg2yRYb7Mj974N168muDWNRN8IBMuIg8RgFKSFy59Gt\/2JxwC2NjYYGdn58Pji0Fg4GwfG4Gb3scyIWmSEaWKhz2Na0mS1JDKOSr2kJeeFWhlMCafzDE2OFGMpTSOtmm6ZdRZLskpKR3HodlsEkURxhiiKCJJEvI8Lxwy082AIiPr3+L12xbf+s4PUJZgNBpRcSTZ6SP+6K92cU2fitpD2eBVHFxbo5VElxWlqoWjBLYlEdLFmIlHBUL1ep3BYEC\/38cYQ7\/f5\/j4GCEESqlZjwAr6TOvdjl\/ZYWdg33+5l\/e4Ctf+2vc01scHW\/zhV82LIv7tPM9atUyyTgnH+W4UuM5GqUknmvhWhpfKaRglkPD4ZDxeIwQAtu2CcOQRqOB53lEUcSrB5qN4XvDN8nIYX+Tk\/4jRonHx1sP2AsNJ72IjzxVxVEujZrHOIkZpGMkEqkhyzKUkATao6JrBOmIoP0Mti5NsmxK3CzLsCyrEKs8z98nlO\/RHyao7R0LWp7kWvNndNo1alHMK4cZcZhya3\/A+UYPO9DM1SqkYUoaCeo1HyuXeMrBNxkCiRLvC1mWZURRhOM4jEYj6vU6juPMsto8ua0tLXN\/O6TmCsJwzHd\/sk8y2OOffnzI85crLDWaqFzQ2xkgKVOpdRmk58hEAIBWkhE1onyCjcjz3KRpysHBwaSo5jmWZeH7\/uPwTNP+ZFahk3iE45Qop\/d45Y23+eQVh+MQYuGydeRyuXnIvKeplgV1v8Sd7CqJsTAI6vltOu6IxaCN5V1EapuqDdY0JH\/62pjVquTWXoLnOmgrA2AhUPzer5YRWY6XDEhlidSyGQ5POd78Dl98tkGcG15PEgb+b2DVJX7cZ7l2yK74GO88\/D5X5zOSxGJUrmCiI6Tlssd1dt7+ZwbthGqrwkp3ESHkY1J\/8819qrZhP8yRUpLnBstSNMouH19yGKSKcRSTIzFCEA+PMeNjmvUySkl6eY3+yKBFSmoUmghLwv5RyHxNU3ZsBichUkqyPAch0MJgpCJNM66sdbEt9ZjUr26MWQoEt3Zjrnc0n7vqUCq52LYNwPHOQ3q9XhGuKbL9Xg\/Lsrh1HPHNH+9jhCDJEvLoBOHXEHnM+NEGX\/rMr\/GNnzzC0RIJ5MZQVQlbWxscPPhP\/u7Lv8\/KuQWsqTB+YtWlahu6FYuWL3EcZ1Iw38vps7F7e3vEcczi4iJSTvKi4oxYqR5ja9i9\/X0qRw\/o2x7x0R6+yUj6Fxndf4vTLEXkCV60xfqdVxkNDoiiiDz9XYwxjxG6cX\/EUkXw5m7CRxZsfrHrPYHG1Hq9HmmaMjc3h+dNxtXSIy6YbdoqYd0N+ewXPsMIg9EOqRG8ud3j4fpbeK6DFQ+oRBt0Sy5edZGNvR7irKMsSP0rKx7zZYv5akonUBhjJgI2VemzbAO4dOkSxhi01sU1bcaINKR\/Injwztts1EvsnPSwGw1c10boJbz0Xdr4LLUdnj73NCtzDq5tEeY5jWoZIcRjhH60GbJYEdw+SLk2b3OxrKjVaoUztVrtiRBOTUpJHJTQIkIITbVkUav5NJ0rZLYiSVMuttZwP\/8p5so27WpApewjBQyjhDDKEGoyd8Gh55Y8WmWL+WpOJ1B4nij4AVAulwvE4jim3W4XwmmMIQxDglqTLMu4ePU6aZrieR7NZrO43+0u4LouxhhardYMHaZFvEDoh++OWPAN7xxkXJvXXCjbBT9gouTTRdrt9hMo5XlOkiS4rkur1SpCPH1hYwxpmhLHMfPz80VZen87XHDo2aUyLV\/SmZN0A0WjYc8sqJTC8zy01gyHQ9I0LUJqjEEpheu6SCkZDodkWUYQBAXK0+cBTk9PybIM3\/exrAIThBCPhfEP\/\/EBnZLhkCqC4quEli\/5rY\/6hGHIaDT6QA4JIdhJA27tnGKEnEws5NkmQMDHqiHrm7sYk2NMjq01JU6YC1xsrVi99AyeV3rMoafP1egEiodHCVKIIraBPalvh4eHM8I4dWT69jfHHf7+p4dIZSGUQkoLpSyEmjg2ctb5+j+8QtOOef7pJa4v19CBz96jEcKSLK09Ncuh25sH9APJ+mGKpRRpmgAwH2heWJmfQeTu3btEUcTly5cLYqe9bSr5GE8KcuEglY2yNEIKtF3iUkPx4gU4322zutql5JfZf7BFLAzKUU9y6MryHJ3AwgsSrPdoT8URuK4745DWeiYDARrhOvNv36BWdjkYhJzoKn1jc5rZ7MceL33+Os\/9wjK+X0IoTZIktJfbJKfHnIwzzBnJC4TubPc5dFK2RzaVSsCFhsVnn5p1ZGpra2tPXOu2GlxcW8SSku6CwrY1CIlSkjg1CG3x0\/sndM9liHc3uXxhif7RAbpUI8oUytKzITu\/UKMbWLj9yU+Dsp6k8hSJTqdDo9EouFN8+kqJZVmMR8ucWz5PlmWUPBel7cknjpTkxuCVSgSrV0kqFc6Pe2RpzLKtSTKDcnzss9AXpL5mbREfxzyDodPpABCGPuVyGZg4NxgM8DyvaN7yPKdUKmHbNlJKBidDyn5AEARUq9UZBE9PT+noISoe4gX1gjP+mVRIqWY59Ac323x0weLfH8RIAc8v2fzJp2e7xiRJqNfrSClJkoRGo1F0mVk2+Y0z5Ve\/36dSqRS1cCqMWmuUmizu+35RjqZCWejQ5uYmxpiz5mzSxsZxjOu6NJvNGdV+v31QR\/DzjhFnUlOE7De\/ZfFLC5pv34+QwuLXl22+\/OJc8cBXv\/rnfPc\/buBosC2P2qVPcO76JxGlOr4n6ZRavHYvha0bqEqHNFjBCA+T5QgSfvuFEre3HvDtb3ydrfV7jEchUTjGKwckccTX\/uIvac81+W9xS9XYCGf+5QAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-before-map_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022911.20234604106\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-before-place_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022892.66666666667\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAhCAYAAACxzQkrAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGuklEQVRYhcWXzW8kRxnGf1XVXf1p99je9Ud2vcN6DVlyixBhySESUoT4CBJCyoED\/wo3rvwDHEGIC0TLJUIILkEkaCOtILkgJ2SD7azxLuuZnfH09EdVcZiZ9jjucRaB4D1VV1XX+9TzPu\/7dovdH7zpaLEk1axEHtY5nHMUpaWsLUoJitISh4q8MCwnPr1BSVHZtmMmZ4WKG1d8Tg6fMNY+pdOMyla3iNqY9pX\/olljGY1GVFVJUTmi0CPLsta9npKydeHjBx+xt7dHkiQURYH2NcudDkrA8198AYQABwgQwNPBAFOXaM9DCEFtDNY6lJIIAcI5JJY08oiiiInf6QHQjL35h3nbe\/8+P\/7RDxkWOVIofOWRRjFOSEqh+e7r3+eVV19j47nnCLXkT+\/eZyVboixzYl\/ymzd+SlFbfKWQwmFqg\/A0X33lVbq7L7Bz6\/Of8jkZe87NInY+cuOiREu4spxhgaUwZDQuKKucyuT8+mc\/4fd3f8Gdr32br3\/rO\/z8l3f53R\/eJohDvvnSLrc3M\/LeECUdRWVJN9cYHPe5+8aveO17ATd3dttD1joLZEshuzvXkELhjGVYOE5sQGd1iTs765wOTxn0h\/z5j78lFAXWGKhrqrLi4aM+z69nDCufK8seSegQIsQGI059i7fQ6yWAkjihsDWJtJgqZyWKSdZ3SLRio6Ppax9fB4SRJE1KcGBqi6hqnvRH5EXJSf8xV9MrBErhjU8Zjka8\/JUX2dq6vhBQu6IBgcUXCs8T5E6TO82gd4xWlqN\/jjh8eMTYWPxklRfvfAPPd1hjMWXFRwdPeOeDQ97+8CF\/fzKgso7KwGhccv+vn1CP68UMCSFaF\/KixJiCcCnmS7du44TEBhm3dm\/R6XTwg4CydtTG4emYauxwtaVyDmMK3vnLAb7WlKWll9dspQFxGPDll15meXWFRX6Fc861ZdnB3nscfvAea+tbJNkatTFo7VNVNUJIrIOyqhkXJWGc8ta773P4yUNGozEIiZAChKDTieleXSZbSgBBECXs3PoC2zc+R5vfKaCL9vjxY5xzKKXwPA9rLVEUIaWc1Jm65ujoqJl3zhHHMWma4s2p9q2jN7EYpFFcL28DsLq6urgwnn88Q5ymKXU9ifXMqVKKoiio6xrf9wnDEKUUWmuqqsL3ffI8RwhBmqYAXI22AJBOkerJnNa6lR0AYa1tZchaS7\/fxxiDlJIkSZBS8qR4RGgm4ziOUUoBcHp6inMOL0gwduJOSXAOYt2ulzZbmGXNBimx1jIYDAAYuJNmrqoqZhE3xgAQ+oIkEKSBIPLFvwUGLskyACEEQgjkfL+bMu15Ht60bwkBWbY8WWjpT89ubnFhBHDOYa3FOYcQAmstsxajtcb3\/eagBw8+JooijDHEcUyn02nAWGu5d+9ec8lut8vGxkYbBZ+tIa01URQ1bB33\/kEgQqSUaK0JggCAp8cnJOMR1fpas9c516znp0OsF5MEsrlgm13KkBACYwz9fp8syxBCEKmYsiwJgoC6rhuHhYLBwQG1qxswzjnW1tammnOIasSwosnAVkAToLPYn1EHMB6PEULgeV5Tf4IgmKbtJGyzmwa+wux0UVN2tdasrKw0WSjEJONmYCfvXdSYdzZxkcIwDBtNjEYjlFKUZdmwNwMGE70ZYxqAVVVxfHzcaG0+RGmaTp8v+vQWFGqcc5RlSV3XaK3RWiOlbKryvE4ATkePuOoC5MZW876UsmGo1ztBxxmxlk0422yhhpxz5HlOp9PBGENRFE0Lmd8ThiG+7zP2LId7H0JVN2zMhJ+mKVoHmOKUSoRz2XnRLs2yXq83Qe15TV+DibaiKCJJkmZ\/nufU9RmYWUJIKRs2hBBNC1pkCxmaAVJKUdc1Ukq63S482Ce8ce1cA53tn\/W+5rZTULPQzreahYAW1QMpJWtra01hXF1dRQjB39bHXG+pI0EQNM7m68xsPM\/wDOyCLLucoZWVFZxz9Ho94jimexxib1w8bH9\/nziOEUKQZRlhGM6d5tjfP+Dw8BDnHDdv3mRzc5O2FjP3G8Q5B1JKOp1Ow1CWZSilGoY+fbNy9JT0yg1qCxWS8NyqYHt7m+3tRd\/Sc37PJi6Gbpa61lqGwyEA3Yd6ju4zu7bd5eqSYnNZkQaLGmq7nzmPi+vQTAOzNJ\/VH5ScguUcqHS5M33v7DKXW\/v6Z34PwSR8RVE8y9b\/2BbWof+XPRND\/0u79PMjryY\/eIEnOC0tnhRIAZEvGBQWKQShLyhrh3WT+XHl0B4UNWgPajNRS+gJhoUliyTyEl3\/C8C8KrFX1sBMAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-before-place_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022892.66666666667\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-before-submit_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022811.96261682243\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAeCAYAAABE4bxTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEl0lEQVRYhcWX328bRRDHP7M\/7nx3dpxcQvqLEl6QSiMEVXkAiWfUf4A\/EvVv4AkhJFSJhyIkhITatClJXSexfbbPd7e3PASntnFcpyrqV1p5bzw7Ozvfnbk54buH3lrFnY9SfFFQOo8SOO7l7LRCXg0KtAKjFN2s4MZmg9NhwXYroKhqTrOSUeGYhwdk5hcaVmG14sF+ix9+7bDtctgwdKqYs3F9sVIe\/nzgeR+Y7irzYqnr2jvnOD4+Znd3FxFBRFBKISKUZYkxBhHB+3Mrq+YA3vsL+axsHR3x3vt+v8\/jx48JggCtNVEUMR6PMcaQZRmtVov9\/f3\/JVDTAMxFyHvP4eEhVVURRRFlWRLHMcPhkCRJGI1GaK1pt9vv3CFrLdbaeYdmw77ovfeePM8ZDAZ47\/HeX1A7qzOdwzug7E2ncG4xi9aH9x5jzFL5okMAZg1\/KMuSsixJkuTKDi1Gfxkbs8\/mMqVZ+WKWXQXT9aucmqXMzN6Fy05YFAX9fp80TZeGfxXeZH9RV+q6XusOVVV1EamrQil1qQOLUb+41KsoexuqpvDeo7VeO8su4r+KslfZhIPjE7bSlDAIAMjzHmQnNBoBYRIwqps4L4S+R1kUTJQiDmJiq0njzbUpWyvLJhLQsjW2HOKKjMlkQl8cTZkwqmvq0iOq5slZQlIXDL3leNzl\/o7DO8tWtLqgzmXZYuFa9Nh7T+WFH0fXaeZjsjrEo9B1Rlr+yUhtEelD+u4GIzZo5keEdGhEjt9f1uylH3M7vbWUstl9pjI1K1wcs8oAafUHsXRxVU3uIvrRfVS4g\/I9arPNhj0hsROsTNDiESVQzNtfBRFBTS\/tqiFAgy5no4ry4De0UVirUcUAycf0zTcYFdCoTkhcDxtqtAhaBDHLbS5SNh1qMQqLHgP4umJ7\/Igiuc3eJ5pE9zDDF7R5zlb0lNNnv\/Dh5CeuhR3Cdkg5dIRiCbShEdn5t\/mSSM3K1iqMohSv4q8wUjKaJARVlw15QkhB3in47FZCGiXYQJMVOVUaE2jDtjY0g9ZK+4t7rZVlHsXYt7FMCM0uH8gzbKwpS0vrZszZUUZnXFBUjrAdsBlH9E9yTDMkEPPGOnbld9kUzgc0VI4ucora8fywwzAbEkURn+7toYAXgxMaI02zfQMTJTiSS1uU2X2mMjVL2aosU97hvSerUhqJxaCJWze5e\/ceJv2S7qjPcDwhDZsk7TaPizsQ3qSWZM7+KqxNGa7i1vgR14Ix1gYcv3Q8j77GJY7h4JQNNaBnvsBMfmd8NuKk3MaGBd2zLhvt6\/jm+pSt1TFmwyFHR0e0Wglawbi2OAxWHKVXqDpnp91+\/eEjCiXn9pTWBDZ4tx3j4mlEhIPsKQ\/\/+h7va2rvEYHP03t8e\/vBpd3gMjtv1TEug1WWzWAT4fVda9rmym5w1SGnWIuyq8ynG7xtk79WYVzm4Ox\/6xa9dXTEOfd+PqUvgZnWB+89z3oVkRE2I30x1+o8cwItJFbRGTqUAi2wHWs6Q4f3oBXsJJq\/B46df+WRFWIrnI5rNhvna3cSTTap0UrYSfR\/KPsHj\/b+fF+Z7QQAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-before-submit_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022811.96261682243\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EAfter:\u003C\/h3\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-after-home_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022784.8\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAdCAYAAADCdc79AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAJQElEQVRYha2Wy49l11XGf2vvfc499123ul7u6lbb3XI3dkIejgMTgnhaiaIQQbCiCGWUDBghZkiREEiI\/4ARAgYMQEIMkFAiGGBkWRkgO2AIsR0nbne7u+3uqlv3UfdxHvuxGNzqcrdRhBSxdAZ7n3O0z3e+9a1vLWn\/9t8pqoCCAiRQBY2QEmhk397iqa332GtX\/MedNtF7fufzn+Erv\/prfPNP\/ozxdI51GVtdYdBpc++kJgSPiFAUlk\/uTMAI9yvDblHhWi0yo6AJ5xzedti9eIX56QQnKAg8eTiiTaRuAs4K3nsW65rj2YphZ8214YJX7wzRGIi+4R9ffp2qVsbT+eYHUmIyT0xOPc7luFYLEbg8LBHTcNy0SepY+xyThH4WSOJZRk8mJfdujRERbPbMi3887GREH1hVntpHah+pmoBBiTGS6Zhr28cUboHQZr6KrMuGH9y8i6pirCVpAiDLC1JKXBx6yuhwLiOII0bhuU\/8Am3\/HmIrcmtQEYwRYowYqxiTcKDYas1xNDgDAvgQ+NSe560TR+MjzghlA9084\/KoZrLOWSwqNCWMsagqKUbEGGLwtAvDi1\/6MkV7lw\/GE0adivsnU+7813eASNFzGHUk8WTiiE5pq9JIwqDKSbQAhKj4mADh9QeWyicSgjEBZx0xKiGW9Npxw0RMRO8J3qO6Wfu6whjDm7fucbi\/x9XhKVcPD2lOvk+rSNhcyFWx0lAYQ4dEF8GqYhCMAnlmORh16HdaIBbrHPvbA3ZGfbAtILGqT5nVgbcmu7QLg8tzsrxFigmNCRFBUyKGwHy24u77U6bjN\/n+f79EUWxxYWtISpFQJaZVi7XmOIRZpRhVMpORNw7Xy5VRzxBCQ9cp\/YEwXVQ8ODo9q7RIliuFgdurAbGpuDWJ2Ayacg0iiDUgBjEGDYHnnn0G\/APqxlCap3n5tVcY9D\/G1tZ9fnRvyY+P2uz2a65fqLi72Od6f0lAqE2Ja2fCfFlR1QE9E\/HhdhvtGtDIeLpENXL7aIej44ayqkAVMQZUADDGYI0hpoSqsjUc8OvP\/wyv3Zzw7e++SbsNl\/ZGtLOczMFn9sfU6shKpVqvGc8ajE2oBmTrt\/5KU1IEQBOQGLQd3geMJDQE+rzLevwOMQRENlUuAiIGm2eIMaQQid5jncMYw8\/d6LFjS3ot5T\/vW945AWMEa2C3Ay9cKqmSUpJRWEg+sPaKG3Uc2\/0Ws2VFWXvWVaST57giI4XA8XTNaRUxMYAoqgZQVIWiPwBjaVYLNEUg8Zuff4HV9DaHzdvknRaaAi88mbh5wTGyJe+vLJmxWISOE07WijhlZ9CniAZXVRUzDRS5RSMEo7Ss4owiRsiMnmlEIJ05OputXy8JIbKJhDGGV777Er\/xNAwKyyoGrAjWWA6yipZEyBsehC4zU+DXS5rQ5v2Z5yi0ODwY4aJvsIXQySy+DmhoGE88aCSEQIqeJ7fbPPvsx\/ngeEIV5FxDm1SFDR4BYy0fP2zT7dVkuWXfghHwCYq+YjUwSMpll\/PGvMUzFxtIysky8tZyxFHdwrUzxWggeDBEMpPo5BYUFo2H5Pnln3+eb33jC3w0jBE6rY0x\/n+EiOCqssRqxla7w8lqjW8aeoMegkGiYblKzBYVv\/cXrwMw7OaEmFhVgSt7Xf7wxRs03m8oQum02z81IAWck0AKidUKRD1WA6enC1KKrNcVKQaGHcOf\/u6nN9\/8SMyTgnXn+7LxPzWgljG40FR4VUZdy3KxxIhSdLtoAlMYUjCoJm5O5\/gQEBFiilhrP5xYHkmZiJyn8OHaGIOqoijDbvcnAtrKM1xhFWcNViP9QmiaAKnBCczXK5qmQVLgswc7\/+cfNj79xGdiBGsEHxJyxvSj0hMBZwTXVGskd5RlwtclwQeMbowxxRojkRga5qenlOs11lqquuZgf588z89ZePXNI\/7gz39AAhQlycbIRQQRuHGpxwvP7\/E3r9yhyCwPlhFBsShOI5My8MVP7eJSqOh0e3RzocmFWVVzukikFCkywfuEFaVotdCUQITMGVLaNNSHkbUMB9d6iLEElPjev5MOblCvZizff4vyXqDzua8zGGbkzjEYJIyALj7gzg9fg7tvs86exNUR7i88ad6AKskHdgYtVMGIoi4jes\/p6QIfPP1+H+My2h+ppkxLLsXb7AwLbCz58d2XeKJ4hxAhf6LF\/sETnNy5yxsv\/yuSArEp2Qs3WYzfpmxKyqpmdW0H52mxNdglRsUYmN5fIxrQGDg6mZFSBI0Mh4PHAFRV9dg+J7LLKd35McuTu1w\/PODLX\/gVfnjrFq7doTPY5o0HM6bjm\/SKHCPKMsBTl6+y2\/ZUIfHU4QFOZ+8ynb3Lw0HfoJTFkBQjvbYjJcFZOROhfqjARyrJOYclUKQJmC7Tkzk6G\/PqP\/0z826HLM\/Z3a\/IucCuO+Fip8fVnYIbh1c4GOVYa2mScnD9WZzE5qw76dmltJyQdwqOxxPquiF4z3K1YjabgYLERDRQtApGoy1arRaaPC5NyFNFO4s8qNa4VkZLoaxr5qcz9i4dcGV\/RWFKyLfYGh7QarfxCW7fm3CruoXT9NDIzk0FTYGm8gy6LY7WS1IKeO9RVfb39lCEQb\/3WMouX7nGV77++8SUzntdjJFBv0+\/3yfGiKrys5\/4NHmWoygXtrdx7kNTjTHiSP6MfT0Htjidb9JnhCJ3ZNawv7fH3u7ueZk\/2r8erjudDnVdk7kMKWvsVp9Op\/NYNfZ7PVJSkhqq2Sn5oLdh+OwMRwrnQOQsZVv9NqqK957JckntA3\/9L+88xog+BKJgRfjaL11hOp1RliU7uzt0RwOKouCjMR6foKrs7Fygs7W1cfxH4hFAGzCbLyVC2Ogmc4Z11fD33ztCkE0\/eyhq3dBsUb76i5fZ29t97PBHK\/FhCzk8vHh+r2max94XEZxqfNzDgePxCTFFjAgxJpwVruzmHAwsV0cZP5p42haGLYOTRGGFO9OGv\/y3B9TKZuA\/G\/pFDCLCpYHjs9vCd177gLqJlHWkqRp81RB8QEPgc588wKH\/u\/9cGA0Q4PhkCii5hS9ezzBmM2IcHDoysxm8Fqs13\/6Hv+X603\/E9+4uMMYg1iHGYq3FiEWsIybhuUHEhzV1UlYxsPaesvb4OpBqz3xd8z8wvSjf7jlH7gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-after-home_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022784.8\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-after-place_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022647.34864300626\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHIklEQVRIibWVS6slVxXHf\/tRj3Oq6jzu+9Hv0OkkEgQHcSLJwDgWjAMRR4ofQZwKfgU\/giMdiBMRHCQoSETQxkQx706nO7dvbvc9fZ51qmrvvRzUubfP7VbBgYsqqgr247f\/\/7VWqeyNX4jWgUhrRAIKIXiPdw3BN1w6\/iXF9APyvIcKnk5\/k29994fcvPUCj47usnf5CtdvvkCUpGiliCMwRvGDH\/2YD+58xMsDTe0atjeG5HmXuiyJjebeaMpB0cFYzZ2jE3pbhxSRwoLQTVN2+gkqOIwWvPPMyiUnpw2DtEOfnNFsjNLQPGr4+c9+ShwnmChiXjvy3oDvfO\/7vPLq62zv7GANhCBEcYpkXTpNydbGJgbPZDRC5z2aZck0tgzijMP9fe4fHzM82MHEL377J10aRouayaLi8bSirhuWVUPjHN3xOwz8iGEvx3lF0Y3Z7PUIwVPXFbVrCN7x\/u0\/8dZvfsXDk4fsHVzhzbffZr6sGFVQGcP9k4ccFinLquKL0YSmqrlxuEPlBI8i0bCzv4uFwKQRggRY3U0dkOAgeHaGBVt6A\/GO\/d0dHo0mNKLwcUYUZzy\/NWD8eISRVpU\/v\/lbbv\/+dzyI+tTGkhYFC2cIIaKfdZnMpmgFl3c36eYF09MxD05G9LsWaRqsUcKXrgyoGk9sQSOUVYN3DZPpnH6Vcn2wQXCB4Dwqs3QGO3wyaVDAlY0u2y89x7JqmC8qptMpWRy4e69CaUM5m5FkGcZGPJ4tyPOctL9DXE84GU+ZLxY8OD6md+0AgmC997zz8UMEIbEKhVBXNcE3qODwiecvH91lK0vxixIksLu9xV6\/y8H2JptJjdLCu+9\/TF3XPHz4iBuXcrzvUTmwkcXNF+giZyGaUVnz4ecf8fXnD8iTgn98eJe8mxAnKSeLJZbg6FNS2i4EjyJgcMRWqCpHbBX7O5t0Y808SWmIuD+aU+mKqkj5+4Mx20WCtYqr125yeOkSr772Gp\/9+i2q08cgEIJHe89fT2rGszmxaGzc4XQ6pmlqOpHm+q1bzMZzbJEotM25HC35dCTUroEQcOJQwXE6mdJP5yTGcuv5F6nKOdN5DdmAW7dusre7Q5bnRFFK5QM+CD6Adw0iggJiG1EvK1xTowR0mrKsK7I0YjDo0ywXOOdxErBagbWG+zNLExwoizIBjSZ4jenso7eucu16H5sUPHewh0I4On3MYH+fxkZ8djxiUh6RCgwPrvDJxx\/gfEBCwDtHU5XYJEUrCwowKbenUDdLbuzt4RdT3GxKPryMHdeGIskYbPWRWcOy9mSpZauXcOd4xvZVw+begEfjd9lMFfc+f4B3jjyJee+9f\/LJ3SNevrHL7e41Xpp\/xod\/vEOnN+Tq4QFJZ9xWrxJAE6cJadYl6XSpmoqujTjVMZv729xvBLvwWHzDYlFisXQ0JIlgVMODhyU4xzdf\/ypvfOMrANR1TRRFKKX4f4VFPHGkUUoxmteICIMsIo00ywqUAmMMSik+PzqiLEu00gw3hmxubNA4x3QyJU0TtNakaYpIO+9\/CaUUIoJVk09ZTmApAhJQEhiLbysuOJCb55OybpfIRtjIopUG4HE1YTQfsRH65HkOgABNveR4dMLOxiFpbBCRCxsDlGWJ9\/58XquQW6KgHbQCkhUQ4truvQpjLGnagnS73XYBaymKgsSm1HWrcJp2cMryt7Hjy+4IozUiIAi9ogAUgqCVxlr7lGVu2b6JAE9+H4iH4NrnU9IqpZjPF8RxTBBBRNBKkff7iAgikBrN1\/Y2UbTeaa0IIawUFLqdzjMwLZBfImtAsgKS4FHiLyg0mU6IrCXtdIiidrGmrjk+\/gIzVIQgFEXeQobA6ekpaZIQgqB0iya0lT+ZTDBas729fQHMiqtWAgqIrCwLLUwIF4BaudtoGkdVVfRsxtR0sJEFBO89WhtEa\/q9Pskq2VnlzdnZtW5z6emKtfglSOtqa1ULxfq9iulsRpZlbAyH54m5XC7Z399HJGCMwRizqjJFr1esQTy7+VkKXABSrnqCfQaFrFQKK5HbKIoC1zSMRiOyLCOKIhJV4l1JMAXeX8w37wNRHKH\/Qw9wzq0U1WuW+ercW0RQhPOKewLYxmQywXtPr+ixWJTAgiTpUAlEa2OKokfpHH+4c49Xdjex1qDgPMfOVBGR80Rfs6xe+5Q1pQQhXPBeKYVC4b3DmLZk47IC50mHw\/MeIwKxUjyXWhbz+QWA2XxGka+glCLPsqeAgluzRVb7rynEkxNkWYZ3Dq01\/X4fgJGd0NSK9Ck7lFKktu3wZz1HRCjynM6q5Neb5BpQs5YlsrpWXZWLg402YCFaK1OR8MyiZ3EGISKIDmitmc8XTKdTjLVk3S7GGDqdzhrQqvGdLalk\/UsuWDadTgEhiFAul3TSlN54yXxZQm\/rfFwQwRjDwcH+vwX9b\/EvDlDrxomykUsAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-after-place_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022647.34864300626\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-after-submit_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221381.6666666667\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAkCAYAAAB8DZEQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGMklEQVRIiZWXu49cSRXGf6eq7qMf0z0z3Z6xkb32yAgk2AC0EhEkCBGw\/wABCcEGkBOQEbMBfwQiQUggLQsRiIAACRAIFrRazzK2sfFjPJ5H337ce6vqENx+zcyOMSepUt17zrnnq\/N9p1s+861f6UYnIbNKCIHJZMbebsIvfvgNyqqiKAo0KoPBNiKCiKCqrNviTEQA5ntQBRFwViB6z6RWhIAzisYIgDGGfq+PtWbpfDHB4vz4+ARjhH6\/T1EUdLvdeXJwiXjKWhAUiTVWK4QmqAAxRpyzlwJfMgHvAzFGQojLqgCcSywmRkBRIHoQVpWohv+dAGi3WlhrMcaQt\/LzSYpJTTt3TGYRK2DFEeeVTEPk4en4nMNFmID5c8UYQ+qS5mE14Va3hRVwvhxzVipooI4BjTVxuwvAg8dnvPf7fW7fuMbL0wlv3k7YaJv5ZTpSB6mrELHMakdiA8YqQYXEWujcRIzDqZ80X6QBjR6NFbFu7uD54WMOPvo1b7\/1TX7w3s\/46ckRuVMePpuSZhlfuDlCsjHEFCFhO59QmJq2zem2+nzvO+\/S29jExfUkwaOhIvp8Dkfkb\/uH\/OT93\/DhwSOsdRgR8laLYbfCaMHpKGW7HXH2jDOvRKNM4xSrngZlxYRqTKzGhHJMqMaEaoL6GQCJE06KKT\/\/3R8B8L4mKux0J8xCyle\/9m3yGGhnNc4anDGk4omxZBqUoAoILpbFGlyBGGuC7wCQOc9g0\/H8cEYdakARhCSDT7ee848\/\/5hrmzNMsKSpgEYSSRipYEOFzCnlfFUAETSiMaChRn0PgHFpGY0FjQ2DEWE2meBnQm09D54KW1nk3umQuzsFRje4lo\/p+AoFrGmUwMVqBKqoxlU1dQNXXdWcHR8jxpHmGaH2ILDbU6azHg9OHZndYG9zwo4oxz4gXogTyxtv3GLR+C5W43m\/xyZRDGgoAdgdbvH1L38JbIr3FaGu6bQzvnKnJksto1IoS0+Ihp1O4OUMNnLD2Fe0sj7GOkQEF+tJw3XVBjINaKgA+Nzd2\/zo+9+l1WqtCBgj\/zq4T97KGQ4GZFkGwLNnzwDo9Xrn31fFRT9dsVcjqBKjBxpZsdadE8Woig8eYwxFMSbPm3ZvVsE5d0kh3Bc\/v9dUwUK94LN3by2TpKk5J+HGGIaDIS5xpGm6lPiiGtHL+1R1TVVVdDqdpeRIjPGydl+wJocspf7Rw306GwNarRZJkpIkjuLFEbbTJkkSRARr7fID3PrAWQ0e5fzYaM4W1tvcxVpDlmUY04jpSTmD2QxjDVma0ev1liNCVNcrOY\/lvZP7\/PLBbxvoxBA18tbwTW5OuvS2dhAxdLod8ixlNGrUOkkT0iRZQgWs4HrVWL1oDw4f0U+65K0WeZYhIhzs\/5PBzs0lTKrQ7Tb34haOV43VT7Jtn2C72bJuVWWwewuNSpZlWHt+krpVuy0CfvKAWliMkSfFIV0NdLvN3MnznNOjJ+zcuINz7pLPa3XXRTs5ekl\/e+scH46LUxIsnU7nMk8W7fl61mD9+OlTRtMJ\/X6fVp6TpgnxbER27fqy2xpkmrgGVtg36\/r+\/L0stu12m1ae4+Y\/HECYpUJZlRRFQVVVLHgF4BaOq6C8MhHAcDhARBqJ8R5rLZvkuKRp3\/WuVFXMspeX6\/p+ta7jfG\/\/Yw5fvMCYhpAiwlFxRF3VhBAu+ZqLBwt2rydd2OLs+u4u21tbhBCo6xqArcGnCDFgjLn8kf8vGa86+\/f9j9i5cYc0TS69t2iF1ybjVWfZ1jZlWVLX\/tJ7ay28arl159dlkStK0mEf69zSx8j8jl9Fxo\/\/M+b9Pzy5MnDqDJWPVz5\/5+09WplFdFnXqpIPDk55590\/kTqhkxtCCIzGJVYCiXhORwXqZyTGkxnPyckxdVnQyZTMRE5OXjKbFkRfoRobgVz9aWm6ygfl5agidXA2aeZ6DJ6qLHHimU1n1PUUG0sIU6bFGcGPub43pN+xOKn56+PHRF+CRtx5Eq6xXiOqQuoMMQhRBPWQpRYnjnJmKacRa+b3qYqzhjRx\/P3Dg1VA9KrJCGgkeBhPAmigqio0VFRljdGKuq6pqppYT5tfOBr4ywf7RD8jxsD6JP0v8DmijnnKJUoAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/naked-after-submit_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221381.6666666667\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["bootstrap","colour","design","redesign","refactoring","naked","naked adventure","naturism","webdevelopment","website","font","symfony","javascript","booster"],"hasMore":true,"image":"https:\/\/avris.it\/image\/naked-revamp_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-revamp_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-revamp_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022161.70744403956\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EYet another one of my projects, \u003Ca href=\u0022\/projects\/naked-adventure-de.lite\u0022\u003E Naked Adventure\u003C\/a\u003E,\ngrew too outdated to support it. I had to rewrite it from scratch.\u003C\/p\u003E\n\u003Cp\u003EI took the opportunity to redesign it as well. (screenshots before \u0026amp; after at the bottom)\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-revamp_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-revamp_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022161.70744403956\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EYet another one of my projects, \u003Ca href=\u0022\/projects\/naked-adventure-de.lite\u0022\u003E Naked Adventure\u003C\/a\u003E,\ngrew too outdated to support it. I had to rewrite it from scratch.\u003C\/p\u003E\n\u003Cp\u003EI took the opportunity to redesign it as well. (screenshots before \u0026amp; after at the bottom)\u003C\/p\u003E\n\u003Cp\u003EHere\u0027s an overview of what I did:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ereplaced my abandoned framework \u003Ca href=\u0022\/projects\/micrus-v4.lite\u0022\u003E Micrus v4 \u2022 Beauty of simplicity\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/symfony.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Symfony 5\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Ebased the project on \u003Ca href=\u0022\/projects\/avris-booster-quick-start-of-new-projects.lite\u0022\u003E Avris Booster: Quick start of new projects\u003C\/a\u003E, to take advantage of built-in features:\nuser management (including a passwordless approach to authentication \u2013 \u003Ca href=\u0022\/blog\/passwords-are-pass%C3%A9.lite\u0022\u003E Passwords are pass\u00e9\u003C\/a\u003E), push notifications, etc.\u003C\/li\u003E\n\u003Cli\u003Ereplaced \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Micrus-Assetic\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E custom Assetic setup\u003C\/a\u003E\nwith \u003Ca href=\u0022https:\/\/symfony.com\/doc\/current\/frontend\/encore\/installation.html\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Webpack Encore\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Eupdated \u003Ca href=\u0022https:\/\/getbootstrap.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Bootstrap\u003C\/a\u003E from 3.0 to 4.4,\u003C\/li\u003E\n\u003Cli\u003Eadded more contrast to the design, filled the excess of white spaces with content, making filters and maps more prominent,\u003C\/li\u003E\n\u003Cli\u003Ereplaced Google Maps with Apple Maps, because of privacy concerns (see: \u003Ca href=\u0022\/blog\/ungoogling.lite\u0022\u003E Ungoogling\u003C\/a\u003E, \u003Ca href=\u0022\/blog\/log-out-for-privacy.lite\u0022\u003E Log out for privacy\u003C\/a\u003E) \u2013 the website is now officially Google-free,\u003C\/li\u003E\n\u003Cli\u003Eremoved a couple of unnecessary and unused features:\n\u003Cul\u003E\n\u003Cli\u003Ethe homepage (now the user is shown the map right away \u2013 after all, the map is the whole point of the project),\u003C\/li\u003E\n\u003Cli\u003Ethe \u201dgeographic\u201d links (there\u0027s no separate map of e.g. German nude beaches anymore, it got integrated into the main map),\u003C\/li\u003E\n\u003Cli\u003Eseparate events section (now they show up together with places on the same map),\u003C\/li\u003E\n\u003Cli\u003Eforum (it wasn\u0027t used at all),\u003C\/li\u003E\n\u003Cli\u003Eadmin panel (now the buttons for admins are just integrated across the website),\u003C\/li\u003E\n\u003C\/ul\u003E\u003C\/li\u003E\n\u003Cli\u003Eimproved filters (for instance added filtering by name and location),\u003C\/li\u003E\n\u003Cli\u003Ethe process of submission of new steps isn\u0027t split into steps anymore: place info, review and description are finally just one single form,\u003C\/li\u003E\n\u003Cli\u003Eincluded some more \u003Ca href=\u0022\/blog\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome.lite\u0022\u003E optimisations\u003C\/a\u003E.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Ch3\u003EBefore:\u003C\/h3\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-before-home_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-before-home_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022286.83333333333\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-before-map_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-before-map_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022227.80058651026\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-before-place_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-before-place_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022223.16666666667\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-before-submit_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-before-submit_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022202.99065420561\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EAfter:\u003C\/h3\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-after-home_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-after-home_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022196.2\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-after-place_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-after-place_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022161.83716075157\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/naked-after-submit_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/naked-after-submit_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022345.41666666667\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E","words":262,"readTime":2,"lang":"en"}}},"projects\/avris-booster-quick-start-of-new-projects":{"key":"projects\/avris-booster-quick-start-of-new-projects","type":"article","published":true,"meta":{"createdAt":"2020-04-13T11:56:14+02:00","publishedAt":"2020-04-13T11:56:14+02:00","group":null,"links":[{"icon":"brands gitlab","colour":"primary","url":"https:\/\/gitlab.com\/Avris\/Booster","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-booster-quick-start-of-new-projects"},"content":{"en":{"slug":"avris-booster-quick-start-of-new-projects","title":"Avris Booster: Quick start of new projects","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/booster_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022329.18322295806\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADQUlEQVRIib2WS3IjVRBFT75PValUalltdxA0joABMzbQO2MXLIGFsA5mDBgYogMCW2pZn\/pmMijZVskf2jbqO3tV73Pz3nyZT84+\/GjscDYbM52MABCBi49z8lFKVTUoRlU1mAmvgQicpo7SR9LoWa5Kmlbv\/v\/08y\/2xPpX4f1XM9IkPjmnrGo+\/r24I6Sqt4QuLi6o6hrvPJvtFucEJ47z828Yj8fPJlTVLWkS+PW3j\/zw\/dd0qvz+xyXfvn\/Ln38t+O78lHo35wZhf4M8z4lJQvCe0ShDzXh39o4Yw73DPgcicLlYcTIZcblYY2ZkaaBuWoJ3\/HO1YjrJhmvM7Fah9WpF23VMp9MXETiEasenT0tEBBFH13WIgHMOU6OYTHoXnLtdMwg9zTKsalksN2AK9FydGKqKSUQwTBtEBCSCtYiAqhJjpKkbvPcYRpam1G3H7GT2gHwQgkdVh5\/3c6jrOjbbhs56Am+nY8x66W9wOO6\/WU\/wAOuypaxaVA3DwNjNM5pOSHzHmyIj2UuJgWVlWXK1LNmWNUn0JF5Isgwzw4lgXcVs9kC0j0BV2Yv3vkK+V2hg2R4fAJLgaWNABNq2YnttZGmkGCVk+RsO5z8FEcH7x+vWjbL7ew5yyHtPEhpUHeI8qp7MC1WjbKs+b\/JR8tmEXoJ7ls3nc5qmoSgK\/E5Skf4mqGpv305iMzBTnI90JjgUrLuLNgSKongWoYFlznmyLCeElqrzBBzgOTt5flG8wXMshgPLzBQ1o25aRnkkTZIHb88xEfYPNDNMW9qm5HpRIidTkpggcty82ce9OtS2HWZ9sUrT9MsrtD9YLq9Zr1eI8wgwnU7J8\/yoBA7jHViWJJG6yTBTzOB6tcKHgHPHU8mJGzTvwS0zoOtafAhkSSTEBCfutt\/ckD9sFcIrCAuPF0ZVpW1a6rphs17vlBImxRhxDhGH7DZQVUKIjEYZzvmXEzpAOExaw26T2oknphFxDuc8zjnG49ED27zm0SkDtQeWCeyqshBCwtnZ6X07\/u8H71OWhRDJ8xwRoSgmRzn\/vzDoZavVirZt6bq+f81mJ1+GxGOWmRlX8zkC5OMx680GVDHxOOeP1un3OfwL1QqaGbIjT+wAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/booster_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022329.18322295806\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EI got super annoyed having to set up all the dependencies for each project every time I started one,\nand especially implementing user management... Log in, register, confirm email, forgot password,\nMFA, change email, impersonate, manage avatars, over and over again, booooooring!\u003C\/p\u003E\n\u003Cp\u003ESo here it is: a template for quickstarting new projects,\nwith all of the above (and more!) included out of the box!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/booster_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022658.36644591611\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADQUlEQVRIib2WS3IjVRBFT75PValUalltdxA0joABMzbQO2MXLIGFsA5mDBgYogMCW2pZn\/pmMijZVskf2jbqO3tV73Pz3nyZT84+\/GjscDYbM52MABCBi49z8lFKVTUoRlU1mAmvgQicpo7SR9LoWa5Kmlbv\/v\/08y\/2xPpX4f1XM9IkPjmnrGo+\/r24I6Sqt4QuLi6o6hrvPJvtFucEJ47z828Yj8fPJlTVLWkS+PW3j\/zw\/dd0qvz+xyXfvn\/Ln38t+O78lHo35wZhf4M8z4lJQvCe0ShDzXh39o4Yw73DPgcicLlYcTIZcblYY2ZkaaBuWoJ3\/HO1YjrJhmvM7Fah9WpF23VMp9MXETiEasenT0tEBBFH13WIgHMOU6OYTHoXnLtdMwg9zTKsalksN2AK9FydGKqKSUQwTBtEBCSCtYiAqhJjpKkbvPcYRpam1G3H7GT2gHwQgkdVh5\/3c6jrOjbbhs56Am+nY8x66W9wOO6\/WU\/wAOuypaxaVA3DwNjNM5pOSHzHmyIj2UuJgWVlWXK1LNmWNUn0JF5Isgwzw4lgXcVs9kC0j0BV2Yv3vkK+V2hg2R4fAJLgaWNABNq2YnttZGmkGCVk+RsO5z8FEcH7x+vWjbL7ew5yyHtPEhpUHeI8qp7MC1WjbKs+b\/JR8tmEXoJ7ls3nc5qmoSgK\/E5Skf4mqGpv305iMzBTnI90JjgUrLuLNgSKongWoYFlznmyLCeElqrzBBzgOTt5flG8wXMshgPLzBQ1o25aRnkkTZIHb88xEfYPNDNMW9qm5HpRIidTkpggcty82ce9OtS2HWZ9sUrT9MsrtD9YLq9Zr1eI8wgwnU7J8\/yoBA7jHViWJJG6yTBTzOB6tcKHgHPHU8mJGzTvwS0zoOtafAhkSSTEBCfutt\/ckD9sFcIrCAuPF0ZVpW1a6rphs17vlBImxRhxDhGH7DZQVUKIjEYZzvmXEzpAOExaw26T2oknphFxDuc8zjnG49ED27zm0SkDtQeWCeyqshBCwtnZ6X07\/u8H71OWhRDJ8xwRoSgmRzn\/vzDoZavVirZt6bq+f81mJ1+GxGOWmRlX8zkC5OMx680GVDHxOOeP1un3OfwL1QqaGbIjT+wAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/booster_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022658.36644591611\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EI got super annoyed having to set up all the dependencies for each project every time I started one,\nand especially implementing user management... Log in, register, confirm email, forgot password,\nMFA, change email, impersonate, manage avatars, over and over again, booooooring!\u003C\/p\u003E\n\u003Cp\u003ESo here it is: a template for quickstarting new projects,\nwith all of the above (and more!) included out of the box!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["booster","quickstart","symfony","php","webpack","bootstrap","javascript","css","user management","template"],"hasMore":false,"image":"https:\/\/avris.it\/image\/booster_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/booster_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/booster_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022164.59161147903\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EI got super annoyed having to set up all the dependencies for each project every time I started one,\nand especially implementing user management... Log in, register, confirm email, forgot password,\nMFA, change email, impersonate, manage avatars, over and over again, booooooring!\u003C\/p\u003E\n\u003Cp\u003ESo here it is: a template for quickstarting new projects,\nwith all of the above (and more!) included out of the box!\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/booster_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/booster_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022164.59161147903\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EI got super annoyed having to set up all the dependencies for each project every time I started one,\nand especially implementing user management... Log in, register, confirm email, forgot password,\nMFA, change email, impersonate, manage avatars, over and over again, booooooring!\u003C\/p\u003E\n\u003Cp\u003ESo here it is: a template for quickstarting new projects,\nwith all of the above (and more!) included out of the box!\u003C\/p\u003E","words":64,"readTime":null,"lang":"en"}}},"blog\/technology\/redesigning-a-website-avi":{"key":"blog\/technology\/redesigning-a-website-avi","type":"article","published":true,"meta":{"createdAt":"2020-04-10T19:33:59+02:00","publishedAt":"2020-04-10T19:33:59+02:00","group":"redesign","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/avi.avris.it","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Avi","displayUrl":null}],"category":"blog","subcategory":"technology","slug":"redesigning-a-website-avi"},"content":{"en":{"slug":"redesigning-a-website-avi","title":"Redesigning a website: Avi","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avi-comparison_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022403.61904761905\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAeCAYAAABE4bxTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAF+ElEQVRYhbWXy48cVxXGf\/dVVd093Z6ezKPHYw\/jJNhjj+PEsRWwMxEKCFYIBSWLwIIFiCURfwQrlrCBDQKiyAobXlFYBITA4BBDHE8snPBMzMSKHz3TM+6Z7urqqntZVPdtT+ZhGw+f1OqS6tx7T33nO9+pEkmSOOccUkruFc45AJ59\/is0m2sYY2i1WzgHQgicc6Rpis2yu95TO+cQQnD+\/HmMMTz22HG0Vj4gSRJWV1awzoFzaKNJuylSKarVqk+qHcdYa1FKAQLnLEJIlJI460AIwIGDzFqSpLt1Qv2Lw4cPo7XGZimJTQFQSqO1Yqhc9guiKPLXWe\/JR0aqABitEVIA+eHW5sz3kxYCnANrLUmSbJmQSJLEAbTX1nHOMjRUpsf54L8HafSGxWmaehaNMcRxjDEBYRhsU5A7w5esEIbgQChJmmXE7VZPB6CUxBiD6MXCQD\/5+lx\/aZaRZXHvXn5fKYUxpsdQvnbx2lVe\/cNrzD00y\/zxTw7YEQLdD8I6XJpBIUQIEAiscxip0Nr0tt8McRuDpVKJoHf4TrGLt5a5uHqdlUXFU4+f2vCAg5K1214T9JiwvSCtNcYYrwchhP8BdLspQWBwzvVEvTWszfdbaq9x4dr7TO8Z5dBILU9ESpQUiE6n44QQxHFMlmVIIUAKPCXO4chlSq+VlVIEQXBba2dEUchO9pFllub6em\/PPmUgpcRogzYBRjFIKE3TPKk0RWntD+vDOYfW2h8oZa4r5xytuEM3SUjTlCiKKBaL27J0J\/iSOedyhqTcoIsdF\/fi1lsxURjgkmyD33g2BL5rRaB7dG+546DLlFI71n8rWGsHLFqHW+sgymF+KNBsNr0uwzDM9+8mBMF2tuAGXVav1ymVSpRKpY0hzuVGlib8+Nff44HKGF88\/aVNLCEFohgg1EBDQRAgLCBAK7XJxz4KIcTAqSuVMlJIkqRD\/6GDIMA5h3OOThrzD3eZ6+1hnnHP+24DUEoglUQMheSGkUP\/D1ryJUuShHK5sjlroNvtotB8\/uRzVMwwQggW6x+yf3Qy7zqpsFlGo9HAWkutVrvn8vvz+qJOkoRCobBlkLUWYIPgrzVuMlrOZ1i3m6KUJI5jnAgQLvFdqZTybEop83lpLVLKLZP2JTt7+S\/caq+hZS7uTjcffk8cfJSPTUxtWlirjvlZBnhLSJIWUiqkFGRZ5jXYF7eUkiiKkFKSpqlP3DPU96G1uEWapZsOHiqUCPTW46DfZb87e27g8vcJPbiQCJQ3xEqlckc\/6pfypTM\/YWm5gTEayIetdQ5Bzoi1lrjTAbfdRBzAa+i7535BfX2VRnuNzwYzvPjyGZIk4Wtf\/jrf+fZZqtUiT3\/mGG\/86QxxHBNFET986UdArqFicWv93Stk39iWKxFTDx\/i6kiBbpYx\/+STnDhxgrjt+GDBMP3AIRofKFauLPPCN16g8f4SwIbxsisJ9csyceAhupNjHDx2klqtRitNMcUi46MTfGLuNHK1Rq26n6MzR3jxWz\/g6MwRgLseM3cLr6HH\/3aTG\/UbzABjD5d4cGIBKRXDI3Oog79hWQiCqScwS2X2DGuCbSzifuFLViwVeWTuGFNTU2T2KtPTYwyVl2g2b1Aw+wnlFH+92ODKuUXmT85z5Y\/\/ATa+Oe7GzzO0d2qSTrfDRHEcI95Dhx8yNrGH1nKZhddXCSPD6U\/tZbY8y60LTWYrh\/8vDPnh+stfvcK7\/3wXgK8+\/QX+\/PPchR99rsqnv\/kmAKeO7mVhr+Wt+luMfm4U2H0N+ZK9dulnzD91ipff+D4rly5TaXbovHmJG\/\/6O8P7asweeYS3l\/7Nqwuvs2\/u47xy8Ryw+13mGaocEPz+2k+ZOB4xqjS3Llxk\/OZNhgtF3tEN6iJget9+wpkav118h8KBSWDA0G4x5Y1xuX2duNsCYFKN011aBkCNj1KX+VdmSYesr7dJbYaWionyMLC7xuhnWX\/y9r8qpZRw27s+gBSCzFqiIATwwzNNs11LSPdnV38uATu8YpK\/+9wW+9EPx\/vFfwEsBAWgUvaJSgAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avi-comparison_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022403.61904761905\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EYet another one of my projects, \u003Ca href=\u0022\/projects\/avi-simple-placeholder-avatars\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avi \u2022 Simple placeholder avatars\u003C\/a\u003E,\ngrew too outdated to support it. I had to rewrite it from scratch.\u003C\/p\u003E\n\u003Cp\u003EI took the opportunity to redesign it as well.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avi-comparison_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022807.2380952381\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAeCAYAAABE4bxTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAF+ElEQVRYhbWXy48cVxXGf\/dVVd093Z6ezKPHYw\/jJNhjj+PEsRWwMxEKCFYIBSWLwIIFiCURfwQrlrCBDQKiyAobXlFYBITA4BBDHE8snPBMzMSKHz3TM+6Z7urqqntZVPdtT+ZhGw+f1OqS6tx7T33nO9+pEkmSOOccUkruFc45AJ59\/is0m2sYY2i1WzgHQgicc6Rpis2yu95TO+cQQnD+\/HmMMTz22HG0Vj4gSRJWV1awzoFzaKNJuylSKarVqk+qHcdYa1FKAQLnLEJIlJI460AIwIGDzFqSpLt1Qv2Lw4cPo7XGZimJTQFQSqO1Yqhc9guiKPLXWe\/JR0aqABitEVIA+eHW5sz3kxYCnANrLUmSbJmQSJLEAbTX1nHOMjRUpsf54L8HafSGxWmaehaNMcRxjDEBYRhsU5A7w5esEIbgQChJmmXE7VZPB6CUxBiD6MXCQD\/5+lx\/aZaRZXHvXn5fKYUxpsdQvnbx2lVe\/cNrzD00y\/zxTw7YEQLdD8I6XJpBIUQIEAiscxip0Nr0tt8McRuDpVKJoHf4TrGLt5a5uHqdlUXFU4+f2vCAg5K1214T9JiwvSCtNcYYrwchhP8BdLspQWBwzvVEvTWszfdbaq9x4dr7TO8Z5dBILU9ESpQUiE6n44QQxHFMlmVIIUAKPCXO4chlSq+VlVIEQXBba2dEUchO9pFllub6em\/PPmUgpcRogzYBRjFIKE3TPKk0RWntD+vDOYfW2h8oZa4r5xytuEM3SUjTlCiKKBaL27J0J\/iSOedyhqTcoIsdF\/fi1lsxURjgkmyD33g2BL5rRaB7dG+546DLlFI71n8rWGsHLFqHW+sgymF+KNBsNr0uwzDM9+8mBMF2tuAGXVav1ymVSpRKpY0hzuVGlib8+Nff44HKGF88\/aVNLCEFohgg1EBDQRAgLCBAK7XJxz4KIcTAqSuVMlJIkqRD\/6GDIMA5h3OOThrzD3eZ6+1hnnHP+24DUEoglUQMheSGkUP\/D1ryJUuShHK5sjlroNvtotB8\/uRzVMwwQggW6x+yf3Qy7zqpsFlGo9HAWkutVrvn8vvz+qJOkoRCobBlkLUWYIPgrzVuMlrOZ1i3m6KUJI5jnAgQLvFdqZTybEop83lpLVLKLZP2JTt7+S\/caq+hZS7uTjcffk8cfJSPTUxtWlirjvlZBnhLSJIWUiqkFGRZ5jXYF7eUkiiKkFKSpqlP3DPU96G1uEWapZsOHiqUCPTW46DfZb87e27g8vcJPbiQCJQ3xEqlckc\/6pfypTM\/YWm5gTEayIetdQ5Bzoi1lrjTAbfdRBzAa+i7535BfX2VRnuNzwYzvPjyGZIk4Wtf\/jrf+fZZqtUiT3\/mGG\/86QxxHBNFET986UdArqFicWv93Stk39iWKxFTDx\/i6kiBbpYx\/+STnDhxgrjt+GDBMP3AIRofKFauLPPCN16g8f4SwIbxsisJ9csyceAhupNjHDx2klqtRitNMcUi46MTfGLuNHK1Rq26n6MzR3jxWz\/g6MwRgLseM3cLr6HH\/3aTG\/UbzABjD5d4cGIBKRXDI3Oog79hWQiCqScwS2X2DGuCbSzifuFLViwVeWTuGFNTU2T2KtPTYwyVl2g2b1Aw+wnlFH+92ODKuUXmT85z5Y\/\/ATa+Oe7GzzO0d2qSTrfDRHEcI95Dhx8yNrGH1nKZhddXCSPD6U\/tZbY8y60LTWYrh\/8vDPnh+stfvcK7\/3wXgK8+\/QX+\/PPchR99rsqnv\/kmAKeO7mVhr+Wt+luMfm4U2H0N+ZK9dulnzD91ipff+D4rly5TaXbovHmJG\/\/6O8P7asweeYS3l\/7Nqwuvs2\/u47xy8Ryw+13mGaocEPz+2k+ZOB4xqjS3Llxk\/OZNhgtF3tEN6iJget9+wpkav118h8KBSWDA0G4x5Y1xuX2duNsCYFKN011aBkCNj1KX+VdmSYesr7dJbYaWionyMLC7xuhnWX\/y9r8qpZRw27s+gBSCzFqiIATwwzNNs11LSPdnV38uATu8YpK\/+9wW+9EPx\/vFfwEsBAWgUvaJSgAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avi-comparison_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022807.2380952381\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EYet another one of my projects, \u003Ca href=\u0022\/projects\/avi-simple-placeholder-avatars\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avi \u2022 Simple placeholder avatars\u003C\/a\u003E,\ngrew too outdated to support it. I had to rewrite it from scratch.\u003C\/p\u003E\n\u003Cp\u003EI took the opportunity to redesign it as well.\u003C\/p\u003E\n\u003Cp\u003EIt\u0027s quite a simple project, so it only took me a couple of hours. Here\u0027s what I did:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ereplaced my abandoned framework \u003Ca href=\u0022\/projects\/micrus-v4\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus v4 \u2022 Beauty of simplicity\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/symfony.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Symfony 5\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Ereplaced \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Micrus-Assetic\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E custom Assetic setup\u003C\/a\u003E\nwith \u003Ca href=\u0022https:\/\/symfony.com\/doc\/current\/frontend\/encore\/installation.html\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Webpack Encore\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Eupdated \u003Ca href=\u0022https:\/\/getbootstrap.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Bootstrap\u003C\/a\u003E from 3.0 to 4.4,\u003C\/li\u003E\n\u003Cli\u003Eadded more contrast to the design, while keeping it simple,\u003C\/li\u003E\n\u003Cli\u003Eremoved the ugly logo,\u003C\/li\u003E\n\u003Cli\u003Ereplaced the font that I used to overuse, \u003Ca href=\u0022https:\/\/design.ubuntu.com\/font\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Ubuntu\u003C\/a\u003E,\nwith the beautiful \u003Ca href=\u0022https:\/\/fonts.google.com\/specimen\/Baloo+Thambi+2\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Baloo Thambi 2\u003C\/a\u003E\nand \u003Ca href=\u0022https:\/\/www.jetbrains.com\/lp\/mono\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E JetBrains Mono\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Emoved the generation of links from backend to frontend \u2013\u00a0now it gives you an immediate feedback\nto changes in the form, without having to reload the website,\u003C\/li\u003E\n\u003Cli\u003Eremoved the \u201cLatest generated avatars\u201d section \u2013 I never liked it, but I needed some showcase\nof what this project does\u2026 with the immediate feedback in the \u201cTry it!\u201d section, it\u0027s not needed anymore,\u003C\/li\u003E\n\u003Cli\u003Eincluded some more \u003Ca href=\u0022\/blog\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E optimisations\u003C\/a\u003E.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Ch3\u003EBefore:\u003C\/h3\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avi-old_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221695.2\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAkCAYAAACJ8xqgAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFCklEQVRIia2W229UVRjFf3vvc84MnTkzhU5LOy3QYQqUQAKUIAoGFNFETEgw+mTiizFi4pN\/hNEXH4gxMSaGmKiJBpWgCeqDYPVBEeQqlGulF2m1tMN0hjlzLtuH6TntOAVF\/B73\/vaab+219pojHMfRAEII7qe01gAY4YIQgv7+fjb29WGnUg0HyqUSgQ7QGnzfxzAMgiBAAFYshpSyHnB4eJhSqYTnezhOBbRGCIkQAtOyKJfLuJ4HaKRUEWAIFA0WUgYIggDDMFBK3TNdz\/NqE4Z353sebrmCNk2wTNAahIBg5vekBB2AEKiY1QAY4kSUDakQUmHEYwhD4bou5XIZKSU6CBBSYlkWSkqk1typZi9Aa3TVJXDdOZuCwPeRCAwhUTPgd6toQl+A22ThaZ9gehoAZRqIGSUDoRFSoaSILHJXwMD3qVartQmEACUQ7qy\/tNZUKg5SCISU0XoymaxT2gg3pFKYpokQoR7zG11rjZQSKWuWCoKgrjdSOWysVqu1DcNAiBq9+SgGQYDWGqVUdBZAVKvVqFtrPa9Z\/6nqJowoz9C4V1PPHQTmUHYch9u3b2PbNrFYrOFQeOC2U+b6+DUMZZLPrmyYsi4cEokEpmlGh+eW7\/sAnB0+yb7Dr1EoT\/HZq0cb+iLKge\/jem5Dg2ma0TVorbFsi+Z1C8nQGokVigd\/EwW4oyDVanUmADRNTYloffTmOLdKRVZ25uoBPc9DCIFlWfMC3smXnu\/jBz5KyHrK47ducmnkGkopDGXMNNciKd1ks6FnzbyAhlIoKRvjS0mFZVoRbcHsvfwbK4U4UcCGT+m\/VJ0Pw8VCqcjQ+O8IKTGEJKYlgQYlJYlEArRJaboCwMJFSaanp6Jn2tbWRjwer6d8YnyQN3\/4nA3tOa4Vxukbs9j\/0Qek7BRrenupjq3i4IFjrF6bZfeeBzh44HXsdIqTx3\/hnf3vsnvP7voJLdvmqS1P8M2NAdoXLWeRX2HvCy9iJ5NcGRxkaiJLe3wVjz+8gaRKkom38NIrL\/P1wcPE1ezLkmGamLbNmWaDnX3bSOVytGQy3Jia5PLIEO2dWZrNTrZv3sqFfknCyJC12\/nwjfcpDhZYIGNRKkWUcxXBM0MeMMbG+AIy+TSWrKne3pbhtwUOA+evA7DywQ6M5h3c\/PMmANkVSxrf8nRhElku4zgV\/vBc\/PQlpqZ+QkqNUznNJx8vJWnHOH9uCNcPOP7Fl2zYup5vDx2lt3c1+VX5GmDoNdtOkevupimeYGJqAskw6XQfvu9R9SYwRZYdj6zn+qUjGKKFXCJHT1sParPCNuzZT5FwVNu2EWbtHhYvbgM\/y2TxEKaRxjLyLOtawf63LyJlF4tbu8j2rsO56GAXU2QWtjRSPnX2FG+9tw+Azo5Onl79ED9+6gDj9GzO0bn9Css6TgDQui7NkZEzjIyOQitsiveRZ3m9yjcKQ3T0tNC2PM33l79iemCAFs9nxZKlFI79zPnJIbZt3smWTY8yWBznuwuneWzXk1wpTjA6OdGosmkLvHSBZDyFXRRklMnkrwOIWyWyHe20LO2mlLAoOiVSiRbsXCcnRq8yZrpYqUQj5XzXCs5NtgLw7LLnWOJsIlGs\/eEn167B6VnF1eIYC+LNrMvkCXYJJooF9nY\/T35Jd2TsunC4n2oIh7lp43kerusihEAatejyfA\/LsHB9FykkgQ6ImTHkTPyHgOL\/\/iT+C3VfUNvDPRWOAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avi-old_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221695.2\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EAfter:\u003C\/h3\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avi-new_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022632\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAXCAYAAABj7u2bAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACzElEQVRIib2Wu3IjVRCGvz6XmfHu4hvrMhkpkSNT1FJFsC9BxhtQvAAxAQHPCMHmrHGNR3NuTXBGkrXWSLLA+1epdGZa6v77fuT23XtlBt1JizGWh\/4BUEAmydz5v8OpzPLBWsvZ6SnOWUTM6r2qIsCwWJBzRkSQidqSYEzxOEJoVSUioKAoTAZiTAzDgDEGQRAjaCnVpBjevH6FKogIqmX6rrQ+3v1DKfPOzhJ6993tUZ68FKTscCPGyGKxIKXMxcX5ZyHkVswehXuJUgoPDwPGGj7e3eG9B11XSts0eO+3lvWfH\/4ipMjl6QVXl283ZCL116r65Lw3QilnTrru2Z7+8MuPfPnFOd9+c8OvP\/188P\/cLqG1FrZEbhuWni5xdXPD12+\/4s3F1cFkYE8NpZQopdA0zV5FOZfaoRM+3P9NLIWztuOye700hzEGa45MmaqScsa7nYGkqNL3A2MYgToCVMGYddS67gTF0rUeb+d1SQhxllCIAWtsTd1ngsulzAr7fmAYBkC5vr7+\/6zu2ECyGMN8ynJBhwhG6gdAp0rJkyPWAIqoVIWd389n2QBbCLmZ92vjY0S8Q175yTiEcaQf+2m\/Kd55mrahlAJjoWvbvaQAJh82zg42h9qnA06cnSK0Xq5ihNbXzrMIiOD2FP6hqCmbCdEh8+cooztStrPth8WCMI7kXDDGcH5+9iIEH8N9OmE3hNYQRTBGsNY8mcYvQmiXsKZMMNaDCPf396s0LmeTqmKMoZSC9w3WmjpQU6Lrumc7YdaGH5OoWN4DVetqiDFSSiGl9GRYigjjuCCEelPspoWsqrP6t51F91RuSom+7+sOshYRUBVEapRyzqtrbL09VnLee8zUmSEE2rZdPe+C++33P2aF63vy+vnQ7X8s5Pb797pt6wI452iaBkHJueC8I6WMMUIpSts0hBgJIZBz3kz3I+LPOf8L0k9\/atxDHsEAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avi-new_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022632\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["bootstrap","colour","design","redesign","refactoring","avi","avatar","webdevelopment","website","font","symfony","javascript"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avi-comparison_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avi-comparison_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avi-comparison_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022201.80952380952\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EYet another one of my projects, \u003Ca href=\u0022\/projects\/avi-simple-placeholder-avatars.lite\u0022\u003E Avi \u2022 Simple placeholder avatars\u003C\/a\u003E,\ngrew too outdated to support it. I had to rewrite it from scratch.\u003C\/p\u003E\n\u003Cp\u003EI took the opportunity to redesign it as well.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avi-comparison_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avi-comparison_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022201.80952380952\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EYet another one of my projects, \u003Ca href=\u0022\/projects\/avi-simple-placeholder-avatars.lite\u0022\u003E Avi \u2022 Simple placeholder avatars\u003C\/a\u003E,\ngrew too outdated to support it. I had to rewrite it from scratch.\u003C\/p\u003E\n\u003Cp\u003EI took the opportunity to redesign it as well.\u003C\/p\u003E\n\u003Cp\u003EIt\u0027s quite a simple project, so it only took me a couple of hours. Here\u0027s what I did:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ereplaced my abandoned framework \u003Ca href=\u0022\/projects\/micrus-v4.lite\u0022\u003E Micrus v4 \u2022 Beauty of simplicity\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/symfony.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Symfony 5\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Ereplaced \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Micrus-Assetic\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E custom Assetic setup\u003C\/a\u003E\nwith \u003Ca href=\u0022https:\/\/symfony.com\/doc\/current\/frontend\/encore\/installation.html\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Webpack Encore\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Eupdated \u003Ca href=\u0022https:\/\/getbootstrap.com\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Bootstrap\u003C\/a\u003E from 3.0 to 4.4,\u003C\/li\u003E\n\u003Cli\u003Eadded more contrast to the design, while keeping it simple,\u003C\/li\u003E\n\u003Cli\u003Eremoved the ugly logo,\u003C\/li\u003E\n\u003Cli\u003Ereplaced the font that I used to overuse, \u003Ca href=\u0022https:\/\/design.ubuntu.com\/font\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Ubuntu\u003C\/a\u003E,\nwith the beautiful \u003Ca href=\u0022https:\/\/fonts.google.com\/specimen\/Baloo+Thambi+2\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Baloo Thambi 2\u003C\/a\u003E\nand \u003Ca href=\u0022https:\/\/www.jetbrains.com\/lp\/mono\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E JetBrains Mono\u003C\/a\u003E,\u003C\/li\u003E\n\u003Cli\u003Emoved the generation of links from backend to frontend \u2013\u00a0now it gives you an immediate feedback\nto changes in the form, without having to reload the website,\u003C\/li\u003E\n\u003Cli\u003Eremoved the \u201cLatest generated avatars\u201d section \u2013 I never liked it, but I needed some showcase\nof what this project does\u2026 with the immediate feedback in the \u201cTry it!\u201d section, it\u0027s not needed anymore,\u003C\/li\u003E\n\u003Cli\u003Eincluded some more \u003Ca href=\u0022\/blog\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome.lite\u0022\u003E optimisations\u003C\/a\u003E.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Ch3\u003EBefore:\u003C\/h3\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avi-old_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avi-old_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022423.8\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EAfter:\u003C\/h3\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avi-new_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avi-new_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022158\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E","words":169,"readTime":null,"lang":"en"}}},"projects\/avris-twemoji-backend-generated-twitter-emoji":{"key":"projects\/avris-twemoji-backend-generated-twitter-emoji","type":"article","published":true,"meta":{"createdAt":"2020-02-08T22:49:48+01:00","publishedAt":"2020-02-08T22:49:48+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/packagist.org\/packages\/avris\/twemoji","displayUrl":"avris\/twemoji"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Twemoji","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-twemoji-backend-generated-twitter-emoji"},"content":{"en":{"slug":"avris-twemoji-backend-generated-twitter-emoji","title":"Avris Twemoji \u2013 Backend-generated Twitter Emoji","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/twemoji_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHlUlEQVRIiX2Xya8dRxXGf2eo6r73vfsmPz87ozMRCAEsAhEREUqIlEkooIAYAlIEC1iAWPAnsGfHAoFYwwqxCUECgUgiJRIEBCETEQlxJsfYsd9w33S7qw6LvnYQIEpd3S11DV99X506X8vV19wcUSpCELVCVMydWgpBoCK4GqZKcmc2O6TWChEQgQAigjAUEUFEgOBiiYh5rZeeREUEVARzx0RomhEeIUQEpRYkQIBSCsIwsKoOQEWhVpIq\/XwCRObtuNReBEBQlXcnl4vvQtSCqBHxbj9DSGpoLfjFDoISVCJAQxAdJiMEVQeEvlQMQRFCFFOdszEsBBm+za\/5zXA3ZrMOEYgYFiii6LyvqeJmJFU8RKGWOcEDI0QgIagaboqJYKK4KRKVWiu1lmEA92H1taJql6RSEaJWgmB5ZYXN8xeACiGIQ9SCqkCAmZLMSH4RkAAqUOdsCYjoXAZDUcyMbIlx00D07O3v07jTJCd7otZKKT19KSAM+6VWAC47tsHhzhSoA2kRqOY5KMV0kDib4qKJiA4JA6nopU0qqNlArSVUFBVDxVloFlgdLXNhuoWGEiVoPKGeIQohQt93A0MCJ66+mrdffQ2RQAJMBSGAhEjMJVOSKa4p0wfziLGLsQKqAztqmBrZnWwJxRBJNDlx7dFFdvemHHYdx45vMNvfY7q9g4mQXalRuf2eO3j5+RdZyg1BDJEFqA6iqIIIJFOyGx6akDSXC6EGmCiqhori5rga2TMuQjInSSJpw9raMp\/96udZW13hdz\/7Ja+feh1rFkk+RNNkeZHb77qD5x57kpV2BBQiYgCjggqYCaYDa+6Ckxukd2qNub4Aiqih5ogYbo5qws3mNXHn\/Z\/goW99kZeefoFHvv9TEoUbL7ucqJWd3Smeja989zs8\/fNHuXJpiVnpqNETUQbpdB5dadhDOSmm4NIuULuC1DqcQwGIIeKoJZI5qkYyp02ZsTtf++bnuPfBO5le2OHRHz5C1hGr45brb7ic3a1zbO0dcNe3v0xSoZ56g\/ddtsF0f4+DfkapPaV2oJXkhpngriQXUjJcxkvIrIdSCRj2CIpIQsUQT2R12pQYp8RDD9\/NvQ\/eCcAzTzxLomGyOGFx3LBzfp8TH\/0Q9zxwO942PPW9H7OxvoxGx9Z20PeJEgOgkIpqkLLjLqSkeBZcRhPIPRSQUAhFUBAHTZg6yZycEidPXsunv\/DJSylh+8yUI8eOcsWJDU7cfBVX3XIdC+tLRASv\/+pxFkaZUhdpm57cVJBKjY6+nxG1Qw1UA3MjN44nwZksQ1+IkAFMDNFlOK4JxZH5AfjwN+6\/dDID3Pf1u\/nPEhG8+fgfmZ09x9FrjnC4lel2N1nSDrGKWFBrR+0PEXrUBHMl5Yw3Da6TCakw5BkUDyVhZHFyGFmNjHLLyau54oq1\/wLw76WWwsu\/\/gM7L71Mu6C0y2OO3nQl\/dYC26cFlRlCB5KJkhCpQ4Qlx3LGmhE+WZlQCjBnyBA8nFaMFqXFaKpw28du+L9gpme3eP4XTzJ75yyjBlDo9vfYe6fDZcZ4uaF2ZTh7DFQSMpdL3bHcos0IP742ou+DWqCGoqEoRgohYbShNEW48br1\/wlkf3uPvz3xLG\/+6UWydIzaOqSOCtFBPTRolDxSIikmMZcpoaZYymhukNRAHuEf2GjYO+iYHRZmfaWUSqkVCUGiYkUwEdZXx5dA7E73OfXSm7z6l1d487l\/0ETH2AuRCk4layU0wAJmQ66UFCQP3AQzQVNCcgvJIGfIDXiLP7D6FrsHlem0Y3u3Mu2DnUPYm8FBB7NeKD386Ac\/YX93n81z2+ye3yaXQqKQqLRaGVnPQgqW2spsXGESpBBaG2yGlA71wLJhNeg6w5jQHRraJrYujOlokTtvXo+lNnFwMFglt0yIU3FCEgWnaqavEKKgzvHjl1H7ws729jzHGdmERmEhw7HVMesLsJK32Vg3FhaE105vMt3fp+SOlcuv4LHf\/J5XTx+y1FY2NiYcdsFTz+8iiytroSkjalhKeNMianhu8JSx1KBq5KbFPJE88\/FbP0LX9WTg2PoRullhbXmZ82fOsTYZIwf7NKWjbJ3jyKKyugBJe5L1rCz03HhyzObpKWdPbzMZgUvP0dvuZu+vv8Vv+syXaBaX6Cu0CxM8Nag6Yk7yhIghDHlHQpBSKUtjPODK9WX+eXaTYh0aLfvtKiwvMzma2Dpzjpi17CYlJ6NNlWqVg6bS2Qpr74XN6SukkdB4T39hj8X334sXjOnePlhitrODyC6ggxeKwYAPXgikVCiVc6cr9eCAZ2ohmyElkAisFl7AcCqtJSbJmbiz3CTGSXAtjDNMDzpu\/eASb1xQ6vmepRFMNt\/iPfd9GL9w6u\/Mug71TC0Vb0bw7j8EAnhKqCoSQdRAYwCgtSJ9f8ng1+4QF2PzzGu0ucVFWF5c4sjSCh6Vvb1tVpcm\/PlF5+1TI85sHfDqOweMctDojE\/1byDr198UtRT62YzaHZIWJkgIZXaApmZIB7XHcwsweG5Aa6AIEhc99ODFNQKhYiK4Ci6gVLIZqkHfdwiFjYmz3Brn9web2zjcdgL+Bf4aPDyLSPA9AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/twemoji_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/github.com\/twitter\/twemoji\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Twemoji\u003C\/a\u003E is a great way to make emoji\u0027s on your website independent of system and browser.\nBut alas, it requires JavaScript...\u003C\/p\u003E\n\u003Cp\u003EUnless you just use this library to replace emojis with \u003Ccode\u003E\u0026lt;img\u0026gt;\u003C\/code\u003E tags in your backend.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/twemoji_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHlUlEQVRIiX2Xya8dRxXGf2eo6r73vfsmPz87ozMRCAEsAhEREUqIlEkooIAYAlIEC1iAWPAnsGfHAoFYwwqxCUECgUgiJRIEBCETEQlxJsfYsd9w33S7qw6LvnYQIEpd3S11DV99X506X8vV19wcUSpCELVCVMydWgpBoCK4GqZKcmc2O6TWChEQgQAigjAUEUFEgOBiiYh5rZeeREUEVARzx0RomhEeIUQEpRYkQIBSCsIwsKoOQEWhVpIq\/XwCRObtuNReBEBQlXcnl4vvQtSCqBHxbj9DSGpoLfjFDoISVCJAQxAdJiMEVQeEvlQMQRFCFFOdszEsBBm+za\/5zXA3ZrMOEYgYFiii6LyvqeJmJFU8RKGWOcEDI0QgIagaboqJYKK4KRKVWiu1lmEA92H1taJql6RSEaJWgmB5ZYXN8xeACiGIQ9SCqkCAmZLMSH4RkAAqUOdsCYjoXAZDUcyMbIlx00D07O3v07jTJCd7otZKKT19KSAM+6VWAC47tsHhzhSoA2kRqOY5KMV0kDib4qKJiA4JA6nopU0qqNlArSVUFBVDxVloFlgdLXNhuoWGEiVoPKGeIQohQt93A0MCJ66+mrdffQ2RQAJMBSGAhEjMJVOSKa4p0wfziLGLsQKqAztqmBrZnWwJxRBJNDlx7dFFdvemHHYdx45vMNvfY7q9g4mQXalRuf2eO3j5+RdZyg1BDJEFqA6iqIIIJFOyGx6akDSXC6EGmCiqhori5rga2TMuQjInSSJpw9raMp\/96udZW13hdz\/7Ja+feh1rFkk+RNNkeZHb77qD5x57kpV2BBQiYgCjggqYCaYDa+6Ckxukd2qNub4Aiqih5ogYbo5qws3mNXHn\/Z\/goW99kZeefoFHvv9TEoUbL7ucqJWd3Smeja989zs8\/fNHuXJpiVnpqNETUQbpdB5dadhDOSmm4NIuULuC1DqcQwGIIeKoJZI5qkYyp02ZsTtf++bnuPfBO5le2OHRHz5C1hGr45brb7ic3a1zbO0dcNe3v0xSoZ56g\/ddtsF0f4+DfkapPaV2oJXkhpngriQXUjJcxkvIrIdSCRj2CIpIQsUQT2R12pQYp8RDD9\/NvQ\/eCcAzTzxLomGyOGFx3LBzfp8TH\/0Q9zxwO942PPW9H7OxvoxGx9Z20PeJEgOgkIpqkLLjLqSkeBZcRhPIPRSQUAhFUBAHTZg6yZycEidPXsunv\/DJSylh+8yUI8eOcsWJDU7cfBVX3XIdC+tLRASv\/+pxFkaZUhdpm57cVJBKjY6+nxG1Qw1UA3MjN44nwZksQ1+IkAFMDNFlOK4JxZH5AfjwN+6\/dDID3Pf1u\/nPEhG8+fgfmZ09x9FrjnC4lel2N1nSDrGKWFBrR+0PEXrUBHMl5Yw3Da6TCakw5BkUDyVhZHFyGFmNjHLLyau54oq1\/wLw76WWwsu\/\/gM7L71Mu6C0y2OO3nQl\/dYC26cFlRlCB5KJkhCpQ4Qlx3LGmhE+WZlQCjBnyBA8nFaMFqXFaKpw28du+L9gpme3eP4XTzJ75yyjBlDo9vfYe6fDZcZ4uaF2ZTh7DFQSMpdL3bHcos0IP742ou+DWqCGoqEoRgohYbShNEW48br1\/wlkf3uPvz3xLG\/+6UWydIzaOqSOCtFBPTRolDxSIikmMZcpoaZYymhukNRAHuEf2GjYO+iYHRZmfaWUSqkVCUGiYkUwEdZXx5dA7E73OfXSm7z6l1d487l\/0ETH2AuRCk4layU0wAJmQ66UFCQP3AQzQVNCcgvJIGfIDXiLP7D6FrsHlem0Y3u3Mu2DnUPYm8FBB7NeKD386Ac\/YX93n81z2+ye3yaXQqKQqLRaGVnPQgqW2spsXGESpBBaG2yGlA71wLJhNeg6w5jQHRraJrYujOlokTtvXo+lNnFwMFglt0yIU3FCEgWnaqavEKKgzvHjl1H7ws729jzHGdmERmEhw7HVMesLsJK32Vg3FhaE105vMt3fp+SOlcuv4LHf\/J5XTx+y1FY2NiYcdsFTz+8iiytroSkjalhKeNMianhu8JSx1KBq5KbFPJE88\/FbP0LX9WTg2PoRullhbXmZ82fOsTYZIwf7NKWjbJ3jyKKyugBJe5L1rCz03HhyzObpKWdPbzMZgUvP0dvuZu+vv8Vv+syXaBaX6Cu0CxM8Nag6Yk7yhIghDHlHQpBSKUtjPODK9WX+eXaTYh0aLfvtKiwvMzma2Dpzjpi17CYlJ6NNlWqVg6bS2Qpr74XN6SukkdB4T39hj8X334sXjOnePlhitrODyC6ggxeKwYAPXgikVCiVc6cr9eCAZ2ohmyElkAisFl7AcCqtJSbJmbiz3CTGSXAtjDNMDzpu\/eASb1xQ6vmepRFMNt\/iPfd9GL9w6u\/Mug71TC0Vb0bw7j8EAnhKqCoSQdRAYwCgtSJ9f8ng1+4QF2PzzGu0ucVFWF5c4sjSCh6Vvb1tVpcm\/PlF5+1TI85sHfDqOweMctDojE\/1byDr198UtRT62YzaHZIWJkgIZXaApmZIB7XHcwsweG5Aa6AIEhc99ODFNQKhYiK4Ci6gVLIZqkHfdwiFjYmz3Brn9web2zjcdgL+Bf4aPDyLSPA9AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/twemoji_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/github.com\/twitter\/twemoji\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Twemoji\u003C\/a\u003E is a great way to make emoji\u0027s on your website independent of system and browser.\nBut alas, it requires JavaScript...\u003C\/p\u003E\n\u003Cp\u003EUnless you just use this library to replace emojis with \u003Ccode\u003E\u0026lt;img\u0026gt;\u003C\/code\u003E tags in your backend.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["php","javascript","twitter","emoji","twemoji","backend","symfony","twig"],"hasMore":false,"image":"https:\/\/avris.it\/image\/twemoji_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/twemoji_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/twemoji_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/github.com\/twitter\/twemoji\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Twemoji\u003C\/a\u003E is a great way to make emoji\u0027s on your website independent of system and browser.\nBut alas, it requires JavaScript...\u003C\/p\u003E\n\u003Cp\u003EUnless you just use this library to replace emojis with \u003Ccode\u003E\u0026lt;img\u0026gt;\u003C\/code\u003E tags in your backend.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/twemoji_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/twemoji_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/github.com\/twitter\/twemoji\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Twemoji\u003C\/a\u003E is a great way to make emoji\u0027s on your website independent of system and browser.\nBut alas, it requires JavaScript...\u003C\/p\u003E\n\u003Cp\u003EUnless you just use this library to replace emojis with \u003Ccode\u003E\u0026lt;img\u0026gt;\u003C\/code\u003E tags in your backend.\u003C\/p\u003E","words":38,"readTime":null,"lang":"en"}}},"projects\/sexuality-spectrum":{"key":"projects\/sexuality-spectrum","type":"article","published":true,"meta":{"createdAt":"2020-01-16T23:48:41+01:00","publishedAt":"2020-01-16T23:48:41+01:00","group":"gender-apps","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/spectrum.avris.it","displayUrl":null}],"category":"projects","subcategory":null,"slug":"sexuality-spectrum"},"content":{"en":{"slug":"sexuality-spectrum","title":"Sexuality Spectrum","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/spectrum_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022234.07874015748\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVElEQVRIic2VTW8TQQyGH8\/MfiQhacKBGxKovfD\/fwdXoAcE3FAhqZRkk+5mPOaQhOZjU22BA+\/JI2vmtf3aHqm+zGzqlyQzvPcMBgP6vT7PQUzGerUkz3I8kWgOLLGJCScB8YaEnNQ84H3As6FJDu8csVpDkSEiOOeQ+XxuKaVnBXAKe1AwAxGk9H\/8joggZmZdLyRVPt3eMhqNiDES44Zer89qtSLPc2LcEGMCjLIsqeua6+sbvHfsaUTkSVtSSp0Cmk6nADjnmEwmFzPsSvzXATWf7\/Eqrb7FZg0Cw9A785kZ6qG4aU\/iFEGkneQMrweEomh1lesS7wMhz858KSViXdOVJ5hZp5LOv\/2EZFgyRlcjNIMeOQDbMCOJ2EpSeMHKbpIFgMO+vmQXg5IUE71eScgyotaY22ZdVUtSSgyHo+PqqLKsKnwWGNJe3VN0nrLZbIaqYmaMJxPy7Fyef4FwybGXco\/yTgnmcM7B\/fJIHNWEaiTPtxLep4or18exva\/OyHdN\/e+mrGnIsqy1Oc0MTYngH5fiIZlqxPvQKaDOU7b48J34sGEyHhPCuVwO2O\/7yjf0U47sUpXMIW+GR8Fesi9Kdori+iVXZYn351\/DYrGg3+\/\/9hWbDRICIkJVLQHjxUELHFZlf74o2WEZDzGdTrHdB\/xfbOrq4x1Ohfxk+akqdV1TluW24Xls6qZusJSQ3DN496oLTfexV1UQwe9I9zAzVBXv\/VnD79eEiLRK3YbOm\/rH+69Yo9tLIWMyGR+Ttzy+8DVDLbDMYW9HT76\/t38BvPqThYnDi\/QAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/spectrum_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022234.07874015748\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhere are you on the Sexuality Spectrum?\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/spectrum_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022468.15748031496\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVElEQVRIic2VTW8TQQyGH8\/MfiQhacKBGxKovfD\/fwdXoAcE3FAhqZRkk+5mPOaQhOZjU22BA+\/JI2vmtf3aHqm+zGzqlyQzvPcMBgP6vT7PQUzGerUkz3I8kWgOLLGJCScB8YaEnNQ84H3As6FJDu8csVpDkSEiOOeQ+XxuKaVnBXAKe1AwAxGk9H\/8joggZmZdLyRVPt3eMhqNiDES44Zer89qtSLPc2LcEGMCjLIsqeua6+sbvHfsaUTkSVtSSp0Cmk6nADjnmEwmFzPsSvzXATWf7\/Eqrb7FZg0Cw9A785kZ6qG4aU\/iFEGkneQMrweEomh1lesS7wMhz858KSViXdOVJ5hZp5LOv\/2EZFgyRlcjNIMeOQDbMCOJ2EpSeMHKbpIFgMO+vmQXg5IUE71eScgyotaY22ZdVUtSSgyHo+PqqLKsKnwWGNJe3VN0nrLZbIaqYmaMJxPy7Fyef4FwybGXco\/yTgnmcM7B\/fJIHNWEaiTPtxLep4or18exva\/OyHdN\/e+mrGnIsqy1Oc0MTYngH5fiIZlqxPvQKaDOU7b48J34sGEyHhPCuVwO2O\/7yjf0U47sUpXMIW+GR8Fesi9Kdori+iVXZYn351\/DYrGg3+\/\/9hWbDRICIkJVLQHjxUELHFZlf74o2WEZDzGdTrHdB\/xfbOrq4x1Ohfxk+akqdV1TluW24Xls6qZusJSQ3DN496oLTfexV1UQwe9I9zAzVBXv\/VnD79eEiLRK3YbOm\/rH+69Yo9tLIWMyGR+Ttzy+8DVDLbDMYW9HT76\/t38BvPqThYnDi\/QAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/spectrum_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022468.15748031496\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhere are you on the Sexuality Spectrum?\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/spectrum.avris.it\/mz0v\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E (mine here)\u003C\/a\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EDisclaimer:\u003C\/strong\u003E\u003C\/p\u003E\n\u003Cp\u003EI\u0027m not the author of the original concept of those axes.\nThey were circulating online in form of a picture without a watermark\n\u2013 making it practically impossible to find the author.\nI just made an interactive version of it, with a few adjustments.\u003C\/p\u003E\n\u003Cp\u003EI\u0027m aware that this representation of gender \u0026amp; sexuality is not perfect \u2013 but none is!\nHumans are more complex than just a few axes!\u003C\/p\u003E\n\u003Cp\u003EYes, us nonbinary folx aren\u0027t necessarily in between \u201cmale\u201d and \u201cfemale\u201d,\nyes, lumping bisexuality and pansexuality together is not ideal, etc. etc. etc.\nBut it\u0027s an approximation. If you come up with a better one, I\u0027d gladly make an app for it \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["gender","identity","expression","sexual","orientation","drive","romantic","desire","relationship","male","nonbinary","female","masculine","feminine","straight","bi","pan","gay","asexual","ace","aromantic","romantic","monogamy","polyamory","vanilla","bdsm","svelte","javascript","js","nodejs"],"hasMore":true,"image":"https:\/\/avris.it\/image\/spectrum_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/spectrum_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/spectrum_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022117.03937007874\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhere are you on the Sexuality Spectrum?\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/spectrum_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/spectrum_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022117.03937007874\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhere are you on the Sexuality Spectrum?\u003C\/p\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/spectrum.avris.it\/mz0v\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E (mine here)\u003C\/a\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EDisclaimer:\u003C\/strong\u003E\u003C\/p\u003E\n\u003Cp\u003EI\u0027m not the author of the original concept of those axes.\nThey were circulating online in form of a picture without a watermark\n\u2013 making it practically impossible to find the author.\nI just made an interactive version of it, with a few adjustments.\u003C\/p\u003E\n\u003Cp\u003EI\u0027m aware that this representation of gender \u0026amp; sexuality is not perfect \u2013 but none is!\nHumans are more complex than just a few axes!\u003C\/p\u003E\n\u003Cp\u003EYes, us nonbinary folx aren\u0027t necessarily in between \u201cmale\u201d and \u201cfemale\u201d,\nyes, lumping bisexuality and pansexuality together is not ideal, etc. etc. etc.\nBut it\u0027s an approximation. If you come up with a better one, I\u0027d gladly make an app for it \ud83d\ude09\u003C\/p\u003E","words":119,"readTime":null,"lang":"en"}}},"blog\/technology\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome":{"key":"blog\/technology\/reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome","type":"article","published":true,"meta":{"createdAt":"2020-01-10T11:53:15+01:00","publishedAt":"2020-01-10T11:53:15+01:00","group":null,"links":[{"icon":"box-alt","colour":"primary","url":"https:\/\/packagist.org\/packages\/avris\/fontawesome-optimiser","displayUrl":"avris\/fontawesome-optimiser"}],"category":"blog","subcategory":"technology","slug":"reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome"},"content":{"en":{"slug":"reducing-website-size-by-a-half-by-optimising-bootstrap-and-fontawesome","title":"Reducing website size by a half by optimising Bootstrap and FontAwesome","intro":"\u003Cp\u003EMy new blog, despite being simple and freshly rewritten, loads way too much crap...\nSo I took a few moments to optimise it a bit \u2013 and I ended up with almost 50% reduction in resources size\nin just two steps!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cp\u003EMy new blog, despite being simple and freshly rewritten, loads way too much crap...\nSo I took a few moments to optimise it a bit \u2013 and I ended up with almost 50% reduction in resources size\nin just two steps!\u003C\/p\u003E\n\u003Ch3\u003EBootstrap\u003C\/h3\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/getbootstrap.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Bootstrap\u003C\/a\u003E is awesome. But it\u2019s also a lot.\nModals? Popovers? Tooltips? Badges? Toasts? I don\u2019t use any of that!\u003C\/p\u003E\n\u003Cp\u003EI already don\u2019t include any of Bootstrap\u2019s JavaScripts, but I should definitely clean up its CSS.\u003C\/p\u003E\n\u003Cp\u003ESo instead of including\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs scss border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\u0022\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EI went to its source and copy-pasted the modules that it was loading over there,\ncommenting out the ones I don\u2019t need:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs scss border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/functions\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/variables\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/mixins\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/root\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/reboot\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/type\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/images\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/code\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/grid\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/tables\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/forms\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/buttons\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/transitions\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/dropdown\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/button-group\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/input-group\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/custom-forms\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/nav\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/navbar\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/card\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/breadcrumb\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/pagination\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/badge\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/jumbotron\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/alert\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/progress\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/media\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/list-group\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/close\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/toasts\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/modal\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/tooltip\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/popover\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/carousel\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/@import \u0022~bootstrap\/scss\/spinners\u0022;\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/utilities\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003E@import\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022~bootstrap\/scss\/print\u0022\u003C\/span\u003E;\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EThe only issue is that I do use \u003Ccode\u003Eforms.scss\u003C\/code\u003E \u003Cem\u003Ea bit\u003C\/em\u003E.\nThere is a search form in the header that has its \u003Ccode\u003E\u0026lt;input\u0026gt;\u003C\/code\u003E field styled.\u003C\/p\u003E\n\u003Cp\u003ESo I just inspected that element in Opera and pretty much just copy-pasted the three relevant selectors.\u003C\/p\u003E\n\u003Cp\u003EBum! Starting off with a minified CSS file of \u003Cstrong\u003E244 KB\u003C\/strong\u003E, now it\u2019s down to \u003Cstrong\u003E184 KB\u003C\/strong\u003E.\nA third of its weight is now gone.\u003C\/p\u003E\n\u003Cp\u003EBut that\u2019s just the first step.\u003C\/p\u003E\n\u003Ch3\u003EFontAwesome\u003C\/h3\u003E\n\u003Cp\u003EThe real big deal in terms of the website weight were the \u003Ca href=\u0022https:\/\/fontawesome.com\/icons\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E FontAwesome icons\u003C\/a\u003E.\nThere\u2019s thousands of icons included, but I only use a dozen \u2013 so why do I make visitors download them all?\u003C\/p\u003E\n\u003Cp\u003EYou can load FontAwesome in a number of different ways. One of them are \u003Ca href=\u0022https:\/\/fontawesome.com\/how-to-use\/on-the-web\/advanced\/svg-sprites\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E SVG sprites\u003C\/a\u003E.\nYou can include the definitions of the icons in a form of SVG \u003Ccode\u003E\u0026lt;symbols\u0026gt;\u003C\/code\u003Es, and whenever they\u2019re used,\njust use a \u003Ccode\u003E\u0026lt;use\u0026gt;\u003C\/code\u003E tag to reference it.\u003C\/p\u003E\n\u003Cp\u003ESo a wrote a simple service (plus a Twig extension) that would do exactly that:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eput \u003Ccode\u003E\u0026lt;use\u0026gt;\u003C\/code\u003E tags wherever an icon should be displayed,\u003C\/li\u003E\n\u003Cli\u003Ekeep track of the icons used,\u003C\/li\u003E\n\u003Cli\u003Edump the definions of the used icons at the bottom of the page.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EI just had to add some CSS to display the SVG icons the same way as webfonts\nin terms of size, position and using the color of the surrounding text:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs css border\u0022\u003E\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.icon\u003C\/span\u003E {\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E1.1em\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Eheight\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E1.1em\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Evertical-align\u003C\/span\u003E: -.\u003Cspan class=\u0022hljs-number\u0022\u003E125em\u003C\/span\u003E;\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Efill\u003C\/span\u003E: currentColor;\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EEt voil\u00e0!\nThe homepage of my blog went down from \u003Cstrong\u003E765 KB\u003C\/strong\u003E at the beginning,\nto \u003Cstrong\u003E704 KB\u003C\/strong\u003E after the first step, to \u003Cstrong\u003E393 KB\u003C\/strong\u003E now!\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-optimised_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u0022200\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAJCAYAAABaMo5wAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB3UlEQVQ4ja2U227bMBBEz\/IiUqLapu7\/f2HdGEV0gcXL9kG24rQIkKKdF2KXFDU7M6CoqnKDqiIix3rvAeTrFR\/Cm\/3HFXh372\/OiKrq+XzGe0+tFRFBRGitATAMAwClFEophBDYtg2AruvIOWOMwTkHQG1KLYXWKiEGtuuGAjEEDqiCCKUqzgqX9SfBRr5++rwTmueZeZ4ppWCtJcbIuq6oKqqKMYZxTMzzjDZFb5OmYWBeFgRwzuG7jvPSMCI0bYgItTaitwA8BWG7PCPOA0o8nQ6OtTbGcURaa3qfvpQCgDHmUCWldFh3vV6JMZJzptZKjJFSCiKCtfbh8sq2bfR9T86Z1hrhQaHSFGfkqHPemKl8i+Ou0OVyYV3Xg1BKuxp368QYhr5nXVceMY4jLy8vdF1HrZUuDvyYC8YoqoIR0JtDQ2dJZMpN5fD0BdN1h4XWOVJKrwrdQ\/yvEHYSH+0fuJFyANM04b0\/rLqjtfZHb\/\/2NVsfoagoclQ7NQWaghHINeN9R+8cTkTw3jNPE7XtgYx9z7IsiEBrijWGISWmaXqjZEqJZVn2H4nQ9z3f54rIqyKlNoKziMApGrbnZzAGjDlC7a2n5oJE2TP0OPl779D\/eGMezxz6\/Vb\/AmBJWhxIiYZ2AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-optimised_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u0022200\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EBtw, I\u2019ve put my little helper into \u003Ca href=\u0022https:\/\/packagist.org\/packages\/avris\/fontawesome-optimiser\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E a library\u003C\/a\u003E,\nif you want to check it out.\u003C\/p\u003E\n\u003Cp\u003EThere\u2019s caveats though...\nSVG is heavy. The two \u003Ccode\u003E.woff2\u003C\/code\u003E files I was using are \u003Cstrong\u003E261 KB\u003C\/strong\u003E overall,\nwhile the corresponding two sprites are \u003Cstrong\u003E2.1 MB\u003C\/strong\u003E.\nBut if I filter their content to just the icons I actually use (which is way simpler to do in SVG than in webfonts),\nit goes down to just \u003Cstrong\u003E44 KB\u003C\/strong\u003E!\nSo if your website is using a looot of fonts, you\u2019ll probably be better of generating a custom webfont.\u003C\/p\u003E\n\u003Cp\u003EThere can also be issues related to warm caches possibly circumventing the Optimiser,\nwith data that includes new icons being loaded dynamically in JS (which I don\u2019t do),\nwith the increased execution time (which doesn\u2019t bother me since I use an HTTP cache),\netc. Still, in many cases this trick can be very useful. Like mine.\u003C\/p\u003E\n\u003Cp\u003ESwitching from webfonts to dynamically filtered SVG sprites\nnot only removed the need for two requests \u003Ccode\u003E.woff2\u003C\/code\u003E files,\nbut also the need for the CSS that maps class names to font glyphs.\nMy CSS file went down again, from \u003Cstrong\u003E184 KB\u003C\/strong\u003E to just \u003Cstrong\u003E96 KB\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Ch3\u003ESumming up\u003C\/h3\u003E\n\u003Cp\u003ESo here I am: having spent not even a full evening on it, doing optimisations as simple as they can get,\nand ending up with the website trimmed of \u003Cstrong\u003Ehalf\u003C\/strong\u003E of its fat.\u003C\/p\u003E\n\u003Cp\u003ENice \ud83d\ude0e\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["website","web development","javascript","scss","css","bootstrap","fontawesome","svg","optimisation"],"hasMore":true,"image":null,"introLite":"\u003Cp\u003EMy new blog, despite being simple and freshly rewritten, loads way too much crap...\nSo I took a few moments to optimise it a bit \u2013 and I ended up with almost 50% reduction in resources size\nin just two steps!\u003C\/p\u003E","contentLite":"\u003Cp\u003EMy new blog, despite being simple and freshly rewritten, loads way too much crap...\nSo I took a few moments to optimise it a bit \u2013 and I ended up with almost 50% reduction in resources size\nin just two steps!\u003C\/p\u003E\n\u003Ch3\u003EBootstrap\u003C\/h3\u003E\n\u003Cp\u003E\u003Ca href=\u0022https:\/\/getbootstrap.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Bootstrap\u003C\/a\u003E is awesome. But it\u2019s also a lot.\nModals? Popovers? Tooltips? Badges? Toasts? I don\u2019t use any of that!\u003C\/p\u003E\n\u003Cp\u003EI already don\u2019t include any of Bootstrap\u2019s JavaScripts, but I should definitely clean up its CSS.\u003C\/p\u003E\n\u003Cp\u003ESo instead of including\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-scss\u0022\u003E@import \u0022~bootstrap\u0022\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EI went to its source and copy-pasted the modules that it was loading over there,\ncommenting out the ones I don\u2019t need:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-scss\u0022\u003E@import \u0022~bootstrap\/scss\/functions\u0022;\n@import \u0022~bootstrap\/scss\/variables\u0022;\n@import \u0022~bootstrap\/scss\/mixins\u0022;\n@import \u0022~bootstrap\/scss\/root\u0022;\n@import \u0022~bootstrap\/scss\/reboot\u0022;\n@import \u0022~bootstrap\/scss\/type\u0022;\n\/\/@import \u0022~bootstrap\/scss\/images\u0022;\n@import \u0022~bootstrap\/scss\/code\u0022;\n@import \u0022~bootstrap\/scss\/grid\u0022;\n@import \u0022~bootstrap\/scss\/tables\u0022;\n\/\/@import \u0022~bootstrap\/scss\/forms\u0022;\n@import \u0022~bootstrap\/scss\/buttons\u0022;\n\/\/@import \u0022~bootstrap\/scss\/transitions\u0022;\n\/\/@import \u0022~bootstrap\/scss\/dropdown\u0022;\n@import \u0022~bootstrap\/scss\/button-group\u0022;\n@import \u0022~bootstrap\/scss\/input-group\u0022;\n\/\/@import \u0022~bootstrap\/scss\/custom-forms\u0022;\n\/\/@import \u0022~bootstrap\/scss\/nav\u0022;\n\/\/@import \u0022~bootstrap\/scss\/navbar\u0022;\n@import \u0022~bootstrap\/scss\/card\u0022;\n\/\/@import \u0022~bootstrap\/scss\/breadcrumb\u0022;\n\/\/@import \u0022~bootstrap\/scss\/pagination\u0022;\n\/\/@import \u0022~bootstrap\/scss\/badge\u0022;\n\/\/@import \u0022~bootstrap\/scss\/jumbotron\u0022;\n@import \u0022~bootstrap\/scss\/alert\u0022;\n\/\/@import \u0022~bootstrap\/scss\/progress\u0022;\n\/\/@import \u0022~bootstrap\/scss\/media\u0022;\n\/\/@import \u0022~bootstrap\/scss\/list-group\u0022;\n\/\/@import \u0022~bootstrap\/scss\/close\u0022;\n\/\/@import \u0022~bootstrap\/scss\/toasts\u0022;\n\/\/@import \u0022~bootstrap\/scss\/modal\u0022;\n\/\/@import \u0022~bootstrap\/scss\/tooltip\u0022;\n\/\/@import \u0022~bootstrap\/scss\/popover\u0022;\n\/\/@import \u0022~bootstrap\/scss\/carousel\u0022;\n\/\/@import \u0022~bootstrap\/scss\/spinners\u0022;\n@import \u0022~bootstrap\/scss\/utilities\u0022;\n@import \u0022~bootstrap\/scss\/print\u0022;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EThe only issue is that I do use \u003Ccode\u003Eforms.scss\u003C\/code\u003E \u003Cem\u003Ea bit\u003C\/em\u003E.\nThere is a search form in the header that has its \u003Ccode\u003E\u0026lt;input\u0026gt;\u003C\/code\u003E field styled.\u003C\/p\u003E\n\u003Cp\u003ESo I just inspected that element in Opera and pretty much just copy-pasted the three relevant selectors.\u003C\/p\u003E\n\u003Cp\u003EBum! Starting off with a minified CSS file of \u003Cstrong\u003E244 KB\u003C\/strong\u003E, now it\u2019s down to \u003Cstrong\u003E184 KB\u003C\/strong\u003E.\nA third of its weight is now gone.\u003C\/p\u003E\n\u003Cp\u003EBut that\u2019s just the first step.\u003C\/p\u003E\n\u003Ch3\u003EFontAwesome\u003C\/h3\u003E\n\u003Cp\u003EThe real big deal in terms of the website weight were the \u003Ca href=\u0022https:\/\/fontawesome.com\/icons\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E FontAwesome icons\u003C\/a\u003E.\nThere\u2019s thousands of icons included, but I only use a dozen \u2013 so why do I make visitors download them all?\u003C\/p\u003E\n\u003Cp\u003EYou can load FontAwesome in a number of different ways. One of them are \u003Ca href=\u0022https:\/\/fontawesome.com\/how-to-use\/on-the-web\/advanced\/svg-sprites\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E SVG sprites\u003C\/a\u003E.\nYou can include the definitions of the icons in a form of SVG \u003Ccode\u003E\u0026lt;symbols\u0026gt;\u003C\/code\u003Es, and whenever they\u2019re used,\njust use a \u003Ccode\u003E\u0026lt;use\u0026gt;\u003C\/code\u003E tag to reference it.\u003C\/p\u003E\n\u003Cp\u003ESo a wrote a simple service (plus a Twig extension) that would do exactly that:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eput \u003Ccode\u003E\u0026lt;use\u0026gt;\u003C\/code\u003E tags wherever an icon should be displayed,\u003C\/li\u003E\n\u003Cli\u003Ekeep track of the icons used,\u003C\/li\u003E\n\u003Cli\u003Edump the definions of the used icons at the bottom of the page.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EI just had to add some CSS to display the SVG icons the same way as webfonts\nin terms of size, position and using the color of the surrounding text:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-css\u0022\u003E.icon {\n    width: 1.1em;\n    height: 1.1em;\n    vertical-align: -.125em;\n    fill: currentColor;\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EEt voil\u00e0!\nThe homepage of my blog went down from \u003Cstrong\u003E765 KB\u003C\/strong\u003E at the beginning,\nto \u003Cstrong\u003E704 KB\u003C\/strong\u003E after the first step, to \u003Cstrong\u003E393 KB\u003C\/strong\u003E now!\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-optimised_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-optimised_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u002260\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EBtw, I\u2019ve put my little helper into \u003Ca href=\u0022https:\/\/packagist.org\/packages\/avris\/fontawesome-optimiser\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E a library\u003C\/a\u003E,\nif you want to check it out.\u003C\/p\u003E\n\u003Cp\u003EThere\u2019s caveats though...\nSVG is heavy. The two \u003Ccode\u003E.woff2\u003C\/code\u003E files I was using are \u003Cstrong\u003E261 KB\u003C\/strong\u003E overall,\nwhile the corresponding two sprites are \u003Cstrong\u003E2.1 MB\u003C\/strong\u003E.\nBut if I filter their content to just the icons I actually use (which is way simpler to do in SVG than in webfonts),\nit goes down to just \u003Cstrong\u003E44 KB\u003C\/strong\u003E!\nSo if your website is using a looot of fonts, you\u2019ll probably be better of generating a custom webfont.\u003C\/p\u003E\n\u003Cp\u003EThere can also be issues related to warm caches possibly circumventing the Optimiser,\nwith data that includes new icons being loaded dynamically in JS (which I don\u2019t do),\nwith the increased execution time (which doesn\u2019t bother me since I use an HTTP cache),\netc. Still, in many cases this trick can be very useful. Like mine.\u003C\/p\u003E\n\u003Cp\u003ESwitching from webfonts to dynamically filtered SVG sprites\nnot only removed the need for two requests \u003Ccode\u003E.woff2\u003C\/code\u003E files,\nbut also the need for the CSS that maps class names to font glyphs.\nMy CSS file went down again, from \u003Cstrong\u003E184 KB\u003C\/strong\u003E to just \u003Cstrong\u003E96 KB\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Ch3\u003ESumming up\u003C\/h3\u003E\n\u003Cp\u003ESo here I am: having spent not even a full evening on it, doing optimisations as simple as they can get,\nand ending up with the website trimmed of \u003Cstrong\u003Ehalf\u003C\/strong\u003E of its fat.\u003C\/p\u003E\n\u003Cp\u003ENice \ud83d\ude0e\u003C\/p\u003E","words":752,"readTime":4,"lang":"en"}}},"blog\/technology\/new-year-new-digital-me":{"key":"blog\/technology\/new-year-new-digital-me","type":"article","published":true,"meta":{"createdAt":"2019-12-31T11:22:05+01:00","publishedAt":"2019-12-31T11:22:05+01:00","group":"redesign","category":"blog","subcategory":"technology","slug":"new-year-new-digital-me"},"content":{"en":{"slug":"new-year-new-digital-me","title":"New year \u2013 new (digital) me","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4_small.png\u0022 alt=\u0022Screenshot of the new version of the blog\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022234.07874015748\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADFklEQVRIiaWWz24cRRDGf9XTf2aXJSvHYCLlgEDiyCkQiRtXrhw4IfEaSBx4AA55hQiJIxIvwM0kAiQgcoQcEsmAZGJsrx2CPd6dnunisJ71zu7au0BJo\/7UXfVNTdVXvSu33nlXRUAVAGZxlhlEDAAxVgt9GoyMl+AcYgyqabIpIqgqMUZSE6Dnx1PxVuSCuLEG3377FiLCzs6vpKQcDgZzPrPYWkvIA945rHWE4HHO4pwnBE+WZTjrCN7hg8d7T\/DjNc9z5ONPPlXnHN57fLg4DC0cJoEhzOxN\/ALeO7IsQ0QufZpqTa\/TJiklndtdwfb3D8hDhjCiSjlVVeODZzQckeeBfr+Pnremadcq+F8lVMbI3tM9nHPEKqIITs4oa09KiTzkxBhRFJtZjDFsbLyMtXblDxVV\/U8VAkgpTVqhqgtbsKqpKqqKbYiavFSVlNLEYfppzqfXacL\/YyKCMQZbFEWLzBjTEqExZhKwTJRlWTIYHOH9eOyvr61N\/FbW0LKWNdW5qhvNPVXXNSenp+O4pIgRyjJyWnte7HVZfyFbWilzVSIXuAaUqiq589kdPr\/7BVUsAaWuUyvGiCCMK21EcJml37VYja12X4bNIq1cppPtBz+wu3WfJ99+zeDwoJXItBZbHChnwxLnw9LqANhlk9HSVyrpWUGrClMWk\/1pjmKkdLyQZYaTYU0sayrJKIaRrvdz\/rP40pYtsnRSIJpwGjk5Opw7FxHWruXk+fgWv36tg+t26PdyrHOtj2xL4qIjdrYt08pv7NHWPeKzP\/hrlBgmJZ4VxKOHbG0e8Mprb7Jx8\/UpclBN5z+4Sj8Y6lgRCQvvqtl3zV2hi4bu9+\/uUR7\/yYPdZ\/S6yvrNde5+uUmv2+HDj16C84RUlbIcTSpgTEZVFtS+T27m+RfhlTS0F2u+2nzM91s73Fjr8NYbN9jefc6j3QHvvf8Br55zjBMBRDAy\/l9hvcebEomKBH\/lu4DxlF2QzWOAnx4\/5f6P2wg1x0XJN7\/sc3xW0nHCz7\/tt6cMRWguUeHvYaIoCorh85XG\/h9McAJLnmVpFQAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris4_small.png\u0022 alt=\u0022Screenshot of the new version of the blog\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022234.07874015748\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EIt wasn\u2019t really supposed for the New Year, but I\u2019ve had plenty of free time on my hands\nduring the holiday break, so here it is already: a brand new version of my blog \ud83e\udd73\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4_big.png\u0022 alt=\u0022Screenshot of the new version of the blog\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022468.15748031496\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADFklEQVRIiaWWz24cRRDGf9XTf2aXJSvHYCLlgEDiyCkQiRtXrhw4IfEaSBx4AA55hQiJIxIvwM0kAiQgcoQcEsmAZGJsrx2CPd6dnunisJ71zu7au0BJo\/7UXfVNTdVXvSu33nlXRUAVAGZxlhlEDAAxVgt9GoyMl+AcYgyqabIpIqgqMUZSE6Dnx1PxVuSCuLEG3377FiLCzs6vpKQcDgZzPrPYWkvIA945rHWE4HHO4pwnBE+WZTjrCN7hg8d7T\/DjNc9z5ONPPlXnHN57fLg4DC0cJoEhzOxN\/ALeO7IsQ0QufZpqTa\/TJiklndtdwfb3D8hDhjCiSjlVVeODZzQckeeBfr+Pnremadcq+F8lVMbI3tM9nHPEKqIITs4oa09KiTzkxBhRFJtZjDFsbLyMtXblDxVV\/U8VAkgpTVqhqgtbsKqpKqqKbYiavFSVlNLEYfppzqfXacL\/YyKCMQZbFEWLzBjTEqExZhKwTJRlWTIYHOH9eOyvr61N\/FbW0LKWNdW5qhvNPVXXNSenp+O4pIgRyjJyWnte7HVZfyFbWilzVSIXuAaUqiq589kdPr\/7BVUsAaWuUyvGiCCMK21EcJml37VYja12X4bNIq1cppPtBz+wu3WfJ99+zeDwoJXItBZbHChnwxLnw9LqANhlk9HSVyrpWUGrClMWk\/1pjmKkdLyQZYaTYU0sayrJKIaRrvdz\/rP40pYtsnRSIJpwGjk5Opw7FxHWruXk+fgWv36tg+t26PdyrHOtj2xL4qIjdrYt08pv7NHWPeKzP\/hrlBgmJZ4VxKOHbG0e8Mprb7Jx8\/UpclBN5z+4Sj8Y6lgRCQvvqtl3zV2hi4bu9+\/uUR7\/yYPdZ\/S6yvrNde5+uUmv2+HDj16C84RUlbIcTSpgTEZVFtS+T27m+RfhlTS0F2u+2nzM91s73Fjr8NYbN9jefc6j3QHvvf8Br55zjBMBRDAy\/l9hvcebEomKBH\/lu4DxlF2QzWOAnx4\/5f6P2wg1x0XJN7\/sc3xW0nHCz7\/tt6cMRWguUeHvYaIoCorh85XG\/h9McAJLnmVpFQAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris4_big.png\u0022 alt=\u0022Screenshot of the new version of the blog\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022468.15748031496\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EIt wasn\u2019t really supposed for the New Year, but I\u2019ve had plenty of free time on my hands\nduring the holiday break, so here it is already: a brand new version of my blog \ud83e\udd73\u003C\/p\u003E\n\u003Ch3\u003EWhy?\u003C\/h3\u003E\n\u003Cp\u003EWhere to start? I got increasingly annoyed by the old version.\nThe design started seeming boring and blunt.\nThe code started growing unstable.\nIt was using the \u003Ca href=\u0022\/projects\/micrus-v4\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus framework\u003C\/a\u003E,\nwhich I \u003Ca href=\u0022\/blog\/how-and-why-i-ve-built-and-killed-a-php-framework\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E stopped supporting\u003C\/a\u003E a year ago.\nIt was using \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Micrus-Assetic\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Micrus Assetic\u003C\/a\u003E\n\u2013 an outdated method of asset management,\nwhich highly depended on the server configuration and binaries installed.\nThe deployments were \u201ciffy\u201d, to say the least.\nI was afraid of sending even small changes to the server, for fear something might blow up again.\nSome small things I didn\u2019t even notice were wrong: like still warning about Google Analytics tracking,\neven though I migrated to \u003Ca href=\u0022https:\/\/matomo.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Matomo\u003C\/a\u003E ages ago.\u003C\/p\u003E\n\u003Ch3\u003EWhat changed?\u003C\/h3\u003E\n\u003Cp\u003EI decided to keep it simple. To go with a \u201cless is more\u201d approach.\nI\u2019ve removed soooo many features that just weren\u2019t useful enough.\u003C\/p\u003E\n\u003Cp\u003EI used to have an admin panel: except I didn\u2019t need any fancy editor,\nthe main content was written in an (enhanced) \u003Ca href=\u0022https:\/\/www.markdownguide.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Markdown\u003C\/a\u003E anyway.\nSo for this version, I\u2019ve decided for a filesystem-based approach: I\u2019ve ditched the database completely,\nI don\u2019t need any ORM, I don\u2019t need an admin panel. I just have a bunch of \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/SUML\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E SUML\u003C\/a\u003E files\ntracked by GIT. Using \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Esse\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Esse CMS\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cp\u003EI used to have three language versions of the UI \u2013 but why?\nI don\u2019t think anyone really cared about not seeing the names of the categories in Polish,\nwhen most of recent my posts were in English anyway.\nSo now the posts are still available in the language(s) they were written in,\nbut I\u2019m no longer maintaining the multiple versions of the UI, or the features to filter content by language.\nWhat a relief!\u003C\/p\u003E\n\u003Cp\u003EI used to have a \u201crandom post\u201d box. I used to have tag clouds. I used to have an embedded Twitter timeline.\nI used to have the latest posts on the \u201cabout me\u201d page (really?). I used to have a link shortening feature\n(\u201davris.it\/l\/\u0026lt;whatever\u0026gt;\u201d) that I\u2019ve never used, not a single time.\nI used to have a separate controller and database fields to support redirects for legacy URLs from the even earlier version.\nI used to have database fixtures. I used to have a console command to export legacy comments to \u003Ca href=\u0022https:\/\/disqus.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Disqus\u003C\/a\u003E.\nI used to have tooltips and popovers.\nAll gone now! \ud83d\ude0d\u003C\/p\u003E\n\u003Cp\u003EI replaced the infinite scroll with... just loading the whole page at once \ud83e\udd37\u200d\nIt\u2019s not that big for today\u2019s standards anyway \u2013 the heaviest list of posts is 113 KB of compressed HTML.\nInstead, I now lazy load images using the \u003Ccode\u003EIntersectionObserver\u003C\/code\u003E API.\nWay simpler than infinite scroll or pagination \u2013 which aren\u2019t really necessary with this amount of data.\u003C\/p\u003E\n\u003Cp\u003EOh, and the website is now using a fast an sleek \u003Ca href=\u0022https:\/\/symfony.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Symfony\u003C\/a\u003E setup with an HTTP cache \ud83e\udd70\u003C\/p\u003E\n\u003Cp\u003EDesign-wise, I use the default \u003Ca href=\u0022https:\/\/getbootstrap.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Bootstrap\u003C\/a\u003E theme,\nwith only minor changes of variables and minimal additional styling.\nThe main feature, obviously, are the tilted elements. That\u2019s enough to add some personality to the website,\nwithout making it overcomplicated.\nCompared to the previous version, it\u2019s way more contrasting, better tailored for wider screens and clearer.\u003C\/p\u003E\n\u003Cp\u003EOverall, 41090 (!) lines of code were removed:\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-3-4-diff_big.png\u0022 alt=\u0022424 files changed, 6711 insertions (+), 47801 deletions (-)\u0022 class=\u0022border\u0022 width=\u0022550\u0022 height=\u002289\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAFCAYAAAAt8E4LAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABbUlEQVQokZ2RTY4TQQyFP7uqKwlh0skIISSExBHYchPEATgVaxaciQVigRAw+emku6q6K2UWCYPYDBJePVnPz7I\/ef3slT1\/+YLcnzBtsDJSypmbdcv3r9+YzWesNi2xjwz9QN91pJgB4+GS\/\/L438I5hzaeVEZEhGpGe7tBqRy2B1SVWg1V+RNm18wHF\/6r\/vZ4EGqZMDPCLHDqjghwPBxRjNX6BhMh9pH93Y4nT28J8wXd\/siqXWIohsH5jGsaSimMKSMinKvRrleE4Nn+3LF4vKSWQhMCOV88ghHjyHm6kPFv3r2l3bTUanx8\/4G+O+GcEofEYrkg55FHyzkpjXin5JQQ58EqoopvLkc0zuGcAp7iJkIIDENizBnMQARBqNWotQKgqqgqItP9t\/yXT58RFXyYcTx0dPsDZoYIpBgB4w6wK6JpGu\/Zb3\/sQEAwEtB1ghiYGLGPmBlTzleyRhoGDLlOX5TZtSOAGL8AA7fCc1N6DsoAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-3-4-diff_big.png\u0022 alt=\u0022424 files changed, 6711 insertions (+), 47801 deletions (-)\u0022 class=\u0022border\u0022 width=\u0022550\u0022 height=\u002289\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EThere\u2019s nothing else in the (programming) world I love more than removing useless code!\u003C\/p\u003E\n\u003Cp\u003EDeployments are now stable, simple, reproducible and revertible, thanks to\n\u003Ca href=\u0022https:\/\/symfony.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Symfony\u003C\/a\u003E, \u003Ca href=\u0022https:\/\/webpack.js.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Webpack\u003C\/a\u003E,\nlack of database (no db = no migrations),\nand most importantly my recent child: \u003Ca href=\u0022\/projects\/avris-deployer\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-cogs\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avris Deployer\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-deployer_big.png\u0022 alt=\u0022Console output of deployment\u0022 class=\u0022border\u0022 width=\u0022848\u0022 height=\u0022237\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAKCAYAAADcpvzeAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB1klEQVQ4ja2TMXPUMBCFvyfJdw6JyUDLpKOloOf\/\/w9mAqkokkDu7LP0KNZOLpmbpAAVlvbN0+767ZO+fflsgG4QhzujBK6F\/a8Luov3uE3U8UDfiYvznjbPgLi5\/olbA8T\/XPp6dWUJ1Jt6l0l9Q9tGe0jQhDZG2bgRcTFuggo2tD8JED5Am9JTYsBvFT\/BKZ4S6hv1NpPeNTwJbYSryGeGYtpDQimutjFFliVOvVFp1F2iG2bwUsSE2g2wAjRoYzyDSsSe9Yh5FsUN2iQ8iZaFxwSKZPU+BbnC\/Lvgw9OviVAIgouhGqQjfJmmX8FfrpL6aF1DDeKmQjbeJdSZep\/wlB6llXwk9nFncY7iEdtGKwcj6VE9a4kXjgXCJM+Qtku5tEiYQ1oyKJs8VMpQF\/uuJhZaax19n8UL4SUnsNOc4lm0fYIGrjG+NmaUQJ1Rt8y+b6RZeI7xvmpY\/4Op1S1QMVSFWsl4TNTbDDlwxnXwoG2LZNNrT1680fZJTgFI2xaj6mO3IQ+VdN5QZw43Ja6XMPj6ek6Z8mm91cxpTvnYf+KwHxk+XLJ\/2LEfd5wN53Ql8+P7dTxZwDZb9UzjiI9NvZh15YS3FlNj5GU\/4qzmjtvPOX8BswgOy6gNMP4AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris4-deployer_big.png\u0022 alt=\u0022Console output of deployment\u0022 class=\u0022border\u0022 width=\u0022848\u0022 height=\u0022237\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EVersion 1 (\u201dSilva Idearum\u201d)\u003C\/h3\u003E\n\u003Cp\u003ESo, to finish this post, let me just quickly show you the four versions I\u2019ve been through so far:\u003C\/p\u003E\n\u003Cp\u003EMy first blog was called \u201cSilva Idearum\u201d (Latin for \u201cForest of ideas\u201d).\nIt was anonymous, spirituality-oriented, Polish-speaking, Joomla-running and with a \u201ctoo much\u201d design.\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris1-post_big.png\u0022 alt=\u0022Screenshot of the post page in version 1\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGJUlEQVRIiS2UO49kZxGGn6rvdk736Z6+THt21pfF69sagYUsIECIhAjxL5BICIiQSEj4AyT8AmIiiEgXgQRItgAhC3vB9trMzM7Ozuz09O2cPt+FYLaSkkqvKqnnKfntL94uH58rg8mCz06\/yvok4k1h0AsLvmButxzdW3B4UOMOLMtux\/V6SW+Fq5j4bLOiDApfvz9jVNWYYnHF4kV4\/p8nKHtSdNjgmR7NSD5wcn1FbwzWWUosbG5a+rMnzCeLP9hHV4bZ6xOwR4yvN4zqPSmCN5F5UN585x7TqcebPV3j0Ww4S2fssDx8fMqTYpn3M\/78xy\/55Y++zzDMCOWIkjbE6hFSOtqLFcE4SjXAjGbMAxwMeh4cj3i+CqyWW\/J0zTx32LsP7jGZLoi9MkxbWhcZhinLizWz114nv3zElQ0Ym3FW8P2a98YLOHiF33zwa0LcIvWQeVjx17895N6rb+HNOSVH7h2\/RUlbar\/ExEgYvcR+d4M4gx8M6UOg7QY0s5cIuwva6y+xd195wG67IZcObYYIzwiaGNrAQTTsB4fYwYBQO3wVsKagqtgq8Kuf\/pzPv\/gUlxJvvPMyk4MRRg2npyfEPtGMDlAZIeMZOe4RqdCqQWPDrn3OZX+HVhJ+GJDhAp9W2O0msu96sjqaxUuM2sBhGPOstITNjnmj9NM5zXiM9w5VJZ99gvQbHsxG3K\/fwFWBv4vnal94LRjuD6fknHHZ0G5ajBRkdki2DTrosWkKN4Hd3pCMZ31zQx4echAcNkWDCyPscI7aEfZORTWsubM\/wZoJ86MxebHAhwYVQUTRyTcpWGK+hbeQ+bYqlELJGX0FcopYa2jUUdc1z59+QteuwVZIqqgpdJstlydnbDEU3bHwE6xBMDqAEnDWoIcv0w7HVPWI5maJEbDe4JxirENEEPEg4LktEUMpCTUBck+KHdlEVAXRQru5RNQhpsI5g0k91lasnn2MNY63H7zLo0cf8rTbYW0xEA1pF0kFqmmgV0+ZvYUZr6jiBicGNSBqoPTk0rO6WSMCIpBTRo2iLiBaiCnSOAMUIKNGKDlS8h41FSKC8TXNZErpr5Cy53ix4Pz0c+yiarjedCA99aTC1iNULNYUejth78Z4tXRtAjaIAESC91g\/wBpFbocgt2eDctsFKIJaj+hznHOU0kFZEsKUWf1f\/MKSVp8xn46ZTO9jTTVi3CvPrzqa+yPw1YvlmVDVZCJ9KpScUDUgDqGQU6HsVkQKooailpvLc549PWc2n7DbtjRNw9PHn7Ludrz3rW9DycS4J8anVBKZ3xlgdsLy4gLvGtquxYbaENOIsAewWBswKmQMJHDekzO07R4o5FzwzoMYJAREQVXo+45HH\/6Jf3\/wF8Jkwj8+PueH3\/saD3\/\/O4Z37\/L+d74LuaeoY992RHuCHnjCZol51uCzwWmDbUum626DOfZovyIJmDCh9IloE5VTmqa55SVnhAxiKCUjovT7Fms9fbfhfAOr88d88NEZunnCbHbM9OgQeWEjoohVri8umZgRuhuS1h2pGPZhjd13heRHCBGjYIwi6lABDYILFWgg5oxKIaf4gpmCtZa+7yg5UxB20TCcHfPuN95nefOQeLHk83+dQAkIGTUWRGhGr7KJheVKafwRaXzG5fUl5WyLPaoMZ9s9W23Q0QIzGCEFVBU1FuuHWDVQCsYqwgChEGNGVagHAyADhni9ptlfc\/lFZHB6SXA13DvAHhySzz8ipRYd3cG6Q+qmZfnsKdglySZyUxGGAVsVy2vn\/+Offo6++RWcH76wJWKMR42j37fc3KyBggDeO3JOGDWkXFAVVA0\/+PFPbuE3BvOzFhtb8voU2W+R5RkKZPGUcYPzd3B+w\/X1GjdsyO0TZDDCeh\/guuP+fIujoMYiqlDAqGKN4OsKZz0FEFEgUXKhlIJznhg7VC0xRiRHpF0S+x0xC+wVkRHN4BK1hl1vsH5IFRyD9oqzx2ckZ9l2icPjI6yaAcbXHBvYdlsiHU4NKSdEFZFISYbdboMYf2tgTrcvBqHv15RcEN0jYjBqiAxRGyj9mqI1g7omhxa9OWUwuUvrK0K6IXrP6NW7ZFdDUmLX8X\/09s8geltpKwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris1-post_big.png\u0022 alt=\u0022Screenshot of the post page in version 1\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EVersion 2\u003C\/h3\u003E\n\u003Cp\u003EAfter coming out and becoming independent from my parents,\nI was finally able to put my name on my posts. New domain and a redesign was also in place.\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris2-home_big.png\u0022 alt=\u0022Screenshot of the homepage in version 2\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEQklEQVRIiZWWO2xcRRSGv3nd1+56d+21DY6xnYctIkAIRxGCCAGK6Hg1FFSICgloEAiJBikUFCkCDQUNLVJ6RKjpKJEQUhwLYYKVxHYSdm3f3bk7MxR3d+MkDlmmOpq5959zzv+f\/16xuroaqrUaIgQ6u7t8deEClWoVYyKiyJDnOQDGGJxzHD9xAiUlhy2lFMaYQ8\/GXJe0tZZOu02kBNZaGs0G9XoD7z2tVuuuC7z3dO0ecZSxc\/MGWhuKwqKkwjnPRK2OEBKtNZubm6ysrPzvjHS73WZxaoKF6QY\/\/7ZNllVozUwjEQghCCEghEBKydbNv\/nsm9d485W3WL\/6O9f+uk3e73D5yp\/YQvP5+19zcvE08\/PzLC8vjy4ZYowT6zPPnGR+QhFHGp1UiSODUZper0cABOC8J00SBIpqd4rrv3Y4Ov0Up559nnZ7h4n+T1z9Y41+J2CMptNu07UWrTVKStI0JYqi8To0u3CEONVIZWjEt9jZ2WF3bx9rLVmWkec5cZKQ7+8T6YhHry2RTR\/n1vU6353\/GELOS2fPcpNjFD1D+5823W6POI7Z292lUqkQxzEhhLs69qBYr6+vcWR+njipUTiNMYYkTZmamgKgXq+X1DUatG\/cYLMvqedbSK84c\/oNxETO3NIM3\/\/wLWdefhFtDEIKiqJPCIGiKJBSjk\/ZnkpY21gnMRUiAvn+HkJqCtvD2hKsKCxRFCMkzC1M0r29TdZMmHriSfTeL0w3Fec+eYflpx9Ha4W1Bc45jDFYa+n3++NTNp0ErDAECppxgzhOmJxsAiClJISADx6tNFprPv3iy3sgXh1FSik2NzeZm5tDaw1QVq31+JTVqkdRyR6ul2OdwBaO7e1tpJR474miaORBSkoQAu\/94DwAgRACUsqS3riGcw7vPVBaRbVaRQ6866GULZ1YZmvrOtb2SLUmTROiOB6MPGitEEKglCJ4TxCQRAnGGJSShHCnyiiKyFyOlALv79iFc26U0MOWWF1dDQc3Ll68yPTsDLE2MPCh0cNAGFA5rGy4vPcIIdjY2KBSqZSUC0Gj2RxbP8AlfS+wlJJKmrF2+TJiVFVASjWYGAGIUdXDylutFrVaDSkyarXagEZBYYvSj5QaKyP9oAMfAniP0XqkhyzLRiItEymtM4RAFMUANCdTNtavQAg0WjMkSUKlWhnhPlRDBykBcM7R7XZZWlq6L8mDAIcBOudoNpuc\/+hDlo\/MsfTcCxxZPE5zanKs7hzaoU6ngxCgtSHLspE2hokPrWC4N5wwhCBNEkIITCweI9QibrfbRDvbrPDfo34wvk9Dttej14vpdnvs75efkNJHPEKUehGD0VdK4ZwbdWl29hGq1Sqvv\/sB17Z2qJGzsPDY6J3DunofZYdRAZCm6ej\/RimFNqYc+wDeO6A0QiEE\/X5\/oKsS49yP62w7jcs7vH2qynszM2NT9i\/Q3AYk6KDr5QAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris2-home_big.png\u0022 alt=\u0022Screenshot of the homepage in version 2\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EVersion 3\u003C\/h3\u003E\n\u003Cp\u003EAs announced in \u003Ca href=\u0022\/blog\/brand-new-blog\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-computer-speaker\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Brand new blog\u003C\/a\u003E\u2026\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris3-home_big.png\u0022 alt=\u0022Screenshot of the homepage in version 3\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221603.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAkCAYAAABmMXGeAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFE0lEQVRIia2Wy48cVxXGf+feenRVd0+P7Ywn47ESk4kTiEE8LEACsUECCQHZIRZs2CL+EZD4A9iyjmADUjYIgSJhQmyEIjBCKLKxsScT2zPdPT1Vdd8seqY1j3Y0SHybUl3V+e79zvnOqSt\/uPXnJEqBCKIUSmlaY8mLnKKsECVY4xCBhAAgMWBcoq5ylAgheJJ3xOAhRmT46udTMbpIUqCUJqsHqKIk74\/Iqj55URG9IwGZaBKgQ4QErmuwzmAOptj9Xdxsim8aMm8thfegFSEkwkGDdgGScOOlDWwUHh8U6GpEqTLq1FBoxdNH92mmewRriaYhNDOSDxAiKkWhmU7o9me4zqFUge6tcOO11\/jx975DayM2CNZYunaGFsHZjpgE0zZY0xF8IgaIzhFDQIorbySV5UiezyX3R+i8ABKfePllDlxkajwAKYR57qwlmJZoGnzXEJ0jeEM0Hcl2yDu33jsslELpjHklZF44USAgIoBASiQSpAQxklIixTB\/T4mUIqSEWGsTh0gpISKMx2OUUvT7fZRSADRNQwiBuq7RWh+FICKLuCOoI7LjKMsS7z2TyYQQAj\/76Y\/Ii4KpLdFZASLcfXCw2PA40vNPus9k\/ARFxmBlSDObsHH1JRKCEogxYnyilyuUUidO+lzSGOMJOUeYNJGVfk6KgZ2xY+NCMW+K88h3zuG9X3woInRdR6kszrQIifWRnhdmifzsKOg4fvm7P\/H+Bw8ZDGpsSGTlgO9++VO88sIQ0Zper7cgWIZs2eJf\/vEBv7\/9PvVwxJNpy3C4ws2tdTYv5uiQY42hqmtCCGeIRWS5\/GgNdZbTI3F11MPOxiTnSQeWzphDD5\/N+Qn5p+GN4fHjbRBFVVfM2pboLVlviODpug5IZFm+lHxpTp0x+K7BeU8vS2hvicFTDWu0koU\/T1f9Y3MavUNFj+86ullGWRSYtiN4RxRhMBgsSJdhKen33\/wmNz\/zOvPGn6994cbrdI1hY\/NFnm0\/ZOWFFxfGP42l5j+O4w3RHjSMLqwy29uhHFxckJ6OE2ttOlo8\/TxOehR8GsvadGmhmqbBWkuWZdR1jek66n6fe9v77E92WS0dXSzw2So3ro3Ol1M1GRP2JlRbW4QYefTMMNxP1FnFxitXmZnEWi+nypdFH5KezoleW6d34TIojVbwk7dm8M+\/8uFkk7d+8Vl8SEwPLMUoJzuvT4N3eGPIej3QBV+\/HpleGvF0\/AwRUAIJEJZ31VL5P\/\/NA+78a4x1kW\/cXOPbXxpQ1jfp5TmZVlwc5ljnIUUOB90CIrJcfq+5y9qzv3Otang1fZHB8FsE59FKePu3j7i7k4j+31zpwQ9\/8LUTpM+tfnvvNtu33+ajAtavXUZI9PsVdVVy7+EOt+48ZnfvXb56\/QpwkhSeY\/73bt\/h3v0HiGje+OQW6+uXsS4xGFQ4B+N9S1koRoOS4bBe\/js5bfq2bTFdh840\/f6A8XiKKCjzHKUVs\/0ZohSrq6torc9nfqXmIy8laI3n1+8+oSo1Lio2LxX856MZCWFrM\/KVT6+dT\/4f\/\/aE7d0O7yNbV\/p87volYoKqzGhaQ0QhApmCTKv\/vffj4U1EKYWIYIwhBI9SOb1eceIwHyv\/xK4iJ0bcfuvZHTdUVY+BS1wYlmdiz14xODt8rYv86p1HWBfZmwWezuD+TsuHu92y8JM5\/X9B0hynLNUQk8ZH0EoQSaR09AREKDMhy7IztQD4L+DGHxjr8QA8AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris3-home_big.png\u0022 alt=\u0022Screenshot of the homepage in version 3\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221603.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris3-posts_big.png\u0022 alt=\u0022Screenshot of the list of posts in version 3\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADMElEQVRIib2WzW4cRRSFv1vV1T09f5AZx5EiJAiKWCDxIzZIkYxX7PCCBQs\/BO\/AM\/gV2PEEXrJha4UNwgpKVg6yzHg89sz0X1VdFh0bO1EyvaI2t\/vWUZ1T957WbYkxKhvW2dkZxhim0+kbe+fn54xGI4qixBjBOUdRFDjn8CGQuozZZcWDSY5zbhPVodR1vVHQ\/7gOE9XNek5mJQj0pGJ5tWCQ91gvL0mc4+EHH76BV1VCCAA0PhC852wtPNruv5NHRJCqqjYqqr3iIzhr6KUGAO89Ozs7nJyc3MHu7+9zdHTE8fHxnfze3h4HBwebqA6TTQgAX5c0vsFkGfPSMBmmiAinp6f8\/fLlHexiseCrjx\/z6P4nvDc2JLPf+fnXp8zn8y5UJCLyToCqkqYO5xJ6ec7YtBWirnkyGNO8P+VFYshDZOgjH7mM33qP+Wt7zmS6Yvb0CV989y02PGcTF0AnD5VlyeXlJaPRiMFgQJZlAGzvfsPsnxlfDvsISihLHnz+GT\/ee4F7\/gdJYbnYNfz5cAddf08Xrk4eqqqKEAJZlmFeVSjGSFk1BBVcYqgb2LrXx3vPxapmWSrjfkKIyrifYiV2EXTYqWViU3xUxll6k2+aBmugXC1Ra0mc4+oqkOc5qXimfUG1wpiUzBm8j91athEB+LoA76mqAS5CMsgREYL3eO9pmgYtCvr9Pnmeo6osLhaIEVSVusiYTCZdqLp5yDlH0zSEEIgilMslaZpiE9tG28brdgIYa1BVrDUoEFXZXJ+OX5mIMBwO7+RDCMQQKcsCaxPW6zXOJSRuiqq2LbUW7yMxKqgitwS\/VVAH0dgkJSI4KyS2PbSua9raCjFGjAjD4QgjgjEGY8yNZ4y1ncRAx5bF0KCqqDhiCIh7dQ9jSbMcRBABxdAWIyIIIq2HNEZQpcvQ7FSh69mUZdmdm\/70yzMu1p7pKOWq8BR1YPfTKT98vUXUiKgQNZKYTjQAbJz2twdlkrQHt97wRIWo\/3mwl7b5uq6p65per9e205guvx7wtll2beTX3733ADexbbdgrMFJ65lr3HK5ZLVaEVVJrGFr6\/7N\/usct5\/\/BSOPoERFJpF9AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris3-posts_big.png\u0022 alt=\u0022Screenshot of the list of posts in version 3\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris3-post_big.png\u0022 alt=\u0022Screenshot of the top of the post page in version 3\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACrElEQVRIib2VTW7cRhBGX1V3s0nOUGNLTrIIggTeBYJhJSfwVQzoBr6FDpO1LxB4lUXuIMABpAiSrJnhX3d5IWlkw3ZIB0E+gADRLLJedX2slpyzMaGzszNUlYODg0+eXVxc0DQN222LqhBCYLvdEkJgTIkiRP6+7vhuvyKEMJXqtfR9Pwn0P+q1N5vm+evtWxChiJFmuZxT6b+SiODnBPoQcM6hqqzXa0SElBJFUdC27S2gGUMSDOXJ\/vKLCf9JZjYP6PDwkMvLyzmhHB8fc3JyQtu2mBl1veCPN7\/x8y8veLL\/\/eT7fg7112pz0zGMLWUsyTlTL35C\/WpyhwBmeehrZWJsc2bpHNkyz49+xcVyVnGzWnZfmbu7DDBVyIZgGJAAUUVEMBv4drVCnaMsy1tIs3k7NKdlT0MklzV7zlOpIgJ\/eqEaRp6iDNm4TCPv0shKlNXqEaqKquJDQICc8zygyQjgWb3EkiFApY7TsSfuNXRdy6M+sRChy5kuZX6MJaYFF9uEU3DdSB0dpZ+GgZkeerO+YnN9hRMhmTEWBU04IBQFv5+e4oeBDJjBD92WMRvdkInBURZCWTjIaZ6H5rTs5atXtG27W0t3CUWgKtxH8UdHR6gIhVdU4Go9MCZjVSlOp3dp1tFxfn7OOI6ICKq6q1REdt64H5Z1vaCoFqw7Y9snCicY8E3j0WmgeUeHmaHOoSKYGTFGvH+w3z1QzgnnPGZGPyaiV\/ox87gpUJ0302aZOqWEc+4WTJW265CuRZ2\/NQ6gqvR9T13XlHVkr1YEIQwj19fvKB8v\/pvf\/j5ZSpnlcgFAJUL+oG1mRlVVO+jNZkOMEYBYCk1Z74qZBPrc4odDzMxY1DXGg2fuUBB5mC+bzYamaQC4ubmh6zq8D7hYgUEd3Sff\/dz9e6J1Rd1KBbTbAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris3-post_big.png\u0022 alt=\u0022Screenshot of the top of the post page in version 3\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris3-post-end_big.png\u0022 alt=\u0022Screenshot of the bottom of the post page in version 3\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACD0lEQVRIia2VTW7bMBBG3wxJmaptpE4CFGgO0C56id46y+56ha56gaABEieWLIkzXeTPRZuatTsrShp8fPpmhhQzc\/bE1dUVqsrZ2dlv366vr1kul3Rdj6qQUqLrOlJKTKXQpBk\/bre8O21JKe3b6lKGYdgLtF6vCaqYP6S6OyKCu6Oq5JwREVR1n9ReoOi+l4ebmxsEMHdCCLg77k5QZSrl+R1A27asVquDaESEWJMYYwAEsYJqADfMQVSIO06JCCqHu+TudUA5t5gZzWxGk9IvJRORZzGAEKskX434JPi36PseM2MYBkopAKgq0zjyZj4nPUKaGTlnYtseDlTTQ22bEdHnTZ+ad9cpMyfGiJlRo\/kqUE1SKUaMSlvx58dOWlXJuq5jsVgwjuOjK9A0s5pz5d+BapJ6z+gotDExmqPANEB\/39M2gaCCilDcWeQjm7qm3jO2tCkxn0VUX6Zq0UYE2DX5mP6BypLN354TgjIWYxqcnAJNOvpU\/jNQTdLl12\/ENCPEwMnJyV9zL04zHy+WhwPVWPzlu7PZ3j8+3bKaJxAQhHU3MpYXjc+fzvnwfnEwkGy32+OK\/n\/jMtaM7t3dHapK0zTc9kZOAXi4XIsZQYVhclJ4mLSkSj8WFvllCGpDn5paRHhtrapIaOgnyCmgPoI7UzHERqxMqBheBnCnTFuiOv04sdls9urvrn8CnvD1+u2+X7sAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris3-post-end_big.png\u0022 alt=\u0022Screenshot of the bottom of the post page in version 3\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EVersion 4 (current)\u003C\/h3\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-home_big.png\u0022 alt=\u0022Screenshot of the homepage in version 4\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221666\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAkCAYAAACJ8xqgAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEA0lEQVRIiY2Wz4scRRTHP1VdP3pmd2fdDSIkm7\/CeDC5aPAvEEHwIngSD168ePLi3T9CEFFEzFmQEBFFNqd48WwiyLgTd3p3pqu6uspDd+9sT3eyeXTxul\/xXr336lvfLnHr9huJS3Lz6IhlUbBcFqQUL08hhEQrhRCCBMRYE2NCa43RGmMN6t133sYYg7UGay2zvT2Ai+9mGKyxl2ytNhatFVJKhBDNiDH2MuzEOcf5asV6tSRGSGSkFNmf7TOdTjDGjLkhUkqDgCml0dHNPU+Uc258pa4EIdqSYD4\/wVpLnluUUmRZNvCTmz41wxiDUhn\/zv\/hwf2fkbILLJnN9jBG41zg6XnsLXqx+FhZAH8e\/8IfP90DNrYQamKMhDpis\/G2yLFyV2cLVmcF5X8nlMv5BXxi5ygg1OO9lNspA\/z2w5c8evgrk92MLz7\/DHd2CoDRikwpJloyndjRktXYKt88eMSP94955XCPxVnJh58GJkBZOqQUhDqiQkFuZgPf0YCHL1\/nrbt3yCc5mczoOpPntnXSSDFa8RDYY40OIeCc43RZ4JxrQe\/QSl58O+dx3iM++viTVLZG7zwpJVbrNWXp8JWnqirqOnIFnjcl\/378sGeYTqdYY1gWS25cv8GTv59gbVOqc47Dg0MWTxfcPDrir8ePx3rYb8ZqtW7xKFgWS0BQ1x3rCNblGhCcLBYIIQdHcQDslBJ5npNSajYkpQtIpJQ4ODggpUSMkRjjiwG7qioAsqyZViojb8v2zgMQY0TKobu4dfvNF2z3RrTWGKMx2mCMxlqDaflSfPX1t6khWNsj1bx9v0y+1liM0Ugpe6QKbPQ2H87nC8pyRWZ2uHY4I3sGgAESCa36Z0Nt71Ke1xi7jwDqUMEI53XSbVQvYJdqJ4Vz5FJRx0imRk\/mJsMWAc\/NcL+SrHRNSs1OXiVXZrhEotLV\/4423CDDAZAOMoWQkkxK6rq+IuBwxwZsMy8cJnlijL0TorVGaz0IYHS\/zwPYrFxAxEBq\/yVCCLTaBEokmqfRUoqLY+i9R333\/T3Ky5zWvXvft3mP77T3OOfxvsJXjQ4hNAm8+nr\/bvPS\/j46y1icnlLXAaU0QkCsGoekJLJOkJoatrs8AFpVlgghmWYRpSQxZQgBfmIb3BnI1hVG1\/g6UrhBwC0+9J61EIBAAImq7WVoV2zUeQlKaXZ2+iShPnj\/va2b1dYty2zZWrIw1pKNkcT2LhdFgQ9w7WCP5ToxmwhKn0BArgU+JIwSnJeJnXyIwwGwpzu7ZGYXgHXDpfgaQtv9zuZCc5PopGNsUZZlqqoK5xzl82DjPM432rffpe\/DzXuPeO3O3V7V0zxHZBJoACuAqsVYJyGEZ571\/wHlDJySzIsFTgAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris4-home_big.png\u0022 alt=\u0022Screenshot of the homepage in version 4\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u00221666\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-posts_big.png\u0022 alt=\u0022Screenshot of the list of posts in version 4\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADcklEQVRIiaWWz08kVRDHP+9n\/5gZdkFEgrBZ4wE18Wb8EcOiiRf\/BC\/GswlXjx688U9w5GSMx71hPJLswURijAc3JBrWhGGEZqaZ6ffKQ08PAzuQgJV06tv1rVevurpedav3PvpEBFAKRLgUBQhYa1BKATCqqtosNT8TA2nqiVHQWiMxAmCspaoqqqoixtpxek+lIITwk22CNcZpefLkY3q9HkdH\/xBi4Pi4+5LfNNYarHWkSYq1Bu893nuctSRpgrUWZy3OObz3JGPeJzUGtP3s081Lh8RfOiaexCeXtvF9s7i2JVO+tU1rjVJqopurTn62bqQoClRs6ndP6fcHFOcFxhheWViYbCIid8ZFUfxs\/08yABhLkj+gioLUkSeU3BED2Otlu6u0Uj\/T3mwUY0REJrqxX8cAIYTKlmVJHJ+E2zK\/jzT9M91P07jxaSTP86F1zl0hph365ZBuH6JAogJpcUK6tADjgH+dgtPgZUjOENduTda+KBRW1\/gigNUwn0UybzHG3PgQ9lZSQ8cMsNaSZRk8XJ5wu7u7bG9vz1y3s7PD\/sEhTgtp\/4R8cX7CbWxssLxcx5nV4PYmosFleYFSFxhj6qTG9m63y8HBwcyE9vf32dra4uFchyjC6Vkx4fb29iYJzSzC9caaxiLCoBwAijzPKc7PaeU5AKnSrDpPRxt6RuFDxETh3xhZWVrmmy++opetsTg34tHFb\/y4\/wtPnz2\/ca8G33rKtPWsrj0mSn2atYYqQhRhwVreSVvkRvN7p4UfjXh9UFJUgZFpsztcw6xn5B1D8ewt1tff5+3e98DLA\/FKhW5kgKqqCGFIiNAfgTOQWhDgzQ8\/4PPvvgVgUynGQwilFKuP4OvHP7By1KX994jDNzJ+Xdnkj3e\/vBJ\/VqvcOqkH5ZAXBXgdmQ\/n6Ln2ZfW04s\/nhxhjEIloXetOu8ODTouzkxOiqHFlK7TVmKxF5nPSNL0poae3Vsho8KNjFIpRK4eLISKRLM8BIUkSjNaEEHDO0Wq18N6hreVsOEJE0KrmkzSh7TXOufv3ENqy9NrKlV8MqHuIOCTPMgRhrjM3eV3OOUIItNtttNKIRASwxuL91Zl352NfVRUhDgkBiiF4C5mrGzz3htOzM4wxDAYlEiPaaF5dXMRaS1mWKBQxBrSxiBd8MvszMy3\/AclyutTtBlE0AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris4-posts_big.png\u0022 alt=\u0022Screenshot of the list of posts in version 4\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-post_big.png\u0022 alt=\u0022Screenshot of the top of the post page in version 4\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVUlEQVRIib2Wz04bMRDGf+P1er2ABKrUC2ovPXLupapEi1SpT0DfgqfgoXqteu1DVOqhQfwvCoRge6aHJGSBQKIU9ZMsfzv+Zjy2x7srb999NANEwIwpBDDwvkJEAEg5j8w2Gp\/JgRgDqoZzDlMFoPKenDM5Z1RHwu6cIlBK+eYnwSbGLra333N+fs7BwSFFCycnpw90Xe4ceF8Tm4j3FSEEQgjU3tPEBu89tffUdU0IgWY8HpoRB5z\/tPNhKmjCVNgEmtBMbePnifPI1nS0I5tzDhG57SdtlPzsfoJ+v4\/oZP+WxOHREVqUto3EOGoAZnY74aK83+9\/98skMRgmcDUAzeoGognNiZwzV1dXOBG8QdXGWx\/rFOhjHMDf37ZFsBLDlIcAhAeap3YCQFUxszutlKK+lDJzsOv81IqWwaSuunXmnGNtbe3ap5QeFU3s+\/v79Hq9bsgHN3IePu7s8GV3d77QFsDW1pYB\/9T29vbMzExVb+PO4F\/dOKlugjP5\/4KfVyfPmdQicy11y5bFInO55wp0R3\/Pt3tJ5p2EX+RIvAhRHI1AFEcUoRZH5YSkymkM2E3i5ThUUuXajKEZGUgC1YKLWuhN\/cYHYtPSVhWtq6hFECA4x680ZLDaUkJic1hYdx7FuFFlqMpFyQxU2RD3fDX0OkbadoW28lyXzIsQGKoSXcUPTayvb6Cq\/Pzd43NcxczIalyWzCvXcpZu2AwNIjL3u+YfG+jyZMafUtAxv8iZG1MuS+EkZ8LxGSLClcFxSmxUFQNVFOiXQjbjevxfNA9\/AVXov5JBOanJAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris4-post_big.png\u0022 alt=\u0022Screenshot of the top of the post page in version 4\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-post-end_big.png\u0022 alt=\u0022Screenshot of the bottom of the post page in version 4\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACx0lEQVRIiZ2Wy44cNRSGv2Mfu6qnJ5NZgMSKp2CDkAJIvBALFrwZy4gFQnkMFihCBLVGM9NdrrIPC1dXVV8nyS+V\/Nv++9x8a\/nm2x\/MABEwY4YABqoeEQGgH4Y6bHX+LAfaNlKK4ZzDSgHAqzIMA8MwUEoVLn2KQM75re6N7QeXePPmOzabDe\/f\/0MumQ8f\/jvRLblzgqrSNi2qSoyBGCNBlaZtUFWCKiHU8SbG2ja1VdVBf\/rx+ypojgUNzchTSoQQaJuG2ERUlVW7IgQlhkC7amnbFvUe7z3OecQJVgoiDucdr+\/upkoftwsMUvb1u4KHhwdKKYgIZrUSIJgVEMHMcAsntlh7o67lzc0NMUbMbArkDP9NXwoGYLfrKFawYtXFIjPvHEPOeO9ZtSuKGewdyVglIIQwBXoQ8BHXM2U7watXt+ScAZliKcWIMeC9n4zGGA+MX6nERa57Y8elXvZDCDjncM6RcwEBRQhB60kadaWUgyqc+5aaY5iZ0+fn54uCl5DzcNBfbtZj7r2f+KVVeXp6anW9Xl90mFLCjyfnU\/E5S2Zm6DXRcyr8u3nkqy\/vEXGkDI2Hbmz7Ak7AOxgyIIY6IQ2gHroBVlpPWp8heLgJ1xO5euy3A6QM6xeMfAq8my\/iYzw+Pv5+9ZR5mYMZCvz9AHdtzfyLdZ3fz6mbf\/fXBm4bKFbH79t5LpdaqUu4eg+5Razq4Ov7U81mV9+jbNCqcRtl1I2PHIdcZObHWwWYj\/05nDy4Z7DMfnZ+ym3kQr0e9thzMyPnXAM6vkHP3RulFFJKdCmRutp2XTeNdV0ipW5sa79L3aRNk2buz19PSoldt0N\/\/uXXyfB+IvU9KfX1zuh7tjmTS67ZjBU3myt4uA3H\/y0GeUziY5HzgP7x57uLghgCIYbJqXee1Pd47\/De0fcDpRRUFRFhu91+tPNzEJHyP7\/y5So+jfmBAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris4-post-end_big.png\u0022 alt=\u0022Screenshot of the bottom of the post page in version 4\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022464.5\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["programming","php","javascript","webpack","symfony","symfony encore","doctrine","orm","cms","esse","columnist","version","new year","blog","design","redesign"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avris4_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris4_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4_mini.png\u0022 alt=\u0022Screenshot of the new version of the blog\u0022 width=\u0022240\u0022 height=\u0022117.03937007874\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EIt wasn\u2019t really supposed for the New Year, but I\u2019ve had plenty of free time on my hands\nduring the holiday break, so here it is already: a brand new version of my blog \ud83e\udd73\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris4_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4_mini.png\u0022 alt=\u0022Screenshot of the new version of the blog\u0022 width=\u0022240\u0022 height=\u0022117.03937007874\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EIt wasn\u2019t really supposed for the New Year, but I\u2019ve had plenty of free time on my hands\nduring the holiday break, so here it is already: a brand new version of my blog \ud83e\udd73\u003C\/p\u003E\n\u003Ch3\u003EWhy?\u003C\/h3\u003E\n\u003Cp\u003EWhere to start? I got increasingly annoyed by the old version.\nThe design started seeming boring and blunt.\nThe code started growing unstable.\nIt was using the \u003Ca href=\u0022\/projects\/micrus-v4.lite\u0022\u003E Micrus framework\u003C\/a\u003E,\nwhich I \u003Ca href=\u0022\/blog\/how-and-why-i-ve-built-and-killed-a-php-framework.lite\u0022\u003E stopped supporting\u003C\/a\u003E a year ago.\nIt was using \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Micrus-Assetic\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Micrus Assetic\u003C\/a\u003E\n\u2013 an outdated method of asset management,\nwhich highly depended on the server configuration and binaries installed.\nThe deployments were \u201ciffy\u201d, to say the least.\nI was afraid of sending even small changes to the server, for fear something might blow up again.\nSome small things I didn\u2019t even notice were wrong: like still warning about Google Analytics tracking,\neven though I migrated to \u003Ca href=\u0022https:\/\/matomo.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Matomo\u003C\/a\u003E ages ago.\u003C\/p\u003E\n\u003Ch3\u003EWhat changed?\u003C\/h3\u003E\n\u003Cp\u003EI decided to keep it simple. To go with a \u201cless is more\u201d approach.\nI\u2019ve removed soooo many features that just weren\u2019t useful enough.\u003C\/p\u003E\n\u003Cp\u003EI used to have an admin panel: except I didn\u2019t need any fancy editor,\nthe main content was written in an (enhanced) \u003Ca href=\u0022https:\/\/www.markdownguide.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Markdown\u003C\/a\u003E anyway.\nSo for this version, I\u2019ve decided for a filesystem-based approach: I\u2019ve ditched the database completely,\nI don\u2019t need any ORM, I don\u2019t need an admin panel. I just have a bunch of \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/SUML\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E SUML\u003C\/a\u003E files\ntracked by GIT. Using \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Esse\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Esse CMS\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cp\u003EI used to have three language versions of the UI \u2013 but why?\nI don\u2019t think anyone really cared about not seeing the names of the categories in Polish,\nwhen most of recent my posts were in English anyway.\nSo now the posts are still available in the language(s) they were written in,\nbut I\u2019m no longer maintaining the multiple versions of the UI, or the features to filter content by language.\nWhat a relief!\u003C\/p\u003E\n\u003Cp\u003EI used to have a \u201crandom post\u201d box. I used to have tag clouds. I used to have an embedded Twitter timeline.\nI used to have the latest posts on the \u201cabout me\u201d page (really?). I used to have a link shortening feature\n(\u201davris.it\/l\/\u0026lt;whatever\u0026gt;\u201d) that I\u2019ve never used, not a single time.\nI used to have a separate controller and database fields to support redirects for legacy URLs from the even earlier version.\nI used to have database fixtures. I used to have a console command to export legacy comments to \u003Ca href=\u0022https:\/\/disqus.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Disqus\u003C\/a\u003E.\nI used to have tooltips and popovers.\nAll gone now! \ud83d\ude0d\u003C\/p\u003E\n\u003Cp\u003EI replaced the infinite scroll with... just loading the whole page at once \ud83e\udd37\u200d\nIt\u2019s not that big for today\u2019s standards anyway \u2013 the heaviest list of posts is 113 KB of compressed HTML.\nInstead, I now lazy load images using the \u003Ccode\u003EIntersectionObserver\u003C\/code\u003E API.\nWay simpler than infinite scroll or pagination \u2013 which aren\u2019t really necessary with this amount of data.\u003C\/p\u003E\n\u003Cp\u003EOh, and the website is now using a fast an sleek \u003Ca href=\u0022https:\/\/symfony.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Symfony\u003C\/a\u003E setup with an HTTP cache \ud83e\udd70\u003C\/p\u003E\n\u003Cp\u003EDesign-wise, I use the default \u003Ca href=\u0022https:\/\/getbootstrap.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Bootstrap\u003C\/a\u003E theme,\nwith only minor changes of variables and minimal additional styling.\nThe main feature, obviously, are the tilted elements. That\u2019s enough to add some personality to the website,\nwithout making it overcomplicated.\nCompared to the previous version, it\u2019s way more contrasting, better tailored for wider screens and clearer.\u003C\/p\u003E\n\u003Cp\u003EOverall, 41090 (!) lines of code were removed:\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-3-4-diff_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-3-4-diff_mini.png\u0022 alt=\u0022424 files changed, 6711 insertions (+), 47801 deletions (-)\u0022 width=\u0022240\u0022 height=\u002238.836363636364\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EThere\u2019s nothing else in the (programming) world I love more than removing useless code!\u003C\/p\u003E\n\u003Cp\u003EDeployments are now stable, simple, reproducible and revertible, thanks to\n\u003Ca href=\u0022https:\/\/symfony.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Symfony\u003C\/a\u003E, \u003Ca href=\u0022https:\/\/webpack.js.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Webpack\u003C\/a\u003E,\nlack of database (no db = no migrations),\nand most importantly my recent child: \u003Ca href=\u0022\/projects\/avris-deployer.lite\u0022\u003E Avris Deployer\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris4-deployer_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-deployer_mini.png\u0022 alt=\u0022Console output of deployment\u0022 width=\u0022240\u0022 height=\u002267.075471698113\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EVersion 1 (\u201dSilva Idearum\u201d)\u003C\/h3\u003E\n\u003Cp\u003ESo, to finish this post, let me just quickly show you the four versions I\u2019ve been through so far:\u003C\/p\u003E\n\u003Cp\u003EMy first blog was called \u201cSilva Idearum\u201d (Latin for \u201cForest of ideas\u201d).\nIt was anonymous, spirituality-oriented, Polish-speaking, Joomla-running and with a \u201ctoo much\u201d design.\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris1-post_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris1-post_mini.png\u0022 alt=\u0022Screenshot of the post page in version 1\u0022 width=\u0022240\u0022 height=\u0022116.125\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EVersion 2\u003C\/h3\u003E\n\u003Cp\u003EAfter coming out and becoming independent from my parents,\nI was finally able to put my name on my posts. New domain and a redesign was also in place.\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris2-home_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris2-home_mini.png\u0022 alt=\u0022Screenshot of the homepage in version 2\u0022 width=\u0022240\u0022 height=\u0022116.125\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EVersion 3\u003C\/h3\u003E\n\u003Cp\u003EAs announced in \u003Ca href=\u0022\/blog\/brand-new-blog.lite\u0022\u003E Brand new blog\u003C\/a\u003E\u2026\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris3-home_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris3-home_mini.png\u0022 alt=\u0022Screenshot of the homepage in version 3\u0022 width=\u0022240\u0022 height=\u0022400.875\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris3-posts_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris3-posts_mini.png\u0022 alt=\u0022Screenshot of the list of posts in version 3\u0022 width=\u0022240\u0022 height=\u0022116.125\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris3-post_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris3-post_mini.png\u0022 alt=\u0022Screenshot of the top of the post page in version 3\u0022 width=\u0022240\u0022 height=\u0022116.125\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris3-post-end_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris3-post-end_mini.png\u0022 alt=\u0022Screenshot of the bottom of the post page in version 3\u0022 width=\u0022240\u0022 height=\u0022116.125\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Ch3\u003EVersion 4 (current)\u003C\/h3\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris4-home_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-home_mini.png\u0022 alt=\u0022Screenshot of the homepage in version 4\u0022 width=\u0022240\u0022 height=\u0022416.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris4-posts_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-posts_mini.png\u0022 alt=\u0022Screenshot of the list of posts in version 4\u0022 width=\u0022240\u0022 height=\u0022116.125\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris4-post_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-post_mini.png\u0022 alt=\u0022Screenshot of the top of the post page in version 4\u0022 width=\u0022240\u0022 height=\u0022116.125\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris4-post-end_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris4-post-end_mini.png\u0022 alt=\u0022Screenshot of the bottom of the post page in version 4\u0022 width=\u0022240\u0022 height=\u0022116.125\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E","words":694,"readTime":3,"lang":"en"}}},"blog\/society\/ocz-just-some-googly-eyes":{"key":"blog\/society\/ocz-just-some-googly-eyes","type":"article","published":true,"meta":{"createdAt":"2019-10-16T17:27:18+02:00","publishedAt":"2019-10-16T20:23:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/ocz.avris.it\/","displayUrl":"Demo"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Ocz","displayUrl":null},{"icon":"globe-europe","colour":"secondary","url":"https:\/\/www.npmjs.com\/package\/avris-ocz","displayUrl":null}],"category":"blog","subcategory":"society","slug":"ocz-just-some-googly-eyes"},"content":{"en":{"slug":"ocz-just-some-googly-eyes","title":"Ocz \u2013 Just some googly eyes.","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-ocz_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhUlEQVRIiX2Xy69lRRXGf+tRtfc595776tsXmoZu3gqoHYhGEmJoSRCIQYPGB5oQHehA48A\/wbkzB0bjWEfGCRKj0QgkkCgaH4AtEexuHg1p+nHvPfd19q5aDvbpxqixsl\/Jrtr11ffVWuvbcuzGuyJKRQiiVoiKuVNLIQhUBFfDVEnuzGYH1FohAiIQQEQQhiYiiAgQXGkRMT\/r1TtREQEVwdwxEZpmhEcIEUGpBQkQoJSCMHxYVQegolArSZV+PgEi835c7S8CIKjKe5PLlWchakHUiHhvnCEkNbQW\/MoAQQkqEaAhiA6TEYKqA0JfKoagCCGKqc7ZGBaCDO\/mx\/xiuBuzWYcIRAwLFFF0PtZUcTOSKh6iUMuc4IERIpAQVA03xUQwUdwUiUqtlVrL8AH3YfW1ompXpVIRolaCYHllhcsXLwEVQhCHqAVVgQAzJZmR\/AogAVSgztkSENG5DIaimBnZEuOmgejZ3dujcadJTvZErZVSevpSQBj2S60AHLlmg4PtKVAH0iJQzXNQiukgcTbFRRMRHRIGUtGrm1RQs4FaS6goKoaKs9AssDpa5tJ0Ew0lStB4Qj1DFEKEvu8GhgRuPHaMt0+fRSSQAFNBCCAhEnPJlGSKa8r0wTxi7EqsgOrAjhqmRnYnW0IxRBJNTtx0eJGd3SkHXcc1124w29tlurWNiZBdqVG57xP38+rLp1jKDUEMkQWoDqKogggkU7IbHpqQNJcLoQaYKKqGiuLmuBrZMy5CMidJImnD2toyn\/nK51hbXeG3P\/0Fr585izWLJB+iabK8yH0P3M9LTz\/HSjsCChExgFFBBcwE04E1d8HJDdI7tcZcXwBF1FBzRAw3RzXhZvMzcfKRj\/H4N7\/AKy\/8jSe\/9xMShduPXEfUyvbOFM\/Gl7\/zbV742VNcv7TErHTU6Ikog3Q6j6407KGcFFNwaReoXUFqHfJQAGKIOGqJZI6qkcxpU2bszle\/8Vkeeuwk00vbPPWDJ8k6YnXccsut17Gz+S6bu\/s88K0vkVSoZ97g\/Uc2mO7tst\/PKLWn1A60ktwwE9yV5EJKhst4CZn1UCoBwx5BEUmoGOKJrE6bEuOUePyJB3nosZMA\/OXZF0k0TBYnLI4bti\/ucfzDH+ITj96Htw3Pf\/dHbKwvo9GxuRX0faLEACikohqk7LgLKSmeBZfRBHIPBSQUQhEUxEETpk4yJ6fEiRM38anPf\/xqSdh6Z8qhaw5z9PgGx++6gRvuuZmF9SUigtd\/+QwLo0ypi7RNT24qSKVGR9\/PiNqhBqqBuZEbx5PgTJahL0TIACaG6DIc14TiyDwBPvH1R65mZoCHv\/Yg\/9kigjef+QOz8+9y+MZDHGxmup3LLGmHWEUsqLWj9gcIPWqCuZJyxpsG18mEVBjqDIqHkjCyODmMrEZGuefEMY4eXfsvAP\/eaim8+qvfs\/3Kq7QLSrs85vAd19NvLrB1TlCZIXQgmSgJkTpEWHIsZ6wZ4ZOVCaUAc4YMwcNpxWhRWoymCvd+9Nb\/C2Z6fpOXf\/4cswvnGTWAQre3y+6FDpcZ4+WG2pUh9xioJGQul7pjuUWbEX7t2oi+D2qBGoqGohgphITRhtIU4fab1\/8nkL2tXf7+7Iu8+cdTZOkYtXUoHRWig3pg0Ch5pERSTGIuU0JNsZTR3CCpgTzCP7DRsLvfMTsozPpKKZVSKxKCRMWKYCKsr46vgtiZ7nHmlTc5\/efXePOlf9JEx9gLkQpOJWslNMACZkOtlBQkD9wEM0FTQnILySBnyA14iz+6+hY7+5XptGNrpzLtg+0D2J3BfgezXig9\/PD7P2ZvZ4\/L726xc3GLXAqJQqLSamVkPQspWGors3GFSZBCaG2wGVI61APLhtWg6wxjQndgaJvYvDSmo0VO3rUeS21if3+wSm6ZEKfihCQKTtVMXyFEQR0RxXXI2kONM7IJjcJChkmGwwvBkdXCxrqxsCCcPXeZ6d4eJXesXHeUp3\/9O06fO2CprWxsTDjogudf3kEWV9ZCU0bUsJTwpkXU8NzgKWOpQdXITYt5InnGLQ12U4y777yN1p29nZ5DSyPOnnqN5WSstspKC4cWldUFSNqTrGdloef2E2Mun5ty\/twWkxG49By+90F2\/\/ob\/I5Pf5FmcYm+QrswwVODqiPmJE+IGMJQdyQEKRVKQWqgpTI+so4DaS3ouh42enqBA1MOXNhJSk5GmyrVKvtNpbMV1t4Hl6evkUZC4z39pV0W73wILxjT3T2wxGx7G5EdQAcvFIMBH7wQczAVqZW6vw+1cOHtM0gJJAKrhcTgjccpM0nOxJ3lJjFOgmthnGG63\/GRDy7xxiWlXuxZGsHk8lvc9vDd+KUz\/2DWdahnaql4M4L3\/iEQwFNCVZEIogYaAwCtFen7qwa\/dge4GJffOUubW1yE5cUlDi2t4FHZ3d1idWnCn045b58Z8c7mPqcv7DPKQaMzPtm\/gazfckfUUuhnM2p3QFqYICGU2T6amqEc1B7PLcDguQGtgSJIXPHQgxfXCISKieAquIBSyWaoBn3fIRQ2Js5ya1zcG2xu43DvcfgXoycudg\/N7GgAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-ocz_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFair warning: this library is pretty useless. And only moderately fun... \ud83e\udd37\u200d\u003C\/p\u003E\n\u003Cp\u003EBut it seemed like a cool way to learn a bit about web components, so here it is: a component that creates googly eyes that follow your mouse.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-ocz_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhUlEQVRIiX2Xy69lRRXGf+tRtfc595776tsXmoZu3gqoHYhGEmJoSRCIQYPGB5oQHehA48A\/wbkzB0bjWEfGCRKj0QgkkCgaH4AtEexuHg1p+nHvPfd19q5aDvbpxqixsl\/Jrtr11ffVWuvbcuzGuyJKRQiiVoiKuVNLIQhUBFfDVEnuzGYH1FohAiIQQEQQhiYiiAgQXGkRMT\/r1TtREQEVwdwxEZpmhEcIEUGpBQkQoJSCMHxYVQegolArSZV+PgEi835c7S8CIKjKe5PLlWchakHUiHhvnCEkNbQW\/MoAQQkqEaAhiA6TEYKqA0JfKoagCCGKqc7ZGBaCDO\/mx\/xiuBuzWYcIRAwLFFF0PtZUcTOSKh6iUMuc4IERIpAQVA03xUQwUdwUiUqtlVrL8AH3YfW1ompXpVIRolaCYHllhcsXLwEVQhCHqAVVgQAzJZmR\/AogAVSgztkSENG5DIaimBnZEuOmgejZ3dujcadJTvZErZVSevpSQBj2S60AHLlmg4PtKVAH0iJQzXNQiukgcTbFRRMRHRIGUtGrm1RQs4FaS6goKoaKs9AssDpa5tJ0Ew0lStB4Qj1DFEKEvu8GhgRuPHaMt0+fRSSQAFNBCCAhEnPJlGSKa8r0wTxi7EqsgOrAjhqmRnYnW0IxRBJNTtx0eJGd3SkHXcc1124w29tlurWNiZBdqVG57xP38+rLp1jKDUEMkQWoDqKogggkU7IbHpqQNJcLoQaYKKqGiuLmuBrZMy5CMidJImnD2toyn\/nK51hbXeG3P\/0Fr585izWLJB+iabK8yH0P3M9LTz\/HSjsCChExgFFBBcwE04E1d8HJDdI7tcZcXwBF1FBzRAw3RzXhZvMzcfKRj\/H4N7\/AKy\/8jSe\/9xMShduPXEfUyvbOFM\/Gl7\/zbV742VNcv7TErHTU6Ikog3Q6j6407KGcFFNwaReoXUFqHfJQAGKIOGqJZI6qkcxpU2bszle\/8Vkeeuwk00vbPPWDJ8k6YnXccsut17Gz+S6bu\/s88K0vkVSoZ97g\/Uc2mO7tst\/PKLWn1A60ktwwE9yV5EJKhst4CZn1UCoBwx5BEUmoGOKJrE6bEuOUePyJB3nosZMA\/OXZF0k0TBYnLI4bti\/ucfzDH+ITj96Htw3Pf\/dHbKwvo9GxuRX0faLEACikohqk7LgLKSmeBZfRBHIPBSQUQhEUxEETpk4yJ6fEiRM38anPf\/xqSdh6Z8qhaw5z9PgGx++6gRvuuZmF9SUigtd\/+QwLo0ypi7RNT24qSKVGR9\/PiNqhBqqBuZEbx5PgTJahL0TIACaG6DIc14TiyDwBPvH1R65mZoCHv\/Yg\/9kigjef+QOz8+9y+MZDHGxmup3LLGmHWEUsqLWj9gcIPWqCuZJyxpsG18mEVBjqDIqHkjCyODmMrEZGuefEMY4eXfsvAP\/eaim8+qvfs\/3Kq7QLSrs85vAd19NvLrB1TlCZIXQgmSgJkTpEWHIsZ6wZ4ZOVCaUAc4YMwcNpxWhRWoymCvd+9Nb\/C2Z6fpOXf\/4cswvnGTWAQre3y+6FDpcZ4+WG2pUh9xioJGQul7pjuUWbEX7t2oi+D2qBGoqGohgphITRhtIU4fab1\/8nkL2tXf7+7Iu8+cdTZOkYtXUoHRWig3pg0Ch5pERSTGIuU0JNsZTR3CCpgTzCP7DRsLvfMTsozPpKKZVSKxKCRMWKYCKsr46vgtiZ7nHmlTc5\/efXePOlf9JEx9gLkQpOJWslNMACZkOtlBQkD9wEM0FTQnILySBnyA14iz+6+hY7+5XptGNrpzLtg+0D2J3BfgezXig9\/PD7P2ZvZ4\/L726xc3GLXAqJQqLSamVkPQspWGors3GFSZBCaG2wGVI61APLhtWg6wxjQndgaJvYvDSmo0VO3rUeS21if3+wSm6ZEKfihCQKTtVMXyFEQR0RxXXI2kONM7IJjcJChkmGwwvBkdXCxrqxsCCcPXeZ6d4eJXesXHeUp3\/9O06fO2CprWxsTDjogudf3kEWV9ZCU0bUsJTwpkXU8NzgKWOpQdXITYt5InnGLQ12U4y777yN1p29nZ5DSyPOnnqN5WSstspKC4cWldUFSNqTrGdloef2E2Mun5ty\/twWkxG49By+90F2\/\/ob\/I5Pf5FmcYm+QrswwVODqiPmJE+IGMJQdyQEKRVKQWqgpTI+so4DaS3ouh42enqBA1MOXNhJSk5GmyrVKvtNpbMV1t4Hl6evkUZC4z39pV0W73wILxjT3T2wxGx7G5EdQAcvFIMBH7wQczAVqZW6vw+1cOHtM0gJJAKrhcTgjccpM0nOxJ3lJjFOgmthnGG63\/GRDy7xxiWlXuxZGsHk8lvc9vDd+KUz\/2DWdahnaql4M4L3\/iEQwFNCVZEIogYaAwCtFen7qwa\/dge4GJffOUubW1yE5cUlDi2t4FHZ3d1idWnCn045b58Z8c7mPqcv7DPKQaMzPtm\/gazfckfUUuhnM2p3QFqYICGU2T6amqEc1B7PLcDguQGtgSJIXPHQgxfXCISKieAquIBSyWaoBn3fIRQ2Js5ya1zcG2xu43DvcfgXoycudg\/N7GgAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-ocz_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFair warning: this library is pretty useless. And only moderately fun... \ud83e\udd37\u200d\u003C\/p\u003E\n\u003Cp\u003EBut it seemed like a cool way to learn a bit about web components, so here it is: a component that creates googly eyes that follow your mouse.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["css variables","googly eyes","javascript","js","library","web components"],"hasMore":false,"image":"https:\/\/avris.it\/image\/avris-ocz_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-ocz_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-ocz_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFair warning: this library is pretty useless. And only moderately fun... \ud83e\udd37\u200d\u003C\/p\u003E\n\u003Cp\u003EBut it seemed like a cool way to learn a bit about web components, so here it is: a component that creates googly eyes that follow your mouse.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-ocz_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-ocz_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EFair warning: this library is pretty useless. And only moderately fun... \ud83e\udd37\u200d\u003C\/p\u003E\n\u003Cp\u003EBut it seemed like a cool way to learn a bit about web components, so here it is: a component that creates googly eyes that follow your mouse.\u003C\/p\u003E","words":39,"readTime":null,"lang":"en"}}},"projects\/avris-sorter":{"key":"projects\/avris-sorter","type":"article","published":true,"meta":{"createdAt":"2019-10-13T14:09:02+02:00","publishedAt":"2019-10-13T14:06:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/sorter.avris.it\/","displayUrl":"Demo"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Sorter","displayUrl":null},{"icon":"globe-europe","colour":"secondary","url":"https:\/\/www.npmjs.com\/package\/avris-sorter","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-sorter"},"content":{"en":{"slug":"avris-sorter","title":"Avris Sorter","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sorter_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHkElEQVRIiX2XyY8kRxXGf2+JyKyqrl5m6cEe8HgBgzEwwjLCkoU8WDK2hQwCxC4hOMABxIE\/gTs3DgjEGU6ICxgJBMK2ZEtsYjHGWNh4xstgxp7ppbq7qjIjHoesGSNAhDIyU8pYvvi+ePG+lBtuvD2iVIQgaoWomDu1FIJARXA1TJXkznK5oNYKERCBACKCMBQRQUSA4GqJiFWt155ERQRUBHPHRGiaER4hRASlFiRAgFIKwjCwqg5ARaFWkir9agJEVu241l4EQFCV1yeXq+9C1IKoEfF6P0NIamgt+NUOghJUIkBDEB0mIwRVB4S+VAxBEUIUU12xMSwEGb6trtXNcDeWyw4RiBgWKKLoqq+p4mYkVTxEoZYVwQMjRCAhqBpuiolgorgpEpVaK7WWYQD3YfW1omrXpFIRolaCYGNzk53LV4AKIYhD1IKqQICZksxIfhWQACpQV2wJiOhKBkNRzIxsiXHTQPQcHh3RuNMkJ3ui1kopPX0pIAz7pVYArju1zWJ\/BtSBtAhU8wqUYjpInE1x0UREh4SBVPTaJhXUbKDWEiqKiqHiTJoJW6MNrsx20VCiBI0n1DNEIUTo+25gSODMDTfwj+cvIBJIgKkgBJAQiZVkSjLFNWX6YBUxdjVWQHVgRw1TI7uTLaEYIokmJ246ucbB4YxF13HqDdssjw6Z7e1jImRXalTu\/sA9PPvU06znhiCGyAJUB1FUQQSSKdkND01IWsmFUANMFFVDRXFzXI3sGRchmZMkkbTh2LENPvr5j3Nsa5Nf\/uAnvHD+BaxZI\/kQTdONNe6+9x7+\/MjjbLYjoBARAxgVVMBMMB1Ycxec3CC9U2us9AVQRA01R8Rwc1QTbraqiXMPvo9Pf+WTPPObv\/Cjb36fROHW664namX\/YIZn47Nf\/xq\/+eHDvHF9nWXpqNETUQbpdBVdadhDOSmm4NJOqF1Bah3OoQDEEHHUEskcVSOZ06bM2J0vfPlj3P+Rc8yu7PPwt39E1hFb45Zb3nw9B7uvsns4596vfoakQj3\/Im+7bpvZ0SHzfkmpPaV2oJXkhpngriQXUjJcxuvIsodSCRj2CIpIQsUQT2R12pQYp8SnP3cf93\/kHAB\/fOxJEg3TtSlr44b9y0ecufNdfOChu\/G24YlvfJftExtodOzuBX2fKDEACqmoBik77kJKimfBZTSF3EMBCYVQBAVx0ISpk8zJKXH27E186BPvv5YS9l6ZcfzUSU6f2ebM7W\/iTXfczOTEOhHBCz99lMkoU+oabdOTmwpSqdHR90uidqiBamBu5MbxJDjTDegLETKAiSG6DMc1oTiyOgA\/96UHr53MAA988T7+s0QELz36W5aXXuXkjcdZ7Ga6gx3WtUOsIhbU2lH7BUKPmmCupJzxpsF1OiUVhjyD4qEkjCxODiOrkVHuOHsDp08f+y8A\/15qKTz7s1+z\/8yztBOl3Rhz8rY30u9O2LsoqCwROpBMlIRIHSIsOZYz1ozw6eaUUoAVQ4bg4bRitCgtRlOFu9775v8LZnZpl6d+\/DjL1y4xagCF7uiQw9c6XJaMNxpqV4azx0AlISu51B3LLdqM8DccG9H3QS1QQ9FQFCOFkDDaUJoi3Hrzif8J5GjvkL8+9iQv\/e5psnSM2jqkjgrRQV0YNEoeKZEUk1jJlFBTLGU0N0hqII\/wd2w3HM47lovCsq+UUim1IiFIVKwIJsKJrfE1EAezI84\/8xLP\/+E5Xvrz32miY+yFSAWnkrUSGmAByyFXSgqSB26CmaApIbmFZJAz5Aa8xR\/aepmDeWU269g7qMz6YH8Bh0uYd7DshdLDd771PY4Ojth5dY+Dy3vkUkgUEpVWKyPrmaRgva0sxxWmQQqhtcFmSOlQDywbVoOuM4wp3cLQNrF7ZUxHi5y7\/USst4n5fLBKbpkQp+KEJApO1UxfIURBHRFlMh4zalqW8znZjFEynMokwzTDyUlw3VZh+4QxmQgXLu4wOzqi5I7N60\/zyM9\/xfMXF6y3le3tKYsueOKpA2Rt81hoyogalhLetIganhs8ZSw1qBq5aTFPJM+4Jd575x2kCEZNw2LecfrUNrJcYLXw2vmXyf2czRaOrylbE0jak6xnc9Jz69kxOxdnXLq4x3QELj0n77qPwz\/9Ar\/tw5+iWVunr9BOpnhqUHXEnOQJEUMY8o6EIKVCKSzWxmxtrNGocPDqDldKJlmi1p7dvMX6SFm4cJCUnIw2VapV5k2ls02OvRV2Zs+RRkLjPf2VQ9befj9eMGaHR2CJ5f4+IgeADl4oBgM+eCFWYCpSK\/+8MOcvtZDNkBJIBFYLicEbj1NmmpypOxtNYpwE18I4w2ze8Z53rvPiFaVe7lkfwXTnZd7ywLvxK+f\/xrLrUM\/UUvFmBK\/\/QyCAp4SqIhFEDTQGAFor0vfXDH7tFrgYO69coM0tLsLG2jrH1zfxqBwe7rG1PuX3Tzv\/OD\/ild05z782Z5SDRpd8sH8ROXHLbVFLoV8uqd2CNJkiIZTlHE3NkA5qj+cWYPDcgNZAESSueujBi2sEQsVEcBVcQKlkM1SDvu8QCttTZ6M1Lh8NNrdxuOsM\/AtA9jdb2ZxdiwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-sorter_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ELightweight sorting of tables.\u003C\/p\u003E\n\u003Cp\u003EJust add \u003Ccode\u003E[data-sort]\u003C\/code\u003E attributes to the \u003Ccode\u003Eth\u003C\/code\u003E elements in columns you\u2019d like to sort a table by, include ~1kB of JS \u0026amp; CSS, and initialise with \u003Ccode\u003Esorter()\u003C\/code\u003E \u2013 and that\u2019s it!\u003C\/p\u003E\n\u003Cp\u003EFor installation instructions and more customisation options, you can check out the \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Sorter\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E readme file\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sorter_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHkElEQVRIiX2XyY8kRxXGf2+JyKyqrl5m6cEe8HgBgzEwwjLCkoU8WDK2hQwCxC4hOMABxIE\/gTs3DgjEGU6ICxgJBMK2ZEtsYjHGWNh4xstgxp7ppbq7qjIjHoesGSNAhDIyU8pYvvi+ePG+lBtuvD2iVIQgaoWomDu1FIJARXA1TJXkznK5oNYKERCBACKCMBQRQUSA4GqJiFWt155ERQRUBHPHRGiaER4hRASlFiRAgFIKwjCwqg5ARaFWkir9agJEVu241l4EQFCV1yeXq+9C1IKoEfF6P0NIamgt+NUOghJUIkBDEB0mIwRVB4S+VAxBEUIUU12xMSwEGb6trtXNcDeWyw4RiBgWKKLoqq+p4mYkVTxEoZYVwQMjRCAhqBpuiolgorgpEpVaK7WWYQD3YfW1omrXpFIRolaCYGNzk53LV4AKIYhD1IKqQICZksxIfhWQACpQV2wJiOhKBkNRzIxsiXHTQPQcHh3RuNMkJ3ui1kopPX0pIAz7pVYArju1zWJ\/BtSBtAhU8wqUYjpInE1x0UREh4SBVPTaJhXUbKDWEiqKiqHiTJoJW6MNrsx20VCiBI0n1DNEIUTo+25gSODMDTfwj+cvIBJIgKkgBJAQiZVkSjLFNWX6YBUxdjVWQHVgRw1TI7uTLaEYIokmJ246ucbB4YxF13HqDdssjw6Z7e1jImRXalTu\/sA9PPvU06znhiCGyAJUB1FUQQSSKdkND01IWsmFUANMFFVDRXFzXI3sGRchmZMkkbTh2LENPvr5j3Nsa5Nf\/uAnvHD+BaxZI\/kQTdONNe6+9x7+\/MjjbLYjoBARAxgVVMBMMB1Ycxec3CC9U2us9AVQRA01R8Rwc1QTbraqiXMPvo9Pf+WTPPObv\/Cjb36fROHW664namX\/YIZn47Nf\/xq\/+eHDvHF9nWXpqNETUQbpdBVdadhDOSmm4NJOqF1Bah3OoQDEEHHUEskcVSOZ06bM2J0vfPlj3P+Rc8yu7PPwt39E1hFb45Zb3nw9B7uvsns4596vfoakQj3\/Im+7bpvZ0SHzfkmpPaV2oJXkhpngriQXUjJcxuvIsodSCRj2CIpIQsUQT2R12pQYp8SnP3cf93\/kHAB\/fOxJEg3TtSlr44b9y0ecufNdfOChu\/G24YlvfJftExtodOzuBX2fKDEACqmoBik77kJKimfBZTSF3EMBCYVQBAVx0ISpk8zJKXH27E186BPvv5YS9l6ZcfzUSU6f2ebM7W\/iTXfczOTEOhHBCz99lMkoU+oabdOTmwpSqdHR90uidqiBamBu5MbxJDjTDegLETKAiSG6DMc1oTiyOgA\/96UHr53MAA988T7+s0QELz36W5aXXuXkjcdZ7Ga6gx3WtUOsIhbU2lH7BUKPmmCupJzxpsF1OiUVhjyD4qEkjCxODiOrkVHuOHsDp08f+y8A\/15qKTz7s1+z\/8yztBOl3Rhz8rY30u9O2LsoqCwROpBMlIRIHSIsOZYz1ozw6eaUUoAVQ4bg4bRitCgtRlOFu9775v8LZnZpl6d+\/DjL1y4xagCF7uiQw9c6XJaMNxpqV4azx0AlISu51B3LLdqM8DccG9H3QS1QQ9FQFCOFkDDaUJoi3Hrzif8J5GjvkL8+9iQv\/e5psnSM2jqkjgrRQV0YNEoeKZEUk1jJlFBTLGU0N0hqII\/wd2w3HM47lovCsq+UUim1IiFIVKwIJsKJrfE1EAezI84\/8xLP\/+E5Xvrz32miY+yFSAWnkrUSGmAByyFXSgqSB26CmaApIbmFZJAz5Aa8xR\/aepmDeWU269g7qMz6YH8Bh0uYd7DshdLDd771PY4Ojth5dY+Dy3vkUkgUEpVWKyPrmaRgva0sxxWmQQqhtcFmSOlQDywbVoOuM4wp3cLQNrF7ZUxHi5y7\/USst4n5fLBKbpkQp+KEJApO1UxfIURBHRFlMh4zalqW8znZjFEynMokwzTDyUlw3VZh+4QxmQgXLu4wOzqi5I7N60\/zyM9\/xfMXF6y3le3tKYsueOKpA2Rt81hoyogalhLetIganhs8ZSw1qBq5aTFPJM+4Jd575x2kCEZNw2LecfrUNrJcYLXw2vmXyf2czRaOrylbE0jak6xnc9Jz69kxOxdnXLq4x3QELj0n77qPwz\/9Ar\/tw5+iWVunr9BOpnhqUHXEnOQJEUMY8o6EIKVCKSzWxmxtrNGocPDqDldKJlmi1p7dvMX6SFm4cJCUnIw2VapV5k2ls02OvRV2Zs+RRkLjPf2VQ9befj9eMGaHR2CJ5f4+IgeADl4oBgM+eCFWYCpSK\/+8MOcvtZDNkBJIBFYLicEbj1NmmpypOxtNYpwE18I4w2ze8Z53rvPiFaVe7lkfwXTnZd7ywLvxK+f\/xrLrUM\/UUvFmBK\/\/QyCAp4SqIhFEDTQGAFor0vfXDH7tFrgYO69coM0tLsLG2jrH1zfxqBwe7rG1PuX3Tzv\/OD\/ild05z782Z5SDRpd8sH8ROXHLbVFLoV8uqd2CNJkiIZTlHE3NkA5qj+cWYPDcgNZAESSueujBi2sEQsVEcBVcQKlkM1SDvu8QCttTZ6M1Lh8NNrdxuOsM\/AtA9jdb2ZxdiwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-sorter_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ELightweight sorting of tables.\u003C\/p\u003E\n\u003Cp\u003EJust add \u003Ccode\u003E[data-sort]\u003C\/code\u003E attributes to the \u003Ccode\u003Eth\u003C\/code\u003E elements in columns you\u2019d like to sort a table by, include ~1kB of JS \u0026amp; CSS, and initialise with \u003Ccode\u003Esorter()\u003C\/code\u003E \u2013 and that\u2019s it!\u003C\/p\u003E\n\u003Cp\u003EFor installation instructions and more customisation options, you can check out the \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Sorter\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E readme file\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["html","javascript","js","library","lightweight","sort","sorting","table"],"hasMore":false,"image":"https:\/\/avris.it\/image\/avris-sorter_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-sorter_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sorter_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ELightweight sorting of tables.\u003C\/p\u003E\n\u003Cp\u003EJust add \u003Ccode\u003E[data-sort]\u003C\/code\u003E attributes to the \u003Ccode\u003Eth\u003C\/code\u003E elements in columns you\u2019d like to sort a table by, include ~1kB of JS \u0026amp; CSS, and initialise with \u003Ccode\u003Esorter()\u003C\/code\u003E \u2013 and that\u2019s it!\u003C\/p\u003E\n\u003Cp\u003EFor installation instructions and more customisation options, you can check out the \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Sorter\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E readme file\u003C\/a\u003E.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-sorter_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sorter_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ELightweight sorting of tables.\u003C\/p\u003E\n\u003Cp\u003EJust add \u003Ccode\u003E[data-sort]\u003C\/code\u003E attributes to the \u003Ccode\u003Eth\u003C\/code\u003E elements in columns you\u2019d like to sort a table by, include ~1kB of JS \u0026amp; CSS, and initialise with \u003Ccode\u003Esorter()\u003C\/code\u003E \u2013 and that\u2019s it!\u003C\/p\u003E\n\u003Cp\u003EFor installation instructions and more customisation options, you can check out the \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Sorter\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E readme file\u003C\/a\u003E.\u003C\/p\u003E","words":50,"readTime":null,"lang":"en"}}},"projects\/columnist":{"key":"projects\/columnist","type":"article","published":true,"meta":{"createdAt":"2019-08-26T15:07:32+02:00","publishedAt":"2019-08-26T17:48:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/columnist.avris.it\/","displayUrl":"Demo"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Columnist","displayUrl":null},{"icon":"globe-europe","colour":"secondary","url":"https:\/\/www.npmjs.com\/package\/avris-columnist","displayUrl":null}],"category":"projects","subcategory":null,"slug":"columnist"},"content":{"en":{"slug":"columnist","title":"Columnist \u2013 Simple and lightweight multi-column design","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/columnist_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022244.29473684211\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACMklEQVRIicWVQXPTMBCFv5WtNMRNmik\/iekU\/iX3\/hdOHGE40XOZkDSurF0OshzHiZ0OdIZ3sawn62mfdteiqkYPIoLZ0dSr599iTTkk+otjVB4ffxKaSOGEEBqiKqvVkpn3IML729uTzf8FMnSoj5fwQhMiaooTAQQA7z3en8TyJg6JnWNbbLdb6n1NVMV7T9SICGDJSTNwTpjNrri+ri5G\/xqUE+cBIDQNaoqaUlUVmLURCiLZsfJs1H+DSYf+B04ToYfPX+DhaxrfLiAq7AKECJ6aj80DALOZxzlHjJEQGgB+fP9GXe8pipLFYs5m8xuAT\/d33N996DTMrHMaBg4NyUvzfR7o1uT1\/e9eu6Y8J5jfVXU0N8aqJXOqOso550aDm8yh0DTkrrDdbqmqipTOqboy97zbIa5gPr+CHpfWGk9Pv1iv1x3ny\/FMmexDUZUx2okQNZ7nnEvukjvXMVcWxelBxjp1H6nXJOuf93vezecHThzJ26Gktd+mhtVmzpTMEcqpZG2VAdCo3ThDRLI+na5JulI5fxARGS0QEbncGE0Sv1gsunFWz\/Ef6UrmDggh4L1vN2SyiV50KMVrdP+M3gmS9nDeeodJv5fd7pmbmzLPTLaQySqLMRJHkrpwMso5EZp4vuyLYrrKJq9MzbC2WjabDavlsqscFdclfF3XFKWnLFJ\/MXHdhWYvDirj\/asNprV\/5IkIiLBcrtLuR8kqmAll6TEdFrkcHu0eTGjl8R8MrVmKlGbrrwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/columnist_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022244.29473684211\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EI like multi-column design. Unfortunately, it\u2019s really annoying to work with. If your tiles don\u2019t all have the same height, it looks awful.\u003C\/p\u003E\n\u003Cp\u003EThat\u2019s why we have \u003Ca href=\u0022https:\/\/masonry.desandro.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Masonry\u003C\/a\u003E (and \u003Ca href=\u0022https:\/\/alternativeto.net\/software\/masonry\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E alternatives\u003C\/a\u003E) \u2013 but they all use absolute positioning, which can be problematic for lazy loading of images, dynamically adding more elements, etc. We can \u003Ca href=\u0022https:\/\/tobiasahlin.com\/blog\/masonry-with-css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E try doing it with plain CSS\u003C\/a\u003E \u2013 alas, it either breaks the order of tiles or requires knowing the height of the container in advance.\u003C\/p\u003E\n\u003Cp\u003EBut I think I might have a solution to that: \u003Ca href=\u0022https:\/\/columnist.avris.it\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E DEMO\u003C\/a\u003E\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/columnist_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022488.58947368421\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAASCAYAAAAzI3woAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACMklEQVRIicWVQXPTMBCFv5WtNMRNmik\/iekU\/iX3\/hdOHGE40XOZkDSurF0OshzHiZ0OdIZ3sawn62mfdteiqkYPIoLZ0dSr599iTTkk+otjVB4ffxKaSOGEEBqiKqvVkpn3IML729uTzf8FMnSoj5fwQhMiaooTAQQA7z3en8TyJg6JnWNbbLdb6n1NVMV7T9SICGDJSTNwTpjNrri+ri5G\/xqUE+cBIDQNaoqaUlUVmLURCiLZsfJs1H+DSYf+B04ToYfPX+DhaxrfLiAq7AKECJ6aj80DALOZxzlHjJEQGgB+fP9GXe8pipLFYs5m8xuAT\/d33N996DTMrHMaBg4NyUvzfR7o1uT1\/e9eu6Y8J5jfVXU0N8aqJXOqOso550aDm8yh0DTkrrDdbqmqipTOqboy97zbIa5gPr+CHpfWGk9Pv1iv1x3ny\/FMmexDUZUx2okQNZ7nnEvukjvXMVcWxelBxjp1H6nXJOuf93vezecHThzJ26Gktd+mhtVmzpTMEcqpZG2VAdCo3ThDRLI+na5JulI5fxARGS0QEbncGE0Sv1gsunFWz\/Ef6UrmDggh4L1vN2SyiV50KMVrdP+M3gmS9nDeeodJv5fd7pmbmzLPTLaQySqLMRJHkrpwMso5EZp4vuyLYrrKJq9MzbC2WjabDavlsqscFdclfF3XFKWnLFJ\/MXHdhWYvDirj\/asNprV\/5IkIiLBcrtLuR8kqmAll6TEdFrkcHu0eTGjl8R8MrVmKlGbrrwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/columnist_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022488.58947368421\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EI like multi-column design. Unfortunately, it\u2019s really annoying to work with. If your tiles don\u2019t all have the same height, it looks awful.\u003C\/p\u003E\n\u003Cp\u003EThat\u2019s why we have \u003Ca href=\u0022https:\/\/masonry.desandro.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Masonry\u003C\/a\u003E (and \u003Ca href=\u0022https:\/\/alternativeto.net\/software\/masonry\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E alternatives\u003C\/a\u003E) \u2013 but they all use absolute positioning, which can be problematic for lazy loading of images, dynamically adding more elements, etc. We can \u003Ca href=\u0022https:\/\/tobiasahlin.com\/blog\/masonry-with-css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E try doing it with plain CSS\u003C\/a\u003E \u2013 alas, it either breaks the order of tiles or requires knowing the height of the container in advance.\u003C\/p\u003E\n\u003Cp\u003EBut I think I might have a solution to that: \u003Ca href=\u0022https:\/\/columnist.avris.it\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E DEMO\u003C\/a\u003E\u003C\/p\u003E\n\u003Cp\u003ETake a look at this graphic:\u003C\/p\u003E\n\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/columnist-how_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022475.49103330487\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACAElEQVRIiZVV207jMBA9M3ZWon0Csd\/B\/\/8E8MAPIMGudgtFglawJJ7ZB8d3h4ZRk9rj4zP2GTtDIqLT5ADCSSMQmAlO5DQYABNDoVDVVXhrDBgAnAhEtHh2u6fG50Qgqo3\/4\/0Du6d941cVSIf74eFX4\/N4hQ2rq3ex2WwbHxF1seM4YrvZdJTo47fbHnaeISI6ThMoz9nLi\/8\/P2\/4iQiTc4D6cIqUbU0wKAGWOSq6hCFNvh+D9QoNNgrl7XgAXl+Bn5fNDpyIZ4JGojqcYo6W2RImsXizIQ2FnZ0B+z3QG0PuDhoVo42vpenNmxfUzeXFBXA8Agt5Vsw6R72z\/IVAlCUz9yNvt\/x9heJGlsYo\/Pw5CPQd+GAt6hiqWvjyfl+hFDbeBiJK7RPfFapavRi1L\/S\/VggodhLbRPF65ZkhoLx21fw8+PcUensDDodFheI7HoXqUitiunP+guNbCj0+Avf3wNVVoxATwTKVMiRE0WPmRqGwqKXMkIjov8+xpFL1D3NDxobhJtclq80YA1GByrpaNgwWKSKFXRNAhNu7u9SfH+1hQXjeP+P3n78lnvJvTYm\/vrn1IxUPkCm0xogIxjCmlQpZk0rHGoulIwRbtSgAvBLrb+PyeelZUcT8Sfd3eRYw1ppQfJkZxpjm9qT55eY+RYpDnDC+vpGW1ew\/BCdqPrjZC2cAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/columnist-how_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022475.49103330487\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EOur main job is to make the empty space marked with the red arrow disappear. If we can calculate its height, we can give the tile right below it a negative \u003Ccode\u003Emargin-top\u003C\/code\u003E to compensate for the height of the empty space.\u003C\/p\u003E\n\u003Cp\u003EAnd we can! All we need is to make sure that the column only has one child element. The difference between the height of the column and of that child is what we need to compensate for.\u003C\/p\u003E\n\u003Cp\u003EWe can find the tile right below from it (\u003Ccode\u003Ei + numberOfColumns\u003C\/code\u003E), give it \u003Ccode\u003Emargin-top: -${diff}px\u003C\/code\u003E et voil\u00e0!\u003C\/p\u003E\n\u003Ch3\u003ELimitations\u003C\/h3\u003E\n\u003Cp\u003EMy script does not do any maths fancier than this. If your first column contains a very tall tile A and a small tile B, and your second column only contains a small tile C, it would look nicer, if B were moved to the second column. My script doesn\u2019t do that. That\u2019s the price of simplicity.\u003C\/p\u003E\n\u003Ch3\u003EFuture work\u003C\/h3\u003E\n\u003Cp\u003ECurrent implementation relies a \u003Ccode\u003EsetInterval\u003C\/code\u003E that reapplies the layout every 300 ms. Firstly, because a couple of iterations are needed to get the final layout, and secondly, because the DOM and window can change.\u003C\/p\u003E\n\u003Cp\u003EObviously, I can get rid of both those problems. Applying the layout in a loop or in some smarter way, adding event listeners, etc.\u003C\/p\u003E\n\u003Cp\u003EBut that\u2019s a job for the next free evening \/ weekend.\u003C\/p\u003E\n\u003Cp\u003EAnyways, check out the links below and enjoy \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["column","design","javascript","layout","library","masonry","multi-column","npm"],"hasMore":true,"image":"https:\/\/avris.it\/image\/columnist_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/columnist_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/columnist_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022122.14736842105\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EI like multi-column design. Unfortunately, it\u2019s really annoying to work with. If your tiles don\u2019t all have the same height, it looks awful.\u003C\/p\u003E\n\u003Cp\u003EThat\u2019s why we have \u003Ca href=\u0022https:\/\/masonry.desandro.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Masonry\u003C\/a\u003E (and \u003Ca href=\u0022https:\/\/alternativeto.net\/software\/masonry\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E alternatives\u003C\/a\u003E) \u2013 but they all use absolute positioning, which can be problematic for lazy loading of images, dynamically adding more elements, etc. We can \u003Ca href=\u0022https:\/\/tobiasahlin.com\/blog\/masonry-with-css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E try doing it with plain CSS\u003C\/a\u003E \u2013 alas, it either breaks the order of tiles or requires knowing the height of the container in advance.\u003C\/p\u003E\n\u003Cp\u003EBut I think I might have a solution to that: \u003Ca href=\u0022https:\/\/columnist.avris.it\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E DEMO\u003C\/a\u003E\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/columnist_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/columnist_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022122.14736842105\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EI like multi-column design. Unfortunately, it\u2019s really annoying to work with. If your tiles don\u2019t all have the same height, it looks awful.\u003C\/p\u003E\n\u003Cp\u003EThat\u2019s why we have \u003Ca href=\u0022https:\/\/masonry.desandro.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Masonry\u003C\/a\u003E (and \u003Ca href=\u0022https:\/\/alternativeto.net\/software\/masonry\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E alternatives\u003C\/a\u003E) \u2013 but they all use absolute positioning, which can be problematic for lazy loading of images, dynamically adding more elements, etc. We can \u003Ca href=\u0022https:\/\/tobiasahlin.com\/blog\/masonry-with-css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E try doing it with plain CSS\u003C\/a\u003E \u2013 alas, it either breaks the order of tiles or requires knowing the height of the container in advance.\u003C\/p\u003E\n\u003Cp\u003EBut I think I might have a solution to that: \u003Ca href=\u0022https:\/\/columnist.avris.it\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E DEMO\u003C\/a\u003E\u003C\/p\u003E\n\u003Cp\u003ETake a look at this graphic:\u003C\/p\u003E\n\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/columnist-how_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/columnist-how_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022118.87275832622\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EOur main job is to make the empty space marked with the red arrow disappear. If we can calculate its height, we can give the tile right below it a negative \u003Ccode\u003Emargin-top\u003C\/code\u003E to compensate for the height of the empty space.\u003C\/p\u003E\n\u003Cp\u003EAnd we can! All we need is to make sure that the column only has one child element. The difference between the height of the column and of that child is what we need to compensate for.\u003C\/p\u003E\n\u003Cp\u003EWe can find the tile right below from it (\u003Ccode\u003Ei + numberOfColumns\u003C\/code\u003E), give it \u003Ccode\u003Emargin-top: -${diff}px\u003C\/code\u003E et voil\u00e0!\u003C\/p\u003E\n\u003Ch3\u003ELimitations\u003C\/h3\u003E\n\u003Cp\u003EMy script does not do any maths fancier than this. If your first column contains a very tall tile A and a small tile B, and your second column only contains a small tile C, it would look nicer, if B were moved to the second column. My script doesn\u2019t do that. That\u2019s the price of simplicity.\u003C\/p\u003E\n\u003Ch3\u003EFuture work\u003C\/h3\u003E\n\u003Cp\u003ECurrent implementation relies a \u003Ccode\u003EsetInterval\u003C\/code\u003E that reapplies the layout every 300 ms. Firstly, because a couple of iterations are needed to get the final layout, and secondly, because the DOM and window can change.\u003C\/p\u003E\n\u003Cp\u003EObviously, I can get rid of both those problems. Applying the layout in a loop or in some smarter way, adding event listeners, etc.\u003C\/p\u003E\n\u003Cp\u003EBut that\u2019s a job for the next free evening \/ weekend.\u003C\/p\u003E\n\u003Cp\u003EAnyways, check out the links below and enjoy \ud83d\ude09\u003C\/p\u003E","words":331,"readTime":2,"lang":"en"}}},"projects\/block-checker":{"key":"projects\/block-checker","type":"article","published":true,"meta":{"createdAt":"2019-03-12T10:39:28+01:00","publishedAt":"2019-03-12T10:38:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/blockchecker.avris.it\/","displayUrl":null}],"category":"projects","subcategory":null,"slug":"block-checker"},"content":{"en":{"slug":"block-checker","title":"Block Checker","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/block-checker_small.png\u0022 alt=\u0022Block Checker screenshot\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022287.69716088328\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAVCAYAAAAuJkyQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB2klEQVRIic2WX2\/TMBTFf9dO0n9Ou7KBKBLw0i\/JR+QbbLCJJyQoINFlWZOmiXnY0oU0SZMAFefFke+5zrF9fG2x1loeYa1FRCgiD4vIPl7mFTl1Y7XlOHXkHMW+qvjfhmRZZo\/TTgenz6yrtrYNp2qLyhzVVUifWBd0EnQKDzn5x6frK24+f2fkCq8WC5TWfPn6jYtnZ4zGEz5cXfL6zVvieEsQrDk\/vyAIApbLJb6ZHIhtI76KsxfkT2csUsV2ExLHEf5sDlh834BoXr54ThDeMxkNOZtOWa\/XjMdjjJm0nn0rkfkpK3ugKvnJhJYiXURI0xStFDzmNRk\/yzKUUpWc\/SkLw5DVaoUojaMViGKXbNntUoajAWEYoR2NGQ\/ZxgnRNsHVgvYGpEmC7xtub9dY5TLyHJIkwYoijiJcR2OMIQgCtOMhZDjegE14h+sNmM\/nzKb+7yv0v6BXHfqXcLrWj\/wuu08gtVBOFx5sZLx+gjrVoSJ2Gfh6g7x\/x8\/IcrnK+PjDohT8iQk6e+hgheI78MxTHFAKJu6JBZXbtpymPABVZ+o2l+exnCpOXb3LW9Vk6iZRfa8GKRTOKtSuUFNSFxzbgfI\/Dk7ZSV6FDa9QVUfs299nQsWcX0hG\/OBSpUM6AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/block-checker_small.png\u0022 alt=\u0022Block Checker screenshot\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022287.69716088328\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ECheck how many people you blocked on Twitter and compare yourself to others.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/block-checker_big.png\u0022 alt=\u0022Block Checker screenshot\u0022 class=\u0022border\u0022 width=\u0022634\u0022 height=\u0022380\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAVCAYAAAAuJkyQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB2klEQVRIic2WX2\/TMBTFf9dO0n9Ou7KBKBLw0i\/JR+QbbLCJJyQoINFlWZOmiXnY0oU0SZMAFefFke+5zrF9fG2x1loeYa1FRCgiD4vIPl7mFTl1Y7XlOHXkHMW+qvjfhmRZZo\/TTgenz6yrtrYNp2qLyhzVVUifWBd0EnQKDzn5x6frK24+f2fkCq8WC5TWfPn6jYtnZ4zGEz5cXfL6zVvieEsQrDk\/vyAIApbLJb6ZHIhtI76KsxfkT2csUsV2ExLHEf5sDlh834BoXr54ThDeMxkNOZtOWa\/XjMdjjJm0nn0rkfkpK3ugKvnJhJYiXURI0xStFDzmNRk\/yzKUUpWc\/SkLw5DVaoUojaMViGKXbNntUoajAWEYoR2NGQ\/ZxgnRNsHVgvYGpEmC7xtub9dY5TLyHJIkwYoijiJcR2OMIQgCtOMhZDjegE14h+sNmM\/nzKb+7yv0v6BXHfqXcLrWj\/wuu08gtVBOFx5sZLx+gjrVoSJ2Gfh6g7x\/x8\/IcrnK+PjDohT8iQk6e+hgheI78MxTHFAKJu6JBZXbtpymPABVZ+o2l+exnCpOXb3LW9Vk6iZRfa8GKRTOKtSuUFNSFxzbgfI\/Dk7ZSV6FDa9QVUfs299nQsWcX0hG\/OBSpUM6AAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/block-checker_big.png\u0022 alt=\u0022Block Checker screenshot\u0022 class=\u0022border\u0022 width=\u0022634\u0022 height=\u0022380\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ECheck how many people you blocked on Twitter and compare yourself to others.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["api","ban","block","javascript","twitter","zeroserver"],"hasMore":false,"image":"https:\/\/avris.it\/image\/block-checker_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/block-checker_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/block-checker_mini.png\u0022 alt=\u0022Block Checker screenshot\u0022 width=\u0022240\u0022 height=\u0022143.84858044164\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ECheck how many people you blocked on Twitter and compare yourself to others.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/block-checker_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/block-checker_mini.png\u0022 alt=\u0022Block Checker screenshot\u0022 width=\u0022240\u0022 height=\u0022143.84858044164\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ECheck how many people you blocked on Twitter and compare yourself to others.\u003C\/p\u003E","words":13,"readTime":null,"lang":"en"}}},"projects\/avris-sync":{"key":"projects\/avris-sync","type":"article","published":true,"meta":{"createdAt":"2019-01-01T18:55:16+01:00","publishedAt":"2019-01-01T18:53:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/www.npmjs.com\/package\/avris-sync","displayUrl":"npm: avris-sync"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Sync","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-sync"},"content":{"en":{"slug":"avris-sync","title":"avris-sync","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sync_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHmklEQVRIiX2X2a9lRRXGf2uo2me459yh+17oZmgmUUDtQDSSEAOSMMWgQeOAJkQf9EHjg3+C7775YDQ+65PxBTHRaAQSSBSNAyB2BGmmhtB9+w7nTmfvquXDPt0YNVb2lOyqXV99X621vi3XXndbRKkIQdQKUTF3aikEgYrgapgqyZ35\/IhaK0RABAKICELfRAQRAYJLLSIWZ718JyoioCKYOyZC0wzxCCEiKLUgAQKUUhD6D6tqD1QUaiWp0i0mQGTRj8v9RQAEVXlvcrn0LEQtiBoR740zhKSG1oJfGiAoQSUCNATRfjJCUHVA6ErFEBQhRDHVBRv9QpD+3eJYXAx3Yz5vEYGIfoEiii7GmipuRlLFQxRqWRDcM0IEEoKq4aaYCCaKmyJRqbVSa+k\/4N6vvlZU7bJUKkLUShAsr6ywtXkRqBCCOEQtqAoEmCnJjOSXAAmgAnXBloCILmQwFMXMyJYYNQ1Ex\/7BAY07TXKyJ2qtlNLRlQJCv19qBeDEFRsc7c6A2pMWgWpegFJMe4mzKS6aiGiRMJCKXt6kgpr11FpCRVExVJxxM2Z1uMzF2TYaSpSg8YR6hiiECF3X9gwJnLr2Wt5+9TVEAgkwFYQAEiKxkExJprimTBcsIsYuxQqo9uyoYWpkd7IlFEMk0eTE9etL7O3POGpbrrhyg\/nBPrOdXUyE7EqNyl33383LL77ENDcE0UcWoNqLogoikEzJbnhoQtJCLoQaYKKoGiqKm+NqZM+4CMmcJImkDWtry3zmK59jbXWF3\/70F7x+9nWsWSJ5H02T5SXuuvduXnjyGVYGQ6AQET0YFVTATDDtWXMXnNwgnVNrLPQFUEQNNUfEcHNUE262OBP3PPRxHv3mFzjz3N94\/Hs\/IVG4+cRJolZ292Z4Nr78nW\/z3M+e4OrplHlpqdERUXrpdBFdqd9DOSmm4DIYU9uC1NrnoQDEEHHUEskcVSOZM0iZkTtf\/cZneeCRe5hd3OWJHzxO1iGrowE33nSSve3zbO8fcu+3vkRSoZ59gw+c2GB2sM9hN6fUjlJb0Epyw0xwV5ILKRkuoyky76BUAvo9giKSUDHEE1mdQUqMUuLRx+7jgUfuAeAvTz9PomGyNGFp1LC7ecCpj3yY+x++Cx80PPvdH7FxfBmNlu2doOsSJXpAIRXVIGXHXUhJ8Sy4DCeQOyggoRCKoCAOmjB1kjk5JU6fvp5Pff4Tl0vCzjszjl2xzlWnNjh12zVcc8cNjI9PiQhe\/+VTjIeZUpcYNB25qSCVGi1dNydqixqoBuZGbhxPgjNZhq4QIT2Y6KPLcFwTiiOLBPjY1x+6nJkBHvzaffxniwjefOoPzN89z\/p1xzjazrR7W0y1RawiFtTaUrsjhA41wVxJOeNNg+tkQir0dQbFQ0kYWZwcRlYjo9xx+lquumrtvwD8e6ul8PKvfs\/umZcZjJXB8oj1W66m2x6zc05QmSO0IJkoCZHaR1hyLGesGeKTlQmlAAuGDMHDGYgxQBlgNFW482M3\/V8ws3e3efHnzzC\/8C7DBlBoD\/bZv9DiMme03FDb0uceA5WELORSdywP0GaIX7k2pOuCWqCGoqEoRgohYQxCaYpw8w3H\/yeQg519\/v7087z5x5fI0jIc1L50VIgW6pFBo+ShEkkxiYVMCTXFUkZzg6QG8hD\/4EbD\/mHL\/Kgw7yqlVEqtSAgSFSuCiXB8dXQZxN7sgLNn3uTVP7\/Cmy\/8kyZaRl6IVHAqWSuhARYw72ulpCB54CaYCZoSkgeQDHKG3IAP8IdX32LvsDKbtezsVWZdsHsE+3M4bGHeCaWDH37\/xxzsHbB1foe9zR1yKSQKicpAK0PrGKdgOqjMRxUmQQphYL3NkNKiHlg2rAZtaxgT2iNDB4ntiyNaBsg9tx2P6SBxeNhbJbdMiFNxQhIFp2qmqxCioI6I4tpn7WOrKxztH5BNaBTGGSYZ1sfBidXCxnFjPBZeO7fF7OCAkltWTl7Fk7\/+Ha+eO2I6qGxsTDhqg2df3EOWVtZCU0bUsJTwZoCo4bnBU8ZSg6qRmwHmiZPr69x+6028fX6X8XDI+soqm5s7HF+eorXS7e1x46mTHG1uErubTFPL6hiSdiTrWBl33Hx6xNa5Ge+e22EyBJeO9TvvY\/+vv8Fv+fQXaZamdBUG4wmeGlQdMSd5QsQQ+rojIVyzNqUTuPqEsb2zx7xJjIdrXNg95LoTa0gpbJWCjtaRMmSPjpyMQapUqxw2ldZWWHs\/bM1eIQ2Fxju6i\/ss3foAXjBm+wdgifnuLiJ7gPZeKHoD3nshkFI5\/9brSK3Uw0OohWyGlEAiOHMm8BC0FkYpM0nOxJ3lJjFKgmthlGF22PLRD01546JSNzumQ5hsvcX7Hrwdv3j2H8zbFvVMLRVvhvDePwQCeEqoKhJB1ECjB6C1Il132eDX9ggXY+ud1xjkAS7C8tKUY9MVPCr7+zusTif86SXn7bND3tk+5NULhwxz0OicT3ZvIMdvvCVqKXTzObU9Io0nSAhlfoimpi8HtcPzAKD33IDWQBEkLnno3otrBELFRHAVXECpZDNUg65rEQobE2d5YGwe9Da3cbjzFPwLLIk8ktJRts4AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-sync_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA simple file synchronisation tool using \u003Ccode\u003Eavris-fs\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWarning!\u003C\/strong\u003E It\u2019s a \u003Cem\u003Every\u003C\/em\u003E early version! Conflict handling is not implemented,\nso only use it when you can safely assume often synchronisations\/rare conflicts\/versioning on the remote, etc.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sync_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHmklEQVRIiX2X2a9lRRXGf2uo2me459yh+17oZmgmUUDtQDSSEAOSMMWgQeOAJkQf9EHjg3+C7775YDQ+65PxBTHRaAQSSBSNAyB2BGmmhtB9+w7nTmfvquXDPt0YNVb2lOyqXV99X621vi3XXndbRKkIQdQKUTF3aikEgYrgapgqyZ35\/IhaK0RABAKICELfRAQRAYJLLSIWZ718JyoioCKYOyZC0wzxCCEiKLUgAQKUUhD6D6tqD1QUaiWp0i0mQGTRj8v9RQAEVXlvcrn0LEQtiBoR740zhKSG1oJfGiAoQSUCNATRfjJCUHVA6ErFEBQhRDHVBRv9QpD+3eJYXAx3Yz5vEYGIfoEiii7GmipuRlLFQxRqWRDcM0IEEoKq4aaYCCaKmyJRqbVSa+k\/4N6vvlZU7bJUKkLUShAsr6ywtXkRqBCCOEQtqAoEmCnJjOSXAAmgAnXBloCILmQwFMXMyJYYNQ1Ex\/7BAY07TXKyJ2qtlNLRlQJCv19qBeDEFRsc7c6A2pMWgWpegFJMe4mzKS6aiGiRMJCKXt6kgpr11FpCRVExVJxxM2Z1uMzF2TYaSpSg8YR6hiiECF3X9gwJnLr2Wt5+9TVEAgkwFYQAEiKxkExJprimTBcsIsYuxQqo9uyoYWpkd7IlFEMk0eTE9etL7O3POGpbrrhyg\/nBPrOdXUyE7EqNyl33383LL77ENDcE0UcWoNqLogoikEzJbnhoQtJCLoQaYKKoGiqKm+NqZM+4CMmcJImkDWtry3zmK59jbXWF3\/70F7x+9nWsWSJ5H02T5SXuuvduXnjyGVYGQ6AQET0YFVTATDDtWXMXnNwgnVNrLPQFUEQNNUfEcHNUE262OBP3PPRxHv3mFzjz3N94\/Hs\/IVG4+cRJolZ292Z4Nr78nW\/z3M+e4OrplHlpqdERUXrpdBFdqd9DOSmm4DIYU9uC1NrnoQDEEHHUEskcVSOZM0iZkTtf\/cZneeCRe5hd3OWJHzxO1iGrowE33nSSve3zbO8fcu+3vkRSoZ59gw+c2GB2sM9hN6fUjlJb0Epyw0xwV5ILKRkuoyky76BUAvo9giKSUDHEE1mdQUqMUuLRx+7jgUfuAeAvTz9PomGyNGFp1LC7ecCpj3yY+x++Cx80PPvdH7FxfBmNlu2doOsSJXpAIRXVIGXHXUhJ8Sy4DCeQOyggoRCKoCAOmjB1kjk5JU6fvp5Pff4Tl0vCzjszjl2xzlWnNjh12zVcc8cNjI9PiQhe\/+VTjIeZUpcYNB25qSCVGi1dNydqixqoBuZGbhxPgjNZhq4QIT2Y6KPLcFwTiiOLBPjY1x+6nJkBHvzaffxniwjefOoPzN89z\/p1xzjazrR7W0y1RawiFtTaUrsjhA41wVxJOeNNg+tkQir0dQbFQ0kYWZwcRlYjo9xx+lquumrtvwD8e6ul8PKvfs\/umZcZjJXB8oj1W66m2x6zc05QmSO0IJkoCZHaR1hyLGesGeKTlQmlAAuGDMHDGYgxQBlgNFW482M3\/V8ws3e3efHnzzC\/8C7DBlBoD\/bZv9DiMme03FDb0uceA5WELORSdywP0GaIX7k2pOuCWqCGoqEoRgohYQxCaYpw8w3H\/yeQg519\/v7087z5x5fI0jIc1L50VIgW6pFBo+ShEkkxiYVMCTXFUkZzg6QG8hD\/4EbD\/mHL\/Kgw7yqlVEqtSAgSFSuCiXB8dXQZxN7sgLNn3uTVP7\/Cmy\/8kyZaRl6IVHAqWSuhARYw72ulpCB54CaYCZoSkgeQDHKG3IAP8IdX32LvsDKbtezsVWZdsHsE+3M4bGHeCaWDH37\/xxzsHbB1foe9zR1yKSQKicpAK0PrGKdgOqjMRxUmQQphYL3NkNKiHlg2rAZtaxgT2iNDB4ntiyNaBsg9tx2P6SBxeNhbJbdMiFNxQhIFp2qmqxCioI6I4tpn7WOrKxztH5BNaBTGGSYZ1sfBidXCxnFjPBZeO7fF7OCAkltWTl7Fk7\/+Ha+eO2I6qGxsTDhqg2df3EOWVtZCU0bUsJTwZoCo4bnBU8ZSg6qRmwHmiZPr69x+6028fX6X8XDI+soqm5s7HF+eorXS7e1x46mTHG1uErubTFPL6hiSdiTrWBl33Hx6xNa5Ge+e22EyBJeO9TvvY\/+vv8Fv+fQXaZamdBUG4wmeGlQdMSd5QsQQ+rojIVyzNqUTuPqEsb2zx7xJjIdrXNg95LoTa0gpbJWCjtaRMmSPjpyMQapUqxw2ldZWWHs\/bM1eIQ2Fxju6i\/ss3foAXjBm+wdgifnuLiJ7gPZeKHoD3nshkFI5\/9brSK3Uw0OohWyGlEAiOHMm8BC0FkYpM0nOxJ3lJjFKgmthlGF22PLRD01546JSNzumQ5hsvcX7Hrwdv3j2H8zbFvVMLRVvhvDePwQCeEqoKhJB1ECjB6C1Il132eDX9ggXY+ud1xjkAS7C8tKUY9MVPCr7+zusTif86SXn7bND3tk+5NULhwxz0OicT3ZvIMdvvCVqKXTzObU9Io0nSAhlfoimpi8HtcPzAKD33IDWQBEkLnno3otrBELFRHAVXECpZDNUg65rEQobE2d5YGwe9Da3cbjzFPwLLIk8ktJRts4AAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-sync_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA simple file synchronisation tool using \u003Ccode\u003Eavris-fs\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWarning!\u003C\/strong\u003E It\u2019s a \u003Cem\u003Every\u003C\/em\u003E early version! Conflict handling is not implemented,\nso only use it when you can safely assume often synchronisations\/rare conflicts\/versioning on the remote, etc.\u003C\/p\u003E\n\u003Ch3\u003EExample\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eimport\u003C\/span\u003E {AvrisSync} \u003Cspan class=\u0022hljs-keyword\u0022\u003Efrom\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022avris-sync\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eimport\u003C\/span\u003E {AvrisFilesystem} \u003Cspan class=\u0022hljs-keyword\u0022\u003Efrom\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022avris-fs\/dist\/AvrisFilesystem\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eimport\u003C\/span\u003E {LocalAdapter} \u003Cspan class=\u0022hljs-keyword\u0022\u003Efrom\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022avris-fs\/dist\/adapter\/LocalAdapter\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eimport\u003C\/span\u003E {S3Adapter} \u003Cspan class=\u0022hljs-keyword\u0022\u003Efrom\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022avris-fs\/dist\/adapter\/S3Adapter\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eimport\u003C\/span\u003E {dump} \u003Cspan class=\u0022hljs-keyword\u0022\u003Efrom\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022avris-sync\/dist\/helpers\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eimport\u003C\/span\u003E {config \u003Cspan class=\u0022hljs-keyword\u0022\u003Eas\u003C\/span\u003E dotenv} \u003Cspan class=\u0022hljs-keyword\u0022\u003Efrom\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dotenv\u0027\u003C\/span\u003E;\n\ndotenv();\n\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eas\u003C\/span\u003E = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E AvrisSync(\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E AvrisFilesystem(\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E LocalAdapter(__dirname + \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/data\/\u0027\u003C\/span\u003E),\n    ),\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E AvrisFilesystem(\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E S3Adapter(\n            process.env.AWS_BUCKET,\n            process.env.AWS_KEY,\n            process.env.AWS_SECRET\n        ),\n    ),\n);\n\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eas\u003C\/span\u003E.sync().then(\u003Cspan class=\u0022hljs-function\u0022\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Eres\u003C\/span\u003E) =\u0026gt;\u003C\/span\u003E {\n    dump(res);\n});\n\u003C\/code\u003E\u003C\/pre\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["javascript","sync","synchronisation","typescript"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avris-sync_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-sync_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sync_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA simple file synchronisation tool using \u003Ccode\u003Eavris-fs\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWarning!\u003C\/strong\u003E It\u2019s a \u003Cem\u003Every\u003C\/em\u003E early version! Conflict handling is not implemented,\nso only use it when you can safely assume often synchronisations\/rare conflicts\/versioning on the remote, etc.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-sync_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-sync_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA simple file synchronisation tool using \u003Ccode\u003Eavris-fs\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWarning!\u003C\/strong\u003E It\u2019s a \u003Cem\u003Every\u003C\/em\u003E early version! Conflict handling is not implemented,\nso only use it when you can safely assume often synchronisations\/rare conflicts\/versioning on the remote, etc.\u003C\/p\u003E\n\u003Ch3\u003EExample\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Eimport {AvrisSync} from \u0022avris-sync\u0022;\nimport {AvrisFilesystem} from \u0022avris-fs\/dist\/AvrisFilesystem\u0022;\nimport {LocalAdapter} from \u0022avris-fs\/dist\/adapter\/LocalAdapter\u0022;\nimport {S3Adapter} from \u0022avris-fs\/dist\/adapter\/S3Adapter\u0022;\nimport {dump} from \u0022avris-sync\/dist\/helpers\u0022;\nimport {config as dotenv} from \u0027dotenv\u0027;\n\ndotenv();\n\nconst as = new AvrisSync(\n    new AvrisFilesystem(\n        new LocalAdapter(__dirname + \u0027\/data\/\u0027),\n    ),\n    new AvrisFilesystem(\n        new S3Adapter(\n            process.env.AWS_BUCKET,\n            process.env.AWS_KEY,\n            process.env.AWS_SECRET\n        ),\n    ),\n);\n\nas.sync().then((res) =\u0026gt; {\n    dump(res);\n});\u003C\/code\u003E\u003C\/pre\u003E","words":113,"readTime":null,"lang":"en"}}},"projects\/avris-fs":{"key":"projects\/avris-fs","type":"article","published":true,"meta":{"createdAt":"2019-01-01T18:53:52+01:00","publishedAt":"2019-01-01T18:51:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/www.npmjs.com\/package\/avris-fs","displayUrl":"npm: avris-fs"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Filesystem","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-fs"},"content":{"en":{"slug":"avris-fs","title":"avris-fs","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-fs_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHoUlEQVRIiX2Xy69lRRXGf+tRtfe595776u4LTQMNNLQCIpFgJEEDkiAQgwaNDzQhOtCBxoF\/gnNnDozGsY6IE8REoxFIIFE0PqBFIo9uumlIN933ce7r7F21HOzTF6PGyn4lu2rXV99Xa61vy\/U33B5RKkIQtUJUzJ1aCkGgIrgapkpyZzrdp9YKERCBACKCMDQRQUSA4EqLiNlZD+5ERQRUBHPHRGiaER4hRASlFiRAgFIKwvBhVR2AikKtJFX62QSIzPpx0F8EQFCV9yeXK89C1IKoEfH+OENIamgt+JUBghJUIkBDEB0mIwRVB4S+VAxBEUIUU52xMSwEGd7NjtnFcDem0w4RiBgWKKLobKyp4mYkVTxEoZYZwQMjRCAhqBpuiolgorgpEpVaK7WW4QPuw+prRdUOpFIRolaCYGl5mfVLl4EKIYhD1IKqQICZksxIfgWQACpQZ2wJiOhMBkNRzIxsibmmgejZ2d2lcadJTvZErZVSevpSQBj2S60AHL1qjf2tCVAH0iJQzTNQiukgcTbFRRMRHRIGUtGDTSqo2UCtJVQUFUPFmW\/mWRktcXmygYYSJWg8oZ4hCiFC33cDQwLHr7+ed948g0ggAaaCEEBCJGaSKckU15Tpg1nE2JVYAdWBHTVMjexOtoRiiCSanLjxyALbOxP2u46rrl5jurvDZHMLEyG7UqNy76fu47VTr7CYG4IYIgtQHURRBRFIpmQ3PDQhaSYXQg0wUVQNFcXNcTWyZ1yEZE6SRNKG1dUlPve1L7C6sszvnvwlb51+C2sWSD5E03hpgXsfuI+Xn3me5XYEFCJiAKOCCpgJpgNr7oKTG6R3ao2ZvgCKqKHmiBhujmrCzWZn4v5HPsHj3\/4Sr774d576wc9IFE4evYaola3tCZ6Nr37vu7z486e5dnGRaemo0RNRBul0Fl1p2EM5Kabg0s5Tu4LUOuShAMQQcdQSyRxVI5nTpsycO1\/\/1ud56LH7mVze4ukfPUXWEStzLSduvobtjYts7OzxwHe+QlKhnj7LB4+uMdndYa+fUmpPqR1oJblhJrgryYWUDJe5RWTaQ6kEDHsERSShYognsjptSsylxONPPMhDj90PwF+fe4lEw3hhzMJcw9alXY7f\/WE+9ei9eNvwwvd\/wtrhJTQ6NjaDvk+UGACFVFSDlB13ISXFs+AyGkPuoYCEQiiCgjhowtRJ5uSUuPPOG\/nMFz95UBI2351w6KojHDu+xvHbr+O6u25i\/vAiEcFbv3qW+VGm1AXapic3FaRSo6Pvp0TtUAPVwNzIjeNJcMZL0BciZAATQ3QZjmtCcWSWAJ\/45iMHmRng4W88yH+2iODcs39keuEiR244xP5GptteZ1E7xCpiQa0dtd9H6FETzJWUM940uI7HpMJQZ1A8lISRxclhZDUyyl13Xs+xY6v\/BeDfWy2F1379B7ZefY12XmmX5jhy67X0G\/NsnhdUpggdSCZKQqQOEZYcyxlrRvh4eUwpwIwhQ\/BwWjFalBajqcI9H7v5\/4KZXNjg1C+eZ\/reBUYNoNDt7rDzXofLlLmlhtqVIfcYqCRkJpe6Y7lFmxF+9eqIvg9qgRqKhqIYKYSE0YbSFOHkTYf\/J5DdzR3+8dxLnPvTK2TpGLV1KB0VooO6b9AoeaREUkxiJlNCTbGU0dwgqYE8wj+01rCz1zHdL0z7SimVUisSgkTFimAiHF6ZOwCxPdnl9KvnePMvr3Pu5TdoomPOC5EKTiVrJTTAAqZDrZQUJA\/cBDNBU0JyC8kgZ8gNeIs\/uvI223uVyaRjc7sy6YOtfdiZwl4H014oPfz4hz9ld3uX9YubbF\/aJJdCopCotFoZWc98ChbbynSuwjhIIbQ22AwpHeqBZcNq0HWGMabbN7RNbFyeo6NF7r\/9cCy2ib29wSq5ZUKcihOSKDhVM32FEAV1RBTXIWtnd1aXlpjubtMonDxxjM13z3FkPji6Ulg7bMzPC2fOrzPZ3aXkjuVrjvHMb37Pm+f3WWwra2tj9rvghVPbyMLyamjKiBqWEt60iBqeGzxlLDWoGrlpMU8kz7glHvr43Zw9f4nrjl7N1tYuV60sc\/70Oe647Wbq9oSLr7\/BcguHFpSVeUjak6xneb7n5J1zrJ+fcOH8JuMRuPQcuedBdv72W\/zWz36ZZmGRvkI7P8ZTg6oj5iRPiBjCUHckBCkVSuHQLSeoqxtsbG3D0hhZXmLj\/DZnNgtrS0fYH0\/Zd2E7KTkZbapUq+w1lc6WWf0ArE9eJ42Exnv6yzss3PYQXjAmO7tgienWFiLbgA5eKAYDPnghZmAqUitPPv061EI2Q0pwKgKrhfcuvI3WwlzKjJMzdmepScwlwbUwl2Gy1\/HROxY5e1mpl3oWRzBef5tbHv4Ifvn0P5l2HeqZWirejOD9fwgE8JRQVSSCqIFGIBForUjfHxj82u3jYqy\/e4Y2t7gISwuLHFpcxqOys7PJyuKYP7\/ivHN6xLsbe7z53h6jHDQ65dP9WeTwiVujlkI\/nVK7fdL8GAmhTPfQ1AzloPZ4bgEGzw1oDRRB4oqHHry4RiBUTARXwQWUSjZDNej7DqGwNnaWWuPS7mBzG4d7jsO\/AOFtP6chpFTOAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-fs_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA filesystem management abstraction layer for JavaScript.\nManage files on local filesystem, on FTP server, on Amazon S3, etc. all through the same interface.\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWarning!\u003C\/strong\u003E It\u2019s a \u003Cem\u003Every\u003C\/em\u003E early version!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-fs_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHoUlEQVRIiX2Xy69lRRXGf+tRtfe595776u4LTQMNNLQCIpFgJEEDkiAQgwaNDzQhOtCBxoF\/gnNnDozGsY6IE8REoxFIIFE0PqBFIo9uumlIN933ce7r7F21HOzTF6PGyn4lu2rXV99Xa61vy\/U33B5RKkIQtUJUzJ1aCkGgIrgapkpyZzrdp9YKERCBACKCMDQRQUSA4EqLiNlZD+5ERQRUBHPHRGiaER4hRASlFiRAgFIKwvBhVR2AikKtJFX62QSIzPpx0F8EQFCV9yeXK89C1IKoEfH+OENIamgt+JUBghJUIkBDEB0mIwRVB4S+VAxBEUIUU52xMSwEGd7NjtnFcDem0w4RiBgWKKLobKyp4mYkVTxEoZYZwQMjRCAhqBpuiolgorgpEpVaK7WW4QPuw+prRdUOpFIRolaCYGl5mfVLl4EKIYhD1IKqQICZksxIfgWQACpQZ2wJiOhMBkNRzIxsibmmgejZ2d2lcadJTvZErZVSevpSQBj2S60AHL1qjf2tCVAH0iJQzTNQiukgcTbFRRMRHRIGUtGDTSqo2UCtJVQUFUPFmW\/mWRktcXmygYYSJWg8oZ4hCiFC33cDQwLHr7+ed948g0ggAaaCEEBCJGaSKckU15Tpg1nE2JVYAdWBHTVMjexOtoRiiCSanLjxyALbOxP2u46rrl5jurvDZHMLEyG7UqNy76fu47VTr7CYG4IYIgtQHURRBRFIpmQ3PDQhaSYXQg0wUVQNFcXNcTWyZ1yEZE6SRNKG1dUlPve1L7C6sszvnvwlb51+C2sWSD5E03hpgXsfuI+Xn3me5XYEFCJiAKOCCpgJpgNr7oKTG6R3ao2ZvgCKqKHmiBhujmrCzWZn4v5HPsHj3\/4Sr774d576wc9IFE4evYaola3tCZ6Nr37vu7z486e5dnGRaemo0RNRBul0Fl1p2EM5Kabg0s5Tu4LUOuShAMQQcdQSyRxVI5nTpsycO1\/\/1ud56LH7mVze4ukfPUXWEStzLSduvobtjYts7OzxwHe+QlKhnj7LB4+uMdndYa+fUmpPqR1oJblhJrgryYWUDJe5RWTaQ6kEDHsERSShYognsjptSsylxONPPMhDj90PwF+fe4lEw3hhzMJcw9alXY7f\/WE+9ei9eNvwwvd\/wtrhJTQ6NjaDvk+UGACFVFSDlB13ISXFs+AyGkPuoYCEQiiCgjhowtRJ5uSUuPPOG\/nMFz95UBI2351w6KojHDu+xvHbr+O6u25i\/vAiEcFbv3qW+VGm1AXapic3FaRSo6Pvp0TtUAPVwNzIjeNJcMZL0BciZAATQ3QZjmtCcWSWAJ\/45iMHmRng4W88yH+2iODcs39keuEiR244xP5GptteZ1E7xCpiQa0dtd9H6FETzJWUM940uI7HpMJQZ1A8lISRxclhZDUyyl13Xs+xY6v\/BeDfWy2F1379B7ZefY12XmmX5jhy67X0G\/NsnhdUpggdSCZKQqQOEZYcyxlrRvh4eUwpwIwhQ\/BwWjFalBajqcI9H7v5\/4KZXNjg1C+eZ\/reBUYNoNDt7rDzXofLlLmlhtqVIfcYqCRkJpe6Y7lFmxF+9eqIvg9qgRqKhqIYKYSE0YbSFOHkTYf\/J5DdzR3+8dxLnPvTK2TpGLV1KB0VooO6b9AoeaREUkxiJlNCTbGU0dwgqYE8wj+01rCz1zHdL0z7SimVUisSgkTFimAiHF6ZOwCxPdnl9KvnePMvr3Pu5TdoomPOC5EKTiVrJTTAAqZDrZQUJA\/cBDNBU0JyC8kgZ8gNeIs\/uvI223uVyaRjc7sy6YOtfdiZwl4H014oPfz4hz9ld3uX9YubbF\/aJJdCopCotFoZWc98ChbbynSuwjhIIbQ22AwpHeqBZcNq0HWGMabbN7RNbFyeo6NF7r\/9cCy2ib29wSq5ZUKcihOSKDhVM32FEAV1RBTXIWtnd1aXlpjubtMonDxxjM13z3FkPji6Ulg7bMzPC2fOrzPZ3aXkjuVrjvHMb37Pm+f3WWwra2tj9rvghVPbyMLyamjKiBqWEt60iBqeGzxlLDWoGrlpMU8kz7glHvr43Zw9f4nrjl7N1tYuV60sc\/70Oe647Wbq9oSLr7\/BcguHFpSVeUjak6xneb7n5J1zrJ+fcOH8JuMRuPQcuedBdv72W\/zWz36ZZmGRvkI7P8ZTg6oj5iRPiBjCUHckBCkVSuHQLSeoqxtsbG3D0hhZXmLj\/DZnNgtrS0fYH0\/Zd2E7KTkZbapUq+w1lc6WWf0ArE9eJ42Exnv6yzss3PYQXjAmO7tgienWFiLbgA5eKAYDPnghZmAqUitPPv061EI2Q0pwKgKrhfcuvI3WwlzKjJMzdmepScwlwbUwl2Gy1\/HROxY5e1mpl3oWRzBef5tbHv4Ifvn0P5l2HeqZWirejOD9fwgE8JRQVSSCqIFGIBForUjfHxj82u3jYqy\/e4Y2t7gISwuLHFpcxqOys7PJyuKYP7\/ivHN6xLsbe7z53h6jHDQ65dP9WeTwiVujlkI\/nVK7fdL8GAmhTPfQ1AzloPZ4bgEGzw1oDRRB4oqHHry4RiBUTARXwQWUSjZDNej7DqGwNnaWWuPS7mBzG4d7jsO\/AOFtP6chpFTOAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-fs_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA filesystem management abstraction layer for JavaScript.\nManage files on local filesystem, on FTP server, on Amazon S3, etc. all through the same interface.\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWarning!\u003C\/strong\u003E It\u2019s a \u003Cem\u003Every\u003C\/em\u003E early version!\u003C\/p\u003E\n\u003Ch3\u003EExample\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Eimport\u003C\/span\u003E {AvrisFilesystem} \u003Cspan class=\u0022hljs-keyword\u0022\u003Efrom\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022avris-fs\u0022\u003C\/span\u003E;\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eimport\u003C\/span\u003E {LocalAdapter} \u003Cspan class=\u0022hljs-keyword\u0022\u003Efrom\u003C\/span\u003E \u003Cspan class=\u0022hljs-string\u0022\u003E\u0022avris-fs\/dist\/adapter\/LocalAdapter\u0022\u003C\/span\u003E;\n\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Econst\u003C\/span\u003E afs = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E AvrisFilesystem(\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E LocalAdapter(__dirname + \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027\/data\/\u0027\u003C\/span\u003E)\n);\n\nafs.put(                    \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ put = create or update\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dir\/subdir\/foo.txt\u0027\u003C\/span\u003E,\n     \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027OSIEM!\u0027\u003C\/span\u003E\n).then(\u003Cspan class=\u0022hljs-function\u0022\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Emeta\u003C\/span\u003E) =\u0026gt;\u003C\/span\u003E {\n    afs.read(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dir\/subdir\/foo.txt\u0027\u003C\/span\u003E).then(\u003Cspan class=\u0022hljs-function\u0022\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Econtent\u003C\/span\u003E) =\u0026gt;\u003C\/span\u003E {\n        \u003Cspan class=\u0022hljs-built_in\u0022\u003Econsole\u003C\/span\u003E.log(content);  \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ \u0027OSIEM!\u0027\u003C\/span\u003E\n    });\n})\n\nafs.create(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dir\/bar.txt\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027OK!\u0027\u003C\/span\u003E).then(\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-params\u0022\u003E()\u003C\/span\u003E =\u0026gt;\u003C\/span\u003E {\n    afs.list(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dir\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-literal\u0022\u003Etrue\u003C\/span\u003E).then(\u003Cspan class=\u0022hljs-function\u0022\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Eobjects\u003C\/span\u003E) =\u0026gt;\u003C\/span\u003E {\n        \u003Cspan class=\u0022hljs-built_in\u0022\u003Econsole\u003C\/span\u003E.log(objects);\n    });\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003EAvailable adapters\u003C\/h3\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003ELocalAdapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EMemoryAdapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003ENullAdapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003ES3Adapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003ESftpAdapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EBrowserStorageAdapter\u003C\/code\u003E (\u003Ccode\u003ElocalStorage\u003C\/code\u003E or \u003Ccode\u003EsessionStorage\u003C\/code\u003E)\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Ch3\u003EAPI\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003Elist(directory: string = \u0027\u0027, recursive: boolean = false): Promise\u0026lt;{ [path: string]: Metadata }\u0026gt;;\nhas(path: string): Promise\u0026lt;boolean\u0026gt;;\ngetMetadata(path: string): Promise\u0026lt;Metadata\u0026gt;;\nread(path: string): Promise\u0026lt;Buffer\u0026gt;;\ncreate(path: string, content: Buffer): Promise\u0026lt;Metadata\u0026gt;;\nupdate(path: string, content: Buffer): Promise\u0026lt;Metadata\u0026gt;;\nput(path: string, content: Buffer): Promise\u0026lt;Metadata\u0026gt;;\nmove(path: string, newPath: string): Promise\u0026lt;Metadata\u0026gt;;\ncopy(path: string, newPath: string): Promise\u0026lt;Metadata\u0026gt;;\nremove(path: string): Promise\u0026lt;void\u0026gt;;\npublish(path: string): Promise\u0026lt;Metadata\u0026gt;;\nunpublish(path: string): Promise\u0026lt;Metadata\u0026gt;;\ncreateDir(path: string): Promise\u0026lt;Metadata\u0026gt;;\nremoveDir(path: string): Promise\u0026lt;void\u0026gt;;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003ECredits\u003C\/h3\u003E\n\u003Cp\u003EGreatly inspired by \u003Ca href=\u0022https:\/\/flysystem.thephpleague.com\/docs\/\u0022\u003EFlysystem\u003C\/a\u003E, a similar project for PHP.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["filesystem","javascript","local","localstorage","npm","s3","sessionstorage","typescript"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avris-fs_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-fs_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-fs_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA filesystem management abstraction layer for JavaScript.\nManage files on local filesystem, on FTP server, on Amazon S3, etc. all through the same interface.\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWarning!\u003C\/strong\u003E It\u2019s a \u003Cem\u003Every\u003C\/em\u003E early version!\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-fs_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-fs_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA filesystem management abstraction layer for JavaScript.\nManage files on local filesystem, on FTP server, on Amazon S3, etc. all through the same interface.\u003C\/p\u003E\n\u003Cp\u003E\u003Cstrong\u003EWarning!\u003C\/strong\u003E It\u2019s a \u003Cem\u003Every\u003C\/em\u003E early version!\u003C\/p\u003E\n\u003Ch3\u003EExample\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Eimport {AvrisFilesystem} from \u0022avris-fs\u0022;\nimport {LocalAdapter} from \u0022avris-fs\/dist\/adapter\/LocalAdapter\u0022;\n\nconst afs = new AvrisFilesystem(\n    new LocalAdapter(__dirname + \u0027\/data\/\u0027)\n);\n\nafs.put(                    \/\/ put = create or update\n    \u0027dir\/subdir\/foo.txt\u0027,\n     \u0027OSIEM!\u0027\n).then((meta) =\u0026gt; {\n    afs.read(\u0027dir\/subdir\/foo.txt\u0027).then((content) =\u0026gt; {\n        console.log(content);  \/\/ \u0027OSIEM!\u0027\n    });\n})\n\nafs.create(\u0027dir\/bar.txt\u0027, \u0027OK!\u0027).then(() =\u0026gt; {\n    afs.list(\u0027dir\u0027, true).then((objects) =\u0026gt; {\n        console.log(objects);\n    });\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003EAvailable adapters\u003C\/h3\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003ELocalAdapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EMemoryAdapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003ENullAdapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003ES3Adapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003ESftpAdapter\u003C\/code\u003E\u003C\/li\u003E\n\u003Cli\u003E\u003Ccode\u003EBrowserStorageAdapter\u003C\/code\u003E (\u003Ccode\u003ElocalStorage\u003C\/code\u003E or \u003Ccode\u003EsessionStorage\u003C\/code\u003E)\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Ch3\u003EAPI\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003Elist(directory: string = \u0027\u0027, recursive: boolean = false): Promise\u0026lt;{ [path: string]: Metadata }\u0026gt;;\nhas(path: string): Promise\u0026lt;boolean\u0026gt;;\ngetMetadata(path: string): Promise\u0026lt;Metadata\u0026gt;;\nread(path: string): Promise\u0026lt;Buffer\u0026gt;;\ncreate(path: string, content: Buffer): Promise\u0026lt;Metadata\u0026gt;;\nupdate(path: string, content: Buffer): Promise\u0026lt;Metadata\u0026gt;;\nput(path: string, content: Buffer): Promise\u0026lt;Metadata\u0026gt;;\nmove(path: string, newPath: string): Promise\u0026lt;Metadata\u0026gt;;\ncopy(path: string, newPath: string): Promise\u0026lt;Metadata\u0026gt;;\nremove(path: string): Promise\u0026lt;void\u0026gt;;\npublish(path: string): Promise\u0026lt;Metadata\u0026gt;;\nunpublish(path: string): Promise\u0026lt;Metadata\u0026gt;;\ncreateDir(path: string): Promise\u0026lt;Metadata\u0026gt;;\nremoveDir(path: string): Promise\u0026lt;void\u0026gt;;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003ECredits\u003C\/h3\u003E\n\u003Cp\u003EGreatly inspired by \u003Ca href=\u0022https:\/\/flysystem.thephpleague.com\/docs\/\u0022\u003EFlysystem\u003C\/a\u003E, a similar project for PHP.\u003C\/p\u003E","words":238,"readTime":null,"lang":"en"}}},"projects\/daemonise":{"key":"projects\/daemonise","type":"article","published":true,"meta":{"createdAt":"2018-08-11T11:49:57+02:00","publishedAt":"2018-08-11T11:48:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/www.npmjs.com\/package\/avris-daemonise","displayUrl":"npm: avris-daemonise"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Daemonise","displayUrl":null}],"category":"projects","subcategory":null,"slug":"daemonise"},"content":{"en":{"slug":"daemonise","title":"Daemonise","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-daemonise_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022256\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAATCAYAAAD4f6+NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVUlEQVRIie2VS4\/TMBSFv2s7ryZNSzswIAYk2A\/\/\/1+wQfwAQIBmaOkrTeIkviw6rZgFQuIhuuBsrGvJ9vG5x8fyKnupnBGc6lnxwQnyrzncg1POTCHOTSE5Lz64Y8fGzxzx2CIO6IXmxmGzOWIdoWsJCtYYxEUM3oMRrLEkw55sXLBeLLEuotps8L4HBWOFEALGmNOoqqjqoRaDomgIaDgSulOoMJdE3jEpZjR1xXa0Y34xBuuo1gGMpSxz2qZht\/XU+z2Pn15SV1A+mJLEMdYZ1mmCixxplqFhIARFREAMeZGxuF3Q7Gvmj+b4tqecjnn7+g2+9QDIdXrIoYvLC6yziBhAcdHhtnE2wlmDbz1hGOj7gXI2pd3vcVGEquLbjihyuNihQem6jiiO2e8qjLV0bUvfD+Tj\/G7fLQpMHkwBZfN1zWa1PSgkcuhZCIEiL+i7QDpKWH1ZkpclWT7i87sP5JMSEWFUFvTes1quEOOYzUuaugZSFGXoe+IkYbX4Suc909mMwRosQpql3H66oW0aAHbrzck7Ry\/LdfpCAZ48v0JDT5yO8HXFerVFgBAUUJq6+RsePpE55rM7TlbckEwsbbRGE8G1DjeagY3QriUK4NydqduDqY0xxF1FPilZL5bEScKn9x9\/i9yJ0Cy5Yjqe4NuBwXrmV5ZquyMrEgwRdd3gnMMYQYqc5Zcljy8fsrz1VJsdwxBY3i5+iwyAXGeHlglgjEUBDQF+kOAiBj2+UQQR+a7+dRxPO+WQAsMw\/HzhvcMPmfIn4c7s5\/j\/2\/8UZ6fQN+aNGGDFN9nmAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-daemonise_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022256\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EUse this library to run any process in the background without blocking the console. It will start a child process, detach it, and save its PID to a file in order to be able to stop it later.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-daemonise_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022480\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAATCAYAAAD4f6+NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACVUlEQVRIie2VS4\/TMBSFv2s7ryZNSzswIAYk2A\/\/\/1+wQfwAQIBmaOkrTeIkviw6rZgFQuIhuuBsrGvJ9vG5x8fyKnupnBGc6lnxwQnyrzncg1POTCHOTSE5Lz64Y8fGzxzx2CIO6IXmxmGzOWIdoWsJCtYYxEUM3oMRrLEkw55sXLBeLLEuotps8L4HBWOFEALGmNOoqqjqoRaDomgIaDgSulOoMJdE3jEpZjR1xXa0Y34xBuuo1gGMpSxz2qZht\/XU+z2Pn15SV1A+mJLEMdYZ1mmCixxplqFhIARFREAMeZGxuF3Q7Gvmj+b4tqecjnn7+g2+9QDIdXrIoYvLC6yziBhAcdHhtnE2wlmDbz1hGOj7gXI2pd3vcVGEquLbjihyuNihQem6jiiO2e8qjLV0bUvfD+Tj\/G7fLQpMHkwBZfN1zWa1PSgkcuhZCIEiL+i7QDpKWH1ZkpclWT7i87sP5JMSEWFUFvTes1quEOOYzUuaugZSFGXoe+IkYbX4Suc909mMwRosQpql3H66oW0aAHbrzck7Ry\/LdfpCAZ48v0JDT5yO8HXFerVFgBAUUJq6+RsePpE55rM7TlbckEwsbbRGE8G1DjeagY3QriUK4NydqduDqY0xxF1FPilZL5bEScKn9x9\/i9yJ0Cy5Yjqe4NuBwXrmV5ZquyMrEgwRdd3gnMMYQYqc5Zcljy8fsrz1VJsdwxBY3i5+iwyAXGeHlglgjEUBDQF+kOAiBj2+UQQR+a7+dRxPO+WQAsMw\/HzhvcMPmfIn4c7s5\/j\/2\/8UZ6fQN+aNGGDFN9nmAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-daemonise_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022480\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EUse this library to run any process in the background without blocking the console. It will start a child process, detach it, and save its PID to a file in order to be able to stop it later.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["background","daemon","detach","javascript","js","nodejs","process","server"],"hasMore":false,"image":"https:\/\/avris.it\/image\/avris-daemonise_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-daemonise_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-daemonise_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022128\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EUse this library to run any process in the background without blocking the console. It will start a child process, detach it, and save its PID to a file in order to be able to stop it later.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-daemonise_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-daemonise_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022128\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EUse this library to run any process in the background without blocking the console. It will start a child process, detach it, and save its PID to a file in order to be able to stop it later.\u003C\/p\u003E","words":38,"readTime":null,"lang":"en"}}},"projects\/vanillin":{"key":"projects\/vanillin","type":"article","published":true,"meta":{"createdAt":"2018-02-10T22:05:06+01:00","publishedAt":"2018-02-10T22:03:00+01:00","group":"vanillin","links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/www.npmjs.com\/package\/avris-vanillin","displayUrl":"npm: avris-vanillin"},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Vanillin","displayUrl":null}],"category":"projects","subcategory":null,"slug":"vanillin"},"content":{"en":{"slug":"vanillin","title":"Vanillin \u2013 Almost like vanilla JavaScript","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/vanillin_small.png\u0022 alt=\u0022Vanillin.js\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022269.94727592267\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADvElEQVRIie2VXUxbZRjHf+05W6nAYGXyjXQQBwlpJpQLGwxZIioGF73QeGMiMSaGRA3BmV15YbhYxAuucLvQxCySJYZENgwKk5oomYUOSIflK5J+WAqF5qwttKctpz1eWBAZSxZDvdo\/eXPe\/J8n7\/N7P877wmP9B83Pzz8zPT39bnt7+4vOmpp+f23t+qzRaL9WVtac7driYWN2dva5qqqqn3t7e0WDwUCiuJhSQaBQkkpXUqnvns\/NPTsRjSrZAtIeNhRFeXloaEjc3t6mtbWVqYYG0GpJqioyVAqiaMgWzJFANpvt5vj4eDKVSiHLMo4TJ\/g+HOY3Wcaxu3tXCoc3\/xeg1dXVdo\/HY19cXPw8Ho\/vCILAxsYGoVCIr8vKKLp6lS6rNe\/D69efzSaQCNDd3S0WFBTcGBgYKEylUpSXl1NcXExlZSWRSARtURHeWIzXzp2rX1he\/gpoeISxtUCaf85pOtOOyvk3UCwWY2JiQlxYWKClpYWcnBwmJydxu900NTWRm5vL6OgoJpMJt9t9cLBPgSvA+8A3wCaQl4m3AaeACPACsAhcAwqBDaAUuACMA3EgBiAAzMzMpGVZTgiC8FIymWR9fZ1AIICiKMiyjN\/vJxAI8NPt27GNQOBNp9PpBVTgdeAs4AI+AFqBtzP+\/cyEt4Fa4EnAnImFgJ1M\/hXADqztA42MjDyh0+k+iUQiNRaLhWQySTQaRa\/X09jYiCiKvOJw0Ol2a8rcbvG0VvuDPR5PAT6gDxgA3gCimUL3MyASYATqM34UuMvfW14C5APhTP+X\/S2rrq5+p7m5ua2np4elpSUkScJiseDz+YhEItT6fHSk01BUJMrBYGeJXm8nFPoCuAeYgCTwauZ7UGke\/JP3vE7ABsxmVox9IJfLRUVFBWazGavVisFgYHd3F0VRsNvt5IfDfHvmDClVJZFIIMXjTx8osAcR42gdPsh73pdHJQsAer3+XiAQMMZisbzTd+7IHwWD+TUuF6LXy1MdHbzV10eivh5rMMif5eVcvHw52WQ2\/zg2NrbzEIjj04zR+Gvq\/Hk13damBk0mVdraUtPptCrLstrf369OTU2p8XhcHRwcvJGN+g\/c1CuKsuLZ2WHL62UhGuX3uTlCoRDLy8s4HA7q6uqQJAm\/35+VJ0Q4bJScPGnzqGqjQ1GM2y0tGoxGbt66xfDwMC6XC41Gg81m887NzXU5nc614wbSPCzw8aVLF04VFHT5fD6nTqebXFtbe8\/j8fzh9Xo\/29zcjBw3yGM9qv4CsPqrHrao4OAAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/vanillin_small.png\u0022 alt=\u0022Vanillin.js\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022269.94727592267\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EjQuery used to be virtually indispensable,\nif you wanted to develop a cross-browser website without getting a headache.\u003C\/p\u003E\n\u003Cp\u003EToday, however, you might not need jQuery,\nespecially, if you\u2019re developing a library and want to avoid unnecessary dependencies.\u003C\/p\u003E\n\u003Cp\u003EStill, some helpers could be useful...\nVanillin is an opinionated set of helpers\nthat I find most useful, a bare minimum to make life easier.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/vanillin_big.png\u0022 alt=\u0022Vanillin.js\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022539.89455184534\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADvElEQVRIie2VXUxbZRjHf+05W6nAYGXyjXQQBwlpJpQLGwxZIioGF73QeGMiMSaGRA3BmV15YbhYxAuucLvQxCySJYZENgwKk5oomYUOSIflK5J+WAqF5qwttKctpz1eWBAZSxZDvdo\/eXPe\/J8n7\/N7P877wmP9B83Pzz8zPT39bnt7+4vOmpp+f23t+qzRaL9WVtac7driYWN2dva5qqqqn3t7e0WDwUCiuJhSQaBQkkpXUqnvns\/NPTsRjSrZAtIeNhRFeXloaEjc3t6mtbWVqYYG0GpJqioyVAqiaMgWzJFANpvt5vj4eDKVSiHLMo4TJ\/g+HOY3Wcaxu3tXCoc3\/xeg1dXVdo\/HY19cXPw8Ho\/vCILAxsYGoVCIr8vKKLp6lS6rNe\/D69efzSaQCNDd3S0WFBTcGBgYKEylUpSXl1NcXExlZSWRSARtURHeWIzXzp2rX1he\/gpoeISxtUCaf85pOtOOyvk3UCwWY2JiQlxYWKClpYWcnBwmJydxu900NTWRm5vL6OgoJpMJt9t9cLBPgSvA+8A3wCaQl4m3AaeACPACsAhcAwqBDaAUuACMA3EgBiAAzMzMpGVZTgiC8FIymWR9fZ1AIICiKMiyjN\/vJxAI8NPt27GNQOBNp9PpBVTgdeAs4AI+AFqBtzP+\/cyEt4Fa4EnAnImFgJ1M\/hXADqztA42MjDyh0+k+iUQiNRaLhWQySTQaRa\/X09jYiCiKvOJw0Ol2a8rcbvG0VvuDPR5PAT6gDxgA3gCimUL3MyASYATqM34UuMvfW14C5APhTP+X\/S2rrq5+p7m5ua2np4elpSUkScJiseDz+YhEItT6fHSk01BUJMrBYGeJXm8nFPoCuAeYgCTwauZ7UGke\/JP3vE7ABsxmVox9IJfLRUVFBWazGavVisFgYHd3F0VRsNvt5IfDfHvmDClVJZFIIMXjTx8osAcR42gdPsh73pdHJQsAer3+XiAQMMZisbzTd+7IHwWD+TUuF6LXy1MdHbzV10eivh5rMMif5eVcvHw52WQ2\/zg2NrbzEIjj04zR+Gvq\/Hk13damBk0mVdraUtPptCrLstrf369OTU2p8XhcHRwcvJGN+g\/c1CuKsuLZ2WHL62UhGuX3uTlCoRDLy8s4HA7q6uqQJAm\/35+VJ0Q4bJScPGnzqGqjQ1GM2y0tGoxGbt66xfDwMC6XC41Gg81m887NzXU5nc614wbSPCzw8aVLF04VFHT5fD6nTqebXFtbe8\/j8fzh9Xo\/29zcjBw3yGM9qv4CsPqrHrao4OAAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/vanillin_big.png\u0022 alt=\u0022Vanillin.js\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022539.89455184534\u0022\u003E\u003C\/span\u003E\n                \u003Cfigcaption\u003E\n                    \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Vanillin#\/media\/File:Vanillin-3d.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\n                        \u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E\n                        en.wikipedia.org\/wiki\/Vanillin#\/media\/File:Vanillin-3d.png\n                    \u003C\/a\u003E\n                \u003C\/figcaption\u003E\n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EjQuery used to be virtually indispensable,\nif you wanted to develop a cross-browser website without getting a headache.\u003C\/p\u003E\n\u003Cp\u003EToday, however, you might not need jQuery,\nespecially, if you\u2019re developing a library and want to avoid unnecessary dependencies.\u003C\/p\u003E\n\u003Cp\u003EStill, some helpers could be useful...\nVanillin is an opinionated set of helpers\nthat I find most useful, a bare minimum to make life easier.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["helper","javascript","js","library","programming","vanilla"],"hasMore":false,"image":"https:\/\/avris.it\/image\/vanillin_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/vanillin_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/vanillin_mini.png\u0022 alt=\u0022Vanillin.js\u0022 width=\u0022240\u0022 height=\u0022134.97363796134\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EjQuery used to be virtually indispensable,\nif you wanted to develop a cross-browser website without getting a headache.\u003C\/p\u003E\n\u003Cp\u003EToday, however, you might not need jQuery,\nespecially, if you\u2019re developing a library and want to avoid unnecessary dependencies.\u003C\/p\u003E\n\u003Cp\u003EStill, some helpers could be useful...\nVanillin is an opinionated set of helpers\nthat I find most useful, a bare minimum to make life easier.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/vanillin_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/vanillin_mini.png\u0022 alt=\u0022Vanillin.js\u0022 width=\u0022240\u0022 height=\u0022134.97363796134\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003Cfigcaption\u003E\n                    \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Vanillin#\/media\/File:Vanillin-3d.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csmall\u003Een.wikipedia.org\/wiki\/Vanillin#\/media\/File:Vanillin-3d.png\u003C\/small\u003E\u003C\/a\u003E\n                \u003C\/figcaption\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EjQuery used to be virtually indispensable,\nif you wanted to develop a cross-browser website without getting a headache.\u003C\/p\u003E\n\u003Cp\u003EToday, however, you might not need jQuery,\nespecially, if you\u2019re developing a library and want to avoid unnecessary dependencies.\u003C\/p\u003E\n\u003Cp\u003EStill, some helpers could be useful...\nVanillin is an opinionated set of helpers\nthat I find most useful, a bare minimum to make life easier.\u003C\/p\u003E","words":73,"readTime":null,"lang":"en"}}},"blog\/technology\/moving-to-vanilla-js":{"key":"blog\/technology\/moving-to-vanilla-js","type":"article","published":true,"meta":{"createdAt":"2018-01-19T19:02:20+01:00","publishedAt":"2018-01-31T19:01:00+01:00","group":"vanillin","category":"blog","subcategory":"technology","slug":"moving-to-vanilla-js"},"content":{"en":{"slug":"moving-to-vanilla-js","title":"Moving to vanilla JS","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022201.10091743119\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAPCAYAAACMa21tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB5klEQVRIib2VTW4TQRCFv+rpiRMyDnISLyEcACkhXAEuAVsuxQk4AogFSNkgWLIFkVVAiW1kouD58XQXi\/H4D409YxHeZko93VWvq15VS5ymygrI5KsKIov2yoMbwgrCoD8gsIY8dwTWgiqdTmcSXFHVKZESegtsjDFYADFCnueIGARwqihFdkSEb1+\/cH1zw\/5Bl6P799Y67l1d8uPyijwbc\/r4tBEpiZPVJQOmGWqK8lK1yYhgq4\/M3JXaMcasdeq9R4Gg5l738RPu7Axz8gj79AlWKq8w+2HE0B\/0iKI92tFuZYDcOdJ0TBiGDIdDRAzdw\/3K\/Wk2Ri++Q6+PPz9HBCQpu6xMSFkdma1536RkUnRgnTKLIKMROvyFtCOk3UbiNFs4KUw6aEpON9ZQU4gY7HL\/6l8GGCMkSUJrq4W1ttKh844sG2PDkDRJCIKAne3tyv25c+Sv3+DevcecHBM+f7asobk6LVGM4wRrLVaqCQUmILCTm6jHe1nfZqrgHKiWGsr+Tz1qwtbRh\/P+1giMfMrP8W92gxaHW22q8z+HOjNlU7y6+MDbwWcObMTLhy+wayfp0oO6YP+DYj\/Y6XLX3uF476h4quKk0NAsmCIUYtSJ0Ip1QUQX7IKYTMdCM3t+Xs3sP+dY5dEk0L+pAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022201.10091743119\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhile working on \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Forms\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avris Forms v4.0\u003C\/a\u003E, I\u2019ve decided to migrate some code from \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E CoffeScript\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E to \u003Ca href=\u0022http:\/\/vanilla-js.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Vanilla JS\u003C\/a\u003E. And I guess it might be a good idea to share this transition \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022654\u0022 height=\u0022274\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAPCAYAAACMa21tAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB5klEQVRIib2VTW4TQRCFv+rpiRMyDnISLyEcACkhXAEuAVsuxQk4AogFSNkgWLIFkVVAiW1kouD58XQXi\/H4D409YxHeZko93VWvq15VS5ymygrI5KsKIov2yoMbwgrCoD8gsIY8dwTWgiqdTmcSXFHVKZESegtsjDFYADFCnueIGARwqihFdkSEb1+\/cH1zw\/5Bl6P799Y67l1d8uPyijwbc\/r4tBEpiZPVJQOmGWqK8lK1yYhgq4\/M3JXaMcasdeq9R4Gg5l738RPu7Axz8gj79AlWKq8w+2HE0B\/0iKI92tFuZYDcOdJ0TBiGDIdDRAzdw\/3K\/Wk2Ri++Q6+PPz9HBCQpu6xMSFkdma1536RkUnRgnTKLIKMROvyFtCOk3UbiNFs4KUw6aEpON9ZQU4gY7HL\/6l8GGCMkSUJrq4W1ttKh844sG2PDkDRJCIKAne3tyv25c+Sv3+DevcecHBM+f7asobk6LVGM4wRrLVaqCQUmILCTm6jHe1nfZqrgHKiWGsr+Tz1qwtbRh\/P+1giMfMrP8W92gxaHW22q8z+HOjNlU7y6+MDbwWcObMTLhy+wayfp0oO6YP+DYj\/Y6XLX3uF476h4quKk0NAsmCIUYtSJ0Ip1QUQX7IKYTMdCM3t+Xs3sP+dY5dEk0L+pAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022654\u0022 height=\u0022274\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhile working on \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Forms\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Avris Forms v4.0\u003C\/a\u003E, I\u2019ve decided to migrate some code from \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E CoffeScript\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E to \u003Ca href=\u0022http:\/\/vanilla-js.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Vanilla JS\u003C\/a\u003E. And I guess it might be a good idea to share this transition \ud83d\ude09\u003C\/p\u003E\n\u003Cp\u003EThe code handles the form widget visible in the screenshot above. More specifically: those buttons in the right column. Clicking on the green one adds a new element\/row based on a template hidden inside a \u003Ccode\u003E\u0026lt;script\u0026gt;\u003C\/code\u003E tag. Clicking on a red button results in removal of the current row (after asking for a confirmation).\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027body\u0027\u003C\/span\u003E).on \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add\u0027\u003C\/span\u003E, -\u0026gt;\n  $form = $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple\u0027\u003C\/span\u003E)\n  newIndices = $form.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027[data-index^=new]\u0027\u003C\/span\u003E).map((i, el) -\u0026gt; el.dataset[\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027index\u0027\u003C\/span\u003E].substr(\u003Cspan class=\u0022hljs-number\u0022\u003E3\u003C\/span\u003E)).get()\n  newIndex = \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E newIndices.length then \u003Cspan class=\u0022hljs-built_in\u0022\u003EMath\u003C\/span\u003E.max.apply(\u003Cspan class=\u0022hljs-literal\u0022\u003Enull\u003C\/span\u003E, newIndices) + \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eelse\u003C\/span\u003E \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E\n  $template = $($form.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add-template\u0027\u003C\/span\u003E).html().replace(\u003Cspan class=\u0022hljs-regexp\u0022\u003E\/%i%\/g\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027new\u0027\u003C\/span\u003E + newIndex))\n  $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).before $template\n  $template.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027:input:enabled:visible:first\u0027\u003C\/span\u003E).focus()\n\n$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027body\u0027\u003C\/span\u003E).on \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-remove\u0027\u003C\/span\u003E, -\u0026gt;\n  \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E !confirm(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Are you sure?\u0027\u003C\/span\u003E))\n  $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).remove()\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIt was not a part of the library (as the library was supposed to only provide PHP), instead each project included this part on its own. Which led to code duplication (and the worst kind: between projects) and also kinda prevented me from abandoning CoffeeScript in newer projects, even if I wanted to. \u003C\/p\u003E\n\u003Cp\u003EAnd I did want to, because JavaScript has matured as a language over the last years. An additional level of complexity in my projects simply wasn\u2019t necessary anymore. CoffeeScript did a great job of making fontend scripting bearable, but now it\u2019s slowly time for it to get a deserved retirement.\u003C\/p\u003E\n\u003Cp\u003ESo I\u2019ve decided to integrate the frontend part into the library. Except I shouldn\u2019t be forcing users to use CoffeeScript or jQuery, it should just work out of the box in any project.\u003C\/p\u003E\n\u003Cp\u003ESince CoffeeScript compiles into JS (although usually with from some unnecessary returns and similar features), getting rid of it is really simple. After using \u003Ca href=\u0022http:\/\/js2.coffee\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E js2coffee\u003C\/a\u003E or \u003Ca href=\u0022http:\/\/decaffeinate-project.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E decaffeinate\u003C\/a\u003E we would end up with something like this:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027body\u0027\u003C\/span\u003E).on(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E $form, $template, newIndex, newIndices;\n    $form = $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple\u0027\u003C\/span\u003E);\n    newIndices = $form.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027[data-index^=new]\u0027\u003C\/span\u003E).map(\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Ei, el\u003C\/span\u003E) \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E el.dataset[\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027index\u0027\u003C\/span\u003E].substr(\u003Cspan class=\u0022hljs-number\u0022\u003E3\u003C\/span\u003E);\n    }).get();\n    newIndex = newIndices.length ? \u003Cspan class=\u0022hljs-built_in\u0022\u003EMath\u003C\/span\u003E.max.apply(\u003Cspan class=\u0022hljs-literal\u0022\u003Enull\u003C\/span\u003E, newIndices) + \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E : \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E;\n    $template = $($form.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add-template\u0027\u003C\/span\u003E).html().replace(\u003Cspan class=\u0022hljs-regexp\u0022\u003E\/%i%\/g\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027new\u0027\u003C\/span\u003E + newIndex));\n    $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).before($template);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $template.find(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027:input:enabled:visible:first\u0027\u003C\/span\u003E).focus();\n});\n\n$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027body\u0027\u003C\/span\u003E).on(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-remove\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!confirm(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Are you sure?\u0027\u003C\/span\u003E)) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E;\n    }\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).parents(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).remove();\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ERemoving the dependency on jQuery is more tricky.\u003C\/p\u003E\n\u003Cp\u003EThere are some \u003Ca href=\u0022http:\/\/youmightnotneedjquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E nice lists\u003C\/a\u003E that show you how to replace some jQuery usage with plain JS. Those Javascript versions used to be longer, more complicated and require some browser-specific checks and adjustments. Those times are almost over though (as you can see from the list), so the need for jQuery gets smaller and smaller.\u003C\/p\u003E\n\u003Cp\u003EReplacing those calls from the list with Vanilla JS\u2019s counterparts was not enough in my case. I needed two functionalities more: finding an element\u2019s parent by a selector (\u003Ccode\u003E$el.parents(\u0027.foo\u0027)\u003C\/code\u003E) and binding an event listener to elements matching a selector, even if those elements don\u2019t exist yet at the moment of binding (\u003Ccode\u003E$(\u0027body\u0027).on(\u0027click\u0027, \u0027.foo\u0027, =\u0026gt; ... )\u003C\/code\u003E).\u003C\/p\u003E\n\u003Cp\u003EThey were surprisingly easy to implement:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E findParent = \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Eel, selector\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Edo\u003C\/span\u003E {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (el.matches(selector)) {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E el;\n        }\n        el = el.parentNode;\n    } \u003Cspan class=\u0022hljs-keyword\u0022\u003Ewhile\u003C\/span\u003E (el \u0026amp;\u0026amp; el.matches);\n};\n\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E on = \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003Eselector, event, handler\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-built_in\u0022\u003Edocument\u003C\/span\u003E.addEventListener(event, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003Ee\u003C\/span\u003E) \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E match = findParent(e.target, selector);\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (match) {\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E result = handler.apply(match, [e]);\n            \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (result === \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E) {\n                e.preventDefault();\n                e.stopPropagation();\n            }\n        }\n    });\n};\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWith those two helpers I could transform my code to this vanilla JavaScript:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Eon(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E form = findParent(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple\u0027\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!form) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E;\n    }\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E newIndices = \u003Cspan class=\u0022hljs-built_in\u0022\u003EArray\u003C\/span\u003E.from(form.querySelectorAll(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027[data-index^=new]\u0027\u003C\/span\u003E)).map(\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003Eel\u003C\/span\u003E) \u003C\/span\u003E{\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E el.dataset[\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027index\u0027\u003C\/span\u003E].substr(\u003Cspan class=\u0022hljs-number\u0022\u003E3\u003C\/span\u003E);\n    });\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E newIndex = newIndices.length ? \u003Cspan class=\u0022hljs-built_in\u0022\u003EMath\u003C\/span\u003E.max.apply(\u003Cspan class=\u0022hljs-literal\u0022\u003Enull\u003C\/span\u003E, newIndices) + \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E : \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E;\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E template = form.querySelector(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-add-template\u0027\u003C\/span\u003E).innerHTML.replace(\u003Cspan class=\u0022hljs-regexp\u0022\u003E\/%i%\/g\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027new\u0027\u003C\/span\u003E + newIndex);\n\n    findParent(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E).insertAdjacentHTML(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027beforebegin\u0027\u003C\/span\u003E, template);\n\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E firstInput = form.querySelector(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027[data-index=new\u0027\u003C\/span\u003E+newIndex+\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027] :enabled\u0027\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (firstInput) {\n        firstInput.focus();\n    }\n});\n\non(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.form-multiple-remove\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E (\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!confirm(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Are you sure?\u0027\u003C\/span\u003E)) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E;\n    }\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E row = findParent(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tr\u0027\u003C\/span\u003E);\n    row.parentNode.removeChild(row);\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENot bad, is it? \ud83d\ude09\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["coffeescript","javascript","jquery","js","programming","vanilla"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avris-forms-multiple_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022100.5504587156\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhile working on \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Forms\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Avris Forms v4.0\u003C\/a\u003E, I\u2019ve decided to migrate some code from \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E CoffeScript\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E to \u003Ca href=\u0022http:\/\/vanilla-js.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Vanilla JS\u003C\/a\u003E. And I guess it might be a good idea to share this transition \ud83d\ude09\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-forms-multiple_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022100.5504587156\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhile working on \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Forms\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Avris Forms v4.0\u003C\/a\u003E, I\u2019ve decided to migrate some code from \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E CoffeScript\u003C\/a\u003E with \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E to \u003Ca href=\u0022http:\/\/vanilla-js.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Vanilla JS\u003C\/a\u003E. And I guess it might be a good idea to share this transition \ud83d\ude09\u003C\/p\u003E\n\u003Cp\u003EThe code handles the form widget visible in the screenshot above. More specifically: those buttons in the right column. Clicking on the green one adds a new element\/row based on a template hidden inside a \u003Ccode\u003E\u0026lt;script\u0026gt;\u003C\/code\u003E tag. Clicking on a red button results in removal of the current row (after asking for a confirmation).\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003E$(\u0027body\u0027).on \u0027click\u0027, \u0027.form-multiple-add\u0027, -\u0026gt;\n  $form = $(this).parents(\u0027.form-multiple\u0027)\n  newIndices = $form.find(\u0027[data-index^=new]\u0027).map((i, el) -\u0026gt; el.dataset[\u0027index\u0027].substr(3)).get()\n  newIndex = if newIndices.length then Math.max.apply(null, newIndices) + 1 else 0\n  $template = $($form.find(\u0027.form-multiple-add-template\u0027).html().replace(\/%i%\/g, \u0027new\u0027 + newIndex))\n  $(this).parents(\u0027tr\u0027).before $template\n  $template.find(\u0027:input:enabled:visible:first\u0027).focus()\n\n$(\u0027body\u0027).on \u0027click\u0027, \u0027.form-multiple-remove\u0027, -\u0026gt;\n  return false if !confirm(\u0027Are you sure?\u0027))\n  $(this).parents(\u0027tr\u0027).remove()\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIt was not a part of the library (as the library was supposed to only provide PHP), instead each project included this part on its own. Which led to code duplication (and the worst kind: between projects) and also kinda prevented me from abandoning CoffeeScript in newer projects, even if I wanted to. \u003C\/p\u003E\n\u003Cp\u003EAnd I did want to, because JavaScript has matured as a language over the last years. An additional level of complexity in my projects simply wasn\u2019t necessary anymore. CoffeeScript did a great job of making fontend scripting bearable, but now it\u2019s slowly time for it to get a deserved retirement.\u003C\/p\u003E\n\u003Cp\u003ESo I\u2019ve decided to integrate the frontend part into the library. Except I shouldn\u2019t be forcing users to use CoffeeScript or jQuery, it should just work out of the box in any project.\u003C\/p\u003E\n\u003Cp\u003ESince CoffeeScript compiles into JS (although usually with from some unnecessary returns and similar features), getting rid of it is really simple. After using \u003Ca href=\u0022http:\/\/js2.coffee\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E js2coffee\u003C\/a\u003E or \u003Ca href=\u0022http:\/\/decaffeinate-project.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E decaffeinate\u003C\/a\u003E we would end up with something like this:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003E$(\u0027body\u0027).on(\u0027click\u0027, \u0027.form-multiple-add\u0027, function() {\n    var $form, $template, newIndex, newIndices;\n    $form = $(this).parents(\u0027.form-multiple\u0027);\n    newIndices = $form.find(\u0027[data-index^=new]\u0027).map(function(i, el) {\n        return el.dataset[\u0027index\u0027].substr(3);\n    }).get();\n    newIndex = newIndices.length ? Math.max.apply(null, newIndices) + 1 : 0;\n    $template = $($form.find(\u0027.form-multiple-add-template\u0027).html().replace(\/%i%\/g, \u0027new\u0027 + newIndex));\n    $(this).parents(\u0027tr\u0027).before($template);\n    return $template.find(\u0027:input:enabled:visible:first\u0027).focus();\n});\n\n$(\u0027body\u0027).on(\u0027click\u0027, \u0027.form-multiple-remove\u0027, function() {\n    if (!confirm(\u0027Are you sure?\u0027)) {\n        return false;\n    }\n    return $(this).parents(\u0027tr\u0027).remove();\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ERemoving the dependency on jQuery is more tricky.\u003C\/p\u003E\n\u003Cp\u003EThere are some \u003Ca href=\u0022http:\/\/youmightnotneedjquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E nice lists\u003C\/a\u003E that show you how to replace some jQuery usage with plain JS. Those Javascript versions used to be longer, more complicated and require some browser-specific checks and adjustments. Those times are almost over though (as you can see from the list), so the need for jQuery gets smaller and smaller.\u003C\/p\u003E\n\u003Cp\u003EReplacing those calls from the list with Vanilla JS\u2019s counterparts was not enough in my case. I needed two functionalities more: finding an element\u2019s parent by a selector (\u003Ccode\u003E$el.parents(\u0027.foo\u0027)\u003C\/code\u003E) and binding an event listener to elements matching a selector, even if those elements don\u2019t exist yet at the moment of binding (\u003Ccode\u003E$(\u0027body\u0027).on(\u0027click\u0027, \u0027.foo\u0027, =\u0026gt; ... )\u003C\/code\u003E).\u003C\/p\u003E\n\u003Cp\u003EThey were surprisingly easy to implement:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Evar findParent = function(el, selector) {\n    do {\n        if (el.matches(selector)) {\n            return el;\n        }\n        el = el.parentNode;\n    } while (el \u0026amp;\u0026amp; el.matches);\n};\n\nvar on = function (selector, event, handler) {\n    document.addEventListener(event, function (e) {\n        var match = findParent(e.target, selector);\n        if (match) {\n            var result = handler.apply(match, [e]);\n            if (result === false) {\n                e.preventDefault();\n                e.stopPropagation();\n            }\n        }\n    });\n};\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWith those two helpers I could transform my code to this vanilla JavaScript:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Eon(\u0027.form-multiple-add\u0027, \u0027click\u0027, function () {\n    var form = findParent(this, \u0027.form-multiple\u0027);\n    if (!form) {\n        return;\n    }\n\n    var newIndices = Array.from(form.querySelectorAll(\u0027[data-index^=new]\u0027)).map(function (el) {\n        return el.dataset[\u0027index\u0027].substr(3);\n    });\n    var newIndex = newIndices.length ? Math.max.apply(null, newIndices) + 1 : 0;\n\n    var template = form.querySelector(\u0027.form-multiple-add-template\u0027).innerHTML.replace(\/%i%\/g, \u0027new\u0027 + newIndex);\n\n    findParent(this, \u0027tr\u0027).insertAdjacentHTML(\u0027beforebegin\u0027, template);\n\n    var firstInput = form.querySelector(\u0027[data-index=new\u0027+newIndex+\u0027] :enabled\u0027);\n    if (firstInput) {\n        firstInput.focus();\n    }\n});\n\non(\u0027.form-multiple-remove\u0027, \u0027click\u0027, function () {\n    if (!confirm(\u0027Are you sure?\u0027)) {\n        return false;\n    }\n    var row = findParent(this, \u0027tr\u0027);\n    row.parentNode.removeChild(row);\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENot bad, is it? \ud83d\ude09\u003C\/p\u003E","words":731,"readTime":3,"lang":"en"}}},"projects\/oursong-let-s-choose-our-song":{"key":"projects\/oursong-let-s-choose-our-song","type":"article","published":true,"meta":{"createdAt":"2017-12-25T00:38:58+01:00","publishedAt":"2017-12-25T00:33:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/oursong.eurovote.eu\/","displayUrl":null}],"category":"projects","subcategory":null,"slug":"oursong-let-s-choose-our-song"},"content":{"en":{"slug":"oursong-let-s-choose-our-song","title":"OurSong \u2022 Let\u0027s choose our song!","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022603\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAkCAYAAACaJFpUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhElEQVRIiZWXW48cRxmGn6rq0\/ScdmfP6+Pasr2RA0bYkIOQIoyAIIE4SMAlEvwJFEWIn8AlcBP+ATdcAOIiikSEsAgRgQSvYsfr9SHrncPOoXu6u7qquBjvsOudxM4ntdSaqvre+qrrfd9vhLXWCSFwziGEIMsyOp0O9XodACHE9InjmE+LdncAJiGqTNZWq1WEEEfmiM+9\/Ir72qLkvlbc1j5KwNW6pVaJkM0ldjsd5poNiixle28fs3yWhw8eIpxFOAcLKzR\/8FPS0hBIyUoccHm+ylolYCnyyYzlUabZywo+Hmu8cT7GaY+2baDCmKzfZt8VMB7iD7psrKxSrYd4YcblhWVu3NlmN8vQKqLIxlSDACUgNxYLxJ7kYr3CfOgRSck+JQ3fQwlBw\/fwAAJPMiwjwjBkZOFG13BqcZ6fvfpV3vnnP3jxi1dZHN+l12mj4gYnHnV4e7tH2wZsNGM25JjyxDIAX2jV2JyLcc4hBcyFinXr2C9KxqXFE0BHS6wz5FoTBxJdgAsjtgcZr37nu\/h5nyRNOHt6nbgIqEtNpARv3R1wai4ifPAR15\/fRAqQwF6mETjW4oCqJ3HAYuiRGYtav\/jcL3vOo7AOz\/MYpynGlKz6OcnuXXof32e9EfKrP73DOdcBAautCmm\/w72B5e6jLiUeV659mZE27I4LPClo+IpQCZQU5MaRWwcCJEIx0gYRVvCaC8zNt1hZWmatEbE7KhHKY5wXbMxXuLk7oH1\/B18ZXl7L8VzJUj2mnyRsJwWPck2oJANt6BeGkbZ0spKxsYyNmeD89W9\/dwhASLyognKWMPApxinOWRpxRDX0ocyh1KA8wihA6JTeWFA6x0ALls5sIIUEIFKCQE6OsnQO6xzGgScEIs\/zIzwE8DzvCHecc9x4+03iWp3nr1w7NjYYDHDOoZQiCAIAtNaEYTjl8kH+Y4DOOdrtNk\/+ppSi0WgwHA5QykMpD3AIKREqxDqBA9p5lw\/2t1iK57i2+NyRHEIIjpbyODzPwxhDGIbUarUjY\/VaHanUkQqzEtLCkI\/2GfU6nCznqO8JWDyee+aR+r5Pt9vlozs7\/OXNt\/jjH37PzZs3wTmstdPFy8vLvPvuu+R5Pl0vpeTJfE+t0DnH3t4ev\/ntr\/ndG29QiWNKXbB26gybV77E1nvvcPvm+9OEWVGSFQYQBIEPCASWWsU\/fnqzALXWpFmGtpafv\/46J09vsPNwl\/fe3+KlF1\/g69\/6NvvdNjsfvg9AFEVYaemUu9xLdpC6hhuu85VLczjnng4ohCDPM775jev0en1Ori0RRiHddgcpBQuxYqV5mgtnTgJQlJZBotk3Bf2xRuoCvzCzUs8GlFLSnF\/Cbt\/hwYNH\/Ptf7yGkIpCOpHOfhXPrZIUhCv9vV2M3IvQU5+ILMK6wWCmeHRCgGtdIx5p00OHezn2KPOP8xec4sbJMFHiEvk8YTjgXedCqSQba4oQFz6JKfew4YaK1MyOOQj5\/5SqdTocz6y1CkTPq7XL54nnmalUkhnocAZAkCSoTrHpLnKotcGopJlqof5YKBYEvObu+yvd\/\/BO2b33A6XOXWGjNc2HjLGElRuuS\/nAITGgkpURKibEGgZidFhBFUTjgCG+sMZRm8tH3e11Gw8GUS845FpdXqVQqU7A0SUjHY6SUlGWJlBKlPFqt+eNKcxjoANgPAg4YVOoq6bCPcxYlJc5BvV7D94Pp\/H7m+O\/OCCEEgR+gPEEUOFqtZzzShw8fIqUEHM5Btdmi0WggpSRJEgaDIb7vT3edaslu6hN4Er+UJHlBHFqubBy\/NDPF+0m3yLIMYyxCTHT2wBEOKsyyDF2WRI\/dAT7ZLY5VKITgez\/8EeMiZzQa4QUBUgjATUABISWlLqlEIS+\/8AK\/eO01wiCAyTQ83ycMQ8qyfDalUdUYYw1xax4hPeYadcZZhrOTy5SmKVJ6yEqEEZK836YQAVGlMrlEaYq1dlrh4ZjJQ2MMxjr8IGSh2cCOUurCY96PcElOs9HECxTD0QgpBYVXJUkHaK2x1iKEQGs9K\/VsQKdLsAadZ4TOsra2zK0Pt7h1+yMCqVDGYq3FliXOWCQOKXw8pTDGYK09dg8+FXDU79PfazPs9tBIbm9tMRgM2dy8RFCrIQWMOl3S\/pBxmuKUoTQlWV5gjCHP8plg8Anf8PK1E7QurfKfP4\/xy5R6o05Z5OztPiAZpYTVECUdnrRIQIwSlFTAxKAd7jGtnhFwtXmJUIdsbvYQOmM4GHH9+ivUmzWMLpFKUVoo8oILF86jqnOYXveIwx9+PxwzWwxrLWVZPvbFnCRJprIWRRFxHE\/nBkFAng4YJjlBGBJFEVLKiWIdEocpD5\/cwUGSA3InowH37mxN+ees5cq1lwjDiVM453BSojyF7wcT9zcGO8OaZlb4pLYexM72LaKowtLK+rGxYbJPr9MnDCPmmk2MdVQq0bFW81ObqCcFfWl5DSnVkbEDFREiphpn1BvzKKVQj7s7daid\/EwVHh6bABzdzNPiSOdtjHnqilxbjJ3833OAc+B7EmsdQkyaqEqgUPKTjfcg\/geiigyZapzK0gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/oursong_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022603\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA musical competition, in which the managers lead their countries every week to a fight for a title of the best song.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u00221005\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAkCAYAAACaJFpUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhElEQVRIiZWXW48cRxmGn6rq0\/ScdmfP6+Pasr2RA0bYkIOQIoyAIIE4SMAlEvwJFEWIn8AlcBP+ATdcAOIiikSEsAgRgQSvYsfr9SHrncPOoXu6u7qquBjvsOudxM4ntdSaqvre+qrrfd9vhLXWCSFwziGEIMsyOp0O9XodACHE9InjmE+LdncAJiGqTNZWq1WEEEfmiM+9\/Ir72qLkvlbc1j5KwNW6pVaJkM0ldjsd5poNiixle28fs3yWhw8eIpxFOAcLKzR\/8FPS0hBIyUoccHm+ylolYCnyyYzlUabZywo+Hmu8cT7GaY+2baDCmKzfZt8VMB7iD7psrKxSrYd4YcblhWVu3NlmN8vQKqLIxlSDACUgNxYLxJ7kYr3CfOgRSck+JQ3fQwlBw\/fwAAJPMiwjwjBkZOFG13BqcZ6fvfpV3vnnP3jxi1dZHN+l12mj4gYnHnV4e7tH2wZsNGM25JjyxDIAX2jV2JyLcc4hBcyFinXr2C9KxqXFE0BHS6wz5FoTBxJdgAsjtgcZr37nu\/h5nyRNOHt6nbgIqEtNpARv3R1wai4ifPAR15\/fRAqQwF6mETjW4oCqJ3HAYuiRGYtav\/jcL3vOo7AOz\/MYpynGlKz6OcnuXXof32e9EfKrP73DOdcBAautCmm\/w72B5e6jLiUeV659mZE27I4LPClo+IpQCZQU5MaRWwcCJEIx0gYRVvCaC8zNt1hZWmatEbE7KhHKY5wXbMxXuLk7oH1\/B18ZXl7L8VzJUj2mnyRsJwWPck2oJANt6BeGkbZ0spKxsYyNmeD89W9\/dwhASLyognKWMPApxinOWRpxRDX0ocyh1KA8wihA6JTeWFA6x0ALls5sIIUEIFKCQE6OsnQO6xzGgScEIs\/zIzwE8DzvCHecc9x4+03iWp3nr1w7NjYYDHDOoZQiCAIAtNaEYTjl8kH+Y4DOOdrtNk\/+ppSi0WgwHA5QykMpD3AIKREqxDqBA9p5lw\/2t1iK57i2+NyRHEIIjpbyODzPwxhDGIbUarUjY\/VaHanUkQqzEtLCkI\/2GfU6nCznqO8JWDyee+aR+r5Pt9vlozs7\/OXNt\/jjH37PzZs3wTmstdPFy8vLvPvuu+R5Pl0vpeTJfE+t0DnH3t4ev\/ntr\/ndG29QiWNKXbB26gybV77E1nvvcPvm+9OEWVGSFQYQBIEPCASWWsU\/fnqzALXWpFmGtpafv\/46J09vsPNwl\/fe3+KlF1\/g69\/6NvvdNjsfvg9AFEVYaemUu9xLdpC6hhuu85VLczjnng4ohCDPM775jev0en1Ori0RRiHddgcpBQuxYqV5mgtnTgJQlJZBotk3Bf2xRuoCvzCzUs8GlFLSnF\/Cbt\/hwYNH\/Ptf7yGkIpCOpHOfhXPrZIUhCv9vV2M3IvQU5+ILMK6wWCmeHRCgGtdIx5p00OHezn2KPOP8xec4sbJMFHiEvk8YTjgXedCqSQba4oQFz6JKfew4YaK1MyOOQj5\/5SqdTocz6y1CkTPq7XL54nnmalUkhnocAZAkCSoTrHpLnKotcGopJlqof5YKBYEvObu+yvd\/\/BO2b33A6XOXWGjNc2HjLGElRuuS\/nAITGgkpURKibEGgZidFhBFUTjgCG+sMZRm8tH3e11Gw8GUS845FpdXqVQqU7A0SUjHY6SUlGWJlBKlPFqt+eNKcxjoANgPAg4YVOoq6bCPcxYlJc5BvV7D94Pp\/H7m+O\/OCCEEgR+gPEEUOFqtZzzShw8fIqUEHM5Btdmi0WggpSRJEgaDIb7vT3edaslu6hN4Er+UJHlBHFqubBy\/NDPF+0m3yLIMYyxCTHT2wBEOKsyyDF2WRI\/dAT7ZLY5VKITgez\/8EeMiZzQa4QUBUgjATUABISWlLqlEIS+\/8AK\/eO01wiCAyTQ83ycMQ8qyfDalUdUYYw1xax4hPeYadcZZhrOTy5SmKVJ6yEqEEZK836YQAVGlMrlEaYq1dlrh4ZjJQ2MMxjr8IGSh2cCOUurCY96PcElOs9HECxTD0QgpBYVXJUkHaK2x1iKEQGs9K\/VsQKdLsAadZ4TOsra2zK0Pt7h1+yMCqVDGYq3FliXOWCQOKXw8pTDGYK09dg8+FXDU79PfazPs9tBIbm9tMRgM2dy8RFCrIQWMOl3S\/pBxmuKUoTQlWV5gjCHP8plg8Anf8PK1E7QurfKfP4\/xy5R6o05Z5OztPiAZpYTVECUdnrRIQIwSlFTAxKAd7jGtnhFwtXmJUIdsbvYQOmM4GHH9+ivUmzWMLpFKUVoo8oILF86jqnOYXveIwx9+PxwzWwxrLWVZPvbFnCRJprIWRRFxHE\/nBkFAng4YJjlBGBJFEVLKiWIdEocpD5\/cwUGSA3InowH37mxN+ees5cq1lwjDiVM453BSojyF7wcT9zcGO8OaZlb4pLYexM72LaKowtLK+rGxYbJPr9MnDCPmmk2MdVQq0bFW81ObqCcFfWl5DSnVkbEDFREiphpn1BvzKKVQj7s7daid\/EwVHh6bABzdzNPiSOdtjHnqilxbjJ3833OAc+B7EmsdQkyaqEqgUPKTjfcg\/geiigyZapzK0gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u00221005\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA musical competition, in which the managers lead their countries every week to a fight for a title of the best song.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["competition","esc","eurovision","facebook","javascript","micrus","music","php","song","voting","websockets"],"hasMore":false,"image":"https:\/\/avris.it\/image\/oursong_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022301.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA musical competition, in which the managers lead their countries every week to a fight for a title of the best song.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022301.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA musical competition, in which the managers lead their countries every week to a fight for a title of the best song.\u003C\/p\u003E","words":22,"readTime":null,"lang":"en"},"pl":{"slug":"oursong-wybierzmy-nasz\u0105-piosenk\u0119","title":"OurSong \u2022 Wybierzmy nasz\u0105 piosenk\u0119!","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022603\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAkCAYAAACaJFpUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhElEQVRIiZWXW48cRxmGn6rq0\/ScdmfP6+Pasr2RA0bYkIOQIoyAIIE4SMAlEvwJFEWIn8AlcBP+ATdcAOIiikSEsAgRgQSvYsfr9SHrncPOoXu6u7qquBjvsOudxM4ntdSaqvre+qrrfd9vhLXWCSFwziGEIMsyOp0O9XodACHE9InjmE+LdncAJiGqTNZWq1WEEEfmiM+9\/Ir72qLkvlbc1j5KwNW6pVaJkM0ldjsd5poNiixle28fs3yWhw8eIpxFOAcLKzR\/8FPS0hBIyUoccHm+ylolYCnyyYzlUabZywo+Hmu8cT7GaY+2baDCmKzfZt8VMB7iD7psrKxSrYd4YcblhWVu3NlmN8vQKqLIxlSDACUgNxYLxJ7kYr3CfOgRSck+JQ3fQwlBw\/fwAAJPMiwjwjBkZOFG13BqcZ6fvfpV3vnnP3jxi1dZHN+l12mj4gYnHnV4e7tH2wZsNGM25JjyxDIAX2jV2JyLcc4hBcyFinXr2C9KxqXFE0BHS6wz5FoTBxJdgAsjtgcZr37nu\/h5nyRNOHt6nbgIqEtNpARv3R1wai4ifPAR15\/fRAqQwF6mETjW4oCqJ3HAYuiRGYtav\/jcL3vOo7AOz\/MYpynGlKz6OcnuXXof32e9EfKrP73DOdcBAautCmm\/w72B5e6jLiUeV659mZE27I4LPClo+IpQCZQU5MaRWwcCJEIx0gYRVvCaC8zNt1hZWmatEbE7KhHKY5wXbMxXuLk7oH1\/B18ZXl7L8VzJUj2mnyRsJwWPck2oJANt6BeGkbZ0spKxsYyNmeD89W9\/dwhASLyognKWMPApxinOWRpxRDX0ocyh1KA8wihA6JTeWFA6x0ALls5sIIUEIFKCQE6OsnQO6xzGgScEIs\/zIzwE8DzvCHecc9x4+03iWp3nr1w7NjYYDHDOoZQiCAIAtNaEYTjl8kH+Y4DOOdrtNk\/+ppSi0WgwHA5QykMpD3AIKREqxDqBA9p5lw\/2t1iK57i2+NyRHEIIjpbyODzPwxhDGIbUarUjY\/VaHanUkQqzEtLCkI\/2GfU6nCznqO8JWDyee+aR+r5Pt9vlozs7\/OXNt\/jjH37PzZs3wTmstdPFy8vLvPvuu+R5Pl0vpeTJfE+t0DnH3t4ev\/ntr\/ndG29QiWNKXbB26gybV77E1nvvcPvm+9OEWVGSFQYQBIEPCASWWsU\/fnqzALXWpFmGtpafv\/46J09vsPNwl\/fe3+KlF1\/g69\/6NvvdNjsfvg9AFEVYaemUu9xLdpC6hhuu85VLczjnng4ohCDPM775jev0en1Ori0RRiHddgcpBQuxYqV5mgtnTgJQlJZBotk3Bf2xRuoCvzCzUs8GlFLSnF\/Cbt\/hwYNH\/Ptf7yGkIpCOpHOfhXPrZIUhCv9vV2M3IvQU5+ILMK6wWCmeHRCgGtdIx5p00OHezn2KPOP8xec4sbJMFHiEvk8YTjgXedCqSQba4oQFz6JKfew4YaK1MyOOQj5\/5SqdTocz6y1CkTPq7XL54nnmalUkhnocAZAkCSoTrHpLnKotcGopJlqof5YKBYEvObu+yvd\/\/BO2b33A6XOXWGjNc2HjLGElRuuS\/nAITGgkpURKibEGgZidFhBFUTjgCG+sMZRm8tH3e11Gw8GUS845FpdXqVQqU7A0SUjHY6SUlGWJlBKlPFqt+eNKcxjoANgPAg4YVOoq6bCPcxYlJc5BvV7D94Pp\/H7m+O\/OCCEEgR+gPEEUOFqtZzzShw8fIqUEHM5Btdmi0WggpSRJEgaDIb7vT3edaslu6hN4Er+UJHlBHFqubBy\/NDPF+0m3yLIMYyxCTHT2wBEOKsyyDF2WRI\/dAT7ZLY5VKITgez\/8EeMiZzQa4QUBUgjATUABISWlLqlEIS+\/8AK\/eO01wiCAyTQ83ycMQ8qyfDalUdUYYw1xax4hPeYadcZZhrOTy5SmKVJ6yEqEEZK836YQAVGlMrlEaYq1dlrh4ZjJQ2MMxjr8IGSh2cCOUurCY96PcElOs9HECxTD0QgpBYVXJUkHaK2x1iKEQGs9K\/VsQKdLsAadZ4TOsra2zK0Pt7h1+yMCqVDGYq3FliXOWCQOKXw8pTDGYK09dg8+FXDU79PfazPs9tBIbm9tMRgM2dy8RFCrIQWMOl3S\/pBxmuKUoTQlWV5gjCHP8plg8Anf8PK1E7QurfKfP4\/xy5R6o05Z5OztPiAZpYTVECUdnrRIQIwSlFTAxKAd7jGtnhFwtXmJUIdsbvYQOmM4GHH9+ivUmzWMLpFKUVoo8oILF86jqnOYXveIwx9+PxwzWwxrLWVZPvbFnCRJprIWRRFxHE\/nBkFAng4YJjlBGBJFEVLKiWIdEocpD5\/cwUGSA3InowH37mxN+ees5cq1lwjDiVM453BSojyF7wcT9zcGO8OaZlb4pLYexM72LaKowtLK+rGxYbJPr9MnDCPmmk2MdVQq0bFW81ObqCcFfWl5DSnVkbEDFREiphpn1BvzKKVQj7s7daid\/EwVHh6bABzdzNPiSOdtjHnqilxbjJ3833OAc+B7EmsdQkyaqEqgUPKTjfcg\/geiigyZapzK0gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/oursong_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022603\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKonkurs muzyczny, w kt\u00f3rym menad\u017cerowie prowadz\u0105cy wybrane przez siebie kraje z ca\u0142ego \u015bwiata co tydzie\u0144 rywalizuj\u0105 o miano najlepszego utworu.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u00221005\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAkCAYAAACaJFpUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHhElEQVRIiZWXW48cRxmGn6rq0\/ScdmfP6+Pasr2RA0bYkIOQIoyAIIE4SMAlEvwJFEWIn8AlcBP+ATdcAOIiikSEsAgRgQSvYsfr9SHrncPOoXu6u7qquBjvsOudxM4ntdSaqvre+qrrfd9vhLXWCSFwziGEIMsyOp0O9XodACHE9InjmE+LdncAJiGqTNZWq1WEEEfmiM+9\/Ir72qLkvlbc1j5KwNW6pVaJkM0ldjsd5poNiixle28fs3yWhw8eIpxFOAcLKzR\/8FPS0hBIyUoccHm+ylolYCnyyYzlUabZywo+Hmu8cT7GaY+2baDCmKzfZt8VMB7iD7psrKxSrYd4YcblhWVu3NlmN8vQKqLIxlSDACUgNxYLxJ7kYr3CfOgRSck+JQ3fQwlBw\/fwAAJPMiwjwjBkZOFG13BqcZ6fvfpV3vnnP3jxi1dZHN+l12mj4gYnHnV4e7tH2wZsNGM25JjyxDIAX2jV2JyLcc4hBcyFinXr2C9KxqXFE0BHS6wz5FoTBxJdgAsjtgcZr37nu\/h5nyRNOHt6nbgIqEtNpARv3R1wai4ifPAR15\/fRAqQwF6mETjW4oCqJ3HAYuiRGYtav\/jcL3vOo7AOz\/MYpynGlKz6OcnuXXof32e9EfKrP73DOdcBAautCmm\/w72B5e6jLiUeV659mZE27I4LPClo+IpQCZQU5MaRWwcCJEIx0gYRVvCaC8zNt1hZWmatEbE7KhHKY5wXbMxXuLk7oH1\/B18ZXl7L8VzJUj2mnyRsJwWPck2oJANt6BeGkbZ0spKxsYyNmeD89W9\/dwhASLyognKWMPApxinOWRpxRDX0ocyh1KA8wihA6JTeWFA6x0ALls5sIIUEIFKCQE6OsnQO6xzGgScEIs\/zIzwE8DzvCHecc9x4+03iWp3nr1w7NjYYDHDOoZQiCAIAtNaEYTjl8kH+Y4DOOdrtNk\/+ppSi0WgwHA5QykMpD3AIKREqxDqBA9p5lw\/2t1iK57i2+NyRHEIIjpbyODzPwxhDGIbUarUjY\/VaHanUkQqzEtLCkI\/2GfU6nCznqO8JWDyee+aR+r5Pt9vlozs7\/OXNt\/jjH37PzZs3wTmstdPFy8vLvPvuu+R5Pl0vpeTJfE+t0DnH3t4ev\/ntr\/ndG29QiWNKXbB26gybV77E1nvvcPvm+9OEWVGSFQYQBIEPCASWWsU\/fnqzALXWpFmGtpafv\/46J09vsPNwl\/fe3+KlF1\/g69\/6NvvdNjsfvg9AFEVYaemUu9xLdpC6hhuu85VLczjnng4ohCDPM775jev0en1Ori0RRiHddgcpBQuxYqV5mgtnTgJQlJZBotk3Bf2xRuoCvzCzUs8GlFLSnF\/Cbt\/hwYNH\/Ptf7yGkIpCOpHOfhXPrZIUhCv9vV2M3IvQU5+ILMK6wWCmeHRCgGtdIx5p00OHezn2KPOP8xec4sbJMFHiEvk8YTjgXedCqSQba4oQFz6JKfew4YaK1MyOOQj5\/5SqdTocz6y1CkTPq7XL54nnmalUkhnocAZAkCSoTrHpLnKotcGopJlqof5YKBYEvObu+yvd\/\/BO2b33A6XOXWGjNc2HjLGElRuuS\/nAITGgkpURKibEGgZidFhBFUTjgCG+sMZRm8tH3e11Gw8GUS845FpdXqVQqU7A0SUjHY6SUlGWJlBKlPFqt+eNKcxjoANgPAg4YVOoq6bCPcxYlJc5BvV7D94Pp\/H7m+O\/OCCEEgR+gPEEUOFqtZzzShw8fIqUEHM5Btdmi0WggpSRJEgaDIb7vT3edaslu6hN4Er+UJHlBHFqubBy\/NDPF+0m3yLIMYyxCTHT2wBEOKsyyDF2WRI\/dAT7ZLY5VKITgez\/8EeMiZzQa4QUBUgjATUABISWlLqlEIS+\/8AK\/eO01wiCAyTQ83ycMQ8qyfDalUdUYYw1xax4hPeYadcZZhrOTy5SmKVJ6yEqEEZK836YQAVGlMrlEaYq1dlrh4ZjJQ2MMxjr8IGSh2cCOUurCY96PcElOs9HECxTD0QgpBYVXJUkHaK2x1iKEQGs9K\/VsQKdLsAadZ4TOsra2zK0Pt7h1+yMCqVDGYq3FliXOWCQOKXw8pTDGYK09dg8+FXDU79PfazPs9tBIbm9tMRgM2dy8RFCrIQWMOl3S\/pBxmuKUoTQlWV5gjCHP8plg8Anf8PK1E7QurfKfP4\/xy5R6o05Z5OztPiAZpYTVECUdnrRIQIwSlFTAxKAd7jGtnhFwtXmJUIdsbvYQOmM4GHH9+ivUmzWMLpFKUVoo8oILF86jqnOYXveIwx9+PxwzWwxrLWVZPvbFnCRJprIWRRFxHE\/nBkFAng4YJjlBGBJFEVLKiWIdEocpD5\/cwUGSA3InowH37mxN+ees5cq1lwjDiVM453BSojyF7wcT9zcGO8OaZlb4pLYexM72LaKowtLK+rGxYbJPr9MnDCPmmk2MdVQq0bFW81ObqCcFfWl5DSnVkbEDFREiphpn1BvzKKVQj7s7daid\/EwVHh6bABzdzNPiSOdtjHnqilxbjJ3833OAc+B7EmsdQkyaqEqgUPKTjfcg\/geiigyZapzK0gAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022800\u0022 height=\u00221005\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKonkurs muzyczny, w kt\u00f3rym menad\u017cerowie prowadz\u0105cy wybrane przez siebie kraje z ca\u0142ego \u015bwiata co tydzie\u0144 rywalizuj\u0105 o miano najlepszego utworu.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["eurowizja","facebook","g\u0142osowanie","javascript","konkurs","muzyka","php","piosenka","programowanie","websockets"],"hasMore":false,"image":"https:\/\/avris.it\/image\/oursong_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022301.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKonkurs muzyczny, w kt\u00f3rym menad\u017cerowie prowadz\u0105cy wybrane przez siebie kraje z ca\u0142ego \u015bwiata co tydzie\u0144 rywalizuj\u0105 o miano najlepszego utworu.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/oursong_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/oursong_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022301.5\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EKonkurs muzyczny, w kt\u00f3rym menad\u017cerowie prowadz\u0105cy wybrane przez siebie kraje z ca\u0142ego \u015bwiata co tydzie\u0144 rywalizuj\u0105 o miano najlepszego utworu.\u003C\/p\u003E","words":24,"readTime":null,"lang":"pl"}}},"projects\/avris-flags-flags-on-websites-made-easy":{"key":"projects\/avris-flags-flags-on-websites-made-easy","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:48+02:00","publishedAt":"2017-01-26T18:18:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/flags.avris.it","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Flags","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-flags-flags-on-websites-made-easy"},"content":{"en":{"slug":"avris-flags-flags-on-websites-made-easy","title":"Avris Flags \u2013 flags on websites made easy","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022274.28571428571\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADWElEQVRIicWWz24cRRDGf\/1vZpb1rL3eXQdsE8niQOAByAFxBIlX4Yl4Dm6cuPgMgkNkKRKKYxwgbLwmrO2Znu4uDrNe1n\/WThxZfFJL09PV01XfV101ynsvxhiUUqSUEBGstQCICEqp+TOAUmr+fnH9HJfXLtuklBbmAlzcb\/f29ng1HjPa2CDGgIiiqioeP\/6M+0BdV8QQUEqTUkRrg4iQUmKlLFHee7mXk+8IDaC1ng8RuTIu4\/zdxbWL9tfbXL9\/0cYC7O\/vE2NiNBrS7XZ59udvaKXJrGvzCiHEyMONTcavJ5xWp+Q2I0kCFM5aYor0yzUy696JIeW9F+fcPPnOE\/v\/QIyxZWgRSim01sDFG3M+P5f1rrfsJptrHVrE7u4u1lpCCPT7fQ4PD1ldXWWw3mewvo42hpQSxhi8r1EoXJYRmoYkiSzLCSHQW13DuTeT8opkixEdnwYyCaA1vonYzPLy5YSdrQIwpHCK6BymAbO6BpeY+I9VxWK9WcaQ9345QyLCt9\/\/gnv+B4+GGdtF4sfeQ\/afPOXLT58ykEBTjKjih2z9\/B0rX39D7+NHS6S66uidGLrP5H5rhgB8XXP44neQRBLIMkun02U4HLxzUi919DaG6qpicnxM3TQY1dacJkaiBafNrE61PWpr9D5aa2JMGLNwG4EYA9a08Wut78YQQBMC4\/GYKjV8tLND5WvyosCgaWqPwaC1wVjF5OgImfVLEcEYQ9MEUGBN27PKXo9OUdyNoZOTE14cHIDSaKVIszrUzwr0ZIrvd\/n77JSNBw8oy3KmRwKt20aOoGZ\/Em8iq\/f+ZodSStSvJpDaj5MERIhNwK68h9QeSa0DSmaHO4v\/Z4otCkwnR3c7KKXmY87EXSSrqoqDX5+1wcZIEMFpTUqCaBiYAlfkPPnpBza\/+ApjDMormtiQBwhHU+SolU5rTVXVjEZDer3e0jNvdEgphVkrKToFIURc5iAltLGcnZ3R397G5Rmff9JHuRFwNeq3vWU3OpTnOYPRkNfTKcZZ6rpGBIZGUWvN0fGkTVzf4NxfxJSIIeCynBgDoEiSMNqQUuSDzc1bS+StDGV5xvHzCWW3S1EFtLNUVuivrxNCJKVI0ekQY6QoCkIIlGVJlmVLGboJ\/wIrt158LmOnzAAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022274.28571428571\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Cem\u003EFlags on websites made easy.\u003C\/em\u003E\u003C\/p\u003E\n\u003Cp\u003EInlude country flags in your websites using simple CSS classes.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022700\u0022 height=\u0022400\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADWElEQVRIicWWz24cRRDGf\/1vZpb1rL3eXQdsE8niQOAByAFxBIlX4Yl4Dm6cuPgMgkNkKRKKYxwgbLwmrO2Znu4uDrNe1n\/WThxZfFJL09PV01XfV101ynsvxhiUUqSUEBGstQCICEqp+TOAUmr+fnH9HJfXLtuklBbmAlzcb\/f29ng1HjPa2CDGgIiiqioeP\/6M+0BdV8QQUEqTUkRrg4iQUmKlLFHee7mXk+8IDaC1ng8RuTIu4\/zdxbWL9tfbXL9\/0cYC7O\/vE2NiNBrS7XZ59udvaKXJrGvzCiHEyMONTcavJ5xWp+Q2I0kCFM5aYor0yzUy696JIeW9F+fcPPnOE\/v\/QIyxZWgRSim01sDFG3M+P5f1rrfsJptrHVrE7u4u1lpCCPT7fQ4PD1ldXWWw3mewvo42hpQSxhi8r1EoXJYRmoYkiSzLCSHQW13DuTeT8opkixEdnwYyCaA1vonYzPLy5YSdrQIwpHCK6BymAbO6BpeY+I9VxWK9WcaQ9345QyLCt9\/\/gnv+B4+GGdtF4sfeQ\/afPOXLT58ykEBTjKjih2z9\/B0rX39D7+NHS6S66uidGLrP5H5rhgB8XXP44neQRBLIMkun02U4HLxzUi919DaG6qpicnxM3TQY1dacJkaiBafNrE61PWpr9D5aa2JMGLNwG4EYA9a08Wut78YQQBMC4\/GYKjV8tLND5WvyosCgaWqPwaC1wVjF5OgImfVLEcEYQ9MEUGBN27PKXo9OUdyNoZOTE14cHIDSaKVIszrUzwr0ZIrvd\/n77JSNBw8oy3KmRwKt20aOoGZ\/Em8iq\/f+ZodSStSvJpDaj5MERIhNwK68h9QeSa0DSmaHO4v\/Z4otCkwnR3c7KKXmY87EXSSrqoqDX5+1wcZIEMFpTUqCaBiYAlfkPPnpBza\/+ApjDMormtiQBwhHU+SolU5rTVXVjEZDer3e0jNvdEgphVkrKToFIURc5iAltLGcnZ3R397G5Rmff9JHuRFwNeq3vWU3OpTnOYPRkNfTKcZZ6rpGBIZGUWvN0fGkTVzf4NxfxJSIIeCynBgDoEiSMNqQUuSDzc1bS+StDGV5xvHzCWW3S1EFtLNUVuivrxNCJKVI0ekQY6QoCkIIlGVJlmVLGboJ\/wIrt158LmOnzAAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022700\u0022 height=\u0022400\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Cem\u003EFlags on websites made easy.\u003C\/em\u003E\u003C\/p\u003E\n\u003Cp\u003EInlude country flags in your websites using simple CSS classes.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["css","flags","html","javascript","plain css"],"hasMore":false,"image":"https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022137.14285714286\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Cem\u003EFlags on websites made easy.\u003C\/em\u003E\u003C\/p\u003E\n\u003Cp\u003EInlude country flags in your websites using simple CSS classes.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-flags-flags-on-websites-made-easy_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022137.14285714286\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003E\u003Cem\u003EFlags on websites made easy.\u003C\/em\u003E\u003C\/p\u003E\n\u003Cp\u003EInlude country flags in your websites using simple CSS classes.\u003C\/p\u003E","words":15,"readTime":null,"lang":"en"}}},"blog\/technology\/exporting-playlists-from-google-play-music-to-spotify":{"key":"blog\/technology\/exporting-playlists-from-google-play-music-to-spotify","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:58+02:00","publishedAt":"2016-08-10T22:33:00+02:00","group":null,"category":"blog","subcategory":"technology","slug":"exporting-playlists-from-google-play-music-to-spotify"},"content":{"en":{"slug":"exporting-playlists-from-google-play-music-to-spotify","title":"Exporting playlists from Google Play Music to Spotify","intro":"\u003Cp\u003ESpotify is so much better than Google Play Music! Whether it\u2019s in the field of cool features (like using your smartphone to control the music on your computer) or just basic user experience (like ability to filter songs inside a playlist) \u2013 Spotify wins by far!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cp\u003ESpotify is so much better than Google Play Music! Whether it\u2019s in the field of cool features (like using your smartphone to control the music on your computer) or just basic user experience (like ability to filter songs inside a playlist) \u2013 Spotify wins by far!\u003C\/p\u003E\n\u003Cp\u003EThere\u2019s just one thing that for the past two months was stopping me from migrating to Spotify. Neither in Spotify nor in GPM can you export or import a list of songs. Really! And I really don\u2019t have time to search for all my songs again...\u003C\/p\u003E\n\u003Cp\u003EFortunately, there\u2019s \u003Ca href=\u0022https:\/\/soundiiz.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Soundiiz\u003C\/a\u003E! This fancy tool allows you to migrate playlists between different streaming services. Among which... there\u2019s no GPM, because of course there isn\u2019t. Oh, damn you, Google!\u003C\/p\u003E\n\u003Cp\u003EWe can however upload a text file (in format \u003Ccode\u003EArtist\u00a0-\u00a0Title\u003C\/code\u003E for each line) to Soundiiz and it will automatically find our songs in the Spotify database, creating a playlist. Cool! So now we only have to create such file.\u003C\/p\u003E\n\u003Cp\u003EWe might just scrape the data from GPM\u2019s HTML, couldn\u2019t we? Well, Google doesn\u2019t make it easy. It loads the list of songs dynamically while you\u2019re scrolling... Oh, damn you, Google!\u003C\/p\u003E\n\u003Cp\u003EAnyways, my solution is:\u003C\/p\u003E\n\u003Col\u003E\n\u003Cli\u003EOpen GPM, chose the playlist in that you\u2019d like to export.\u003C\/li\u003E\n\u003Cli\u003EOpen the JavaScript console (in Chrome it\u2019s \u003Ccode\u003ECtrl+Alt+J\u003C\/code\u003E, in Firefox \u003Ccode\u003ECtrl+Alt+K\u003C\/code\u003E).\u003C\/li\u003E\n\u003Cli\u003EPaste the following code:\u003C\/li\u003E\n\u003C\/ol\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E fetched = [];\n\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003Efetch\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E playlist = \u003Cspan class=\u0022hljs-built_in\u0022\u003Edocument\u003C\/span\u003E.querySelectorAll(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.song-table tr.song-row\u0027\u003C\/span\u003E);\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Efor\u003C\/span\u003E(\u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E i = \u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E; i \u0026lt; playlist.length; i++) {\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E title = playlist[i].querySelectorAll(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027td[data-col=\u0022title\u0022] .column-content\u0027\u003C\/span\u003E)[\u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E].textContent;\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E artist = playlist[i].querySelectorAll(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027td[data-col=\u0022artist\u0022] .column-content\u0027\u003C\/span\u003E)[\u003Cspan class=\u0022hljs-number\u0022\u003E0\u003C\/span\u003E].textContent;\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E row = artist + \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027 - \u0027\u003C\/span\u003E + title;\n        \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (fetched.indexOf(row) == \u003Cspan class=\u0022hljs-number\u0022\u003E-1\u003C\/span\u003E) {\n            fetched.push(row);\n        }\n    }\n    \u003Cspan class=\u0022hljs-built_in\u0022\u003Econsole\u003C\/span\u003E.log(fetched.length);\n}\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Evar\u003C\/span\u003E interval = setInterval(fetch, \u003Cspan class=\u0022hljs-number\u0022\u003E100\u003C\/span\u003E);\n\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E \u003Cspan class=\u0022hljs-title\u0022\u003Edone\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    clearInterval(interval);\n    \u003Cspan class=\u0022hljs-built_in\u0022\u003Econsole\u003C\/span\u003E.log(fetched.join(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022\\n\u0022\u003C\/span\u003E));\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Col start=\u00224\u0022\u003E\n\u003Cli\u003EScroll down through your playlist. You should see growing numbers appearing in the console. When you\u2019re done scrolling, this number should be equal to the number of songs in the playlist.\u003C\/li\u003E\n\u003Cli\u003EType \u003Ccode\u003Edone();\u003C\/code\u003E and you should see the list of your songs.\u003C\/li\u003E\n\u003Cli\u003ENow just copy-paste it to a file and save it.\u003C\/li\u003E\n\u003Cli\u003EGo to \u003Ca href=\u0022https:\/\/soundiiz.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Soundiiz\u003C\/a\u003E and connect with your Spotify account.\u003C\/li\u003E\n\u003Cli\u003EUpload the file.\u003C\/li\u003E\n\u003Cli\u003ERelax ;-)\u003C\/li\u003E\n\u003C\/ol\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["export","google play music","javascript","music","playlist","spotify","streaming"],"hasMore":true,"image":null,"introLite":"\u003Cp\u003ESpotify is so much better than Google Play Music! Whether it\u2019s in the field of cool features (like using your smartphone to control the music on your computer) or just basic user experience (like ability to filter songs inside a playlist) \u2013 Spotify wins by far!\u003C\/p\u003E","contentLite":"\u003Cp\u003ESpotify is so much better than Google Play Music! Whether it\u2019s in the field of cool features (like using your smartphone to control the music on your computer) or just basic user experience (like ability to filter songs inside a playlist) \u2013 Spotify wins by far!\u003C\/p\u003E\n\u003Cp\u003EThere\u2019s just one thing that for the past two months was stopping me from migrating to Spotify. Neither in Spotify nor in GPM can you export or import a list of songs. Really! And I really don\u2019t have time to search for all my songs again...\u003C\/p\u003E\n\u003Cp\u003EFortunately, there\u2019s \u003Ca href=\u0022https:\/\/soundiiz.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Soundiiz\u003C\/a\u003E! This fancy tool allows you to migrate playlists between different streaming services. Among which... there\u2019s no GPM, because of course there isn\u2019t. Oh, damn you, Google!\u003C\/p\u003E\n\u003Cp\u003EWe can however upload a text file (in format \u003Ccode\u003EArtist\u00a0-\u00a0Title\u003C\/code\u003E for each line) to Soundiiz and it will automatically find our songs in the Spotify database, creating a playlist. Cool! So now we only have to create such file.\u003C\/p\u003E\n\u003Cp\u003EWe might just scrape the data from GPM\u2019s HTML, couldn\u2019t we? Well, Google doesn\u2019t make it easy. It loads the list of songs dynamically while you\u2019re scrolling... Oh, damn you, Google!\u003C\/p\u003E\n\u003Cp\u003EAnyways, my solution is:\u003C\/p\u003E\n\u003Col\u003E\n\u003Cli\u003EOpen GPM, chose the playlist in that you\u2019d like to export.\u003C\/li\u003E\n\u003Cli\u003EOpen the JavaScript console (in Chrome it\u2019s \u003Ccode\u003ECtrl+Alt+J\u003C\/code\u003E, in Firefox \u003Ccode\u003ECtrl+Alt+K\u003C\/code\u003E).\u003C\/li\u003E\n\u003Cli\u003EPaste the following code:\u003C\/li\u003E\n\u003C\/ol\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-js\u0022\u003Evar fetched = [];\nfunction fetch() {\n    var playlist = document.querySelectorAll(\u0027.song-table tr.song-row\u0027);\n    for(var i = 0; i \u0026lt; playlist.length; i++) {\n        var title = playlist[i].querySelectorAll(\u0027td[data-col=\u0022title\u0022] .column-content\u0027)[0].textContent;\n        var artist = playlist[i].querySelectorAll(\u0027td[data-col=\u0022artist\u0022] .column-content\u0027)[0].textContent;\n        var row = artist + \u0027 - \u0027 + title;\n        if (fetched.indexOf(row) == -1) {\n            fetched.push(row);\n        }\n    }\n    console.log(fetched.length);\n}\nvar interval = setInterval(fetch, 100);\nfunction done() {\n    clearInterval(interval);\n    console.log(fetched.join(\u0022\\n\u0022));\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Col start=\u00224\u0022\u003E\n\u003Cli\u003EScroll down through your playlist. You should see growing numbers appearing in the console. When you\u2019re done scrolling, this number should be equal to the number of songs in the playlist.\u003C\/li\u003E\n\u003Cli\u003EType \u003Ccode\u003Edone();\u003C\/code\u003E and you should see the list of your songs.\u003C\/li\u003E\n\u003Cli\u003ENow just copy-paste it to a file and save it.\u003C\/li\u003E\n\u003Cli\u003EGo to \u003Ca href=\u0022https:\/\/soundiiz.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Soundiiz\u003C\/a\u003E and connect with your Spotify account.\u003C\/li\u003E\n\u003Cli\u003EUpload the file.\u003C\/li\u003E\n\u003Cli\u003ERelax ;-)\u003C\/li\u003E\n\u003C\/ol\u003E","words":377,"readTime":2,"lang":"en"}}},"projects\/generator-de":{"key":"projects\/generator-de","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:25+02:00","publishedAt":"2016-03-27T20:51:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/generator.avris.it\/","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Generator","displayUrl":null},{"icon":"pencil","colour":"secondary","url":"https:\/\/www.npmjs.com\/package\/avris-generator","displayUrl":null}],"category":"projects","subcategory":null,"slug":"generator-de"},"content":{"de":{"slug":"generator-de","title":"Generator und Validator f\u00fcr IBAN und TIN, ISBN, EAN, Kennwortgenerator","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320.22808267997\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGqUlEQVRIiaWXu48kVxXGf\/dRj65+TvdOj70DGK9XAmmxAG3ilNABSMb8AUjkyAkBMTEpARIBCWaRJWJAwgksEpaxRLASYAOrhdn1zqu7p7uqq+7jEFRPz4x31iBxpKu+3XXv6e9837nn3FJf\/8brYo2l6Hbp9Qd0Ol2U0vw\/JiLns813gHh5wfap2s4FBGyWJBhjcU3D7PSY3cmENC8oy4qmqcmyHO89RVGwXq8JwaOUxhgNKGKMxBjw3gPgBEJoEHcBwPiAIASjUEqRJymIUNZrksRijEG1eLBsnIcQCc4xne7ROM9Hf\/+Ifq9PVZWUZYnWmul0Slmu6PcHOOeo1hX9Xo+Dx\/+mqWuUUri4YSAGlFIoBTd2hiRJRogKEcGva4iCMmpDlkI2iNTdu18RrYQY2ohskjAc7\/DgwV\/pdgvUJkql1JZtQVAXgrSOAFGGPMtQSDuUpnENezdv8qU7rz4jZyuTtH5EAMFqo7FaIzoSY+THP\/0ZWapIVEK3W1yTIO3HbDYnSiSEwMHjx9x755d893tvMck6xBjpdrtbAIJgtMF7z+lshjEGBKJE7v\/hPu\/\/6X3YBGyNsUgMLKsKgHS4A+LIlWZvundtwiqlGI\/HeO8RIE1TvvjK51lnXTpFjnOeyWSyXbsFJkK\/329\/1xoFfPBBBy50wNokwdehTUgfGGTgPDQSeXT0hOFw+CxLG1vOTvHO45qaTifjM\/2EtXc4cTw6fIwAWZrSKS4xbaFZ19Sn5TUeBWutxddtjogItXiksNzIBhf6PMeGoxFEwTUNEgILaqa9IX1tN3vVtfuyLKPYybbsXTabZzlNVWGNwSlPz2ZgLdXsEHoDdrIeqbYXMWxkEBFUspEDeHoyZy8f4n2kbFZ0i4ydtHdFsnNTSiGJXA8oTRKKNMFojQ+Rk6czer0ukMJszSHrT2UJ4ODjp0h0rI6WaK3QQLX2VKw+dZ+IcLa8vEa1pyzGiNWKTpaD0vR7vf8K4rJTUDTOk2UZeZb+z3vrpiHKJ9h781vflLPDJ\/gYWawqvvzaXbTRNKHBakuR9xh1BiyqOZWr2ekOWIUlRhuWq4rCFDR1w8HBY1763MvU3iOxLSGyAZxazSu3bl8OY8vI8ckxq9UFSxatcSGiFMQYeev7P4CwoogJL+xNKYqrteg8h8qy5HQ2I\/jA6fyEt+\/d4\/XvfJvbWa+V3weyLGN398YlJjcwznNQKX5+7x6\/u\/\/7LUhrjcXHgKLtM+Nugc36pEbhNSxcdT3fiWI0GiJRWJwtWNeO29N9eglXDti1+2PE+E31V1fBWpNYGh\/IrMXHCDTUq8BaBK01vV4Pbcy1mOaLBcF5mqYBEVSomJcNAKPRzvWBAM45lotNHfpEZbGJTfA+bK8EK7\/GpYpJZaGf4Yg4V6O9wkWPTS3BRUxqMEXOJO9ztlxSlSvyYMG2JcIv6+cCUkDeaVNhXddXGUoSS4gRrRXr2lHYDJ2knJUzupJh5jMY9AiugsQi3rEONQM1pJwfEW3bEpzz\/PnDD7GpZTC4Wt07OmV+espqc2s4H9PplHXjrgKySUIMHowmRE+IkVlzRsg7OLcCr5lojRRdOicV9aRgnHWpQ0NnNGCY9amLBa\/eucP+Sy8wHT4r1b+eHG5yJWJMQtM02+Z73uXPpbNGKTp5ijWGQb9PHgzjbHDhbQT4zXyY0NnMUzJQ4KuGqlwRXIWuNIfrGUh7D2pLlJCTUm3++7wxdzenV0SQeImhEDyrqqbxgRd3xzw9WdBZOxaLM87OzphMJuR53gahWq8P\/\/kPbJKyv7+PQnE0XxLl+r61NQGtNU3TUNc1eZ5jjGlrVgjbE2cVQu08L+6O6XYy0sRwc3fCzd3Jc33vTy+eRRGeHDzib395wE9+9ENO5nNW5Zq6cWir2RsNGfR6IBGUxgtom6CNRSnN6ekxwTu0NqAUVmvNF26\/TGhqQgi884u36XRy0jRjNp+zWp6hNBtaFc57JApGw6DfxyQps5Njbt26zZuvfY0bX70DtGyUZcVoZ0TR6XB0dERZVkSJiAhJkqC15je\/\/hXvvvtbYowopbHl4pQ0TTmrVoyGA9584w3SNCXJMrzzxBjay5yA0np75VSAsRalFA8fPuS99\/7IZ++MWSYKHzxpalBYKnF4B+mwSzpsE1mJXBRGgRgFpdphk7wgzhcMRjuMxhMmpWB85DjWGGNIs5ymaUiShG6vS+\/8dGxACVCWFSKRj+0Obj5DRBiPJ6RpCgjeOTYvOgDUVU29WKGUwvuG4B1KG5RS\/Af3xoJXKXZWkwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/generator_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320.22808267997\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EBequemer Service f\u00fcr best\u00e4tigen und generieren von Steuer-IdNr., IBAN, TIN, ISBN, EAN, Kennw\u00f6rter...\u003C\/p\u003E\n\u003Cp\u003EAuch als API und NPM package verf\u00fcgbar.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022640.45616535994\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGqUlEQVRIiaWXu48kVxXGf\/dRj65+TvdOj70DGK9XAmmxAG3ilNABSMb8AUjkyAkBMTEpARIBCWaRJWJAwgksEpaxRLASYAOrhdn1zqu7p7uqq+7jEFRPz4x31iBxpKu+3XXv6e9837nn3FJf\/8brYo2l6Hbp9Qd0Ol2U0vw\/JiLns813gHh5wfap2s4FBGyWJBhjcU3D7PSY3cmENC8oy4qmqcmyHO89RVGwXq8JwaOUxhgNKGKMxBjw3gPgBEJoEHcBwPiAIASjUEqRJymIUNZrksRijEG1eLBsnIcQCc4xne7ROM9Hf\/+Ifq9PVZWUZYnWmul0Slmu6PcHOOeo1hX9Xo+Dx\/+mqWuUUri4YSAGlFIoBTd2hiRJRogKEcGva4iCMmpDlkI2iNTdu18RrYQY2ohskjAc7\/DgwV\/pdgvUJkql1JZtQVAXgrSOAFGGPMtQSDuUpnENezdv8qU7rz4jZyuTtH5EAMFqo7FaIzoSY+THP\/0ZWapIVEK3W1yTIO3HbDYnSiSEwMHjx9x755d893tvMck6xBjpdrtbAIJgtMF7z+lshjEGBKJE7v\/hPu\/\/6X3YBGyNsUgMLKsKgHS4A+LIlWZvundtwiqlGI\/HeO8RIE1TvvjK51lnXTpFjnOeyWSyXbsFJkK\/329\/1xoFfPBBBy50wNokwdehTUgfGGTgPDQSeXT0hOFw+CxLG1vOTvHO45qaTifjM\/2EtXc4cTw6fIwAWZrSKS4xbaFZ19Sn5TUeBWutxddtjogItXiksNzIBhf6PMeGoxFEwTUNEgILaqa9IX1tN3vVtfuyLKPYybbsXTabZzlNVWGNwSlPz2ZgLdXsEHoDdrIeqbYXMWxkEBFUspEDeHoyZy8f4n2kbFZ0i4ydtHdFsnNTSiGJXA8oTRKKNMFojQ+Rk6czer0ukMJszSHrT2UJ4ODjp0h0rI6WaK3QQLX2VKw+dZ+IcLa8vEa1pyzGiNWKTpaD0vR7vf8K4rJTUDTOk2UZeZb+z3vrpiHKJ9h781vflLPDJ\/gYWawqvvzaXbTRNKHBakuR9xh1BiyqOZWr2ekOWIUlRhuWq4rCFDR1w8HBY1763MvU3iOxLSGyAZxazSu3bl8OY8vI8ckxq9UFSxatcSGiFMQYeev7P4CwoogJL+xNKYqrteg8h8qy5HQ2I\/jA6fyEt+\/d4\/XvfJvbWa+V3weyLGN398YlJjcwznNQKX5+7x6\/u\/\/7LUhrjcXHgKLtM+Nugc36pEbhNSxcdT3fiWI0GiJRWJwtWNeO29N9eglXDti1+2PE+E31V1fBWpNYGh\/IrMXHCDTUq8BaBK01vV4Pbcy1mOaLBcF5mqYBEVSomJcNAKPRzvWBAM45lotNHfpEZbGJTfA+bK8EK7\/GpYpJZaGf4Yg4V6O9wkWPTS3BRUxqMEXOJO9ztlxSlSvyYMG2JcIv6+cCUkDeaVNhXddXGUoSS4gRrRXr2lHYDJ2knJUzupJh5jMY9AiugsQi3rEONQM1pJwfEW3bEpzz\/PnDD7GpZTC4Wt07OmV+espqc2s4H9PplHXjrgKySUIMHowmRE+IkVlzRsg7OLcCr5lojRRdOicV9aRgnHWpQ0NnNGCY9amLBa\/eucP+Sy8wHT4r1b+eHG5yJWJMQtM02+Z73uXPpbNGKTp5ijWGQb9PHgzjbHDhbQT4zXyY0NnMUzJQ4KuGqlwRXIWuNIfrGUh7D2pLlJCTUm3++7wxdzenV0SQeImhEDyrqqbxgRd3xzw9WdBZOxaLM87OzphMJuR53gahWq8P\/\/kPbJKyv7+PQnE0XxLl+r61NQGtNU3TUNc1eZ5jjGlrVgjbE2cVQu08L+6O6XYy0sRwc3fCzd3Jc33vTy+eRRGeHDzib395wE9+9ENO5nNW5Zq6cWir2RsNGfR6IBGUxgtom6CNRSnN6ekxwTu0NqAUVmvNF26\/TGhqQgi884u36XRy0jRjNp+zWp6hNBtaFc57JApGw6DfxyQps5Njbt26zZuvfY0bX70DtGyUZcVoZ0TR6XB0dERZVkSJiAhJkqC15je\/\/hXvvvtbYowopbHl4pQ0TTmrVoyGA9584w3SNCXJMrzzxBjay5yA0np75VSAsRalFA8fPuS99\/7IZ++MWSYKHzxpalBYKnF4B+mwSzpsE1mJXBRGgRgFpdphk7wgzhcMRjuMxhMmpWB85DjWGGNIs5ymaUiShG6vS+\/8dGxACVCWFSKRj+0Obj5DRBiPJ6RpCgjeOTYvOgDUVU29WKGUwvuG4B1KG5RS\/Af3xoJXKXZWkwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022640.45616535994\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EBequemer Service f\u00fcr best\u00e4tigen und generieren von Steuer-IdNr., IBAN, TIN, ISBN, EAN, Kennw\u00f6rter...\u003C\/p\u003E\n\u003Cp\u003EAuch als API und NPM package verf\u00fcgbar.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["best\u00e4tigen","ean","express","generator","generieren","iban","isbn","javascript","kennwort","node","nodejs","nummer","passwort","steueridentifikationsnummer","tin","validator","webpack"],"hasMore":false,"image":"https:\/\/avris.it\/image\/generator_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160.11404133999\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EBequemer Service f\u00fcr best\u00e4tigen und generieren von Steuer-IdNr., IBAN, TIN, ISBN, EAN, Kennw\u00f6rter...\u003C\/p\u003E\n\u003Cp\u003EAuch als API und NPM package verf\u00fcgbar.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160.11404133999\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EBequemer Service f\u00fcr best\u00e4tigen und generieren von Steuer-IdNr., IBAN, TIN, ISBN, EAN, Kennw\u00f6rter...\u003C\/p\u003E\n\u003Cp\u003EAuch als API und NPM package verf\u00fcgbar.\u003C\/p\u003E","words":24,"readTime":null,"lang":"de"},"en":{"slug":"generator-and-validator-of-numbers-and-identifiers","title":"Generator and validator of numbers and identifiers","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320.22808267997\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGqUlEQVRIiaWXu48kVxXGf\/dRj65+TvdOj70DGK9XAmmxAG3ilNABSMb8AUjkyAkBMTEpARIBCWaRJWJAwgksEpaxRLASYAOrhdn1zqu7p7uqq+7jEFRPz4x31iBxpKu+3XXv6e9837nn3FJf\/8brYo2l6Hbp9Qd0Ol2U0vw\/JiLns813gHh5wfap2s4FBGyWJBhjcU3D7PSY3cmENC8oy4qmqcmyHO89RVGwXq8JwaOUxhgNKGKMxBjw3gPgBEJoEHcBwPiAIASjUEqRJymIUNZrksRijEG1eLBsnIcQCc4xne7ROM9Hf\/+Ifq9PVZWUZYnWmul0Slmu6PcHOOeo1hX9Xo+Dx\/+mqWuUUri4YSAGlFIoBTd2hiRJRogKEcGva4iCMmpDlkI2iNTdu18RrYQY2ohskjAc7\/DgwV\/pdgvUJkql1JZtQVAXgrSOAFGGPMtQSDuUpnENezdv8qU7rz4jZyuTtH5EAMFqo7FaIzoSY+THP\/0ZWapIVEK3W1yTIO3HbDYnSiSEwMHjx9x755d893tvMck6xBjpdrtbAIJgtMF7z+lshjEGBKJE7v\/hPu\/\/6X3YBGyNsUgMLKsKgHS4A+LIlWZvundtwiqlGI\/HeO8RIE1TvvjK51lnXTpFjnOeyWSyXbsFJkK\/329\/1xoFfPBBBy50wNokwdehTUgfGGTgPDQSeXT0hOFw+CxLG1vOTvHO45qaTifjM\/2EtXc4cTw6fIwAWZrSKS4xbaFZ19Sn5TUeBWutxddtjogItXiksNzIBhf6PMeGoxFEwTUNEgILaqa9IX1tN3vVtfuyLKPYybbsXTabZzlNVWGNwSlPz2ZgLdXsEHoDdrIeqbYXMWxkEBFUspEDeHoyZy8f4n2kbFZ0i4ydtHdFsnNTSiGJXA8oTRKKNMFojQ+Rk6czer0ukMJszSHrT2UJ4ODjp0h0rI6WaK3QQLX2VKw+dZ+IcLa8vEa1pyzGiNWKTpaD0vR7vf8K4rJTUDTOk2UZeZb+z3vrpiHKJ9h781vflLPDJ\/gYWawqvvzaXbTRNKHBakuR9xh1BiyqOZWr2ekOWIUlRhuWq4rCFDR1w8HBY1763MvU3iOxLSGyAZxazSu3bl8OY8vI8ckxq9UFSxatcSGiFMQYeev7P4CwoogJL+xNKYqrteg8h8qy5HQ2I\/jA6fyEt+\/d4\/XvfJvbWa+V3weyLGN398YlJjcwznNQKX5+7x6\/u\/\/7LUhrjcXHgKLtM+Nugc36pEbhNSxcdT3fiWI0GiJRWJwtWNeO29N9eglXDti1+2PE+E31V1fBWpNYGh\/IrMXHCDTUq8BaBK01vV4Pbcy1mOaLBcF5mqYBEVSomJcNAKPRzvWBAM45lotNHfpEZbGJTfA+bK8EK7\/GpYpJZaGf4Yg4V6O9wkWPTS3BRUxqMEXOJO9ztlxSlSvyYMG2JcIv6+cCUkDeaVNhXddXGUoSS4gRrRXr2lHYDJ2knJUzupJh5jMY9AiugsQi3rEONQM1pJwfEW3bEpzz\/PnDD7GpZTC4Wt07OmV+espqc2s4H9PplHXjrgKySUIMHowmRE+IkVlzRsg7OLcCr5lojRRdOicV9aRgnHWpQ0NnNGCY9amLBa\/eucP+Sy8wHT4r1b+eHG5yJWJMQtM02+Z73uXPpbNGKTp5ijWGQb9PHgzjbHDhbQT4zXyY0NnMUzJQ4KuGqlwRXIWuNIfrGUh7D2pLlJCTUm3++7wxdzenV0SQeImhEDyrqqbxgRd3xzw9WdBZOxaLM87OzphMJuR53gahWq8P\/\/kPbJKyv7+PQnE0XxLl+r61NQGtNU3TUNc1eZ5jjGlrVgjbE2cVQu08L+6O6XYy0sRwc3fCzd3Jc33vTy+eRRGeHDzib395wE9+9ENO5nNW5Zq6cWir2RsNGfR6IBGUxgtom6CNRSnN6ekxwTu0NqAUVmvNF26\/TGhqQgi884u36XRy0jRjNp+zWp6hNBtaFc57JApGw6DfxyQps5Njbt26zZuvfY0bX70DtGyUZcVoZ0TR6XB0dERZVkSJiAhJkqC15je\/\/hXvvvtbYowopbHl4pQ0TTmrVoyGA9584w3SNCXJMrzzxBjay5yA0np75VSAsRalFA8fPuS99\/7IZ++MWSYKHzxpalBYKnF4B+mwSzpsE1mJXBRGgRgFpdphk7wgzhcMRjuMxhMmpWB85DjWGGNIs5ymaUiShG6vS+\/8dGxACVCWFSKRj+0Obj5DRBiPJ6RpCgjeOTYvOgDUVU29WKGUwvuG4B1KG5RS\/Af3xoJXKXZWkwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/generator_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320.22808267997\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EGenerate and validate numbers and identifiers like IBAN, ISBN, EAN, PESEL, BSN, passwords...\u003C\/p\u003E\n\u003Cp\u003EAlso available as and API and an NPM package.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022640.45616535994\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGqUlEQVRIiaWXu48kVxXGf\/dRj65+TvdOj70DGK9XAmmxAG3ilNABSMb8AUjkyAkBMTEpARIBCWaRJWJAwgksEpaxRLASYAOrhdn1zqu7p7uqq+7jEFRPz4x31iBxpKu+3XXv6e9837nn3FJf\/8brYo2l6Hbp9Qd0Ol2U0vw\/JiLns813gHh5wfap2s4FBGyWJBhjcU3D7PSY3cmENC8oy4qmqcmyHO89RVGwXq8JwaOUxhgNKGKMxBjw3gPgBEJoEHcBwPiAIASjUEqRJymIUNZrksRijEG1eLBsnIcQCc4xne7ROM9Hf\/+Ifq9PVZWUZYnWmul0Slmu6PcHOOeo1hX9Xo+Dx\/+mqWuUUri4YSAGlFIoBTd2hiRJRogKEcGva4iCMmpDlkI2iNTdu18RrYQY2ohskjAc7\/DgwV\/pdgvUJkql1JZtQVAXgrSOAFGGPMtQSDuUpnENezdv8qU7rz4jZyuTtH5EAMFqo7FaIzoSY+THP\/0ZWapIVEK3W1yTIO3HbDYnSiSEwMHjx9x755d893tvMck6xBjpdrtbAIJgtMF7z+lshjEGBKJE7v\/hPu\/\/6X3YBGyNsUgMLKsKgHS4A+LIlWZvundtwiqlGI\/HeO8RIE1TvvjK51lnXTpFjnOeyWSyXbsFJkK\/329\/1xoFfPBBBy50wNokwdehTUgfGGTgPDQSeXT0hOFw+CxLG1vOTvHO45qaTifjM\/2EtXc4cTw6fIwAWZrSKS4xbaFZ19Sn5TUeBWutxddtjogItXiksNzIBhf6PMeGoxFEwTUNEgILaqa9IX1tN3vVtfuyLKPYybbsXTabZzlNVWGNwSlPz2ZgLdXsEHoDdrIeqbYXMWxkEBFUspEDeHoyZy8f4n2kbFZ0i4ydtHdFsnNTSiGJXA8oTRKKNMFojQ+Rk6czer0ukMJszSHrT2UJ4ODjp0h0rI6WaK3QQLX2VKw+dZ+IcLa8vEa1pyzGiNWKTpaD0vR7vf8K4rJTUDTOk2UZeZb+z3vrpiHKJ9h781vflLPDJ\/gYWawqvvzaXbTRNKHBakuR9xh1BiyqOZWr2ekOWIUlRhuWq4rCFDR1w8HBY1763MvU3iOxLSGyAZxazSu3bl8OY8vI8ckxq9UFSxatcSGiFMQYeev7P4CwoogJL+xNKYqrteg8h8qy5HQ2I\/jA6fyEt+\/d4\/XvfJvbWa+V3weyLGN398YlJjcwznNQKX5+7x6\/u\/\/7LUhrjcXHgKLtM+Nugc36pEbhNSxcdT3fiWI0GiJRWJwtWNeO29N9eglXDti1+2PE+E31V1fBWpNYGh\/IrMXHCDTUq8BaBK01vV4Pbcy1mOaLBcF5mqYBEVSomJcNAKPRzvWBAM45lotNHfpEZbGJTfA+bK8EK7\/GpYpJZaGf4Yg4V6O9wkWPTS3BRUxqMEXOJO9ztlxSlSvyYMG2JcIv6+cCUkDeaVNhXddXGUoSS4gRrRXr2lHYDJ2knJUzupJh5jMY9AiugsQi3rEONQM1pJwfEW3bEpzz\/PnDD7GpZTC4Wt07OmV+espqc2s4H9PplHXjrgKySUIMHowmRE+IkVlzRsg7OLcCr5lojRRdOicV9aRgnHWpQ0NnNGCY9amLBa\/eucP+Sy8wHT4r1b+eHG5yJWJMQtM02+Z73uXPpbNGKTp5ijWGQb9PHgzjbHDhbQT4zXyY0NnMUzJQ4KuGqlwRXIWuNIfrGUh7D2pLlJCTUm3++7wxdzenV0SQeImhEDyrqqbxgRd3xzw9WdBZOxaLM87OzphMJuR53gahWq8P\/\/kPbJKyv7+PQnE0XxLl+r61NQGtNU3TUNc1eZ5jjGlrVgjbE2cVQu08L+6O6XYy0sRwc3fCzd3Jc33vTy+eRRGeHDzib395wE9+9ENO5nNW5Zq6cWir2RsNGfR6IBGUxgtom6CNRSnN6ekxwTu0NqAUVmvNF26\/TGhqQgi884u36XRy0jRjNp+zWp6hNBtaFc57JApGw6DfxyQps5Njbt26zZuvfY0bX70DtGyUZcVoZ0TR6XB0dERZVkSJiAhJkqC15je\/\/hXvvvtbYowopbHl4pQ0TTmrVoyGA9584w3SNCXJMrzzxBjay5yA0np75VSAsRalFA8fPuS99\/7IZ++MWSYKHzxpalBYKnF4B+mwSzpsE1mJXBRGgRgFpdphk7wgzhcMRjuMxhMmpWB85DjWGGNIs5ymaUiShG6vS+\/8dGxACVCWFSKRj+0Obj5DRBiPJ6RpCgjeOTYvOgDUVU29WKGUwvuG4B1KG5RS\/Af3xoJXKXZWkwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022640.45616535994\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EGenerate and validate numbers and identifiers like IBAN, ISBN, EAN, PESEL, BSN, passwords...\u003C\/p\u003E\n\u003Cp\u003EAlso available as and API and an NPM package.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["checksum","express","generate","generator","iban","identifier","isbn","javascript","node","nodejs","numbers","validate","validator","webpack"],"hasMore":false,"image":"https:\/\/avris.it\/image\/generator_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160.11404133999\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EGenerate and validate numbers and identifiers like IBAN, ISBN, EAN, PESEL, BSN, passwords...\u003C\/p\u003E\n\u003Cp\u003EAlso available as and API and an NPM package.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160.11404133999\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EGenerate and validate numbers and identifiers like IBAN, ISBN, EAN, PESEL, BSN, passwords...\u003C\/p\u003E\n\u003Cp\u003EAlso available as and API and an NPM package.\u003C\/p\u003E","words":22,"readTime":null,"lang":"en"},"pl":{"slug":"generator-numer\u00f3w","title":"Generator numer\u00f3w","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320.22808267997\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGqUlEQVRIiaWXu48kVxXGf\/dRj65+TvdOj70DGK9XAmmxAG3ilNABSMb8AUjkyAkBMTEpARIBCWaRJWJAwgksEpaxRLASYAOrhdn1zqu7p7uqq+7jEFRPz4x31iBxpKu+3XXv6e9837nn3FJf\/8brYo2l6Hbp9Qd0Ol2U0vw\/JiLns813gHh5wfap2s4FBGyWJBhjcU3D7PSY3cmENC8oy4qmqcmyHO89RVGwXq8JwaOUxhgNKGKMxBjw3gPgBEJoEHcBwPiAIASjUEqRJymIUNZrksRijEG1eLBsnIcQCc4xne7ROM9Hf\/+Ifq9PVZWUZYnWmul0Slmu6PcHOOeo1hX9Xo+Dx\/+mqWuUUri4YSAGlFIoBTd2hiRJRogKEcGva4iCMmpDlkI2iNTdu18RrYQY2ohskjAc7\/DgwV\/pdgvUJkql1JZtQVAXgrSOAFGGPMtQSDuUpnENezdv8qU7rz4jZyuTtH5EAMFqo7FaIzoSY+THP\/0ZWapIVEK3W1yTIO3HbDYnSiSEwMHjx9x755d893tvMck6xBjpdrtbAIJgtMF7z+lshjEGBKJE7v\/hPu\/\/6X3YBGyNsUgMLKsKgHS4A+LIlWZvundtwiqlGI\/HeO8RIE1TvvjK51lnXTpFjnOeyWSyXbsFJkK\/329\/1xoFfPBBBy50wNokwdehTUgfGGTgPDQSeXT0hOFw+CxLG1vOTvHO45qaTifjM\/2EtXc4cTw6fIwAWZrSKS4xbaFZ19Sn5TUeBWutxddtjogItXiksNzIBhf6PMeGoxFEwTUNEgILaqa9IX1tN3vVtfuyLKPYybbsXTabZzlNVWGNwSlPz2ZgLdXsEHoDdrIeqbYXMWxkEBFUspEDeHoyZy8f4n2kbFZ0i4ydtHdFsnNTSiGJXA8oTRKKNMFojQ+Rk6czer0ukMJszSHrT2UJ4ODjp0h0rI6WaK3QQLX2VKw+dZ+IcLa8vEa1pyzGiNWKTpaD0vR7vf8K4rJTUDTOk2UZeZb+z3vrpiHKJ9h781vflLPDJ\/gYWawqvvzaXbTRNKHBakuR9xh1BiyqOZWr2ekOWIUlRhuWq4rCFDR1w8HBY1763MvU3iOxLSGyAZxazSu3bl8OY8vI8ckxq9UFSxatcSGiFMQYeev7P4CwoogJL+xNKYqrteg8h8qy5HQ2I\/jA6fyEt+\/d4\/XvfJvbWa+V3weyLGN398YlJjcwznNQKX5+7x6\/u\/\/7LUhrjcXHgKLtM+Nugc36pEbhNSxcdT3fiWI0GiJRWJwtWNeO29N9eglXDti1+2PE+E31V1fBWpNYGh\/IrMXHCDTUq8BaBK01vV4Pbcy1mOaLBcF5mqYBEVSomJcNAKPRzvWBAM45lotNHfpEZbGJTfA+bK8EK7\/GpYpJZaGf4Yg4V6O9wkWPTS3BRUxqMEXOJO9ztlxSlSvyYMG2JcIv6+cCUkDeaVNhXddXGUoSS4gRrRXr2lHYDJ2knJUzupJh5jMY9AiugsQi3rEONQM1pJwfEW3bEpzz\/PnDD7GpZTC4Wt07OmV+espqc2s4H9PplHXjrgKySUIMHowmRE+IkVlzRsg7OLcCr5lojRRdOicV9aRgnHWpQ0NnNGCY9amLBa\/eucP+Sy8wHT4r1b+eHG5yJWJMQtM02+Z73uXPpbNGKTp5ijWGQb9PHgzjbHDhbQT4zXyY0NnMUzJQ4KuGqlwRXIWuNIfrGUh7D2pLlJCTUm3++7wxdzenV0SQeImhEDyrqqbxgRd3xzw9WdBZOxaLM87OzphMJuR53gahWq8P\/\/kPbJKyv7+PQnE0XxLl+r61NQGtNU3TUNc1eZ5jjGlrVgjbE2cVQu08L+6O6XYy0sRwc3fCzd3Jc33vTy+eRRGeHDzib395wE9+9ENO5nNW5Zq6cWir2RsNGfR6IBGUxgtom6CNRSnN6ekxwTu0NqAUVmvNF26\/TGhqQgi884u36XRy0jRjNp+zWp6hNBtaFc57JApGw6DfxyQps5Njbt26zZuvfY0bX70DtGyUZcVoZ0TR6XB0dERZVkSJiAhJkqC15je\/\/hXvvvtbYowopbHl4pQ0TTmrVoyGA9584w3SNCXJMrzzxBjay5yA0np75VSAsRalFA8fPuS99\/7IZ++MWSYKHzxpalBYKnF4B+mwSzpsE1mJXBRGgRgFpdphk7wgzhcMRjuMxhMmpWB85DjWGGNIs5ymaUiShG6vS+\/8dGxACVCWFSKRj+0Obj5DRBiPJ6RpCgjeOTYvOgDUVU29WKGUwvuG4B1KG5RS\/Af3xoJXKXZWkwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/generator_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320.22808267997\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWygodne narz\u0119dzie do walidowania i generowania numer\u00f3w PESEL, NIP, REGON, numeru dowodu osobistego, rachunku bankowego, hase\u0142 itp.\u003C\/p\u003E\n\u003Cp\u003EDost\u0119pny r\u00f3wnie\u017c jako API oraz pakiet NPM.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022640.45616535994\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGqUlEQVRIiaWXu48kVxXGf\/dRj65+TvdOj70DGK9XAmmxAG3ilNABSMb8AUjkyAkBMTEpARIBCWaRJWJAwgksEpaxRLASYAOrhdn1zqu7p7uqq+7jEFRPz4x31iBxpKu+3XXv6e9837nn3FJf\/8brYo2l6Hbp9Qd0Ol2U0vw\/JiLns813gHh5wfap2s4FBGyWJBhjcU3D7PSY3cmENC8oy4qmqcmyHO89RVGwXq8JwaOUxhgNKGKMxBjw3gPgBEJoEHcBwPiAIASjUEqRJymIUNZrksRijEG1eLBsnIcQCc4xne7ROM9Hf\/+Ifq9PVZWUZYnWmul0Slmu6PcHOOeo1hX9Xo+Dx\/+mqWuUUri4YSAGlFIoBTd2hiRJRogKEcGva4iCMmpDlkI2iNTdu18RrYQY2ohskjAc7\/DgwV\/pdgvUJkql1JZtQVAXgrSOAFGGPMtQSDuUpnENezdv8qU7rz4jZyuTtH5EAMFqo7FaIzoSY+THP\/0ZWapIVEK3W1yTIO3HbDYnSiSEwMHjx9x755d893tvMck6xBjpdrtbAIJgtMF7z+lshjEGBKJE7v\/hPu\/\/6X3YBGyNsUgMLKsKgHS4A+LIlWZvundtwiqlGI\/HeO8RIE1TvvjK51lnXTpFjnOeyWSyXbsFJkK\/329\/1xoFfPBBBy50wNokwdehTUgfGGTgPDQSeXT0hOFw+CxLG1vOTvHO45qaTifjM\/2EtXc4cTw6fIwAWZrSKS4xbaFZ19Sn5TUeBWutxddtjogItXiksNzIBhf6PMeGoxFEwTUNEgILaqa9IX1tN3vVtfuyLKPYybbsXTabZzlNVWGNwSlPz2ZgLdXsEHoDdrIeqbYXMWxkEBFUspEDeHoyZy8f4n2kbFZ0i4ydtHdFsnNTSiGJXA8oTRKKNMFojQ+Rk6czer0ukMJszSHrT2UJ4ODjp0h0rI6WaK3QQLX2VKw+dZ+IcLa8vEa1pyzGiNWKTpaD0vR7vf8K4rJTUDTOk2UZeZb+z3vrpiHKJ9h781vflLPDJ\/gYWawqvvzaXbTRNKHBakuR9xh1BiyqOZWr2ekOWIUlRhuWq4rCFDR1w8HBY1763MvU3iOxLSGyAZxazSu3bl8OY8vI8ckxq9UFSxatcSGiFMQYeev7P4CwoogJL+xNKYqrteg8h8qy5HQ2I\/jA6fyEt+\/d4\/XvfJvbWa+V3weyLGN398YlJjcwznNQKX5+7x6\/u\/\/7LUhrjcXHgKLtM+Nugc36pEbhNSxcdT3fiWI0GiJRWJwtWNeO29N9eglXDti1+2PE+E31V1fBWpNYGh\/IrMXHCDTUq8BaBK01vV4Pbcy1mOaLBcF5mqYBEVSomJcNAKPRzvWBAM45lotNHfpEZbGJTfA+bK8EK7\/GpYpJZaGf4Yg4V6O9wkWPTS3BRUxqMEXOJO9ztlxSlSvyYMG2JcIv6+cCUkDeaVNhXddXGUoSS4gRrRXr2lHYDJ2knJUzupJh5jMY9AiugsQi3rEONQM1pJwfEW3bEpzz\/PnDD7GpZTC4Wt07OmV+espqc2s4H9PplHXjrgKySUIMHowmRE+IkVlzRsg7OLcCr5lojRRdOicV9aRgnHWpQ0NnNGCY9amLBa\/eucP+Sy8wHT4r1b+eHG5yJWJMQtM02+Z73uXPpbNGKTp5ijWGQb9PHgzjbHDhbQT4zXyY0NnMUzJQ4KuGqlwRXIWuNIfrGUh7D2pLlJCTUm3++7wxdzenV0SQeImhEDyrqqbxgRd3xzw9WdBZOxaLM87OzphMJuR53gahWq8P\/\/kPbJKyv7+PQnE0XxLl+r61NQGtNU3TUNc1eZ5jjGlrVgjbE2cVQu08L+6O6XYy0sRwc3fCzd3Jc33vTy+eRRGeHDzib395wE9+9ENO5nNW5Zq6cWir2RsNGfR6IBGUxgtom6CNRSnN6ekxwTu0NqAUVmvNF26\/TGhqQgi884u36XRy0jRjNp+zWp6hNBtaFc57JApGw6DfxyQps5Njbt26zZuvfY0bX70DtGyUZcVoZ0TR6XB0dERZVkSJiAhJkqC15je\/\/hXvvvtbYowopbHl4pQ0TTmrVoyGA9584w3SNCXJMrzzxBjay5yA0np75VSAsRalFA8fPuS99\/7IZ++MWSYKHzxpalBYKnF4B+mwSzpsE1mJXBRGgRgFpdphk7wgzhcMRjuMxhMmpWB85DjWGGNIs5ymaUiShG6vS+\/8dGxACVCWFSKRj+0Obj5DRBiPJ6RpCgjeOTYvOgDUVU29WKGUwvuG4B1KG5RS\/Af3xoJXKXZWkwAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022640.45616535994\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWygodne narz\u0119dzie do walidowania i generowania numer\u00f3w PESEL, NIP, REGON, numeru dowodu osobistego, rachunku bankowego, hase\u0142 itp.\u003C\/p\u003E\n\u003Cp\u003EDost\u0119pny r\u00f3wnie\u017c jako API oraz pakiet NPM.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["coffeescript","dow\u00f3d osobisty","express","has\u0142o","iban","javascript","nip","node","nodejs","numer","pesel","rachunek bankowy","regon","webpack"],"hasMore":false,"image":"https:\/\/avris.it\/image\/generator_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160.11404133999\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWygodne narz\u0119dzie do walidowania i generowania numer\u00f3w PESEL, NIP, REGON, numeru dowodu osobistego, rachunku bankowego, hase\u0142 itp.\u003C\/p\u003E\n\u003Cp\u003EDost\u0119pny r\u00f3wnie\u017c jako API oraz pakiet NPM.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/generator_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/generator_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160.11404133999\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWygodne narz\u0119dzie do walidowania i generowania numer\u00f3w PESEL, NIP, REGON, numeru dowodu osobistego, rachunku bankowego, hase\u0142 itp.\u003C\/p\u003E\n\u003Cp\u003EDost\u0119pny r\u00f3wnie\u017c jako API oraz pakiet NPM.\u003C\/p\u003E","words":28,"readTime":null,"lang":"pl"}}},"projects\/can-i-go-home-now":{"key":"projects\/can-i-go-home-now","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:45+02:00","publishedAt":"2015-12-10T13:39:00+01:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/canigohome.avris.it\/","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/GoHome","displayUrl":null}],"category":"projects","subcategory":null,"slug":"can-i-go-home-now"},"content":{"en":{"slug":"can-i-go-home-now","title":"Can I go home now?","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022239.24882629108\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGbklEQVRIiV2WuW4TXxuHn5kzS+xxbMd2Fi8xTkgiBAWhAAmFCCgiKGhYGi6Aq6DJTXADFAiJkooOmoQKCMIgpKBAEi\/xJHa8jGc861cgRvp\/U56RzvZ7zvO+0rt37yLXdWk0Guzv73N4eEij0aBQKHDr1i10XefLly\/UajWCIKBcLjM\/P08ymcQwDCRJwjAMyuUyAJ1Oh0KhgBACgDAMiaIIWZYxDIMgCBgMBkiSxGQy4cePH+RyOXzfp9VqoaiqyqtXr+j3+xwdHXFycsLdu3fJZrO8fv2alZUV7t27R7PZxLIsjo6OODs7QwhBpVJhbm4Ox3EIw5B8Po9hGLiui6qqSJJEGIaEYUgmkwHAcZx4g0EQMB6PEUIghCAIApSPHz9Sr9dxXZd8Ps\/t27f59OkT79+\/J5\/Ps7y8jO\/7rK+vc3BwQBAEHB8fA1AsFomiCMdxME0zvi0ASZKQZZkoikgmkwghcF0Xx3Hicd\/3MQyDZDJJo9HAcRxEtVrd\/vz5M2tra2xsbPDy5Uva7TbXrl1jeXmZhYUFgiBgOBxSKpUAEEKgqipCCMIwpFQqMT09jaIoWJaFrusAFAoFoigiCAISiQTn5+eYpkkikUBRFPr9Pp1OJ57PdV2UbrfLs2fPaLVavHnzBs\/zWFpaIpfLsbu7C8DMzAySJHF2dkalUsFxHEajEZIkoaoq37594+rVqwCUSiXS6XQcSSqVQpIk\/v8bDAZ4nkcQBERRRLPZpFgsIjRN2378+DEvXrxACMFoNCKZTLK3t4dpmqytraGqKr7v4zgOtm2ztLREJpNBURT+\/PnD6ekppVIJWZYxTRMAXddRFIUgCPB9nyAIcF2XbreLpmlkMhnG4zG9Xg\/f97EsCwB5amqKTqdDLpej0+lgWRYHBwckEgkymQypVCqGLpvNIoTAtm2EEDFL09PT9Pt9PM\/D933a7Tau68ZRRFGEaZpYloUQgkwmQxiGDIdDbNtmMpkgyzKj0QhlcXGR58+f8\/TpU6Iool6vI4RgOBySy+XQdR3DMBBCkMvlkGWZbDaLJEmkUimCIIg3ValU4n+apiFJElEUoaoqxWKRTqeDruuEYYjv+zFfsiyjqiqmaSL29\/e3wzDk69ev3Lx5k3Q6TavVIpVK0e12WVlZIZ1Ok06nmZ2dpVKp\/Of1HB8fx4tOJhMGgwG9Xg9FUUgmk0wmE2zbJgxDxuMxh4eHNJtNRqMRg8EA3\/dJpVJEUfQ3CVVVt\/\/Jq16vU6vVWFlZod1uk0wmWV9fJ5PJkMlkYrgVRUFVVTzPo1QqMZlMGA6HDAYD2u02p6endLtdhBBEUYRlWfi+j+u61Ot1wjDEdV1s22ZqaoowDJmbm\/ubhKqq257nxQAeHR2haRqbm5t0Oh0uX77MhQsXmJ6exrZtHMchCAJmZmZQFOVv7opCuzuicXhAr9fDNE0cx0FRFDzPw7btWBPtdpswDAHQNC3G4t+YAqCqKqqqIssyruvy8+dPPM\/jwYMHzM\/P47oug8EAXdfxfT+ePJ\/PM5lMODw8pFKugjvC933m5uYoFAo0m02GwyGLi4sIIZBlGUVRSCQSWJaFpmn0ej263S6GYZDP51GEEExNTREEQfwioiji169f\/P79O2YhDEMKhQKzs7NIkkS328W2bTzP4\/z8HNd1WV1djQ28uroKwM7ODslkkmKxCMDe3h7VapVisYiu6\/R6PRKJBLlc7q8Yx+MxhmHgeR7pdBrf95FlmStXrnBwcMDi4iKqqsZ2\/ReX67qcnp7G9cuyLFRV5eTkBNM0GY\/HhGGI4zh0Oh16vR75fJ5yuYymaWiahq7rJJNJbNvm\/PycQqGABESqqsYykySJra0tTk5OODk5wbZtxuMxiUQCx3HQNI3JZEK5XMayLC5dukS9XscwDGq1GsPhkO\/fv8cHK5fLTE9Ps76+zo0bN5BlmX6\/T6lUiotyo9GgVqthGAayLMux0BYWFnjy5Ak7Ozvs7Ozgui6SJBEEAaPRCF3XUVWVfD4fl490Os2jR4+4ePEiHz58QJIkNjY2CMMQWZapVqtsbW3x8OFDNjc3Y5Zc1yWbzcbdwXg8\/lv579y5s22aJvfv30dRFN6+fctkMolbhX9Q+74fC83zPBzHYW5ujoWFBSqVCru7u\/T7fVqtFrlcjuvXr+N5HsvLy1SrVVZXVxmNRjHM\/3opx3GoVquxy\/4H69Nv42Fs0AsAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022239.24882629108\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022478.49765258216\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGbklEQVRIiV2WuW4TXxuHn5kzS+xxbMd2Fi8xTkgiBAWhAAmFCCgiKGhYGi6Aq6DJTXADFAiJkooOmoQKCMIgpKBAEi\/xJHa8jGc861cgRvp\/U56RzvZ7zvO+0rt37yLXdWk0Guzv73N4eEij0aBQKHDr1i10XefLly\/UajWCIKBcLjM\/P08ymcQwDCRJwjAMyuUyAJ1Oh0KhgBACgDAMiaIIWZYxDIMgCBgMBkiSxGQy4cePH+RyOXzfp9VqoaiqyqtXr+j3+xwdHXFycsLdu3fJZrO8fv2alZUV7t27R7PZxLIsjo6OODs7QwhBpVJhbm4Ox3EIw5B8Po9hGLiui6qqSJJEGIaEYUgmkwHAcZx4g0EQMB6PEUIghCAIApSPHz9Sr9dxXZd8Ps\/t27f59OkT79+\/J5\/Ps7y8jO\/7rK+vc3BwQBAEHB8fA1AsFomiCMdxME0zvi0ASZKQZZkoikgmkwghcF0Xx3Hicd\/3MQyDZDJJo9HAcRxEtVrd\/vz5M2tra2xsbPDy5Uva7TbXrl1jeXmZhYUFgiBgOBxSKpUAEEKgqipCCMIwpFQqMT09jaIoWJaFrusAFAoFoigiCAISiQTn5+eYpkkikUBRFPr9Pp1OJ57PdV2UbrfLs2fPaLVavHnzBs\/zWFpaIpfLsbu7C8DMzAySJHF2dkalUsFxHEajEZIkoaoq37594+rVqwCUSiXS6XQcSSqVQpIk\/v8bDAZ4nkcQBERRRLPZpFgsIjRN2378+DEvXrxACMFoNCKZTLK3t4dpmqytraGqKr7v4zgOtm2ztLREJpNBURT+\/PnD6ekppVIJWZYxTRMAXddRFIUgCPB9nyAIcF2XbreLpmlkMhnG4zG9Xg\/f97EsCwB5amqKTqdDLpej0+lgWRYHBwckEgkymQypVCqGLpvNIoTAtm2EEDFL09PT9Pt9PM\/D933a7Tau68ZRRFGEaZpYloUQgkwmQxiGDIdDbNtmMpkgyzKj0QhlcXGR58+f8\/TpU6Iool6vI4RgOBySy+XQdR3DMBBCkMvlkGWZbDaLJEmkUimCIIg3ValU4n+apiFJElEUoaoqxWKRTqeDruuEYYjv+zFfsiyjqiqmaSL29\/e3wzDk69ev3Lx5k3Q6TavVIpVK0e12WVlZIZ1Ok06nmZ2dpVKp\/Of1HB8fx4tOJhMGgwG9Xg9FUUgmk0wmE2zbJgxDxuMxh4eHNJtNRqMRg8EA3\/dJpVJEUfQ3CVVVt\/\/Jq16vU6vVWFlZod1uk0wmWV9fJ5PJkMlkYrgVRUFVVTzPo1QqMZlMGA6HDAYD2u02p6endLtdhBBEUYRlWfi+j+u61Ot1wjDEdV1s22ZqaoowDJmbm\/ubhKqq257nxQAeHR2haRqbm5t0Oh0uX77MhQsXmJ6exrZtHMchCAJmZmZQFOVv7opCuzuicXhAr9fDNE0cx0FRFDzPw7btWBPtdpswDAHQNC3G4t+YAqCqKqqqIssyruvy8+dPPM\/jwYMHzM\/P47oug8EAXdfxfT+ePJ\/PM5lMODw8pFKugjvC933m5uYoFAo0m02GwyGLi4sIIZBlGUVRSCQSWJaFpmn0ej263S6GYZDP51GEEExNTREEQfwioiji169f\/P79O2YhDEMKhQKzs7NIkkS328W2bTzP4\/z8HNd1WV1djQ28uroKwM7ODslkkmKxCMDe3h7VapVisYiu6\/R6PRKJBLlc7q8Yx+MxhmHgeR7pdBrf95FlmStXrnBwcMDi4iKqqsZ2\/ReX67qcnp7G9cuyLFRV5eTkBNM0GY\/HhGGI4zh0Oh16vR75fJ5yuYymaWiahq7rJJNJbNvm\/PycQqGABESqqsYykySJra0tTk5OODk5wbZtxuMxiUQCx3HQNI3JZEK5XMayLC5dukS9XscwDGq1GsPhkO\/fv8cHK5fLTE9Ps76+zo0bN5BlmX6\/T6lUiotyo9GgVqthGAayLMux0BYWFnjy5Ak7Ozvs7Ozgui6SJBEEAaPRCF3XUVWVfD4fl490Os2jR4+4ePEiHz58QJIkNjY2CMMQWZapVqtsbW3x8OFDNjc3Y5Zc1yWbzcbdwXg8\/lv579y5s22aJvfv30dRFN6+fctkMolbhX9Q+74fC83zPBzHYW5ujoWFBSqVCru7u\/T7fVqtFrlcjuvXr+N5HsvLy1SrVVZXVxmNRjHM\/3opx3GoVquxy\/4H69Nv42Fs0AsAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022478.49765258216\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["assetic","countdown","free time","javascript","job","js","micrus","php","programming","programowanie","weekend"],"hasMore":false,"image":"https:\/\/avris.it\/image\/can-i-go-home-now_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022119.62441314554\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/can-i-go-home-now_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022119.62441314554\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EMissing your cosy home? Come in to find out, if you can stop working already and head back home!\u003C\/p\u003E","words":19,"readTime":null,"lang":"en"}}},"blog\/technology\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji":{"key":"blog\/technology\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:44+02:00","publishedAt":"2015-11-15T00:07:00+01:00","group":null,"category":"blog","subcategory":"technology","slug":"proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji"},"content":{"pl":{"slug":"proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji","title":"Proste potwierdzenie w JavaScripcie, a rozdzielenie warstw aplikacji","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022268.48780487805\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEo0lEQVRIib2WS4\/l1BGAvzoP2\/f6PvtB98AwPfRoIkE2JLCJlCChSInEht+BWOVPBGUb\/k8UKSEPokiwIauMEMOgnu5hOt3X9vXj+FQWvj28pi\/DIqnNsc+pcn1Vripbfvve7zRNE1AFEVClrCrycQ4oddOSZSn\/L3F\/\/\/BDfnT3Dvfvf07oOkZ5TuharHVEhXVRcPv4mPliwXSS\/++B3vjFzwE4PLzxncO+D\/S9kiT+mR7W1GsuLgsmk5wYIwKIsaRZyrqqEAEwm1XxPqUsVozGOXW9Zjqd4rY5sNZh7bNH533Czs4OqnHYUEUBI0KWZWhUEJCNvrGGfDLBGoubTBAR3D\/+9tfBuULcaJorDwoIqAxnUUGu9vQrXQWuuFWGjat1swxgQA9Y73n9tdcHe\/PEGwDus3v\/xhhD3zb4xBNjjxXLYr5gthyi7bqAEWgZgORrEBFFjWA2sBHdAAkRMKpMFgsenpzw+IsHmDSjaOonQN8W18UGgxAk0MUeEyImNfzq7bd4593fPPv7+h5569dvQmjIkpQQr9dzl7Ma3yghF9QprhaCV2o6ROR6y6eIql5rU60uKLVnVZwzdePrgUaXyqhSnEInytopgqAtVGXJ6dkjUKVeVxjryVJP0wacH6om9pG2bTEiQ0d5S90FVJVRlqIi3D46Iu2hFEgEvlU23wQyZWSthpeWMy7WNbkKJ21NH2Gc5xyNh2hEBN1U8g+9Bug3iUsjX7XZ04AEw2KSMZ5mHN3a53HVkdYtUSMhhOstf6CsDIwFlledeh2Qc5bjecLB7ojRfM7zLx\/zyccfYVSpqmqrk3uPalQjsgl5MnLMffxGZpxzOOdAYF+HDG0bbe6Vg5y9vRliDX3XEpuanfmCw9nse4v6wZcrZqbh4dkZL968SdGkuHHg9OEJRbFmb3+f\/f1dvPfkEVzYzLJ+C1AbIYSeto2Uj1aEk3Pu3H2Z3cViKwzAz+7uo8Ard24CYAUEZblcPtG5CkoiBB2yc7klRa5qAqfnNYk1PH\/4Aqo9jsg\/\/\/gH3n\/\/99jNuA0GWrEoCQZBVJl0HWrCMMUjdAa6ONSsN4NNzZCVplqRCSQKflsNjZ1jb+xIfMK6uKBtwTlLJynPzRbc\/+wehkgwsLaGQmBaK8tG6YAygcoPTjvAINRWEYVmc69RsYCYIUPzbW1\/9p+CxAi7S8fqvMBYR914Znu7\/OSXr3F8fsr64jFdH9jdP2Bdlnzwpz\/TdJc4gWBhbcFESKLQGMUgmKjc6KAwyjoRrCqjCJlu7XpMsA69cYtV78lmjmziKC4r6qpEtGM2TZn5hqUPjLxl9\/CQn776KohQGFgLjOPwRceCNeCBpRpmETKBnQh7CDvRMFYIW5DcWW9xnz\/AWOU5C8XlJc5Y0r2K9qO\/YAj0XY1NUtqmJ5\/kHEwNx3du8vGn9wk99D2MRDBGGFnDCEsOnNqWqUvotcfHSOYcKw+1vf6dOQ0N2XjJ8e0Dvvj0hLotufvj28xvHZFmGesvH\/Hgk3+Rj5RYPqQrcyS07IwMdpJRNjX0YH3CC9mYPRU6oPeKj54XJzNWdU1Jj7eOcYwM\/wpPl\/8CWIcTbntq1pMAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022268.48780487805\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022615\u0022 height=\u0022344\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAUCAYAAADlep81AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEo0lEQVRIib2WS4\/l1BGAvzoP2\/f6PvtB98AwPfRoIkE2JLCJlCChSInEht+BWOVPBGUb\/k8UKSEPokiwIauMEMOgnu5hOt3X9vXj+FQWvj28pi\/DIqnNsc+pcn1Vripbfvve7zRNE1AFEVClrCrycQ4oddOSZSn\/L3F\/\/\/BDfnT3Dvfvf07oOkZ5TuharHVEhXVRcPv4mPliwXSS\/++B3vjFzwE4PLzxncO+D\/S9kiT+mR7W1GsuLgsmk5wYIwKIsaRZyrqqEAEwm1XxPqUsVozGOXW9Zjqd4rY5sNZh7bNH533Czs4OqnHYUEUBI0KWZWhUEJCNvrGGfDLBGoubTBAR3D\/+9tfBuULcaJorDwoIqAxnUUGu9vQrXQWuuFWGjat1swxgQA9Y73n9tdcHe\/PEGwDus3v\/xhhD3zb4xBNjjxXLYr5gthyi7bqAEWgZgORrEBFFjWA2sBHdAAkRMKpMFgsenpzw+IsHmDSjaOonQN8W18UGgxAk0MUeEyImNfzq7bd4593fPPv7+h5569dvQmjIkpQQr9dzl7Ma3yghF9QprhaCV2o6ROR6y6eIql5rU60uKLVnVZwzdePrgUaXyqhSnEInytopgqAtVGXJ6dkjUKVeVxjryVJP0wacH6om9pG2bTEiQ0d5S90FVJVRlqIi3D46Iu2hFEgEvlU23wQyZWSthpeWMy7WNbkKJ21NH2Gc5xyNh2hEBN1U8g+9Bug3iUsjX7XZ04AEw2KSMZ5mHN3a53HVkdYtUSMhhOstf6CsDIwFlledeh2Qc5bjecLB7ojRfM7zLx\/zyccfYVSpqmqrk3uPalQjsgl5MnLMffxGZpxzOOdAYF+HDG0bbe6Vg5y9vRliDX3XEpuanfmCw9nse4v6wZcrZqbh4dkZL968SdGkuHHg9OEJRbFmb3+f\/f1dvPfkEVzYzLJ+C1AbIYSeto2Uj1aEk3Pu3H2Z3cViKwzAz+7uo8Ard24CYAUEZblcPtG5CkoiBB2yc7klRa5qAqfnNYk1PH\/4Aqo9jsg\/\/\/gH3n\/\/99jNuA0GWrEoCQZBVJl0HWrCMMUjdAa6ONSsN4NNzZCVplqRCSQKflsNjZ1jb+xIfMK6uKBtwTlLJynPzRbc\/+wehkgwsLaGQmBaK8tG6YAygcoPTjvAINRWEYVmc69RsYCYIUPzbW1\/9p+CxAi7S8fqvMBYR914Znu7\/OSXr3F8fsr64jFdH9jdP2Bdlnzwpz\/TdJc4gWBhbcFESKLQGMUgmKjc6KAwyjoRrCqjCJlu7XpMsA69cYtV78lmjmziKC4r6qpEtGM2TZn5hqUPjLxl9\/CQn776KohQGFgLjOPwRceCNeCBpRpmETKBnQh7CDvRMFYIW5DcWW9xnz\/AWOU5C8XlJc5Y0r2K9qO\/YAj0XY1NUtqmJ5\/kHEwNx3du8vGn9wk99D2MRDBGGFnDCEsOnNqWqUvotcfHSOYcKw+1vf6dOQ0N2XjJ8e0Dvvj0hLotufvj28xvHZFmGesvH\/Hgk3+Rj5RYPqQrcyS07IwMdpJRNjX0YH3CC9mYPRU6oPeKj54XJzNWdU1Jj7eOcYwM\/wpPl\/8CWIcTbntq1pMAAAAASUVORK5CYII=\u0022 data-src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022615\u0022 height=\u0022344\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Eonclick\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022return confirm(\u0027{{ \u0027delete.confirm\u0027|l|e }}\u0027)\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EProsta sprawa \u2013 linkujemy do adresu, kt\u00f3ry usunie produkt z bazy, ale przy klikni\u0119ciu pytamy u\u017cytkownika, czy na pewno chce to zrobi\u0107. Je\u015bli nie chce, wtedy \u003Ccode\u003Econfirm()\u003C\/code\u003E zwr\u00f3ci \u003Ccode\u003Efalse\u003C\/code\u003E, a wi\u0119c wykonanie przekierowania zostanie zablokowane.\u003C\/p\u003E\n\u003Cp\u003EJest z tym kodem tylko jeden problem \u2013 mieszamy ze sob\u0105 HTML i JS. A to nie tak powinny dzia\u0142a\u0107 internety.\u003C\/p\u003E\n\u003Cp\u003EPoprawnie napisana strona internetowa sk\u0142ada si\u0119 (oczywi\u015bcie w cz\u0119\u015bci frontendowej) z trzech warstw:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ew HTML-u umieszczamy \u003Cstrong\u003Eustrukturyzowane dane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ew CSS-ach definiujemy, jak te dane maj\u0105 by\u0107 \u003Cstrong\u003Eprezentowane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ea w JS-ie dodajemy wszystkie te \u003Cstrong\u003Efajerwerki\u003C\/strong\u003E i \u015bwiecide\u0142ka, dzi\u0119ki kt\u00f3rym strona jest dynamiczniejsza i atrakcyjniejsza.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003ENajlepiej, gdyby warstwy te w og\u00f3le si\u0119 ze sob\u0105 nie miesza\u0142y. Dzi\u0119ki temu kod jest czystszy, a warstwy mog\u0105 by\u0107 u\u017cywane i modyfikowane niezale\u017cnie od siebie. Mo\u017cna na przyk\u0142ad w banalnie prosty spos\u00f3b zaimplementowa\u0107 r\u00f3\u017cne sk\u00f3rki na stronie, po prostu podmieniaj\u0105c u\u017cywany akrusz styl\u00f3w na inny. Je\u015bli w HTML-u nie umie\u015bcimy \u017cadnych styl\u00f3w inline (mam nadziej\u0119, \u017ce nikomu cho\u0107 troch\u0119 znaj\u0105cemu temat nie trzeba t\u0142umaczy\u0107, jak z\u0142y jest to pomys\u0142), lecz tylko dane oraz struktur\u0119, w jakiej s\u0105 u\u0142o\u017cone, to ca\u0142kowita zmiana wygl\u0105du strony jest nadzwyczaj \u0142atwa. (Dla przyk\u0142adu cho\u0107by \u003Ca href=\u0022http:\/\/bootswatch.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E bootswatch.com\u003C\/a\u003E albo \u003Ca href=\u0022http:\/\/www.csszengarden.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E csszengarden.com\u003C\/a\u003E \u2013 wszystkie podstrony w dziale \u201cthemes\u201d r\u00f3\u017cni\u0105 si\u0119 tylko jedn\u0105 rzecz\u0105: nazw\u0105 pliku .css)\u003C\/p\u003E\n\u003Cp\u003EDok\u0142adnie to samo tyczy si\u0119 JavaScriptu. Je\u015bli kod wykonywalny umie\u015bcimy bezpo\u015brednio wewn\u0105trz znacznika HTML, nasz kod staje si\u0119 zdecydowanie mniej czytelny i bardziej nara\u017cony na powtarzalno\u015b\u0107. Wprowadzanie w nim potem zmian mo\u017ce si\u0119 okaza\u0107 drog\u0105 przez m\u0119k\u0119. Powiedzmy, \u017ce po jakim\u015b czasie zechcemy zmieni\u0107 to brzydkie okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E na przyk\u0142ad na bootstrapowy \u003Ca href=\u0022http:\/\/getbootstrap.com\/javascript\/#modals\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E modal\u003C\/a\u003E. B\u0119dziemy wtedy musieli znale\u017a\u0107 wszystkie u\u017cycia podobnego kodu w naszym projekcie i przerobi\u0107 ka\u017cde z nich. Po co si\u0119 tak m\u0119czy\u0107?\u003C\/p\u003E\n\u003Cp\u003ENatkn\u0105\u0142em si\u0119 ostatnio na taki oto kod, maj\u0105cy wykona\u0107 nasze proste zadanie bez mieszania ze sob\u0105 warstw aplikacji:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Eclass\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022js-delete-event\u0022\u003C\/span\u003E \n    \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022javascript:void(0)\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-delete-url\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E\n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-confirm-message\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENatomiast w pliku JavaScriptu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027.js-delete-event\u0027\u003C\/span\u003E).on(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027click\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (\u003Cspan class=\u0022hljs-literal\u0022\u003Etrue\u003C\/span\u003E == confirm($(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027confirm-message\u0027\u003C\/span\u003E))) {\n        \u003Cspan class=\u0022hljs-built_in\u0022\u003Ewindow\u003C\/span\u003E.location.href = $(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027delete-url\u0027\u003C\/span\u003E);\n    }\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWygl\u0105da na zdecydowanie bardziej skomplikowany ni\u017c powien by\u0107... Niby jest w porz\u0105dku: w HTML-u nie mamy skrypt\u00f3w, a jedno z drugim komunikuje si\u0119 za pomoc\u0105 klas i atrybut\u00f3w \u003Ccode\u003Edata\u003C\/code\u003E, tak jak powinno by\u0107. HTML definiuje, \u017ce link jest klasy \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E, dok\u0105d powinien kierowa\u0107 i jak brzmi przet\u0142umaczona pro\u015bba o potwierdzenie, natomiast JS szuka wszystkich element\u00f3w z klas\u0105 \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E i podpina pod nie listenera, kt\u00f3ry o potwierdzenie faktycznie spyta, i w zale\u017cno\u015bci od odpowiedzi, przekierowuje u\u017cytkownika do strony usuwaj\u0105cej, b\u0105d\u017a te\u017c nie.\u003C\/p\u003E\n\u003Cp\u003EA jednak JS w tym HTML-owym kodzie si\u0119 pojawia, i to w swojej najbrzydszej formie: jako pseudoprotok\u00f3\u0142. Link, zamiast kierowa\u0107 nas do rzeczywistej strony, odsy\u0142a nas do jakiego\u015b \u003Ccode\u003Evoid(0)\u003C\/code\u003E przez nieistniej\u0105cy protok\u00f3\u0142 \u003Ccode\u003Ejavascript\u003C\/code\u003E... Jest to zwyk\u0142y zabieg maj\u0105cy na celu zablokowanie linka, skierowanie go donik\u0105d, ale jak\u017ce strasznie psuje semantyk\u0119 strony...\u003C\/p\u003E\n\u003Cp\u003EI ma w dupie \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Progressive_enhancement\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Progressive enhancement\u003C\/a\u003E. A to bardzo \u017ale, mie\u0107 go w dupie...\u003C\/p\u003E\n\u003Cp\u003EW progressive enhancement chodzi mniej wi\u0119cej o to, aby zapewni\u0107 dost\u0119p do wszystkich podstawowych danych na stronie oraz do wszystkich podstawowych funkcji naszej aplikacji dla \u003Cstrong\u003Eka\u017cdego\u003C\/strong\u003E u\u017cytkownika. Nawet je\u015bli u\u017cywa IE6 albo nie daj bogini jakiego\u015b lynxa czy innej wy\u0142\u0105cznie tekstowej przegl\u0105darki. Natomiast im jego przegl\u0105darka jest lepsza, nowocze\u015bniejsza i zgodniejsza ze standardami, tym wi\u0119cej deweloper mo\u017ce zaszale\u0107 z \u0142adnym wygl\u0105dem i wodotryskami.\u003C\/p\u003E\n\u003Cp\u003ENie zawsze u\u017cytkownikowi zadzia\u0142aj\u0105 skrypty. Mo\u017ce CDN z jak\u0105\u015b bibliotek\u0105 zaszwankuje, mo\u017ce user jedzie poci\u0105giem i mu net przerywa, a mo\u017ce po prostu sam je wy\u0142\u0105czy\u0142 (tak, niekt\u00f3rzy to robi\u0105).\u003C\/p\u003E\n\u003Cp\u003EJak w takim przypadku zadzia\u0142a powy\u017cszy kod? Ano w\u0142a\u015bnie, nie zadzia\u0142a w og\u00f3le. Chyba \u017ce user zajrzy w \u017ar\u00f3d\u0142o strony, domy\u015bli si\u0119, o co chodzi, i r\u0119cznie przejdzie do URL-a podanego w atrybucie \u003Ccode\u003Edata-delete-url\u003C\/code\u003E. Powodzenia.\u003C\/p\u003E\n\u003Cp\u003EA wi\u0119c progressive enhancement le\u017cy. Dla pewnej grupy u\u017cytkownik\u00f3w dost\u0119p do wa\u017cnej funkcjonalno\u015bci jest niemo\u017cliwy.\u003C\/p\u003E\n\u003Cp\u003ESp\u00f3jrzmy teraz na inny kod:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs xml border\u0022\u003E\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E \u003Cspan class=\u0022hljs-attr\u0022\u003Ehref\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\u003C\/span\u003E \n    \u003Cspan class=\u0022hljs-attr\u0022\u003Edata-confirm\u003C\/span\u003E=\u003Cspan class=\u0022hljs-string\u0022\u003E\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n    {{ \u0027delete\u0027|l }}\n\u003Cspan class=\u0022hljs-tag\u0022\u003E\u0026lt;\/\u003Cspan class=\u0022hljs-name\u0022\u003Ea\u003C\/span\u003E\u0026gt;\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003E$(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027a[data-confirm]\u0027\u003C\/span\u003E).click(\u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003E\u003C\/span\u003E) \u003C\/span\u003E{\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E confirm($(\u003Cspan class=\u0022hljs-keyword\u0022\u003Ethis\u003C\/span\u003E).data(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027confirm\u0027\u003C\/span\u003E));\n});\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETutaj mamy w HTML-u najzwyczajniejszy w \u015bwiecie link, po prostu z jednym dodatkowym atrybutem. Gdyby z jakiego\u015b powodu nie za\u0142adowa\u0142 si\u0119 skypt, \u015bwiat si\u0119 nie zawali. U\u017cytkownik dalej ma mo\u017cliwo\u015b\u0107 usuni\u0119cia elementu, po prostu jest bardziej nara\u017cony na zrobienie tego przez przypadek, bo nie zobaczy potwierdzenia.\u003C\/p\u003E\n\u003Cp\u003EJe\u015bli natomiast JS dzia\u0142a, skrypt znajdzie wszystkie elementy posiadaj\u0105ce atrybut \u003Ccode\u003Edata-confirm\u003C\/code\u003E i podepnie pod nie listenera, zadaj\u0105cego u\u017cytkownikowi pytanie, kt\u00f3re si\u0119 w tym atrybucie znajduje.\u003C\/p\u003E\n\u003Cp\u003ETen kod jest o wiele lepszy od poprzedniego nie tylko ze wzgl\u0119du na respektowanie progressive enhancement:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EElement A zosta\u0142 odchudzony ze wszystkich zb\u0119dnych atrybut\u00f3w (czyli po\u0142owy!). W poprzednim kodzie jego autor uda\u0142, \u017ce link donik\u0105d nie kieruje, tylko po to, by p\u00f3\u017aniej przekaza\u0107 odpowiedni URL w osbobnym atrybucie. U\u017cy\u0142 te\u017c specjalnej klasy, po kt\u00f3rej JS mia\u0142 rozpozna\u0107 interesuj\u0105ce go elementy, mimo \u017ce sam fakt posiadania tekstu potwierdzenia ju\u017c dostatecznie jasno identyfikuje elementy, kt\u00f3re powinny wy\u015bwietli\u0107 potwierdzenie.\u003C\/li\u003E\n\u003Cli\u003EWykorzystanli\u015bmy \u015bwietnego ficzera jQuery \u2013 to, \u017ce zwr\u00f3cenie \u003Ccode\u003Efalse\u003C\/code\u003E w event hadlerze automatycznie zatrzymuje propagacj\u0119 zdarzenia. W bardzo elegancki i zwi\u0119z\u0142y spos\u00f3b zatrzymali\u015bmy przekierowanie po klikni\u0119ciu, bez potrzeby uciekania si\u0119 do pseudoprotoko\u0142\u00f3w ani \u003Ccode\u003Eevent.stoppropagation(); event.preventdefault();\u003C\/code\u003E, przy okazji jeszcze pytaj\u0105c o zgod\u0119 u\u017cytkownika \u2013 w jednej prostej linijce!\u003C\/li\u003E\n\u003Cli\u003ENie u\u017cywamy okropnego \u003Ccode\u003Ewindow.location.href\u003C\/code\u003E. Pozwalamy na zwyczajn\u0105 obs\u0142ug\u0119 operacji przekierowania po klikni\u0119ciu w link, po prostu rozszerzaj\u0105c j\u0105 o mo\u017cliwo\u015b\u0107 warunkowego przerwania, zamiast sztucznie i nieelegancko blokowa\u0107 przekierowanie tylko po to, by potem jeszcze sztuczniej wywo\u0142a\u0107 je od nowa...\u003C\/li\u003E\n\u003C\/ul\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["html","javascript","js","programowanie","progressive enhancement","warstwy abstracji","web"],"hasMore":true,"image":"https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022134.24390243902\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/proste-potwierdzenie-w-javascripcie-a-rozdzielenie-warstw-aplikacji_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022134.24390243902\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EProste zadanie: umie\u015bci\u0107 na stronie przycisk, kt\u00f3ry przekieruje nas do usuwania jakiego\u015b obiektu z bazy, ale zanim to zrobi, spyta, czy na pewno tego chcemy.\u003C\/p\u003E\n\u003Cp\u003EStandardowa cz\u0119\u015b\u0107 interfejsu, mo\u017cliwa do zrealizowania w webie na wiele r\u00f3\u017cnych sposob\u00f3w. Najprostszym z nich jest zwyk\u0142e okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E.\u003C\/p\u003E\n\u003Cp\u003EW wersji najbardziej prymitywnej wykonanie zadania wygl\u0105da mniej wi\u0119cej tak:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a href=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\n    onclick=\u0022return confirm(\u0027{{ \u0027delete.confirm\u0027|l|e }}\u0027)\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EProsta sprawa \u2013 linkujemy do adresu, kt\u00f3ry usunie produkt z bazy, ale przy klikni\u0119ciu pytamy u\u017cytkownika, czy na pewno chce to zrobi\u0107. Je\u015bli nie chce, wtedy \u003Ccode\u003Econfirm()\u003C\/code\u003E zwr\u00f3ci \u003Ccode\u003Efalse\u003C\/code\u003E, a wi\u0119c wykonanie przekierowania zostanie zablokowane.\u003C\/p\u003E\n\u003Cp\u003EJest z tym kodem tylko jeden problem \u2013 mieszamy ze sob\u0105 HTML i JS. A to nie tak powinny dzia\u0142a\u0107 internety.\u003C\/p\u003E\n\u003Cp\u003EPoprawnie napisana strona internetowa sk\u0142ada si\u0119 (oczywi\u015bcie w cz\u0119\u015bci frontendowej) z trzech warstw:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Ew HTML-u umieszczamy \u003Cstrong\u003Eustrukturyzowane dane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ew CSS-ach definiujemy, jak te dane maj\u0105 by\u0107 \u003Cstrong\u003Eprezentowane\u003C\/strong\u003E,\u003C\/li\u003E\n\u003Cli\u003Ea w JS-ie dodajemy wszystkie te \u003Cstrong\u003Efajerwerki\u003C\/strong\u003E i \u015bwiecide\u0142ka, dzi\u0119ki kt\u00f3rym strona jest dynamiczniejsza i atrakcyjniejsza.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003ENajlepiej, gdyby warstwy te w og\u00f3le si\u0119 ze sob\u0105 nie miesza\u0142y. Dzi\u0119ki temu kod jest czystszy, a warstwy mog\u0105 by\u0107 u\u017cywane i modyfikowane niezale\u017cnie od siebie. Mo\u017cna na przyk\u0142ad w banalnie prosty spos\u00f3b zaimplementowa\u0107 r\u00f3\u017cne sk\u00f3rki na stronie, po prostu podmieniaj\u0105c u\u017cywany akrusz styl\u00f3w na inny. Je\u015bli w HTML-u nie umie\u015bcimy \u017cadnych styl\u00f3w inline (mam nadziej\u0119, \u017ce nikomu cho\u0107 troch\u0119 znaj\u0105cemu temat nie trzeba t\u0142umaczy\u0107, jak z\u0142y jest to pomys\u0142), lecz tylko dane oraz struktur\u0119, w jakiej s\u0105 u\u0142o\u017cone, to ca\u0142kowita zmiana wygl\u0105du strony jest nadzwyczaj \u0142atwa. (Dla przyk\u0142adu cho\u0107by \u003Ca href=\u0022http:\/\/bootswatch.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E bootswatch.com\u003C\/a\u003E albo \u003Ca href=\u0022http:\/\/www.csszengarden.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E csszengarden.com\u003C\/a\u003E \u2013 wszystkie podstrony w dziale \u201cthemes\u201d r\u00f3\u017cni\u0105 si\u0119 tylko jedn\u0105 rzecz\u0105: nazw\u0105 pliku .css)\u003C\/p\u003E\n\u003Cp\u003EDok\u0142adnie to samo tyczy si\u0119 JavaScriptu. Je\u015bli kod wykonywalny umie\u015bcimy bezpo\u015brednio wewn\u0105trz znacznika HTML, nasz kod staje si\u0119 zdecydowanie mniej czytelny i bardziej nara\u017cony na powtarzalno\u015b\u0107. Wprowadzanie w nim potem zmian mo\u017ce si\u0119 okaza\u0107 drog\u0105 przez m\u0119k\u0119. Powiedzmy, \u017ce po jakim\u015b czasie zechcemy zmieni\u0107 to brzydkie okienko \u003Ccode\u003Econfirm()\u003C\/code\u003E na przyk\u0142ad na bootstrapowy \u003Ca href=\u0022http:\/\/getbootstrap.com\/javascript\/#modals\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E modal\u003C\/a\u003E. B\u0119dziemy wtedy musieli znale\u017a\u0107 wszystkie u\u017cycia podobnego kodu w naszym projekcie i przerobi\u0107 ka\u017cde z nich. Po co si\u0119 tak m\u0119czy\u0107?\u003C\/p\u003E\n\u003Cp\u003ENatkn\u0105\u0142em si\u0119 ostatnio na taki oto kod, maj\u0105cy wykona\u0107 nasze proste zadanie bez mieszania ze sob\u0105 warstw aplikacji:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a class=\u0022js-delete-event\u0022 \n    href=\u0022javascript:void(0)\u0022\n    data-delete-url=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022\n    data-confirm-message=\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ENatomiast w pliku JavaScriptu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$(\u0027.js-delete-event\u0027).on(\u0027click\u0027, function() {\n    if (true == confirm($(this).data(\u0027confirm-message\u0027))) {\n        window.location.href = $(this).data(\u0027delete-url\u0027);\n    }\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWygl\u0105da na zdecydowanie bardziej skomplikowany ni\u017c powien by\u0107... Niby jest w porz\u0105dku: w HTML-u nie mamy skrypt\u00f3w, a jedno z drugim komunikuje si\u0119 za pomoc\u0105 klas i atrybut\u00f3w \u003Ccode\u003Edata\u003C\/code\u003E, tak jak powinno by\u0107. HTML definiuje, \u017ce link jest klasy \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E, dok\u0105d powinien kierowa\u0107 i jak brzmi przet\u0142umaczona pro\u015bba o potwierdzenie, natomiast JS szuka wszystkich element\u00f3w z klas\u0105 \u003Ccode\u003Ejs-delete-event\u003C\/code\u003E i podpina pod nie listenera, kt\u00f3ry o potwierdzenie faktycznie spyta, i w zale\u017cno\u015bci od odpowiedzi, przekierowuje u\u017cytkownika do strony usuwaj\u0105cej, b\u0105d\u017a te\u017c nie.\u003C\/p\u003E\n\u003Cp\u003EA jednak JS w tym HTML-owym kodzie si\u0119 pojawia, i to w swojej najbrzydszej formie: jako pseudoprotok\u00f3\u0142. Link, zamiast kierowa\u0107 nas do rzeczywistej strony, odsy\u0142a nas do jakiego\u015b \u003Ccode\u003Evoid(0)\u003C\/code\u003E przez nieistniej\u0105cy protok\u00f3\u0142 \u003Ccode\u003Ejavascript\u003C\/code\u003E... Jest to zwyk\u0142y zabieg maj\u0105cy na celu zablokowanie linka, skierowanie go donik\u0105d, ale jak\u017ce strasznie psuje semantyk\u0119 strony...\u003C\/p\u003E\n\u003Cp\u003EI ma w dupie \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Progressive_enhancement\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Progressive enhancement\u003C\/a\u003E. A to bardzo \u017ale, mie\u0107 go w dupie...\u003C\/p\u003E\n\u003Cp\u003EW progressive enhancement chodzi mniej wi\u0119cej o to, aby zapewni\u0107 dost\u0119p do wszystkich podstawowych danych na stronie oraz do wszystkich podstawowych funkcji naszej aplikacji dla \u003Cstrong\u003Eka\u017cdego\u003C\/strong\u003E u\u017cytkownika. Nawet je\u015bli u\u017cywa IE6 albo nie daj bogini jakiego\u015b lynxa czy innej wy\u0142\u0105cznie tekstowej przegl\u0105darki. Natomiast im jego przegl\u0105darka jest lepsza, nowocze\u015bniejsza i zgodniejsza ze standardami, tym wi\u0119cej deweloper mo\u017ce zaszale\u0107 z \u0142adnym wygl\u0105dem i wodotryskami.\u003C\/p\u003E\n\u003Cp\u003ENie zawsze u\u017cytkownikowi zadzia\u0142aj\u0105 skrypty. Mo\u017ce CDN z jak\u0105\u015b bibliotek\u0105 zaszwankuje, mo\u017ce user jedzie poci\u0105giem i mu net przerywa, a mo\u017ce po prostu sam je wy\u0142\u0105czy\u0142 (tak, niekt\u00f3rzy to robi\u0105).\u003C\/p\u003E\n\u003Cp\u003EJak w takim przypadku zadzia\u0142a powy\u017cszy kod? Ano w\u0142a\u015bnie, nie zadzia\u0142a w og\u00f3le. Chyba \u017ce user zajrzy w \u017ar\u00f3d\u0142o strony, domy\u015bli si\u0119, o co chodzi, i r\u0119cznie przejdzie do URL-a podanego w atrybucie \u003Ccode\u003Edata-delete-url\u003C\/code\u003E. Powodzenia.\u003C\/p\u003E\n\u003Cp\u003EA wi\u0119c progressive enhancement le\u017cy. Dla pewnej grupy u\u017cytkownik\u00f3w dost\u0119p do wa\u017cnej funkcjonalno\u015bci jest niemo\u017cliwy.\u003C\/p\u003E\n\u003Cp\u003ESp\u00f3jrzmy teraz na inny kod:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;a href=\u0022{{ route(\u0027product_delete\u0027, {id: product.id}) }}\u0022 \n    data-confirm=\u0022{{ \u0027delete.confirm\u0027|l|e }}\u0022\u0026gt;\n    {{ \u0027delete\u0027|l }}\n\u0026lt;\/a\u0026gt;\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cpre\u003E\u003Ccode\u003E$(\u0027a[data-confirm]\u0027).click(function() {\n    return confirm($(this).data(\u0027confirm\u0027));\n});\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETutaj mamy w HTML-u najzwyczajniejszy w \u015bwiecie link, po prostu z jednym dodatkowym atrybutem. Gdyby z jakiego\u015b powodu nie za\u0142adowa\u0142 si\u0119 skypt, \u015bwiat si\u0119 nie zawali. U\u017cytkownik dalej ma mo\u017cliwo\u015b\u0107 usuni\u0119cia elementu, po prostu jest bardziej nara\u017cony na zrobienie tego przez przypadek, bo nie zobaczy potwierdzenia.\u003C\/p\u003E\n\u003Cp\u003EJe\u015bli natomiast JS dzia\u0142a, skrypt znajdzie wszystkie elementy posiadaj\u0105ce atrybut \u003Ccode\u003Edata-confirm\u003C\/code\u003E i podepnie pod nie listenera, zadaj\u0105cego u\u017cytkownikowi pytanie, kt\u00f3re si\u0119 w tym atrybucie znajduje.\u003C\/p\u003E\n\u003Cp\u003ETen kod jest o wiele lepszy od poprzedniego nie tylko ze wzgl\u0119du na respektowanie progressive enhancement:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EElement A zosta\u0142 odchudzony ze wszystkich zb\u0119dnych atrybut\u00f3w (czyli po\u0142owy!). W poprzednim kodzie jego autor uda\u0142, \u017ce link donik\u0105d nie kieruje, tylko po to, by p\u00f3\u017aniej przekaza\u0107 odpowiedni URL w osbobnym atrybucie. U\u017cy\u0142 te\u017c specjalnej klasy, po kt\u00f3rej JS mia\u0142 rozpozna\u0107 interesuj\u0105ce go elementy, mimo \u017ce sam fakt posiadania tekstu potwierdzenia ju\u017c dostatecznie jasno identyfikuje elementy, kt\u00f3re powinny wy\u015bwietli\u0107 potwierdzenie.\u003C\/li\u003E\n\u003Cli\u003EWykorzystanli\u015bmy \u015bwietnego ficzera jQuery \u2013 to, \u017ce zwr\u00f3cenie \u003Ccode\u003Efalse\u003C\/code\u003E w event hadlerze automatycznie zatrzymuje propagacj\u0119 zdarzenia. W bardzo elegancki i zwi\u0119z\u0142y spos\u00f3b zatrzymali\u015bmy przekierowanie po klikni\u0119ciu, bez potrzeby uciekania si\u0119 do pseudoprotoko\u0142\u00f3w ani \u003Ccode\u003Eevent.stoppropagation(); event.preventdefault();\u003C\/code\u003E, przy okazji jeszcze pytaj\u0105c o zgod\u0119 u\u017cytkownika \u2013 w jednej prostej linijce!\u003C\/li\u003E\n\u003Cli\u003ENie u\u017cywamy okropnego \u003Ccode\u003Ewindow.location.href\u003C\/code\u003E. Pozwalamy na zwyczajn\u0105 obs\u0142ug\u0119 operacji przekierowania po klikni\u0119ciu w link, po prostu rozszerzaj\u0105c j\u0105 o mo\u017cliwo\u015b\u0107 warunkowego przerwania, zamiast sztucznie i nieelegancko blokowa\u0107 przekierowanie tylko po to, by potem jeszcze sztuczniej wywo\u0142a\u0107 je od nowa...\u003C\/li\u003E\n\u003C\/ul\u003E","words":1140,"readTime":5,"lang":"pl"}}},"projects\/vocabus-dictionary-at-your-fingertips":{"key":"projects\/vocabus-dictionary-at-your-fingertips","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:42+02:00","publishedAt":"2015-08-05T18:40:00+02:00","group":null,"links":[{"icon":"globe-europe","colour":"primary","url":"https:\/\/vocabus.avris.it\/","displayUrl":null},{"icon":"brands gitlab","colour":"secondary","url":"https:\/\/gitlab.com\/Avris\/Vocabus","displayUrl":null}],"category":"projects","subcategory":null,"slug":"vocabus-dictionary-at-your-fingertips"},"content":{"en":{"slug":"vocabus-dictionary-at-your-fingertips","title":"Vocabus - Dictionary at your fingertips!","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022228.21978021978\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEs0lEQVRIiXWWPYssxxmFn\/ejqrvna\/eufHUNBhsbjGScKFAgEMLO\/TOcODVG\/8ap\/4YzBcaRwaHBicBCV1rQzs7OTHdVvQpqdrhr2QUNnXTVwznnPdUyffZ5qDviA+IJUUdzJueJzc0bdrsbNps7bm7vSHlitx4xTwTBlA0IhhTsDyfu95Uvv97z8N0D337zLWVZAEHEERSAEBBVQPBhZL3dMQ2Jp8dHaplxUQVxUEXUCFEiFHVnqQsPhxM+Nob5xMe\/SAzDzGoMAJIVIoJzCY5D8JNd4YM3E9\/cL8zn9zkeDqgIf\/3nI7UZoCCACp4SlgZChFIbPk5MusbRDJpBBtCMaAJxShuQapgoh6Xxyxv402\/XqCqr1Yr\/Xl+f78nLHSGg3FEjiFZZ5+DDP\/6NxzkBioiibugw8t77dyR3cnLqUjA1XGxCPCM+EJIQHDTRJFNCKceFtHVO88Jf\/v7EV\/\/6N+mnH\/CHTwxVY5omAHZ2i5h0W4B\/fDnz5y\/2fP7pTFgC826fKoFQS2GeF9bbDQasViuWpeHkLWiHQB0xB0uITYhl8IFSg4XMRz\/b8Z\/bX3O3NnLOACxLe0enuL69WQu\/+9VI0hlR6\/sC4hkQ1u+9It\/ecKyVzZg414ICrn6DqCNmHUwM1GjhpGFHqLEwUNX4sX3F7eqMICyn1z+w7d114\/Cbn8N+X0Cf9wYQ8nbHtFkTBKFOQUCMBrj4BlEHlf6h9ECLGaGZiEBTAjGGwZnnBRHh\/v4eEaHWSgS8fv0jROSHYDc3aP4OZSBaw8YRHzILhpRgGoVjgdZgZYKLDaAKoogqqkqIonlFiINCiJFyYrfd4imzXW8YxuF66Ol04nQ6ERHc3r7imWt\/aoxWIQIhEM\/osO5uSKBuzEtDk+MOSwPFrHePJdScsJ6jaI1oBURo0TidzgCUZeF0PrF\/fHyhhJmhqvwPkZA8wjAi0wRUSM55rrSAYk60oLTg3EBF9ZKf7nO3zwk1Ar0EMoEnPCVyzszzDNGVucY5AhAeHh44HA4vgHSc0GFEzPBp3afaEuclqCU4FuF4FlptuF6CHKrdOrVrSWpK4E4tC+5Dz0trmBnr9QpVvR7aWkNFIQIze6mQOVINsR7cWBoigmclJUEaSAvmRXAuICLau0KeVVHUHEkZcaPUSs75Ou4RQa0VgJQSKaUXELVWVglqDaIWJGVoFVTxwSjnQi1COTdEBUI6ZMgzjIFIh\/HeG+GOegZTxJS3b9\/y9PSECETAbre7Av6\/5e5ISkg4eEIEytLQ7BAgJv02MYEal7tMtcOYg9pFoS570MjTBnRmu11h5uSc2O1210PP5zPH44nVanoBuD81krdeIcuCkC5uCOW4YNl7uwcsc0MQHDUw79MhIAKiclHJEM+0aLR4buTodrWGvZMhAezSxu+u1trlBki9p1oQKtiYgaDOELVC7dbJq99\/Ed2mDGqoaQ9zzr0gU8LXW4iZzVCxJF1m6T8JEUBAXZ7D06MS7fkJDmVNhCEEiPYSBqIEUdvVslYqLgSiBlG7VSJgCrSumBmNQIeJJ4c8dpmbgDu06ABNOgACtQUthF4EgVhADRAhWsDSiAYigVifzLZUIhrfA7dv6UObXUFjAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022228.21978021978\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhatever you\u2019re doing on your computer, this dictionary is always \u003Cstrong\u003Ejust two hotkeys away\u003C\/strong\u003E! In a browser, document, pdf reader, everywhere!\u003C\/p\u003E\n\u003Cp\u003EJust select a word you want to look up and press Ctrl+C to put it in the Clipboard. Now just press Ctrl+Shift+C. Vocabus will show up and look up a word for you! It\u2019s \u003Cstrong\u003Equick and comfortable\u003C\/strong\u003E, isn\u2019t it?\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022456.43956043956\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAARCAYAAAC1tw6GAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEs0lEQVRIiXWWPYssxxmFn\/ejqrvna\/eufHUNBhsbjGScKFAgEMLO\/TOcODVG\/8ap\/4YzBcaRwaHBicBCV1rQzs7OTHdVvQpqdrhr2QUNnXTVwznnPdUyffZ5qDviA+IJUUdzJueJzc0bdrsbNps7bm7vSHlitx4xTwTBlA0IhhTsDyfu95Uvv97z8N0D337zLWVZAEHEERSAEBBVQPBhZL3dMQ2Jp8dHaplxUQVxUEXUCFEiFHVnqQsPhxM+Nob5xMe\/SAzDzGoMAJIVIoJzCY5D8JNd4YM3E9\/cL8zn9zkeDqgIf\/3nI7UZoCCACp4SlgZChFIbPk5MusbRDJpBBtCMaAJxShuQapgoh6Xxyxv402\/XqCqr1Yr\/Xl+f78nLHSGg3FEjiFZZ5+DDP\/6NxzkBioiibugw8t77dyR3cnLqUjA1XGxCPCM+EJIQHDTRJFNCKceFtHVO88Jf\/v7EV\/\/6N+mnH\/CHTwxVY5omAHZ2i5h0W4B\/fDnz5y\/2fP7pTFgC826fKoFQS2GeF9bbDQasViuWpeHkLWiHQB0xB0uITYhl8IFSg4XMRz\/b8Z\/bX3O3NnLOACxLe0enuL69WQu\/+9VI0hlR6\/sC4hkQ1u+9It\/ecKyVzZg414ICrn6DqCNmHUwM1GjhpGFHqLEwUNX4sX3F7eqMICyn1z+w7d114\/Cbn8N+X0Cf9wYQ8nbHtFkTBKFOQUCMBrj4BlEHlf6h9ECLGaGZiEBTAjGGwZnnBRHh\/v4eEaHWSgS8fv0jROSHYDc3aP4OZSBaw8YRHzILhpRgGoVjgdZgZYKLDaAKoogqqkqIonlFiINCiJFyYrfd4imzXW8YxuF66Ol04nQ6ERHc3r7imWt\/aoxWIQIhEM\/osO5uSKBuzEtDk+MOSwPFrHePJdScsJ6jaI1oBURo0TidzgCUZeF0PrF\/fHyhhJmhqvwPkZA8wjAi0wRUSM55rrSAYk60oLTg3EBF9ZKf7nO3zwk1Ar0EMoEnPCVyzszzDNGVucY5AhAeHh44HA4vgHSc0GFEzPBp3afaEuclqCU4FuF4FlptuF6CHKrdOrVrSWpK4E4tC+5Dz0trmBnr9QpVvR7aWkNFIQIze6mQOVINsR7cWBoigmclJUEaSAvmRXAuICLau0KeVVHUHEkZcaPUSs75Ou4RQa0VgJQSKaUXELVWVglqDaIWJGVoFVTxwSjnQi1COTdEBUI6ZMgzjIFIh\/HeG+GOegZTxJS3b9\/y9PSECETAbre7Av6\/5e5ISkg4eEIEytLQ7BAgJv02MYEal7tMtcOYg9pFoS570MjTBnRmu11h5uSc2O1210PP5zPH44nVanoBuD81krdeIcuCkC5uCOW4YNl7uwcsc0MQHDUw79MhIAKiclHJEM+0aLR4buTodrWGvZMhAezSxu+u1trlBki9p1oQKtiYgaDOELVC7dbJq99\/Ed2mDGqoaQ9zzr0gU8LXW4iZzVCxJF1m6T8JEUBAXZ7D06MS7fkJDmVNhCEEiPYSBqIEUdvVslYqLgSiBlG7VSJgCrSumBmNQIeJJ4c8dpmbgDu06ABNOgACtQUthF4EgVhADRAhWsDSiAYigVifzLZUIhrfA7dv6UObXUFjAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022456.43956043956\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhatever you\u2019re doing on your computer, this dictionary is always \u003Cstrong\u003Ejust two hotkeys away\u003C\/strong\u003E! In a browser, document, pdf reader, everywhere!\u003C\/p\u003E\n\u003Cp\u003EJust select a word you want to look up and press Ctrl+C to put it in the Clipboard. Now just press Ctrl+Shift+C. Vocabus will show up and look up a word for you! It\u2019s \u003Cstrong\u003Equick and comfortable\u003C\/strong\u003E, isn\u2019t it?\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["dictionary","javascript","node webkit","nodejs","s\u0142ownik","w\u00f6rterbuch"],"hasMore":false,"image":"https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022114.10989010989\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhatever you\u2019re doing on your computer, this dictionary is always \u003Cstrong\u003Ejust two hotkeys away\u003C\/strong\u003E! In a browser, document, pdf reader, everywhere!\u003C\/p\u003E\n\u003Cp\u003EJust select a word you want to look up and press Ctrl+C to put it in the Clipboard. Now just press Ctrl+Shift+C. Vocabus will show up and look up a word for you! It\u2019s \u003Cstrong\u003Equick and comfortable\u003C\/strong\u003E, isn\u2019t it?\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/vocabus-dictionary-at-your-fingertips_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022114.10989010989\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EWhatever you\u2019re doing on your computer, this dictionary is always \u003Cstrong\u003Ejust two hotkeys away\u003C\/strong\u003E! In a browser, document, pdf reader, everywhere!\u003C\/p\u003E\n\u003Cp\u003EJust select a word you want to look up and press Ctrl+C to put it in the Clipboard. Now just press Ctrl+Shift+C. Vocabus will show up and look up a word for you! It\u2019s \u003Cstrong\u003Equick and comfortable\u003C\/strong\u003E, isn\u2019t it?\u003C\/p\u003E","words":66,"readTime":null,"lang":"en"}}},"blog\/technology\/frontendowa-magia-coffeescript-sass-scss-less":{"key":"blog\/technology\/frontendowa-magia-coffeescript-sass-scss-less","type":"article","published":true,"meta":{"createdAt":"2017-04-28T19:43:39+02:00","publishedAt":"2015-07-26T18:00:00+02:00","group":null,"category":"blog","subcategory":"technology","slug":"frontendowa-magia-coffeescript-sass-scss-less"},"content":{"pl":{"slug":"frontendowa-magia-coffeescript-sass-scss-less","title":"Frontendowa magia: CoffeeScript, Sass, Scss, Less...","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022364.93358633776\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEuUlEQVRIib2X228UVRzHP2dmdna6l962l+XSLaVeSiFRsoqAQf8A4jvvtn+CzxhjMDHEEJ8MATG+mfiAzz4QTYCk4UExpqlgAxTa0la67exlZs6Zc3woW7f2tqvQbzKZ35mcM9\/f\/M739zu\/EWYNCCEAeNF24x3Y1XbqgzqasVtBfV2zHEJrbf4T0\/9EHMfYtr3pubUX5I1RmJmZ4fz5j7l27ZstI+XshUMAs7OzXLlyFSkl4+NjFAqFLecJU1fVS8Lc3BxXr36N75cZHx9jePjwjnp04MVnFkAQhFy\/\/gMTExOMjX3IkSMjwO5ZJnZK+0YYY4iiiLt37zI7OwcYOju7KBQGKBQK2LaNMQalFE+ezJNwXNLpBK7IYrcLXGEgjhBOeneHmgn9rVu3uXDhM0ql0iZH29raOHbsKMVikePH3ySVSjM0mAMrBWYZVbZY8Vbokg6iEiN6D227bU05pJTi7NkPKJfL68+klERRhDEGy7LWvzCOY3K5borFtzh9+hT9\/XkqlSqO7XDmVDtOIgdEiMQrW3I1nWWWZaG1BkBrTalUeu6QXp+TzXTQ6e0jWx1m9qcuFjs93jlxiGx7llSqjcjSPFA1hkyJ2oIi27eZ3mlmx2zb5uLFz7l06UsmJycRQtDb04sKLOywg5Q8QF\/yCKP73yVccZl\/sohlWaQqefYfyD8P6W\/UghKHvbexsMj0\/qNZaDg6Gs+b+oSt7NHRUS5f\/gqlFN99Osn33\/6IKttYsUfSypJO99A3fJggMkROBks4xKXnOtGr4Izgq18IHldJWR6dA1vX5JYKoxACx3F4FP9M3D2DlejAjjpxSZPJpsn1SGqpgIXgKWX3EU9H7qH0R6hVDy9zn1wiT2ZgGUT\/thybHNrtEDTGML8yTdw3jek1aNsmSCYptbcz90aRimXxV\/sd0rJGWBrCSIfrn\/zOuQuDlJNZMiIAvA3vbZSNVR8YYzZcWhvi2KCkRkYxUaSIIoXvV\/F9H8dx8DyPTDpJPpsi\/16ITC2TTdfYl1OcyXl4lWc48R3OfTGCuXmbvNE0Hp91rrq9ZYSUNIRhRBRJtNYNixQA0\/P3OJD3KZVsnESCXDeUqwZvKUk50iS7F1gopZnKr5B41oHiVRL6GeL9AbAkQng7FsYNyooVVKsB1WoNKSVKqbUrjpEKypFBrUimpta+I5N1kbEAI9jnS9yMICocxdiaP2faSNYqzC8\/xjcGnNeB5LbaWd+yDQN7LcUNawVOKbVWAMOQMAjQQY3FJR+tfQouHHutzGrJxvb7mZrzWFgKcVYWsJTg6KjDH0nwoxhLJP9NtS02pL0QkM64uK5NtRYS1AKiKEJrjZQRYRixtLRIqEC6gpsT4NiSnqEHtLkpDvqrTP+6xODBVe7dt6jVPGLfJm11NuUMNBTGRqUnXJsON0V7ewqtDTrWxDrGX\/VRShFrxcOqJpFIEAt4vAqOlswlKqQti1AKyhWDMWvb3YhGnq3slvshKRU3btxgYmKChw8fsby8TDZrcGybMEriukm6uroYHBzk5MkTFIvFDeu36yTWe+8X0VMHQUAcxziOQzK5u3B3wp40+a38Bu1Jk98KWnao8T+rGbtlh142Qav4G4sUzOeqTN6uAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022364.93358633776\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022729.86717267552\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAbCAYAAAAULC3gAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEuUlEQVRIib2X228UVRzHP2dmdna6l962l+XSLaVeSiFRsoqAQf8A4jvvtn+CzxhjMDHEEJ8MATG+mfiAzz4QTYCk4UExpqlgAxTa0la67exlZs6Zc3woW7f2tqvQbzKZ35mcM9\/f\/M739zu\/EWYNCCEAeNF24x3Y1XbqgzqasVtBfV2zHEJrbf4T0\/9EHMfYtr3pubUX5I1RmJmZ4fz5j7l27ZstI+XshUMAs7OzXLlyFSkl4+NjFAqFLecJU1fVS8Lc3BxXr36N75cZHx9jePjwjnp04MVnFkAQhFy\/\/gMTExOMjX3IkSMjwO5ZJnZK+0YYY4iiiLt37zI7OwcYOju7KBQGKBQK2LaNMQalFE+ezJNwXNLpBK7IYrcLXGEgjhBOeneHmgn9rVu3uXDhM0ql0iZH29raOHbsKMVikePH3ySVSjM0mAMrBWYZVbZY8Vbokg6iEiN6D227bU05pJTi7NkPKJfL68+klERRhDEGy7LWvzCOY3K5borFtzh9+hT9\/XkqlSqO7XDmVDtOIgdEiMQrW3I1nWWWZaG1BkBrTalUeu6QXp+TzXTQ6e0jWx1m9qcuFjs93jlxiGx7llSqjcjSPFA1hkyJ2oIi27eZ3mlmx2zb5uLFz7l06UsmJycRQtDb04sKLOywg5Q8QF\/yCKP73yVccZl\/sohlWaQqefYfyD8P6W\/UghKHvbexsMj0\/qNZaDg6Gs+b+oSt7NHRUS5f\/gqlFN99Osn33\/6IKttYsUfSypJO99A3fJggMkROBks4xKXnOtGr4Izgq18IHldJWR6dA1vX5JYKoxACx3F4FP9M3D2DlejAjjpxSZPJpsn1SGqpgIXgKWX3EU9H7qH0R6hVDy9zn1wiT2ZgGUT\/thybHNrtEDTGML8yTdw3jek1aNsmSCYptbcz90aRimXxV\/sd0rJGWBrCSIfrn\/zOuQuDlJNZMiIAvA3vbZSNVR8YYzZcWhvi2KCkRkYxUaSIIoXvV\/F9H8dx8DyPTDpJPpsi\/16ITC2TTdfYl1OcyXl4lWc48R3OfTGCuXmbvNE0Hp91rrq9ZYSUNIRhRBRJtNYNixQA0\/P3OJD3KZVsnESCXDeUqwZvKUk50iS7F1gopZnKr5B41oHiVRL6GeL9AbAkQng7FsYNyooVVKsB1WoNKSVKqbUrjpEKypFBrUimpta+I5N1kbEAI9jnS9yMICocxdiaP2faSNYqzC8\/xjcGnNeB5LbaWd+yDQN7LcUNawVOKbVWAMOQMAjQQY3FJR+tfQouHHutzGrJxvb7mZrzWFgKcVYWsJTg6KjDH0nwoxhLJP9NtS02pL0QkM64uK5NtRYS1AKiKEJrjZQRYRixtLRIqEC6gpsT4NiSnqEHtLkpDvqrTP+6xODBVe7dt6jVPGLfJm11NuUMNBTGRqUnXJsON0V7ewqtDTrWxDrGX\/VRShFrxcOqJpFIEAt4vAqOlswlKqQti1AKyhWDMWvb3YhGnq3slvshKRU3btxgYmKChw8fsby8TDZrcGybMEriukm6uroYHBzk5MkTFIvFDeu36yTWe+8X0VMHQUAcxziOQzK5u3B3wp40+a38Bu1Jk98KWnao8T+rGbtlh142Qav4G4sUzOeqTN6uAAAAAElFTkSuQmCC\u0022 data-src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022960\u0022 height=\u0022729.86717267552\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\n\u003Cp\u003EZ drugiej jednak strony t\u0119 sam\u0105 przeno\u015bno\u015b\u0107 mo\u017cna te\u017c uzna\u0107 za wad\u0119. Ca\u0142y Internet sprowadza si\u0119 bowiem ostatnio do tej \u015bwi\u0119tej tr\u00f3jcy: \u003Cstrong\u003EHTML5 + CSS3 + JS\u003C\/strong\u003E. Bo skoro te trzy potrafi\u0105 ju\u017c wszystko to, co kiedy\u015b umia\u0142y tylko \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/flash\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Flash\u003C\/a\u003E czy aplety \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/java\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Javy\u003C\/a\u003E, to po co ryzykowa\u0107 bezpiecze\u0144stwo witryny, zmusza\u0107 u\u017cytkownika do instalowania wtyczek i odbiera\u0107 sobie mo\u017cliwo\u015b\u0107 lepszej integracji element\u00f3w strony? Po prostu \u003Cem\u003Enie ma sensu\u003C\/em\u003E wychodzi\u0107 poza \u015bwi\u0119t\u0105 tr\u00f3jc\u0119. A jej rozw\u00f3j jest niestety ograniczony aktualizacjami przegl\u0105darek. Czy zatem jeste\u015bmy na ni\u0105 \u003Cstrong\u003Eskazani\u003C\/strong\u003E?\u003C\/p\u003E\n\u003Cp\u003ENa szcz\u0119\u015bcie nie! Istnieje ca\u0142a rodzina j\u0119zyk\u00f3w, kt\u00f3re bardzo sprytnie obchodz\u0105 ten problem. Wprowadzaj\u0105 ogromne ulepszenia i u\u0142atwienia, ale bez potrzeby interpretowania ich przez przegl\u0105darki! Po prostu po stronie programisty s\u0105 kompilowane do jednego z tych j\u0119zyk\u00f3w, kt\u00f3re ka\u017cda przegl\u0105darka rozumie.\u003C\/p\u003E\n\u003Cp\u003EPowiedzmy na przyk\u0142ad, \u017ce chcesz stworzy\u0107 w CSS klasy od \u003Ccode\u003Ecol-1\u003C\/code\u003E do \u003Ccode\u003Ecol-12\u003C\/code\u003E, z kt\u00f3rych ka\u017cda b\u0119dzie nadawa\u0142a DIV-owi szeroko\u015b\u0107 r\u00f3wn\u0105 ile\u015btam dwunastych szeroko\u015bci kontenera. W \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/thesassway.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Sass\u003C\/a\u003E\u003C\/strong\u003E zajmuje to trzy linijki:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs scss border\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003E@for\u003C\/span\u003E \u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E from \u003Cspan class=\u0022hljs-number\u0022\u003E1\u003C\/span\u003E through \u003Cspan class=\u0022hljs-number\u0022\u003E12\u003C\/span\u003E\n  .col-#{\u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E}\n    \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-variable\u0022\u003E$i\u003C\/span\u003E\/\u003Cspan class=\u0022hljs-number\u0022\u003E12\u003C\/span\u003E * \u003Cspan class=\u0022hljs-number\u0022\u003E100%\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EA jest kompilowane do takiego kodu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs css border\u0022\u003E\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-1\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E8.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-2\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E16.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-3\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E25%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-4\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E33.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-5\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E41.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-6\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E50%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-7\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E58.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-8\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E66.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-9\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E75%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-10\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E83.33333%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-11\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E91.66667%\u003C\/span\u003E; }\n\n\u003Cspan class=\u0022hljs-selector-class\u0022\u003E.col-12\u003C\/span\u003E {\n  \u003Cspan class=\u0022hljs-attribute\u0022\u003Ewidth\u003C\/span\u003E: \u003Cspan class=\u0022hljs-number\u0022\u003E100%\u003C\/span\u003E; }\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EPierwszy z nich jest prosty, kr\u00f3tki i czytelny dla cz\u0142owieka, drugi natomiast zostanie zrozumiany przez wszystkie przegl\u0105darki. I wilk syty i owca ca\u0142a! Sass zawiera wiele element\u00f3w, kt\u00f3rych prostemu CSS-owi brakuje: zmiennych, instrukcji warunkowych, p\u0119tli, funkcji (tzw. mixins), zagnie\u017cd\u017ce\u0144, operacji arytmetycznych... O ile bardziej \u003Cstrong\u003Eelastyczny\u003C\/strong\u003E staje si\u0119 kod, gdy mo\u017cemy zdefiniowa\u0107 na przyk\u0142ad zmienn\u0105 \u003Ccode\u003E$navWidth: 300px\u003C\/code\u003E i u\u017cy\u0107 jej w pi\u0119ciu innych miejscach (r\u00f3wnie\u017c w wyra\u017ceniach arytmetycznych, np. \u003Ccode\u003Ewidth: $navWidth \/ 2 + 16px\u003C\/code\u003E), zamiast wsz\u0119dzie podawa\u0107 j\u0105 wprost. Ka\u017cda zmiana szeroko\u015bci nawigacji jest wtedy po prostu \u003Cstrong\u003Ebanalna\u003C\/strong\u003E, nie wymaga szukania wszystkich zale\u017cno\u015bci. O ile \u003Cstrong\u003Ekr\u00f3tszy i bardziej przejrzysty\u003C\/strong\u003E staje si\u0119 kod, je\u015bli mo\u017cemy cz\u0119sto powtarzaj\u0105ce si\u0119 elementy zamkn\u0105\u0107 w parametryzowane mixiny i po prostu si\u0119 do nich odwo\u0142ywa\u0107? \u015awietn\u0105 list\u0119 sassowych ficzer\u00f3w mo\u017cna znale\u017a\u0107 cho\u0107by na \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Sass_(stylesheet_language)\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Wikipedii\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cp\u003EPodobnymi do niego j\u0119zykami s\u0105 \u003Cstrong\u003EScss\u003C\/strong\u003E oras \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/lesscss.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Less\u003C\/a\u003E\u003C\/strong\u003E. Wol\u0119 jednak Sassa z jednego powodu \u2013 \u003Cstrong\u003Ebrak klamer\u003C\/strong\u003E. Skoro i tak w ka\u017cdym kodzie powinno si\u0119 stosowa\u0107 odpowiednie wci\u0119cia tabulatorami, to klamry staj\u0105 si\u0119 zwyczajnie zb\u0119dne. J\u0119zyk, kt\u00f3ry wymusza stosowanie wci\u0119\u0107 w kodzie po pierwsze wymaga mniej klepania w klawiatur\u0119, a po drugie daje gwarancj\u0119, \u017ce po kim by\u015bmy kodu nie przej\u0119li, zawsze przynajmniej pod tym wzgl\u0119dem b\u0119dzie on czytelny. Same plusy! Z tego samego za\u0142o\u017cenia wyszli chocia\u017cby tw\u00f3rcy \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.ruby-lang.org\/pl\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Rubiego\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.python.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Pythona\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E CoffeeScriptu\u003C\/a\u003E\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Cp\u003EA no w\u0142a\u015bnie, \u003Cstrong\u003ECoffeeScript\u003C\/strong\u003E. \u017bywy dow\u00f3d, \u017ce nawet tworzenie JavaScript\u00f3w mo\u017ce by\u0107 przyjemne (s\u0142owo daj\u0119, nie uwierzy\u0142bym, gdybym nie spr\u00f3bowa\u0142). W JS to dopiero jest nadmiar nawias\u00f3w i klamer:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Esse = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E EventSource(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_check\u0027\u003C\/span\u003E));\nsse.addEventListener(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Ee\u003C\/span\u003E) \u003C\/span\u003E{\n  \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (e.data == \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027test\u0027\u003C\/span\u003E || e.data == \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dev\u0027\u003C\/span\u003E) { \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E; }\n  $.post(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_fetch\u0027\u003C\/span\u003E), { \u003Cspan class=\u0022hljs-attr\u0022\u003Eids\u003C\/span\u003E: e.data }, \u003Cspan class=\u0022hljs-function\u0022\u003E\u003Cspan class=\u0022hljs-keyword\u0022\u003Efunction\u003C\/span\u003E(\u003Cspan class=\u0022hljs-params\u0022\u003Edata\u003C\/span\u003E) \u003C\/span\u003E{\n    conversation.html(data);\n  });\n}, \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E);\n\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETa sama funkcjonalno\u015b\u0107 w CoffeeScripcie wygl\u0105da nast\u0119puj\u0105co:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs javascript border\u0022\u003Esse = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E EventSource Routing.generate \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_check\u0027\u003C\/span\u003E\nsse.addEventListener \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation\u0027\u003C\/span\u003E, (e) -\u0026gt;\n  \u003Cspan class=\u0022hljs-keyword\u0022\u003Ereturn\u003C\/span\u003E \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E e.data \u003Cspan class=\u0022hljs-keyword\u0022\u003Ein\u003C\/span\u003E [\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027test\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027dev\u0027\u003C\/span\u003E]\n  $.post(Routing.generate(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027conversation_fetch\u0027\u003C\/span\u003E), { \u003Cspan class=\u0022hljs-attr\u0022\u003Eids\u003C\/span\u003E: e.data }, (data) -\u0026gt;\n    conversation.html(data)\n  )\n, \u003Cspan class=\u0022hljs-literal\u0022\u003Efalse\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWystarczy\u0142o zast\u0105pienie sk\u0142adni \u003Ccode\u003Efunction(a) {...}\u003C\/code\u003E prostym \u003Ccode\u003E(a) -\u0026gt; ...\u003C\/code\u003E, zmiana klamer na wci\u0119cia oraz mo\u017cliwo\u015b\u0107 pomini\u0119cia niekt\u00f3rych nawias\u00f3w w parametrach funkcji \u2013 i voil\u00e0! Mniej klepania w klawiatur\u0119 i doszukiwania si\u0119 par nawias\u00f3w, a tre\u015bci tyle samo!\u003C\/p\u003E\n\u003Cp\u003ENie spos\u00f3b si\u0119 nachwali\u0107 wszystkich ficzer\u00f3w CoffeeScriptu... JSON-owe obiekty mo\u017cna w nim definiowa\u0107 podobnie jak w \u003Ca href=\u0022http:\/\/yaml.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E YAML-u\u003C\/a\u003E, p\u0119tl\u0119 mo\u017cna od 1 do 100 zawrze\u0107 w kr\u00f3ciutkim zapisie \u003Ccode\u003E1..100\u003C\/code\u003E, zmiennych nie trzeba deklarowa\u0107, mo\u017cna im przypisywa\u0107 warto\u015bci do wielu na raz (a nawet zamienia\u0107 je warto\u015bciami w jednej linijce: \u003Ccode\u003E[foo, bar] = [bar, foo]\u003C\/code\u003E i tyle!). Najlepiej po prostu przejrze\u0107 jego \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E stron\u0119 domow\u0105\u003C\/a\u003E i milcze\u0107 w \u003Cstrong\u003Ezachwycie\u003C\/strong\u003E!\u003C\/p\u003E\n\u003Cp\u003ER\u00f3wnie\u017c w przypadku HTML-a istnieje wiele technologii, kt\u00f3re pozwalaj\u0105 na wygenerowanie go na postawie bardziej wyrafinowanych j\u0119zyk\u00f3w. Lecz tutaj to troch\u0119 co innego. Mowa o template engines takich jak \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/twig.sensiolabs.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Twig\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.smarty.net\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Smarty\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/haml.info\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Haml\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.stuartellis.eu\/articles\/erb\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Erb\u003C\/a\u003E\u003C\/strong\u003E \u2013 one jednak s\u0105 kompilowane do j\u0119zyk\u00f3w wykonywanych po stronie serwera (PHP, Ruby, Python...), wi\u0119c niezbyt pasuj\u0105 do mojego zestawienia. (Nota bene w Hamlu jeszcze bardziej zredukowana jest klamrowa redundancja: z \u003Ccode\u003E\u0026lt;html\u0026gt;\u0026lt;\/html\u0026gt;\u003C\/code\u003E robi si\u0119 zwyk\u0142e \u003Ccode\u003E%html\u003C\/code\u003E)\u003C\/p\u003E\n\u003Cp\u003EPotrafi\u0119 znale\u017a\u0107 tylko dwie wady ca\u0142ej tej rodziny technologii w por\u00f3wnaniu do \u003Cem\u003E\u015bwi\u0119tej tr\u00f3jcy\u003C\/em\u003E. Po pierwsze, tak jak przegl\u0105darki, tak samo frontendowi programi\u015bci tr\u00f3jc\u0119 znaj\u0105 z ca\u0142\u0105 pewno\u015bci\u0105, czego nie zawsze mo\u017cna powiedzie\u0107 o jej m\u0142odszym rodze\u0144stwie. Wi\u0119c je\u015bli kto\u015b dostanie po tobie projekt, w kt\u00f3rym u\u017cywa\u0142e\u015b Sassa czy CoffeeScriptu, mo\u017ce nie by\u0107 mu zbyt kolorowo. Z drugiej jednak strony, s\u0105 to przecie\u017c technologie \u003Cstrong\u003Ebardzo \u0142atwe do przyswojenia\u003C\/strong\u003E, a zarazem niezmiernie przydatne i wygodne. Wi\u0119c chyba tylko wy\u015bwiadczy\u0142by\u015b mu przys\u0142ug\u0119, prawda?\u003C\/p\u003E\n\u003Cp\u003EPo drugie natomiast, kompilowanie trwa i wymaga zachodu. Wystarczy jednak zainstalowa\u0107 \u003Ca href=\u0022http:\/\/bower.io\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E Bowera\u003C\/a\u003E albo skonfigurowa\u0107 sobie watchera w \u003Ca href=\u0022https:\/\/www.jetbrains.com\/phpstorm\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Csvg class=\u0022icon\u0022\u003E\u003Cuse xlink:href=\u0022#light-link\u0022\u003E\u003C\/use\u003E\u003C\/svg\u003E PhpStormie\u003C\/a\u003E, aby ka\u017cde zapisanie pliku automatycznie uruchamia\u0142o kompilacj\u0119. Naprawd\u0119, wygodniej ju\u017c si\u0119 tego zrobi\u0107 nie da!\u003C\/p\u003E\n\u003Cp\u003EA poza tym \u003Cstrong\u003Esame plusy\u003C\/strong\u003E. Je\u015bli tworzysz strony, a jeszcze nie znasz tych technologii \u2013 \u003Cstrong\u003Ekoniecznie je wypr\u00f3buj!\u003C\/strong\u003E Z odrobin\u0105 wprawy i do\u015bwiadczenia, po\u0142owa twoich frontendowych problem\u00f3w mo\u017ce znikn\u0105\u0107.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["coffeescript","frontend","haml","html","internet","javascript","kompilacja","less","programowanie","sass","scss","twig"],"hasMore":true,"image":"https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_small.jpeg","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_mini.jpeg\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022182.46679316888\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_big.jpeg\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/frontendowa-magia-coffeescript-sass-scss-less_mini.jpeg\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022182.46679316888\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003ETworz\u0105c kiedy\u015b stron\u0119 internetow\u0105, trzeba by\u0142o si\u0119 nie\u017ale napracowa\u0107, by na ka\u017cdym komputerze wygl\u0105da\u0142a mniej wi\u0119cej tak samo. Ka\u017cda przegl\u0105darka interpretowa\u0142a sobie kod po swojemu. Teraz jednak, gdy wszystkie nowe wersje popularnych przegl\u0105darek trzymaj\u0105 si\u0119 standard\u00f3w (a nawet m\u00f3j \u003Cem\u003Eulubiony\u003C\/em\u003E by\u0142y klient, Santander, przerzuci\u0142 si\u0119 z dinozaur\u00f3w na aktualne wydania), no a zdecydowan\u0105 wi\u0119kszo\u015b\u0107 pozosta\u0142ych jeszcze r\u00f3\u017cnic mi\u0119dzy przegl\u0105darkami mo\u017cna zniwelowa\u0107 u\u017cywaj\u0105c \u003Ca href=\u0022https:\/\/necolas.github.io\/normalize.css\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E normalize.css\u003C\/a\u003E oraz \u003Ca href=\u0022https:\/\/jquery.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E jQuery\u003C\/a\u003E, mog\u0119 z ca\u0142\u0105 stanowczo\u015bci\u0105 uzna\u0107 \u003Cstrong\u003Eprzeno\u015bno\u015b\u0107\u003C\/strong\u003E za najwi\u0119ksz\u0105 zalet\u0119 technologii webowych. Piszesz kod raz, a dzia\u0142a wsz\u0119dzie.\u003C\/p\u003E\n\u003Cp\u003EZ drugiej jednak strony t\u0119 sam\u0105 przeno\u015bno\u015b\u0107 mo\u017cna te\u017c uzna\u0107 za wad\u0119. Ca\u0142y Internet sprowadza si\u0119 bowiem ostatnio do tej \u015bwi\u0119tej tr\u00f3jcy: \u003Cstrong\u003EHTML5 + CSS3 + JS\u003C\/strong\u003E. Bo skoro te trzy potrafi\u0105 ju\u017c wszystko to, co kiedy\u015b umia\u0142y tylko \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/flash\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Flash\u003C\/a\u003E czy aplety \u003Ca href=\u0022https:\/\/niebezpiecznik.pl\/tag\/java\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Javy\u003C\/a\u003E, to po co ryzykowa\u0107 bezpiecze\u0144stwo witryny, zmusza\u0107 u\u017cytkownika do instalowania wtyczek i odbiera\u0107 sobie mo\u017cliwo\u015b\u0107 lepszej integracji element\u00f3w strony? Po prostu \u003Cem\u003Enie ma sensu\u003C\/em\u003E wychodzi\u0107 poza \u015bwi\u0119t\u0105 tr\u00f3jc\u0119. A jej rozw\u00f3j jest niestety ograniczony aktualizacjami przegl\u0105darek. Czy zatem jeste\u015bmy na ni\u0105 \u003Cstrong\u003Eskazani\u003C\/strong\u003E?\u003C\/p\u003E\n\u003Cp\u003ENa szcz\u0119\u015bcie nie! Istnieje ca\u0142a rodzina j\u0119zyk\u00f3w, kt\u00f3re bardzo sprytnie obchodz\u0105 ten problem. Wprowadzaj\u0105 ogromne ulepszenia i u\u0142atwienia, ale bez potrzeby interpretowania ich przez przegl\u0105darki! Po prostu po stronie programisty s\u0105 kompilowane do jednego z tych j\u0119zyk\u00f3w, kt\u00f3re ka\u017cda przegl\u0105darka rozumie.\u003C\/p\u003E\n\u003Cp\u003EPowiedzmy na przyk\u0142ad, \u017ce chcesz stworzy\u0107 w CSS klasy od \u003Ccode\u003Ecol-1\u003C\/code\u003E do \u003Ccode\u003Ecol-12\u003C\/code\u003E, z kt\u00f3rych ka\u017cda b\u0119dzie nadawa\u0142a DIV-owi szeroko\u015b\u0107 r\u00f3wn\u0105 ile\u015btam dwunastych szeroko\u015bci kontenera. W \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/thesassway.com\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Sass\u003C\/a\u003E\u003C\/strong\u003E zajmuje to trzy linijki:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E@for $i from 1 through 12\n  .col-#{$i}\n    width: $i\/12 * 100%\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EA jest kompilowane do takiego kodu:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E.col-1 {\n  width: 8.33333%; }\n\n.col-2 {\n  width: 16.66667%; }\n\n.col-3 {\n  width: 25%; }\n\n.col-4 {\n  width: 33.33333%; }\n\n.col-5 {\n  width: 41.66667%; }\n\n.col-6 {\n  width: 50%; }\n\n.col-7 {\n  width: 58.33333%; }\n\n.col-8 {\n  width: 66.66667%; }\n\n.col-9 {\n  width: 75%; }\n\n.col-10 {\n  width: 83.33333%; }\n\n.col-11 {\n  width: 91.66667%; }\n\n.col-12 {\n  width: 100%; }\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EPierwszy z nich jest prosty, kr\u00f3tki i czytelny dla cz\u0142owieka, drugi natomiast zostanie zrozumiany przez wszystkie przegl\u0105darki. I wilk syty i owca ca\u0142a! Sass zawiera wiele element\u00f3w, kt\u00f3rych prostemu CSS-owi brakuje: zmiennych, instrukcji warunkowych, p\u0119tli, funkcji (tzw. mixins), zagnie\u017cd\u017ce\u0144, operacji arytmetycznych... O ile bardziej \u003Cstrong\u003Eelastyczny\u003C\/strong\u003E staje si\u0119 kod, gdy mo\u017cemy zdefiniowa\u0107 na przyk\u0142ad zmienn\u0105 \u003Ccode\u003E$navWidth: 300px\u003C\/code\u003E i u\u017cy\u0107 jej w pi\u0119ciu innych miejscach (r\u00f3wnie\u017c w wyra\u017ceniach arytmetycznych, np. \u003Ccode\u003Ewidth: $navWidth \/ 2 + 16px\u003C\/code\u003E), zamiast wsz\u0119dzie podawa\u0107 j\u0105 wprost. Ka\u017cda zmiana szeroko\u015bci nawigacji jest wtedy po prostu \u003Cstrong\u003Ebanalna\u003C\/strong\u003E, nie wymaga szukania wszystkich zale\u017cno\u015bci. O ile \u003Cstrong\u003Ekr\u00f3tszy i bardziej przejrzysty\u003C\/strong\u003E staje si\u0119 kod, je\u015bli mo\u017cemy cz\u0119sto powtarzaj\u0105ce si\u0119 elementy zamkn\u0105\u0107 w parametryzowane mixiny i po prostu si\u0119 do nich odwo\u0142ywa\u0107? \u015awietn\u0105 list\u0119 sassowych ficzer\u00f3w mo\u017cna znale\u017a\u0107 cho\u0107by na \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Sass_(stylesheet_language)\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Wikipedii\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cp\u003EPodobnymi do niego j\u0119zykami s\u0105 \u003Cstrong\u003EScss\u003C\/strong\u003E oras \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/lesscss.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Less\u003C\/a\u003E\u003C\/strong\u003E. Wol\u0119 jednak Sassa z jednego powodu \u2013 \u003Cstrong\u003Ebrak klamer\u003C\/strong\u003E. Skoro i tak w ka\u017cdym kodzie powinno si\u0119 stosowa\u0107 odpowiednie wci\u0119cia tabulatorami, to klamry staj\u0105 si\u0119 zwyczajnie zb\u0119dne. J\u0119zyk, kt\u00f3ry wymusza stosowanie wci\u0119\u0107 w kodzie po pierwsze wymaga mniej klepania w klawiatur\u0119, a po drugie daje gwarancj\u0119, \u017ce po kim by\u015bmy kodu nie przej\u0119li, zawsze przynajmniej pod tym wzgl\u0119dem b\u0119dzie on czytelny. Same plusy! Z tego samego za\u0142o\u017cenia wyszli chocia\u017cby tw\u00f3rcy \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.ruby-lang.org\/pl\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Rubiego\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022https:\/\/www.python.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Pythona\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E CoffeeScriptu\u003C\/a\u003E\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Cp\u003EA no w\u0142a\u015bnie, \u003Cstrong\u003ECoffeeScript\u003C\/strong\u003E. \u017bywy dow\u00f3d, \u017ce nawet tworzenie JavaScript\u00f3w mo\u017ce by\u0107 przyjemne (s\u0142owo daj\u0119, nie uwierzy\u0142bym, gdybym nie spr\u00f3bowa\u0142). W JS to dopiero jest nadmiar nawias\u00f3w i klamer:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Esse = new EventSource(Routing.generate(\u0027conversation_check\u0027));\nsse.addEventListener(\u0027conversation\u0027, function(e) {\n  if (e.data == \u0027test\u0027 || e.data == \u0027dev\u0027) { return; }\n  $.post(Routing.generate(\u0027conversation_fetch\u0027), { ids: e.data }, function(data) {\n    conversation.html(data);\n  });\n}, false);\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003ETa sama funkcjonalno\u015b\u0107 w CoffeeScripcie wygl\u0105da nast\u0119puj\u0105co:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Esse = new EventSource Routing.generate \u0027conversation_check\u0027\nsse.addEventListener \u0027conversation\u0027, (e) -\u0026gt;\n  return if e.data in [\u0027test\u0027, \u0027dev\u0027]\n  $.post(Routing.generate(\u0027conversation_fetch\u0027), { ids: e.data }, (data) -\u0026gt;\n    conversation.html(data)\n  )\n, false\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EWystarczy\u0142o zast\u0105pienie sk\u0142adni \u003Ccode\u003Efunction(a) {...}\u003C\/code\u003E prostym \u003Ccode\u003E(a) -\u0026gt; ...\u003C\/code\u003E, zmiana klamer na wci\u0119cia oraz mo\u017cliwo\u015b\u0107 pomini\u0119cia niekt\u00f3rych nawias\u00f3w w parametrach funkcji \u2013 i voil\u00e0! Mniej klepania w klawiatur\u0119 i doszukiwania si\u0119 par nawias\u00f3w, a tre\u015bci tyle samo!\u003C\/p\u003E\n\u003Cp\u003ENie spos\u00f3b si\u0119 nachwali\u0107 wszystkich ficzer\u00f3w CoffeeScriptu... JSON-owe obiekty mo\u017cna w nim definiowa\u0107 podobnie jak w \u003Ca href=\u0022http:\/\/yaml.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E YAML-u\u003C\/a\u003E, p\u0119tl\u0119 mo\u017cna od 1 do 100 zawrze\u0107 w kr\u00f3ciutkim zapisie \u003Ccode\u003E1..100\u003C\/code\u003E, zmiennych nie trzeba deklarowa\u0107, mo\u017cna im przypisywa\u0107 warto\u015bci do wielu na raz (a nawet zamienia\u0107 je warto\u015bciami w jednej linijce: \u003Ccode\u003E[foo, bar] = [bar, foo]\u003C\/code\u003E i tyle!). Najlepiej po prostu przejrze\u0107 jego \u003Ca href=\u0022http:\/\/coffeescript.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E stron\u0119 domow\u0105\u003C\/a\u003E i milcze\u0107 w \u003Cstrong\u003Ezachwycie\u003C\/strong\u003E!\u003C\/p\u003E\n\u003Cp\u003ER\u00f3wnie\u017c w przypadku HTML-a istnieje wiele technologii, kt\u00f3re pozwalaj\u0105 na wygenerowanie go na postawie bardziej wyrafinowanych j\u0119zyk\u00f3w. Lecz tutaj to troch\u0119 co innego. Mowa o template engines takich jak \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/twig.sensiolabs.org\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Twig\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.smarty.net\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Smarty\u003C\/a\u003E\u003C\/strong\u003E, \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/haml.info\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Haml\u003C\/a\u003E\u003C\/strong\u003E czy \u003Cstrong\u003E\u003Ca href=\u0022http:\/\/www.stuartellis.eu\/articles\/erb\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Erb\u003C\/a\u003E\u003C\/strong\u003E \u2013 one jednak s\u0105 kompilowane do j\u0119zyk\u00f3w wykonywanych po stronie serwera (PHP, Ruby, Python...), wi\u0119c niezbyt pasuj\u0105 do mojego zestawienia. (Nota bene w Hamlu jeszcze bardziej zredukowana jest klamrowa redundancja: z \u003Ccode\u003E\u0026lt;html\u0026gt;\u0026lt;\/html\u0026gt;\u003C\/code\u003E robi si\u0119 zwyk\u0142e \u003Ccode\u003E%html\u003C\/code\u003E)\u003C\/p\u003E\n\u003Cp\u003EPotrafi\u0119 znale\u017a\u0107 tylko dwie wady ca\u0142ej tej rodziny technologii w por\u00f3wnaniu do \u003Cem\u003E\u015bwi\u0119tej tr\u00f3jcy\u003C\/em\u003E. Po pierwsze, tak jak przegl\u0105darki, tak samo frontendowi programi\u015bci tr\u00f3jc\u0119 znaj\u0105 z ca\u0142\u0105 pewno\u015bci\u0105, czego nie zawsze mo\u017cna powiedzie\u0107 o jej m\u0142odszym rodze\u0144stwie. Wi\u0119c je\u015bli kto\u015b dostanie po tobie projekt, w kt\u00f3rym u\u017cywa\u0142e\u015b Sassa czy CoffeeScriptu, mo\u017ce nie by\u0107 mu zbyt kolorowo. Z drugiej jednak strony, s\u0105 to przecie\u017c technologie \u003Cstrong\u003Ebardzo \u0142atwe do przyswojenia\u003C\/strong\u003E, a zarazem niezmiernie przydatne i wygodne. Wi\u0119c chyba tylko wy\u015bwiadczy\u0142by\u015b mu przys\u0142ug\u0119, prawda?\u003C\/p\u003E\n\u003Cp\u003EPo drugie natomiast, kompilowanie trwa i wymaga zachodu. Wystarczy jednak zainstalowa\u0107 \u003Ca href=\u0022http:\/\/bower.io\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E Bowera\u003C\/a\u003E albo skonfigurowa\u0107 sobie watchera w \u003Ca href=\u0022https:\/\/www.jetbrains.com\/phpstorm\/\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E PhpStormie\u003C\/a\u003E, aby ka\u017cde zapisanie pliku automatycznie uruchamia\u0142o kompilacj\u0119. Naprawd\u0119, wygodniej ju\u017c si\u0119 tego zrobi\u0107 nie da!\u003C\/p\u003E\n\u003Cp\u003EA poza tym \u003Cstrong\u003Esame plusy\u003C\/strong\u003E. Je\u015bli tworzysz strony, a jeszcze nie znasz tych technologii \u2013 \u003Cstrong\u003Ekoniecznie je wypr\u00f3buj!\u003C\/strong\u003E Z odrobin\u0105 wprawy i do\u015bwiadczenia, po\u0142owa twoich frontendowych problem\u00f3w mo\u017ce znikn\u0105\u0107.\u003C\/p\u003E","words":1075,"readTime":5,"lang":"pl"}}}}}