diff --git a/.gitignore b/.gitignore
index 20384474..85a6d1b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,10 @@
_site
.sass-cache
.jekyll-metadata
-Gemfile.lock
\ No newline at end of file
+Gemfile.lock
+
+.jekyll-cache
+
+.idea
+*.iml
+/draft/
diff --git a/CNAME b/CNAME
new file mode 100644
index 00000000..a5a90e95
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+www.writeonly.pl
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 89828dec..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2020 twocolumn
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
deleted file mode 100644
index 0a8da578..00000000
--- a/README.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Minimal Mistakes remote theme starter
-
-Fork this repo for the quickest method of getting started with the [Minimal Mistakes Jekyll theme](https://github.com/mmistakes/minimal-mistakes).
-
-Contains basic configuration to get you a site with:
-
-- Sample posts.
-- Sample top navigation.
-- Sample author sidebar with social links.
-- Sample footer links.
-- Paginated home page.
-- Archive pages for posts grouped by year, category, and tag.
-- Sample about page.
-- Sample 404 page.
-- Site wide search.
-
-Replace sample content with your own and [configure as necessary](https://mmistakes.github.io/minimal-mistakes/docs/configuration/).
-
----
-
-## Troubleshooting
-
-If you have a question about using Jekyll, start a discussion on the [Jekyll Forum](https://talk.jekyllrb.com/) or [StackOverflow](https://stackoverflow.com/questions/tagged/jekyll). Other resources:
-
-- [Ruby 101](https://jekyllrb.com/docs/ruby-101/)
-- [Setting up a Jekyll site with GitHub Pages](https://jekyllrb.com/docs/github-pages/)
-- [Configuring GitHub Metadata](https://github.com/jekyll/github-metadata/blob/master/docs/configuration.md#configuration) to work properly when developing locally and avoid `No GitHub API authentication could be found. Some fields may be missing or have incorrect data.` warnings.
diff --git a/_collections/_books/bdd-w-dzialaniu.html b/_collections/_books/bdd-w-dzialaniu.html
new file mode 100644
index 00000000..fff4ba13
--- /dev/null
+++ b/_collections/_books/bdd-w-dzialaniu.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'BDD w działaniu'
+title: 'BDD w działaniu. Sterowanie zachowaniem w rozwoju aplikacji'
+title-of-original: "BDD in Action: Behavior-Driven Development for the whole software lifecycle"
+year-of-publishment: 2015
+authors:
+ - 'John Ferguson Smart'
+langs: java
+tags: bdd
+---
diff --git a/_collections/_books/bootstrap-4-dla-zaawansowanych.html b/_collections/_books/bootstrap-4-dla-zaawansowanych.html
new file mode 100644
index 00000000..6aca159a
--- /dev/null
+++ b/_collections/_books/bootstrap-4-dla-zaawansowanych.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Bootstrap 4 dla zaawansowanych'
+title: 'Bootstrap 4 dla zaawansowanych. Jak pisać znakomite aplikacje internetowe. Wydanie II'
+title-of-original: "Mastering Bootstrap 4 – Second Edition"
+year-of-publishment: 2018
+authors:
+ - 'Benjamin Jakobus'
+ - 'Jason Marah'
+libs: bootstrap
+---
diff --git a/_collections/_books/bootstrap-tworzenie-interfejsow-stron-www.html b/_collections/_books/bootstrap-tworzenie-interfejsow-stron-www.html
new file mode 100644
index 00000000..58a340c0
--- /dev/null
+++ b/_collections/_books/bootstrap-tworzenie-interfejsow-stron-www.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'Bootstrap. Tworzenie interfejsow stron www'
+title: 'Bootstrap. Tworzenie interfejsow stron www. Technologia na start'
+title-of-original: "Jump Start Bootstrap"
+year-of-publishment: 2014
+authors:
+ - 'Syed Fazle Rahman'
+libs: bootstrap
+---
diff --git a/_collections/_books/bootstrap-tworzenie-wlasnych-stylow-graficznych.html b/_collections/_books/bootstrap-tworzenie-wlasnych-stylow-graficznych.html
new file mode 100644
index 00000000..065b19bc
--- /dev/null
+++ b/_collections/_books/bootstrap-tworzenie-wlasnych-stylow-graficznych.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'Bootstrap. Tworzenie własnych stylów graficznych'
+title: 'Bootstrap. Tworzenie własnych stylów graficznych'
+title-of-original: "Bootstrap. Tworzenie własnych stylów graficznych"
+year-of-publishment: 2017
+authors:
+ - 'Radosław Gryczan'
+libs: bootstrap
+---
diff --git a/_collections/_books/czysta-architektura.html b/_collections/_books/czysta-architektura.html
new file mode 100644
index 00000000..eb61aa9f
--- /dev/null
+++ b/_collections/_books/czysta-architektura.html
@@ -0,0 +1,8 @@
+---
+title-shortcut: 'Czysta Architektura'
+title: 'Czysta architektura. Struktura i design oprogramowania. Przewodnik dla profesjonalistów'
+title-of-original: "Clean Architecture: A Craftsman's Guide to SoftwareStructure and Design (Robert C. Martin Series)"
+year-of-publishment: 2018
+authors:
+ - 'Robert C. Martin'
+---
diff --git a/_collections/_books/czysty-kod.html b/_collections/_books/czysty-kod.html
new file mode 100644
index 00000000..28f64cd4
--- /dev/null
+++ b/_collections/_books/czysty-kod.html
@@ -0,0 +1,8 @@
+---
+title-shortcut: 'Czysty kod'
+title: 'Czysty kod. Podręcznik dobrego programisty'
+title-of-original: "Clean Code: A Handbook of Agile Software Craftsmanship"
+year-of-publishment: 2009
+authors:
+ - 'Robert C. Martin'
+---
diff --git a/_collections/_books/ddd-dla-architektow-oprogramowania.html b/_collections/_books/ddd-dla-architektow-oprogramowania.html
new file mode 100644
index 00000000..b6f92944
--- /dev/null
+++ b/_collections/_books/ddd-dla-architektow-oprogramowania.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'DDD dla architektów oprogramowania'
+title: 'DDD dla architektów oprogramowania'
+title-of-original: "Implementing Domain-Driven Design"
+year-of-publishment: 2013
+authors:
+ - 'Vaughn Vernon'
+tags: ddd
+---
diff --git a/_collections/_books/ddd.html b/_collections/_books/ddd.html
new file mode 100644
index 00000000..017edc92
--- /dev/null
+++ b/_collections/_books/ddd.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'DDD'
+title: 'DDD. Kompendium wiedzy'
+title-of-original: "Domain-Driven Design Distilled"
+year-of-publishment: 2016
+authors:
+ - 'Vaughn Vernon'
+tags: ddd
+---
diff --git a/_collections/_books/docker-dla-praktykow.html b/_collections/_books/docker-dla-praktykow.html
new file mode 100644
index 00000000..0d8b3ab3
--- /dev/null
+++ b/_collections/_books/docker-dla-praktykow.html
@@ -0,0 +1,11 @@
+---
+title-shortcut: 'Docker dla praktyków'
+title: 'Docker dla praktyków. Wydanie II'
+title-of-original: "Learning Docker - Second Edition"
+year-of-publishment: 2017
+authors:
+- 'Jeeva S. Chelladhurai'
+- 'Vinod Singh'
+- 'Pethuru Raj'
+tags: docker
+---
diff --git a/_collections/_books/docker-programowanie-aplikacji-dla-zaawansowanych.html b/_collections/_books/docker-programowanie-aplikacji-dla-zaawansowanych.html
new file mode 100644
index 00000000..7f059fc5
--- /dev/null
+++ b/_collections/_books/docker-programowanie-aplikacji-dla-zaawansowanych.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Docker. Programowanie aplikacji dla zaawansowanych'
+title: 'Docker. Programowanie aplikacji dla zaawansowanych. Wydanie II'
+title-of-original: "Mastering Docker - Second Edition"
+year-of-publishment: 2017
+authors:
+- 'Russ McKendrick'
+- 'Scott Gallagher'
+tags: docker
+---
diff --git a/_collections/_books/domain-driven-design.html b/_collections/_books/domain-driven-design.html
new file mode 100644
index 00000000..e0cf6519
--- /dev/null
+++ b/_collections/_books/domain-driven-design.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'Domain-Driven Design'
+title: 'Domain-Driven Design. Zapanuj nad złożonym systemem informatycznym'
+title-of-original: "Domain-Driven Design: Tackling Complexity in the Heart of Software"
+year-of-publishment: 2004
+authors:
+ - 'Eric Evans'
+tags: ddd
+---
diff --git a/_collections/_books/f-4-0-dla-zaawansowanych.html b/_collections/_books/f-4-0-dla-zaawansowanych.html
new file mode 100644
index 00000000..02932796
--- /dev/null
+++ b/_collections/_books/f-4-0-dla-zaawansowanych.html
@@ -0,0 +1,11 @@
+---
+title-shortcut: 'F# 4.0 dla zaawansowanych'
+title: 'F# 4.0 dla zaawansowanych. Wydanie IV'
+title-of-original: "Expert F# 4.0, 4th Edition"
+year-of-publishment: 2015
+authors:
+ - 'Don Syme'
+ - 'Adam Granicz'
+ - 'Antonio Cisternino'
+langs: fsharp
+---
diff --git a/_collections/_books/fpmortals.html b/_collections/_books/fpmortals.html
new file mode 100644
index 00000000..2c4ad5e7
--- /dev/null
+++ b/_collections/_books/fpmortals.html
@@ -0,0 +1,12 @@
+---
+title-shortcut: 'FP dla dla Śmiertelników'
+title: 'Programowanie Funkcyjne dla Śmiertelników ze Scalaz'
+title-of-original: "Functional Programming for Mortals with Scalaz"
+year-of-publishment: 2019
+authors:
+ - 'Sam Halliday'
+ - 'Wojciech Pituła'
+langs: haskell scala
+libs: scalaz
+---
+Programowanie Funkcyjne dla Śmiertelników ze Scalaz
\ No newline at end of file
diff --git a/_collections/_books/google-app-engine.html b/_collections/_books/google-app-engine.html
new file mode 100644
index 00000000..fa475638
--- /dev/null
+++ b/_collections/_books/google-app-engine.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Google App Engine'
+title: 'Google App Engine. Kod w chmurze'
+title-of-original: "Code in the Could"
+year-of-publishment: 2011
+authors:
+ - 'Mark C. Chu-Carroll'
+langs: java python
+libs: gwt
+---
diff --git a/_collections/_books/hibernate-search.html b/_collections/_books/hibernate-search.html
new file mode 100644
index 00000000..2126b846
--- /dev/null
+++ b/_collections/_books/hibernate-search.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Hibernate Search'
+title: 'Hibernate Search. Skuteczne wyszukiwanie'
+title-of-original: "Hibernate Search by Example"
+year-of-publishment: 2013
+authors:
+ - 'Steve Perkins'
+langs: java
+libs: hibernate
+---
diff --git a/_collections/_books/java-programowanie-funkcyjne.html b/_collections/_books/java-programowanie-funkcyjne.html
new file mode 100644
index 00000000..e023f978
--- /dev/null
+++ b/_collections/_books/java-programowanie-funkcyjne.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'Java. Programowanie funkcyjne'
+title: 'Java. Programowanie funkcyjne'
+title-of-original: "Functional Programming in Java: How to improve your Java programs using functional techniques"
+year-of-publishment: 2018
+authors:
+ - 'Pierre-Yves Saumont'
+langs: java
+---
diff --git a/_collections/_books/jquery.html b/_collections/_books/jquery.html
new file mode 100644
index 00000000..d87de0be
--- /dev/null
+++ b/_collections/_books/jquery.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'jQuery'
+title: 'jQuery. Kod doskonały'
+title-of-original: "jQuery. Kod doskonały"
+year-of-publishment: 2012
+authors:
+ - 'Peweł Mikołajewski'
+langs: javascript
+libs: jquery
+---
diff --git a/_collections/_books/junit.html b/_collections/_books/junit.html
new file mode 100644
index 00000000..80852230
--- /dev/null
+++ b/_collections/_books/junit.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'JUnit'
+title: 'Testowanie aplikacji Java za pomocą JUnit'
+title-of-original: "Testowanie aplikacji Java za pomocą JUnit"
+year-of-publishment: 2018
+authors:
+ - 'Radosław Sokół'
+langs: java
+libs: junit
+---
diff --git a/_collections/_books/kotlin-w-akcji.html b/_collections/_books/kotlin-w-akcji.html
new file mode 100644
index 00000000..baaf8b5e
--- /dev/null
+++ b/_collections/_books/kotlin-w-akcji.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Kotlin w akcji'
+title: 'Kotlin w akcji'
+title-of-original: "Kotlin in Action"
+year-of-publishment: 2017
+authors:
+ - 'Dmitry Jemerov'
+ - 'Svetlana Isakova'
+langs: kotlin
+---
diff --git a/_collections/_books/legendarny-osobomiesiac-opowiesci-o-inzynierii-oprogramowania-wydanie-ii.html b/_collections/_books/legendarny-osobomiesiac-opowiesci-o-inzynierii-oprogramowania-wydanie-ii.html
new file mode 100644
index 00000000..597ffbbd
--- /dev/null
+++ b/_collections/_books/legendarny-osobomiesiac-opowiesci-o-inzynierii-oprogramowania-wydanie-ii.html
@@ -0,0 +1,15 @@
+---
+title-shortcut: 'Legendarny osobomiesiąc'
+title: 'Legendarny osobomiesiąc. Opowieści o inżynierii oprogramowania. Wydanie II'
+title-of-original: "The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition (2nd Edition)"
+year-of-publishment: 1995
+authors:
+ - 'Frederick P. Brooks Jr.'
+---
+
+
+
+
+
+
+
diff --git a/_collections/_books/mistrz-czystego-kodu.html b/_collections/_books/mistrz-czystego-kodu.html
new file mode 100644
index 00000000..8d56fbc2
--- /dev/null
+++ b/_collections/_books/mistrz-czystego-kodu.html
@@ -0,0 +1,8 @@
+---
+title-shortcut: 'Mistrz czystego kodu'
+title: 'Mistrz czystego kodu. Kodeks postępowania profesjonalnych programistów'
+title-of-original: "The Clean Coder: A Code of Conduct for Professional Programmers"
+year-of-publishment: 2011
+authors:
+ - 'Robert C. Martin'
+---
diff --git a/_collections/_books/nosql-newsql-bigdata.html b/_collections/_books/nosql-newsql-bigdata.html
new file mode 100644
index 00000000..326cb7f0
--- /dev/null
+++ b/_collections/_books/nosql-newsql-bigdata.html
@@ -0,0 +1,8 @@
+---
+title-shortcut: 'NoSQL, NewSQL i BigData'
+title: 'NoSQL, NewSQL i BigData. Bazy danych następnej generacji'
+title-of-original: "Next Generation Databases: NoSQL and Big Data"
+year-of-publishment: 2015
+authors:
+ - 'Guy Harrison'
+---
diff --git a/_collections/_books/pragmatyczny-programista.html b/_collections/_books/pragmatyczny-programista.html
new file mode 100644
index 00000000..bb8b053d
--- /dev/null
+++ b/_collections/_books/pragmatyczny-programista.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'Pragmatyczny programista'
+title: 'Pragmatyczny programista. Od czeladnika do mistrza'
+title-of-original: 'The Pragmatic Programmer. From Journeyman to Master'
+year-of-publishment: 2010
+authors:
+ - 'Andrew Hunt'
+ - 'David Thomas'
+---
diff --git a/_collections/_books/programowanie-funkcyjne-krok-po-kroku.html b/_collections/_books/programowanie-funkcyjne-krok-po-kroku.html
new file mode 100644
index 00000000..f5b0f680
--- /dev/null
+++ b/_collections/_books/programowanie-funkcyjne-krok-po-kroku.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'Programowanie funkcyjne. Krok po kroku'
+title: 'Programowanie funkcyjne. Krok po kroku'
+title-of-original: "Becoming Functional"
+year-of-publishment: 2014
+authors:
+ - 'Joshua Backfield'
+langs: java scala
+---
diff --git a/_collections/_books/programowanie-funkcyjne.html b/_collections/_books/programowanie-funkcyjne.html
new file mode 100644
index 00000000..548ee09c
--- /dev/null
+++ b/_collections/_books/programowanie-funkcyjne.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'Programowanie funkcyjne'
+title: 'Programowanie funkcyjne. Poznaj Clojure Elixir Haskell Scala Swift'
+title-of-original: "Functional Programming: A PragPub Anthology: Exploring Clojure, Elixir, Haskell, Scala, and Swift"
+year-of-publishment: 2014
+authors:
+ - 'Swaine Michael'
+langs: clojure elixir haskell scala swift
+---
diff --git a/_collections/_books/programowanie-w-jezyku-clojure.html b/_collections/_books/programowanie-w-jezyku-clojure.html
new file mode 100644
index 00000000..59bc86e0
--- /dev/null
+++ b/_collections/_books/programowanie-w-jezyku-clojure.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Programowanie w języku Clojure'
+title: 'Programowanie w języku Clojure'
+title-of-original: "Programming Clojure"
+year-of-publishment: 2012
+authors:
+ - 'Stuart Halloway'
+ - 'Aaron Bedra'
+langs: clojure
+---
diff --git a/_collections/_books/programowanie-w-jezyku-rust.html b/_collections/_books/programowanie-w-jezyku-rust.html
new file mode 100644
index 00000000..2abfe99a
--- /dev/null
+++ b/_collections/_books/programowanie-w-jezyku-rust.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Programowanie w języku Rust'
+title: 'Programowanie w języku Rust'
+title-of-original: "The Rust Programming Language"
+year-of-publishment: 2019
+authors:
+ - 'Klabnik Steve'
+ - 'Nichols Carol'
+langs: rust
+---
diff --git a/_collections/_books/refaktoryzacja-ulepszanie-struktury-istniejacego-kodu.html b/_collections/_books/refaktoryzacja-ulepszanie-struktury-istniejacego-kodu.html
new file mode 100644
index 00000000..2f61c55b
--- /dev/null
+++ b/_collections/_books/refaktoryzacja-ulepszanie-struktury-istniejacego-kodu.html
@@ -0,0 +1,20 @@
+---
+title-shortcut: 'Refaktoryzacja. Ulepszanie struktury istniejącego kodu'
+title: 'Refaktoryzacja. Ulepszanie struktury istniejącego kodu'
+title-of-original: "Refactoring: Improving the Design of Existing Code"
+year-of-publishment: 1999
+authors:
+ - 'Martin Fowler'
+ - 'Kent Beck'
+ - 'John Brant'
+ - 'William Opdyke'
+ - 'Don Roberts'
+ - 'Erich Gamma'
+---
+
+
+
+
+
+
+
diff --git a/_collections/_books/rest.html b/_collections/_books/rest.html
new file mode 100644
index 00000000..c7ccea9b
--- /dev/null
+++ b/_collections/_books/rest.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'REST'
+title: 'REST. Najlepsze praktyki i wzorce w języku Java'
+title-of-original: "RESTful Java Patterns and Best Practices"
+year-of-publishment: 2015
+authors:
+ - 'Bhakti Mehta'
+langs: java
+tags: rest
+---
diff --git a/_collections/_books/scala-nauka-programowania.html b/_collections/_books/scala-nauka-programowania.html
new file mode 100644
index 00000000..133b560d
--- /dev/null
+++ b/_collections/_books/scala-nauka-programowania.html
@@ -0,0 +1,9 @@
+---
+title-shortcut: 'Scala. Nauka programowania'
+title: 'Scala. Nauka programowania'
+title-of-original: "Learning Scala Programming"
+year-of-publishment: 2018
+authors:
+ - 'Vikash Sharma'
+langs: scala
+---
diff --git a/_collections/_books/selenium.html b/_collections/_books/selenium.html
new file mode 100644
index 00000000..f43b2b30
--- /dev/null
+++ b/_collections/_books/selenium.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Selenium'
+title: 'Selenium. Automatyczne testowanie aplikacji'
+title-of-original: "Selenium Essentials"
+year-of-publishment: 2015
+authors:
+ - 'Prashanth'
+langs: java
+libs: selenium
+---
diff --git a/_collections/_books/spark.html b/_collections/_books/spark.html
new file mode 100644
index 00000000..a682d25b
--- /dev/null
+++ b/_collections/_books/spark.html
@@ -0,0 +1,13 @@
+---
+title-shortcut: 'Spark'
+title: 'Spark. Zaawansowana analiza danych'
+title-of-original: "Advanced Analytics with Spark"
+year-of-publishment: 2015
+authors:
+ - 'Sandy Ryza'
+ - 'Uri Laserson'
+ - 'Sean Owen'
+ - 'Josh Wills'
+langs: scala
+libs: spark
+---
diff --git a/_collections/_books/structura-i-interpretacja-programow-komputerowych.html b/_collections/_books/structura-i-interpretacja-programow-komputerowych.html
new file mode 100644
index 00000000..39b3866b
--- /dev/null
+++ b/_collections/_books/structura-i-interpretacja-programow-komputerowych.html
@@ -0,0 +1,11 @@
+---
+title-shortcut: 'Struktura i interpretacja programów komputerowych'
+title: 'Struktura i interpretacja programów komputerowych. Klasyka informatyki'
+title-of-original: "Structure and Interpretation of Computer Programs"
+year-of-publishment: 1996
+authors:
+ - 'Harold Abelson'
+ - 'Gerald Jay Sussman'
+ - 'Julie Sussman'
+langs: lisp scheme
+---
diff --git a/_collections/_books/tdd.html b/_collections/_books/tdd.html
new file mode 100644
index 00000000..918ad29f
--- /dev/null
+++ b/_collections/_books/tdd.html
@@ -0,0 +1,11 @@
+---
+title-shortcut: 'TDD'
+title: 'TDD. Programowanie w Javie sterowanie testami'
+title-of-original: "Test-Driven Java Development"
+year-of-publishment: 2015
+authors:
+ - 'Viktor Farcic'
+ - 'Alex Garcia'
+langs: java
+libs: junit
+---
diff --git a/_collections/_books/testuj-oprogramowanie-jak-google.html b/_collections/_books/testuj-oprogramowanie-jak-google.html
new file mode 100644
index 00000000..f929de0c
--- /dev/null
+++ b/_collections/_books/testuj-oprogramowanie-jak-google.html
@@ -0,0 +1,10 @@
+---
+title-shortcut: 'Testuj oprogramowanie jak Google'
+title: 'Testuj oprogramowanie jak Google. Metody automatyzacji'
+title-of-original: "How Google Tests Software"
+year-of-publishment: 2012
+authors:
+ - 'James A. Whittaker'
+ - 'Jason Arbon'
+ - 'Jeff Carollo'
+---
diff --git a/_collections/_books/zwinne-wytwarzanie-oprogramowania.html b/_collections/_books/zwinne-wytwarzanie-oprogramowania.html
new file mode 100644
index 00000000..93d58d1a
--- /dev/null
+++ b/_collections/_books/zwinne-wytwarzanie-oprogramowania.html
@@ -0,0 +1,8 @@
+---
+title-shortcut: 'Zwinne wytwarzanie oprogramowania'
+title: 'Zwinne wytwarzanie oprogramowania. Najlepsze zasady, wzorce i praktyki'
+title-of-original: "Agile Software Development, principles, Patterns and Practices"
+year-of-publishment: 2003
+authors:
+ - 'Robert C. Martin'
+---
diff --git a/_collections/_categories/cli.html b/_collections/_categories/cli.html
new file mode 100644
index 00000000..b32f8a9a
--- /dev/null
+++ b/_collections/_categories/cli.html
@@ -0,0 +1,4 @@
+---
+category: cli
+---
+Ang. command line interpreter/interface , czyli wiersz poleceń.
diff --git a/_collections/_categories/haskell-eta.html b/_collections/_categories/haskell-eta.html
new file mode 100644
index 00000000..6b786acc
--- /dev/null
+++ b/_collections/_categories/haskell-eta.html
@@ -0,0 +1,4 @@
+---
+category: haskell-eta
+redirect_from:
+---
diff --git a/_collections/_categories/java.html b/_collections/_categories/java.html
new file mode 100644
index 00000000..762460b8
--- /dev/null
+++ b/_collections/_categories/java.html
@@ -0,0 +1,3 @@
+---
+category: java
+---
diff --git a/_collections/_categories/jekyll.html b/_collections/_categories/jekyll.html
new file mode 100644
index 00000000..2bcceae3
--- /dev/null
+++ b/_collections/_categories/jekyll.html
@@ -0,0 +1,4 @@
+---
+category: jekyll
+---
+Opis walki z generatorem statycznych stron Jekyll i powstawania tematu WriteOnlyDoc.
diff --git a/_collections/_categories/programming.html b/_collections/_categories/programming.html
new file mode 100644
index 00000000..2be6a29b
--- /dev/null
+++ b/_collections/_categories/programming.html
@@ -0,0 +1,4 @@
+---
+category: programming
+---
+Techniczne opowieści o programowaniu i językach programowania.
diff --git a/_collections/_categories/relationships.html b/_collections/_categories/relationships.html
new file mode 100644
index 00000000..027c07d5
--- /dev/null
+++ b/_collections/_categories/relationships.html
@@ -0,0 +1,4 @@
+---
+category: relationships
+---
+Relacje z wydarzeń
diff --git a/_collections/_categories/rust.html b/_collections/_categories/rust.html
new file mode 100644
index 00000000..d57c1949
--- /dev/null
+++ b/_collections/_categories/rust.html
@@ -0,0 +1,4 @@
+---
+category: rust
+redirect_from:
+---
diff --git a/_collections/_categories/scala-jvm.html b/_collections/_categories/scala-jvm.html
new file mode 100644
index 00000000..7cb6b966
--- /dev/null
+++ b/_collections/_categories/scala-jvm.html
@@ -0,0 +1,6 @@
+---
+category: scala-jvm
+redirect_from:
+---
+Opis powstawania projektu hyde
+w języku programowania Scala ,
diff --git a/_collections/_categories/scala-native.html b/_collections/_categories/scala-native.html
new file mode 100644
index 00000000..a3bdcbb7
--- /dev/null
+++ b/_collections/_categories/scala-native.html
@@ -0,0 +1,6 @@
+---
+category: scala-native
+---
+Opis powstawania projektu resentiment
+w języku programowania Scala ,
+Scala.js i Scala native .
diff --git a/_collections/_categories/scheme-racket.html b/_collections/_categories/scheme-racket.html
new file mode 100644
index 00000000..fc7c4f50
--- /dev/null
+++ b/_collections/_categories/scheme-racket.html
@@ -0,0 +1,4 @@
+---
+category: scheme-racket
+redirect_from:
+---
diff --git a/_collections/_categories/thoughts.html b/_collections/_categories/thoughts.html
new file mode 100644
index 00000000..901c832b
--- /dev/null
+++ b/_collections/_categories/thoughts.html
@@ -0,0 +1,4 @@
+---
+category: thoughts
+---
+Przemyślenia niedokońca technicznie.
diff --git a/_collections/_eso/beatnik.html b/_collections/_eso/beatnik.html
new file mode 100644
index 00000000..b1cfa468
--- /dev/null
+++ b/_collections/_eso/beatnik.html
@@ -0,0 +1,5 @@
+---
+eso: beatnik
+title: Beatnik
+tags: esolang
+---
diff --git a/_collections/_eso/brainfuck.html b/_collections/_eso/brainfuck.html
new file mode 100644
index 00000000..67c4a24d
--- /dev/null
+++ b/_collections/_eso/brainfuck.html
@@ -0,0 +1,7 @@
+---
+eso: brainfuck
+title: BrainFuck
+tags: esolang
+color: rainbow
+---
+🌈
diff --git a/_collections/_eso/eas.html b/_collections/_eso/eas.html
new file mode 100644
index 00000000..6e9f39fd
--- /dev/null
+++ b/_collections/_eso/eas.html
@@ -0,0 +1,7 @@
+---
+eso: ets
+title: EAS
+tags: assembler
+color: red
+---
+❤️ Assembler dla ETA
diff --git a/_collections/_eso/esoassembly.html b/_collections/_eso/esoassembly.html
new file mode 100644
index 00000000..a2ebf478
--- /dev/null
+++ b/_collections/_eso/esoassembly.html
@@ -0,0 +1,7 @@
+---
+lang: esoassembly
+title: EsoAssembly
+description: ''
+redirect_from:
+- langs/easm
+---
diff --git a/_collections/_eso/eta.html b/_collections/_eso/eta.html
new file mode 100644
index 00000000..7828a0b7
--- /dev/null
+++ b/_collections/_eso/eta.html
@@ -0,0 +1,7 @@
+---
+eso: eta
+title: ETA
+tags: esolang
+color: red
+---
+❤️
diff --git a/_collections/_eso/false.html b/_collections/_eso/false.html
new file mode 100644
index 00000000..1ea26cbf
--- /dev/null
+++ b/_collections/_eso/false.html
@@ -0,0 +1,18 @@
+---
+eso: false
+title: False
+tags: esolang
+---
+
+Istnieją w Haskellu dwie implementacje ezoterycznego języka False:
+
+
+Przykładowy program:
+
+{[n: 0 1 [n;0=~][$2o+n;1-n:]# %%]f: 300f;!}
+[0 1 @ [0=~][1o3o+\1-]# %%%]f: 300f;!
+{4 0 1 @ 1o 3o + \ 1 -}
+
diff --git a/_collections/_eso/funge.html b/_collections/_eso/funge.html
new file mode 100644
index 00000000..3b41748e
--- /dev/null
+++ b/_collections/_eso/funge.html
@@ -0,0 +1,8 @@
+---
+eso: funge
+title: Funge
+tags: compiler esolang
+langs: scheme
+color: yellow
+---
+💛 Kompilator podzbioru Scheme do Funge
diff --git a/_collections/_eso/piet.html b/_collections/_eso/piet.html
new file mode 100644
index 00000000..61164450
--- /dev/null
+++ b/_collections/_eso/piet.html
@@ -0,0 +1,12 @@
+---
+eso: piet
+title: Piet
+tags: esolang
+color: green
+---
+💚
+
+Istnieje jeden interpreter ezoterycznego języka Piet napisany w Haskellu:
+
diff --git a/_collections/_eso/sponge.html b/_collections/_eso/sponge.html
new file mode 100644
index 00000000..3bfbc0a3
--- /dev/null
+++ b/_collections/_eso/sponge.html
@@ -0,0 +1,7 @@
+---
+eso: sponge
+title: Sponge
+tags: esolang
+color: yellow
+---
+💛 Compiler Subset of Scheme to BeFunge98
diff --git a/_collections/_eso/sqasm.html b/_collections/_eso/sqasm.html
new file mode 100644
index 00000000..e476c3e8
--- /dev/null
+++ b/_collections/_eso/sqasm.html
@@ -0,0 +1,7 @@
+---
+eso: sqasm
+title: SqAsm
+tags: assembler
+color: blue
+---
+💙 Assembler dla SubLeq
diff --git a/_collections/_eso/subleq.html b/_collections/_eso/subleq.html
new file mode 100644
index 00000000..28b1682d
--- /dev/null
+++ b/_collections/_eso/subleq.html
@@ -0,0 +1,7 @@
+---
+eso: subleq
+title: SubLeq
+tags: esolang
+color: blue
+---
+💙
diff --git a/_collections/_eso/wasm.html b/_collections/_eso/wasm.html
new file mode 100644
index 00000000..32ad266f
--- /dev/null
+++ b/_collections/_eso/wasm.html
@@ -0,0 +1,7 @@
+---
+eso: wasm
+title: WAsm
+tags: assembler
+color: black
+---
+🖤 Assembler Maszyny W
diff --git a/_collections/_eso/whitespace.html b/_collections/_eso/whitespace.html
new file mode 100644
index 00000000..95288203
--- /dev/null
+++ b/_collections/_eso/whitespace.html
@@ -0,0 +1,15 @@
+---
+eso: whitespace
+title: WhiteSpace
+tags: esolang
+color: white
+---
+🤍
+
+Istnieją cztery interpretery ezoterycznego języka WhiteSpace napisane w Haskellu:
+
diff --git a/_collections/_eso/wsa.html b/_collections/_eso/wsa.html
new file mode 100644
index 00000000..a9aaf7d9
--- /dev/null
+++ b/_collections/_eso/wsa.html
@@ -0,0 +1,7 @@
+---
+eso: wsa
+title: WSA
+tags: assembler
+color: white
+---
+🤍 Assembler dla WhiteSpace
diff --git a/_collections/_langs/agda.html b/_collections/_langs/agda.html
new file mode 100644
index 00000000..30c0dee8
--- /dev/null
+++ b/_collections/_langs/agda.html
@@ -0,0 +1,10 @@
+---
+lang: agda
+title: Agda
+description:
+---
+
diff --git a/_collections/_langs/ams-js.html b/_collections/_langs/ams-js.html
new file mode 100644
index 00000000..28e6d860
--- /dev/null
+++ b/_collections/_langs/ams-js.html
@@ -0,0 +1,5 @@
+---
+lang: ams-js
+title: asm.js
+description: ''
+---
diff --git a/_collections/_langs/awk.html b/_collections/_langs/awk.html
new file mode 100644
index 00000000..d871292d
--- /dev/null
+++ b/_collections/_langs/awk.html
@@ -0,0 +1,17 @@
+---
+lang: awk
+title: AWK
+description: dynamicznie typowany, skryptowy język programowania.
+---
+
+
+Blogi
+
diff --git a/_collections/_langs/ceylon.html b/_collections/_langs/ceylon.html
new file mode 100644
index 00000000..82074b50
--- /dev/null
+++ b/_collections/_langs/ceylon.html
@@ -0,0 +1,16 @@
+---
+lang: ceylon
+title: Ceylon
+description: statycznie typowany język programowania kompliwany do kodu maszynowego Javy.
+---
+
diff --git a/_collections/_langs/clojure.html b/_collections/_langs/clojure.html
new file mode 100644
index 00000000..4311cf28
--- /dev/null
+++ b/_collections/_langs/clojure.html
@@ -0,0 +1,52 @@
+---
+lang: clojure
+title: Clojure
+description: 'obiektowo-funkcyjny dialekt funkcyjnego języka programowania Lisp kompilowany do kodu bajtowego Javy.'
+---
+
+
+Istnieją także poboczne kompilatory i transpilatory języka Clojure:
+
+
+ ClojureScript - transpilator Clojure do języka JavaScript.
+
+
+ ClojureCLR - kompilator Clojure do CLR dla platformu .Net.
+
+
+ ClojureC - transpilator Clojure do C.
+
+
+ ClojureScheme - transpilator Clojure do Scheme.
+ Później Scheme można transpilować do C.
+
+
+ clojure-py - transpilator Clojure do języka Python.
+
+
+
+Tutoriale i książki
+
diff --git a/_collections/_langs/coffeescript.html b/_collections/_langs/coffeescript.html
new file mode 100644
index 00000000..a4bf3929
--- /dev/null
+++ b/_collections/_langs/coffeescript.html
@@ -0,0 +1,21 @@
+---
+lang: coffeescript
+title: CoffeeScript
+description: 'dynamicznie typowany język programowania transpilowany do języka JavaScript .'
+redirect_from:
+- langs/cs
+---
+
diff --git a/_collections/_langs/common-lisp.html b/_collections/_langs/common-lisp.html
new file mode 100644
index 00000000..30733feb
--- /dev/null
+++ b/_collections/_langs/common-lisp.html
@@ -0,0 +1,35 @@
+---
+lang: common-lisp
+title: Common Lisp
+description: 'obiektowo-funkcyjny standard funkcyjnego języka programowania Lisp .'
+redirect_from:
+- langs/cl
+---
+
+
+Blogi
+
+
+Inne
+
diff --git a/_collections/_langs/coq.html b/_collections/_langs/coq.html
new file mode 100644
index 00000000..b0cae685
--- /dev/null
+++ b/_collections/_langs/coq.html
@@ -0,0 +1,13 @@
+---
+lang: coq
+title: Coq
+description:
+---
+
\ No newline at end of file
diff --git a/_collections/_langs/crystal.html b/_collections/_langs/crystal.html
new file mode 100644
index 00000000..57d1e28f
--- /dev/null
+++ b/_collections/_langs/crystal.html
@@ -0,0 +1,19 @@
+---
+lang: crystal
+title: Crystal
+description: statycznie typowany, natywny język programowania ze składnią inspirowaną językiem Ruby.
+---
+
diff --git a/_collections/_langs/dart.html b/_collections/_langs/dart.html
new file mode 100644
index 00000000..429b4bc3
--- /dev/null
+++ b/_collections/_langs/dart.html
@@ -0,0 +1,16 @@
+---
+lang: dart
+title: Dart
+description: statycznie typowany język programowania
+---
+
diff --git a/_collections/_langs/dc.html b/_collections/_langs/dc.html
new file mode 100644
index 00000000..d47be398
--- /dev/null
+++ b/_collections/_langs/dc.html
@@ -0,0 +1,5 @@
+---
+lang: dc
+title: DC
+description: ''
+---
\ No newline at end of file
diff --git a/_collections/_langs/eiffel.html b/_collections/_langs/eiffel.html
new file mode 100644
index 00000000..fff7e457
--- /dev/null
+++ b/_collections/_langs/eiffel.html
@@ -0,0 +1,13 @@
+---
+lang: eiffel
+title: Eiffel
+description: statycznie typowany, obiektowy język programowania.
+---
+
diff --git a/_collections/_langs/elixir.html b/_collections/_langs/elixir.html
new file mode 100644
index 00000000..30544b2b
--- /dev/null
+++ b/_collections/_langs/elixir.html
@@ -0,0 +1,19 @@
+---
+lang: elixir
+title: Elixir
+description: dynamicznie i silnie typowany oraz funkcyjny i współbieżny język programowania działający na maszynie wirtualnej Erlanga ze składnią inspirowaną językiem Ruby.
+---
+
diff --git a/_collections/_langs/elm.html b/_collections/_langs/elm.html
new file mode 100644
index 00000000..204f99e4
--- /dev/null
+++ b/_collections/_langs/elm.html
@@ -0,0 +1,33 @@
+---
+lang: elm
+title: Elm
+description: 'język funkcyjny transpilowany do JS ispirowany językami ML i Haskell .'
+---
+
+
+Tutoriale i książki
+
+
+Blogi
+
diff --git a/_collections/_langs/emacs-lisp.html b/_collections/_langs/emacs-lisp.html
new file mode 100644
index 00000000..c4e6c9be
--- /dev/null
+++ b/_collections/_langs/emacs-lisp.html
@@ -0,0 +1,20 @@
+---
+lang: emacs-lisp
+title: Emacs Lisp
+description: 'Elisp, dialekt języka programowania Lisp używany do pisania rozszerzeń i skryptów edytora Emacs.'
+redirect_from:
+- langs/el
+- langs/elc
+- langs/elisp
+---
+
diff --git a/_collections/_langs/erlang.html b/_collections/_langs/erlang.html
new file mode 100644
index 00000000..97479219
--- /dev/null
+++ b/_collections/_langs/erlang.html
@@ -0,0 +1,13 @@
+---
+lang: erlang
+title: Erlang
+description: dynamicznie i silnie typowany oraz funkcyjny i współbieżny język programowania działający na maszynie wirtualnej Erlanga
+---
+
diff --git a/_collections/_langs/eta.html b/_collections/_langs/eta.html
new file mode 100644
index 00000000..3760e95f
--- /dev/null
+++ b/_collections/_langs/eta.html
@@ -0,0 +1,41 @@
+---
+lang: eta
+title: Eta
+description: 'implementacja czysto-funkcyjnego języka programowania Haskell kompilowana do kodu bajtowego Javy.'
+---
+
+
+Wykłady i prezentacje
+
diff --git a/_collections/_langs/forth.html b/_collections/_langs/forth.html
new file mode 100644
index 00000000..9e8191ef
--- /dev/null
+++ b/_collections/_langs/forth.html
@@ -0,0 +1,5 @@
+---
+lang: forth
+title: Forth
+description: ''
+---
diff --git a/_collections/_langs/frege.html b/_collections/_langs/frege.html
new file mode 100644
index 00000000..8c503693
--- /dev/null
+++ b/_collections/_langs/frege.html
@@ -0,0 +1,20 @@
+---
+lang: frege
+title: Frege
+description: 'dialekt czysto-funkcyjnego języka programowania Haskell kompilowany do kodu bajtowego Javy.'
+---
+
+
+Nagrania
+
diff --git a/_collections/_langs/fsharp.html b/_collections/_langs/fsharp.html
new file mode 100644
index 00000000..28977a6a
--- /dev/null
+++ b/_collections/_langs/fsharp.html
@@ -0,0 +1,16 @@
+---
+lang: fsharp
+title: F#
+description: statycznie typowany, obiektowo-funkcyjny język programowania. Dialekt języka OCaml
+---
+
diff --git a/_collections/_langs/genie.html b/_collections/_langs/genie.html
new file mode 100644
index 00000000..1fe51174
--- /dev/null
+++ b/_collections/_langs/genie.html
@@ -0,0 +1,13 @@
+---
+lang: genie
+title: Genie
+description: statycznie typowany, natywny i obiektowy język programowania transpilowany do C.
+---
+
diff --git a/_collections/_langs/go.html b/_collections/_langs/go.html
new file mode 100644
index 00000000..97b153c0
--- /dev/null
+++ b/_collections/_langs/go.html
@@ -0,0 +1,16 @@
+---
+lang: go
+title: Go
+description: statycznie typowany, natywny język programowania.
+---
+
diff --git a/_collections/_langs/hamler.html b/_collections/_langs/hamler.html
new file mode 100644
index 00000000..a3124e7b
--- /dev/null
+++ b/_collections/_langs/hamler.html
@@ -0,0 +1,15 @@
+---
+lang: hamler
+title: hamler
+description: 'dialekt funkcyjnego języka programowania Haskell działający na maszynie wirtualnej Erlanga .'
+redirect_from:
+- langs/ps
+---
+
\ No newline at end of file
diff --git a/_collections/_langs/haskell.html b/_collections/_langs/haskell.html
new file mode 100644
index 00000000..25020d92
--- /dev/null
+++ b/_collections/_langs/haskell.html
@@ -0,0 +1,85 @@
+---
+lang: haskell
+title: Haskell
+description: 'statycznie typowany, natywny i czysto-funkcyjny język programowania.'
+redirect_from:
+- langs/hs
+- langs/lhs
+---
+
+
+Niestandardowe implementacje i dialekty
+
diff --git a/_collections/_langs/idris.html b/_collections/_langs/idris.html
new file mode 100644
index 00000000..37d9fe47
--- /dev/null
+++ b/_collections/_langs/idris.html
@@ -0,0 +1,23 @@
+---
+lang: idris
+title: Idris
+description: 'statycznie typowany, natywny i czysto-funkcyjny język programowania. Prawdopodobnie następca języka Haskell .'
+---
+
+
+Książki
+
diff --git a/_collections/_langs/java.html b/_collections/_langs/java.html
new file mode 100644
index 00000000..461b84c8
--- /dev/null
+++ b/_collections/_langs/java.html
@@ -0,0 +1,5 @@
+---
+lang: java
+title: Java
+description: statycznie typowany język programowania kompilowany do kodu maszynowego Javy.
+---
\ No newline at end of file
diff --git a/_collections/_langs/javascript.html b/_collections/_langs/javascript.html
new file mode 100644
index 00000000..4759a073
--- /dev/null
+++ b/_collections/_langs/javascript.html
@@ -0,0 +1,7 @@
+---
+lang: javascript
+title: JavaScript
+description: 'dynamicznie i słabo typowany, skryptowy język programowania.'
+redirect_from:
+- langs/js
+---
diff --git a/_collections/_langs/joy.html b/_collections/_langs/joy.html
new file mode 100644
index 00000000..4dab6dcb
--- /dev/null
+++ b/_collections/_langs/joy.html
@@ -0,0 +1,13 @@
+---
+lang: joy
+title: Joy
+description: funkcyjny, stosowy, dynamicznie typowany język programowania
+---
+
diff --git a/_collections/_langs/julia.html b/_collections/_langs/julia.html
new file mode 100644
index 00000000..21dddc8d
--- /dev/null
+++ b/_collections/_langs/julia.html
@@ -0,0 +1,13 @@
+---
+lang: julia
+title: Julia
+description: dynamicznie typowany język przeznaczony do wysokowydajnej analizy numerycznej i nauk obliczeniowych.
+---
+
diff --git a/_collections/_langs/kotlin.html b/_collections/_langs/kotlin.html
new file mode 100644
index 00000000..2e33c9a1
--- /dev/null
+++ b/_collections/_langs/kotlin.html
@@ -0,0 +1,26 @@
+---
+lang: kotlin
+title: Kotlin
+description: statycznie typowany język programowania kompilowany do kodu maszynowego Javy.
+---
+
+
+Nagrania
+
\ No newline at end of file
diff --git a/_collections/_langs/lisp.html b/_collections/_langs/lisp.html
new file mode 100644
index 00000000..d05d4e35
--- /dev/null
+++ b/_collections/_langs/lisp.html
@@ -0,0 +1,29 @@
+---
+lang: lisp
+title: Lisp
+description: dynamicznie typowany, funkcyjny język programowania.
+---
+Pięć głównych dialektów to:
+
+
+ Scheme - minimalistyczny,
+ mocno funkcyjny (rekurencja ogonkowa i pełne kontunuacje) Lisp wymyślony w MIT do katowania studentów
+
+
+ Racket - dialekt Scheme używany do zastosowań naukowych
+
+
+ Clojure - dialekt Lispa,
+ mocno podobny do Scheme,
+ zoptymalizowany do działania na JVM
+ i czerpiący mocno z języka Haskell
+
+
+ Common Lisp - wszystkomający,
+ obiektowo-funkcyjny (Common Lisp Object System) Lisp
+
+
+ Emacs Lisp - dialekt Lispa,
+ mocno podobny do Common Lisp, używany w edytorze Emacs
+
+
diff --git a/_collections/_langs/livescript.html b/_collections/_langs/livescript.html
new file mode 100644
index 00000000..5e28f92f
--- /dev/null
+++ b/_collections/_langs/livescript.html
@@ -0,0 +1,18 @@
+---
+lang: livescript
+title: LiveScript
+description: 'dynamicznie i słabo typowany język programowania transpilowany do języka JavaScript .'
+redirect_from:
+- langs/ls
+---
+
diff --git a/_collections/_langs/lua.html b/_collections/_langs/lua.html
new file mode 100644
index 00000000..73d84932
--- /dev/null
+++ b/_collections/_langs/lua.html
@@ -0,0 +1,22 @@
+---
+lang: lua
+title: Lua
+description: dynamicznie typowany, skryptowy język programowania.
+---
+
diff --git a/_collections/_langs/meta-language.html b/_collections/_langs/meta-language.html
new file mode 100644
index 00000000..47ff8939
--- /dev/null
+++ b/_collections/_langs/meta-language.html
@@ -0,0 +1,49 @@
+---
+lang: meta-language
+title: Meta Language
+description: 'ML, rodzina statycznie typowanych języków funkcyjnych. Jako jeden z pierwszych posiadał typy polimorficzne umożliwiajace metaprogramowanie. Zaprojektowany jako LISP z typami.'
+redirect_from:
+- posts-by-langs/meta-language
+- langs/ml
+- langs/sml
+---
+Dialekty języka ML
+
+
+ OCaml - prawdopodobnie pierwszy statycznie typowany język wszystkomający (obiektowo-funkcyjny).
+
+
+ Standard ML , (SML ) - ustandaryzowana wersja języka.
+
+
+ Concurrent ML , (CML ) - dialekt Standard ML posiadający rozszerzenia do programowania współbierznego.
+
+
+ Dependent ML , (DML ) - eksperymentalna wersja ML posiadająca typy zależne .
+
+
+ Lazy ML , (LML ) - język ML z leniwą ewaluacją kompilowany do kodu natywnego.
+ Jeden z protoplastów języka Haskell
+
+
+ MacroML - eksperymentalna wersja ML posiadająca makra inspirowane makrami z języka Scheme
+
+
+ Elm - język transpilowany do JS, inspirowany językami ML i Haskell .
+
+
+ LinearML - ML działąjący bez GC
+
+
+
+Kursy
+
+
+
diff --git a/_collections/_langs/mouse.html b/_collections/_langs/mouse.html
new file mode 100644
index 00000000..620b98a4
--- /dev/null
+++ b/_collections/_langs/mouse.html
@@ -0,0 +1,10 @@
+---
+lang: mouse
+title: Mouse
+description: ''
+---
+
diff --git a/_collections/_langs/ocaml.html b/_collections/_langs/ocaml.html
new file mode 100644
index 00000000..b26a1c9e
--- /dev/null
+++ b/_collections/_langs/ocaml.html
@@ -0,0 +1,55 @@
+---
+lang: ocaml
+title: OCaml
+description: 'Obiektowe rozwinięcie języka programowania ML i pradopodobnie pierwszy statycznie typowany język wszystkomający (obiektowo-funkcyjny)'
+redirect_from:
+- langs/caml
+- langs/mli
+---
+
+
+Blogi i youtube
+
+
+Dialekty języka OCaml i języki inspirowane nim
+
+
+ Scala - język programowania na wirtualną maszynę Javy
+ inspirowany językiem OCaml.
+ Podobno co wersję Scali Martina Odersky zastanawia się czy nie zastąpić wąsatych nawiasów wcięciami jak w języku OCaml.
+
+
+ F# -implementacja języka OCaml na platformę .Net która powoli staje się nowym dialektem i językiem.
+
+
+ ReasonML - dialekt języka OCaml
+ kompilowany do JS
+ za pomocą BuckleScript .
+
+
diff --git a/_collections/_langs/perl.html b/_collections/_langs/perl.html
new file mode 100644
index 00000000..20d07cd2
--- /dev/null
+++ b/_collections/_langs/perl.html
@@ -0,0 +1,22 @@
+---
+lang: perl
+title: Perl
+description: dynamicznie i słabo typowany, skryptowy język programowania.
+---
+
\ No newline at end of file
diff --git a/_collections/_langs/pony.html b/_collections/_langs/pony.html
new file mode 100644
index 00000000..4fc4aeed
--- /dev/null
+++ b/_collections/_langs/pony.html
@@ -0,0 +1,23 @@
+---
+lang: pony
+title: Pony
+description: natywny język programowania.
+---
+
+
+Artykuły i youtube
+
diff --git a/_collections/_langs/postscript.html b/_collections/_langs/postscript.html
new file mode 100644
index 00000000..faedd241
--- /dev/null
+++ b/_collections/_langs/postscript.html
@@ -0,0 +1,10 @@
+---
+lang: postscript
+title: PostScript
+description: ''
+---
+
diff --git a/_collections/_langs/prolog.html b/_collections/_langs/prolog.html
new file mode 100644
index 00000000..6823846d
--- /dev/null
+++ b/_collections/_langs/prolog.html
@@ -0,0 +1,27 @@
+---
+lang: prolog
+title: Prolog
+description: język programowania logicznego.
+---
+
+
+ Wikipedia
+
+
+ wazniak.mimuw.edu.pl:
+
+
+
+Blogi
+
diff --git a/_collections/_langs/purescript.html b/_collections/_langs/purescript.html
new file mode 100644
index 00000000..36a1cd03
--- /dev/null
+++ b/_collections/_langs/purescript.html
@@ -0,0 +1,21 @@
+---
+lang: purescript
+title: PureScript
+description: 'dialekt funkcyjnego języka programowania Haskell transpilowany do języka JavaScript .'
+redirect_from:
+- langs/ps
+---
+
\ No newline at end of file
diff --git a/_collections/_langs/python.html b/_collections/_langs/python.html
new file mode 100644
index 00000000..cd48edc5
--- /dev/null
+++ b/_collections/_langs/python.html
@@ -0,0 +1,16 @@
+---
+lang: python
+title: Python
+description: dynamicznie typowany, skryptowy język programowania.
+---
+
diff --git a/_collections/_langs/racket.html b/_collections/_langs/racket.html
new file mode 100644
index 00000000..8780ba25
--- /dev/null
+++ b/_collections/_langs/racket.html
@@ -0,0 +1,19 @@
+---
+lang: racket
+title: Racket
+description: statycznie i dynamicznie typowany, funkcyjno-obiektowy dialekt języka programowania Scheme .
+---
+
diff --git a/_collections/_langs/reasonml.html b/_collections/_langs/reasonml.html
new file mode 100644
index 00000000..61b5dcf8
--- /dev/null
+++ b/_collections/_langs/reasonml.html
@@ -0,0 +1,35 @@
+---
+lang: reasonml
+title: ReasonML
+description: 'Reason, rozszerzenie obiektowo-funkcyjnego języka programowania OCaml transpilowane do języka JavaScript .'
+redirect_from:
+- langs/reason
+- langs/re
+---
+
+
+YouTube
+
diff --git a/_collections/_langs/rpl.html b/_collections/_langs/rpl.html
new file mode 100644
index 00000000..29b794bc
--- /dev/null
+++ b/_collections/_langs/rpl.html
@@ -0,0 +1,5 @@
+---
+lang: rpl
+title: RPL
+description: ''
+---
diff --git a/_collections/_langs/ruby.html b/_collections/_langs/ruby.html
new file mode 100644
index 00000000..1c7e6554
--- /dev/null
+++ b/_collections/_langs/ruby.html
@@ -0,0 +1,22 @@
+---
+lang: ruby
+title: Ruby
+description: dynamicznie typowany, w pełni obiektowy oraz interpretowany język programowania.
+---
+
\ No newline at end of file
diff --git a/_collections/_langs/rust.html b/_collections/_langs/rust.html
new file mode 100644
index 00000000..966d9557
--- /dev/null
+++ b/_collections/_langs/rust.html
@@ -0,0 +1,22 @@
+---
+lang: rust
+title: Rust
+description: statycznie typowany, natywny język programowania.
+---
+
diff --git a/_collections/_langs/sather.html b/_collections/_langs/sather.html
new file mode 100644
index 00000000..bb8d27bc
--- /dev/null
+++ b/_collections/_langs/sather.html
@@ -0,0 +1,13 @@
+---
+lang: sather
+title: Sather
+description: statycznie typowany, obiektowy język programowania.
+---
+
diff --git a/_collections/_langs/scala.html b/_collections/_langs/scala.html
new file mode 100644
index 00000000..5611004d
--- /dev/null
+++ b/_collections/_langs/scala.html
@@ -0,0 +1,32 @@
+---
+lang: scala
+title: Scala
+description: statycznie typowany, obiektowo-funkcyjny język programowania kompilowany do kodu maszynowego Javy inspirowany językami OCaml , Erlang i Haskell .
+---
+
+
+Tutoriale i książki
+
diff --git a/_collections/_langs/scheme.html b/_collections/_langs/scheme.html
new file mode 100644
index 00000000..f3fe0828
--- /dev/null
+++ b/_collections/_langs/scheme.html
@@ -0,0 +1,131 @@
+---
+lang: scheme
+title: Scheme
+description: 'standard funkcyjnego języka programowania Lisp .'
+---
+
+
+Książki
+
+
+Implementacja rozwijane
+Racket wszystkomający dialekt.
+
+CHICKEN scheme - embedded intepreter z kontunuacjami
+
+
+Chibi-Scheme - nowy embedded intepreter
+
+
+Guile Scheme - wersja Scheme z łatwą integracją z C oparty na SCM
+
+
+Implementacje historyczne
+s7 - embedded intepreter oparty na TinyScheme
+
+
+TinyScheme - embedded intepreter aktualnie używany w Gimpie
+
+
+Scsh (a Scheme Shell ) - powłoka systemowa oparta na Scheme 48
+
+
+Scheme 48 - interpreter będący podstawą powłoki Scheme Shell
+
+
+SCM - wersja scheme oparta na SIOD
+
+
+SIOD - embedded intepreter pierwotnie używany w Gimpie
+
+
+PreScheme - Niskopoziomowy Scheme działąjący bez GC
diff --git a/_collections/_langs/smalltalk.html b/_collections/_langs/smalltalk.html
new file mode 100644
index 00000000..9dd3b7df
--- /dev/null
+++ b/_collections/_langs/smalltalk.html
@@ -0,0 +1,32 @@
+---
+lang: smalltalk
+title:
+description: dynamicznie typowany, w pełni obiektowy, reflektywny języki programowania.
+---
+
+Książki
+
+Implementacje
+Squeak -implementacja języka Smalltalk.
+
diff --git a/_collections/_langs/tcl.html b/_collections/_langs/tcl.html
new file mode 100644
index 00000000..eafcef0a
--- /dev/null
+++ b/_collections/_langs/tcl.html
@@ -0,0 +1,25 @@
+---
+lang: tcl
+title: Tcl
+description: 'dynamicznie typowany, skryptowy język programowania inspirowany językiem Lisp .'
+---
+
+Tutoriale
+
\ No newline at end of file
diff --git a/_collections/_langs/typescript.html b/_collections/_langs/typescript.html
new file mode 100644
index 00000000..d4a8e0d7
--- /dev/null
+++ b/_collections/_langs/typescript.html
@@ -0,0 +1,21 @@
+---
+lang: typescript
+title: TypeScript
+description: 'statycznie typowany język programowania transpilowany do języka JavaScript .'
+redirect_from:
+- langs/ts
+---
+
diff --git a/_collections/_langs/vala.html b/_collections/_langs/vala.html
new file mode 100644
index 00000000..0c8c1d26
--- /dev/null
+++ b/_collections/_langs/vala.html
@@ -0,0 +1,16 @@
+---
+lang: vala
+title: Vala
+description: statycznie typowany, natywny i obiektowy język programowania transpilowany do C.
+---
+
diff --git a/_collections/_langs/webassembly.html b/_collections/_langs/webassembly.html
new file mode 100644
index 00000000..974c2912
--- /dev/null
+++ b/_collections/_langs/webassembly.html
@@ -0,0 +1,7 @@
+---
+lang: webassembly
+title: WebAssembly
+description: ''
+redirect_from:
+- langs/wasm
+---
diff --git a/_collections/_langs/zig.html b/_collections/_langs/zig.html
new file mode 100644
index 00000000..245a12bf
--- /dev/null
+++ b/_collections/_langs/zig.html
@@ -0,0 +1,5 @@
+---
+lang: zig
+title: Zig
+description: ''
+---
diff --git a/_collections/_libs/akka-http.html b/_collections/_libs/akka-http.html
new file mode 100644
index 00000000..e47e5f41
--- /dev/null
+++ b/_collections/_libs/akka-http.html
@@ -0,0 +1,7 @@
+---
+lib: akka-http
+title: Akka HTTP
+langs: scala
+tags: http
+---
+Akka HTTP
diff --git a/_collections/_libs/akka-js.html b/_collections/_libs/akka-js.html
new file mode 100644
index 00000000..efb7b4a4
--- /dev/null
+++ b/_collections/_libs/akka-js.html
@@ -0,0 +1,6 @@
+---
+lib: akka-js
+title: Akka.js
+langs: scala javascript
+---
+AKKA.JS
diff --git a/_collections/_libs/akka.html b/_collections/_libs/akka.html
new file mode 100644
index 00000000..7947e68c
--- /dev/null
+++ b/_collections/_libs/akka.html
@@ -0,0 +1,7 @@
+---
+lib: akka
+title: akka
+langs: scala
+---
+akka - biblioteka dla języka Scala ,
+która umożliwia programowanie z użyciem aktoróœ w jak w języku Erlang .
\ No newline at end of file
diff --git a/_collections/_libs/arrow.html b/_collections/_libs/arrow.html
new file mode 100644
index 00000000..afc6f171
--- /dev/null
+++ b/_collections/_libs/arrow.html
@@ -0,0 +1,8 @@
+---
+lib: arrow
+title: ARROW
+langs: kotlin
+tags: fp
+---
+ARROW - biblioteka dla języka Kotlin ,
+która umożliwia programowanie czysto-funkcyjne znane z języka Haskell .
\ No newline at end of file
diff --git a/_collections/_libs/attoparsec.html b/_collections/_libs/attoparsec.html
new file mode 100644
index 00000000..b8b1352c
--- /dev/null
+++ b/_collections/_libs/attoparsec.html
@@ -0,0 +1,21 @@
+---
+lib: attoparsec
+title: Attoparsec
+langs: haskell eta
+tags: parser
+---
+AttoParsec - biblioteka do budowania parserów dla języków Haskell i Eta .
+
diff --git a/_collections/_libs/cats.html b/_collections/_libs/cats.html
new file mode 100644
index 00000000..56eab6fa
--- /dev/null
+++ b/_collections/_libs/cats.html
@@ -0,0 +1,8 @@
+---
+lib: cats
+title: Cats
+langs: scala
+tags: fp
+---
+Cats - biblioteka dla języka Scala ,
+która umożliwia programowanie czysto-funkcyjne znane z języka Haskell .
\ No newline at end of file
diff --git a/_collections/_libs/dagger.html b/_collections/_libs/dagger.html
new file mode 100644
index 00000000..f180040e
--- /dev/null
+++ b/_collections/_libs/dagger.html
@@ -0,0 +1,6 @@
+---
+lib: dagger
+title: Dagger
+langs: java
+tags: di
+---
diff --git a/_collections/_libs/dropwizard.html b/_collections/_libs/dropwizard.html
new file mode 100644
index 00000000..d141346d
--- /dev/null
+++ b/_collections/_libs/dropwizard.html
@@ -0,0 +1,8 @@
+---
+lib: dropwizard
+title: DropWizard
+langs: java
+tags: http
+---
+
+https://github.com/dropwizard/dropwizard
\ No newline at end of file
diff --git a/_collections/_libs/earley.html b/_collections/_libs/earley.html
new file mode 100644
index 00000000..517ff646
--- /dev/null
+++ b/_collections/_libs/earley.html
@@ -0,0 +1,7 @@
+---
+lib: earley
+title: Earley
+langs: haskell
+tags: parser
+---
+Earley - biblioteka do budowania parserów dla języka Haskell .
diff --git a/_collections/_libs/fastparse.html b/_collections/_libs/fastparse.html
new file mode 100644
index 00000000..71bb97ee
--- /dev/null
+++ b/_collections/_libs/fastparse.html
@@ -0,0 +1,7 @@
+---
+lib: fastparse
+title: FastParse
+langs: scala
+tags: parser
+---
+FastParse - biblioteka do budowania parserów dla języka Scala .
diff --git a/_collections/_libs/fastparser.html b/_collections/_libs/fastparser.html
new file mode 100644
index 00000000..72048c0a
--- /dev/null
+++ b/_collections/_libs/fastparser.html
@@ -0,0 +1,7 @@
+---
+lib: fastparser
+title: FastParser
+langs: haskell
+tags: parser
+---
+FastParser - biblioteka do budowania parserów dla języka Haskell .
diff --git a/_collections/_libs/functionaljava.html b/_collections/_libs/functionaljava.html
new file mode 100644
index 00000000..15a7fbcc
--- /dev/null
+++ b/_collections/_libs/functionaljava.html
@@ -0,0 +1,10 @@
+---
+lib: functionaljava
+title: Functional Java
+langs: java
+tags: fp
+---
+Functional Java - biblioteka dla języka Java ,
+która umożliwia programowanie czysto-funkcyjne znane z języka Haskell .
+
+Twitter : @@functionaljava
\ No newline at end of file
diff --git a/_collections/_libs/gson.html b/_collections/_libs/gson.html
new file mode 100644
index 00000000..ee0d6bea
--- /dev/null
+++ b/_collections/_libs/gson.html
@@ -0,0 +1,6 @@
+---
+lib: gson
+title: Gson
+langs: java
+tags: json
+---
diff --git a/_collections/_libs/guice.html b/_collections/_libs/guice.html
new file mode 100644
index 00000000..bc309587
--- /dev/null
+++ b/_collections/_libs/guice.html
@@ -0,0 +1,6 @@
+---
+lib: guice
+title: Guice
+langs: java
+tags: di
+---
diff --git a/_collections/_libs/happly-alex.html b/_collections/_libs/happly-alex.html
new file mode 100644
index 00000000..382e6836
--- /dev/null
+++ b/_collections/_libs/happly-alex.html
@@ -0,0 +1,21 @@
+---
+lib: happy-alex
+title: Happy & Alex
+langs: haskell eta
+tags: parser
+---
+Happy i Alex - biblioteki do budowania parserów dla języków Haskell i Eta .
+
diff --git a/_collections/_libs/happy-alex.html b/_collections/_libs/happy-alex.html
new file mode 100644
index 00000000..382e6836
--- /dev/null
+++ b/_collections/_libs/happy-alex.html
@@ -0,0 +1,21 @@
+---
+lib: happy-alex
+title: Happy & Alex
+langs: haskell eta
+tags: parser
+---
+Happy i Alex - biblioteki do budowania parserów dla języków Haskell i Eta .
+
diff --git a/_collections/_libs/hspec.html b/_collections/_libs/hspec.html
new file mode 100644
index 00000000..0f156f6a
--- /dev/null
+++ b/_collections/_libs/hspec.html
@@ -0,0 +1,14 @@
+---
+lib: hspec
+title: HSpec
+langs: haskell eta
+tags: testing
+---
+HSpec - biblioteki do pisania testów dla języków Haskell i Eta .
+
+
+
diff --git a/_collections/_libs/hunit.html b/_collections/_libs/hunit.html
new file mode 100644
index 00000000..a5d6dcc9
--- /dev/null
+++ b/_collections/_libs/hunit.html
@@ -0,0 +1,14 @@
+---
+lib: hunit
+title: HUnit
+langs: haskell eta
+tags: testing
+---
+HUnit - biblioteki do pisania testów dla języków Haskell i Eta .
+
+
+
diff --git a/_collections/_libs/jackson.html b/_collections/_libs/jackson.html
new file mode 100644
index 00000000..efc604f3
--- /dev/null
+++ b/_collections/_libs/jackson.html
@@ -0,0 +1,6 @@
+---
+lib: jackson
+title: Jackson
+langs: java
+tags: json
+---
diff --git a/_collections/_libs/jdbi.html b/_collections/_libs/jdbi.html
new file mode 100644
index 00000000..e5147045
--- /dev/null
+++ b/_collections/_libs/jdbi.html
@@ -0,0 +1,6 @@
+---
+lib: jdbi
+title: JDBI
+langs: java
+tags: sql
+---
diff --git a/_collections/_libs/jolt.html b/_collections/_libs/jolt.html
new file mode 100644
index 00000000..0b8092b4
--- /dev/null
+++ b/_collections/_libs/jolt.html
@@ -0,0 +1,6 @@
+---
+lib: jolt
+title: Jolt
+langs: java
+tags: json
+---
diff --git a/_collections/_libs/jool.html b/_collections/_libs/jool.html
new file mode 100644
index 00000000..bd07f80c
--- /dev/null
+++ b/_collections/_libs/jool.html
@@ -0,0 +1,6 @@
+---
+lib: jool
+title: JOOL
+langs: java
+tags: fp
+---
diff --git a/_collections/_libs/jooq.html b/_collections/_libs/jooq.html
new file mode 100644
index 00000000..38049401
--- /dev/null
+++ b/_collections/_libs/jooq.html
@@ -0,0 +1,6 @@
+---
+lib: jooq
+title: JOOQ
+langs: java
+tags: sql
+---
diff --git a/_collections/_libs/jquery.html b/_collections/_libs/jquery.html
new file mode 100644
index 00000000..5452ea13
--- /dev/null
+++ b/_collections/_libs/jquery.html
@@ -0,0 +1,6 @@
+---
+lib: jquery
+langs: javascript
+title: JQuery
+---
+JQuery
\ No newline at end of file
diff --git a/_collections/_libs/jsonpath.html b/_collections/_libs/jsonpath.html
new file mode 100644
index 00000000..814e2659
--- /dev/null
+++ b/_collections/_libs/jsonpath.html
@@ -0,0 +1,6 @@
+---
+lib: jsonpath
+title: JsonPath
+langs: java
+tags: json
+---
diff --git a/_collections/_libs/jsonsurfer.html b/_collections/_libs/jsonsurfer.html
new file mode 100644
index 00000000..21815dc8
--- /dev/null
+++ b/_collections/_libs/jsonsurfer.html
@@ -0,0 +1,6 @@
+---
+lib: jsonsurfer
+title: JsonSurfer
+langs: java
+tags: json
+---
diff --git a/_collections/_libs/logback.html b/_collections/_libs/logback.html
new file mode 100644
index 00000000..157626f6
--- /dev/null
+++ b/_collections/_libs/logback.html
@@ -0,0 +1,8 @@
+---
+lib: logback
+title: Logback
+langs: java
+tags: logging
+---
+Locback - biblioteka do logowania dla języków
+Java , Kotlin i Scala .
diff --git a/_collections/_libs/macwire.html b/_collections/_libs/macwire.html
new file mode 100644
index 00000000..26b32d7a
--- /dev/null
+++ b/_collections/_libs/macwire.html
@@ -0,0 +1,6 @@
+---
+lib: macwire
+title: MacWire
+langs: scala
+tags: http
+---
diff --git a/_collections/_libs/megaparsec.html b/_collections/_libs/megaparsec.html
new file mode 100644
index 00000000..104e7b1a
--- /dev/null
+++ b/_collections/_libs/megaparsec.html
@@ -0,0 +1,24 @@
+---
+lib: megaparsec
+title: Megaparsec
+langs: haskell eta
+tags: parser
+---
+MegaParsec - biblioteka do budowania parserów dla języków Haskell i Eta
+
diff --git a/_collections/_libs/optparse-applicative.html b/_collections/_libs/optparse-applicative.html
new file mode 100644
index 00000000..526e6bb5
--- /dev/null
+++ b/_collections/_libs/optparse-applicative.html
@@ -0,0 +1,5 @@
+---
+lib: optparse-applicative
+title: optparse-applicative
+langs: haskell eta
+---
diff --git a/_collections/_libs/parsec.html b/_collections/_libs/parsec.html
new file mode 100644
index 00000000..86fb8383
--- /dev/null
+++ b/_collections/_libs/parsec.html
@@ -0,0 +1,12 @@
+---
+lib: parsec
+title: Parsec
+langs: haskell eta
+tags: parser
+---
+Parsec - biblioteka do budowania parserów dla języków Haskell i Eta
+
diff --git a/_collections/_libs/pulsar.html b/_collections/_libs/pulsar.html
new file mode 100644
index 00000000..62629fac
--- /dev/null
+++ b/_collections/_libs/pulsar.html
@@ -0,0 +1,9 @@
+---
+lib: pulsar
+langs: clojure
+title: Pulsar
+---
+Pulsar - biblioteka dla języka Clojure ,
+która umożliwia programowanie z użyciem włókien (ang. fiber ),
+kanałów jak w języku Go
+oraz aktoróœ w jak w języku Erlang .
\ No newline at end of file
diff --git a/_collections/_libs/quasar.html b/_collections/_libs/quasar.html
new file mode 100644
index 00000000..e91226f8
--- /dev/null
+++ b/_collections/_libs/quasar.html
@@ -0,0 +1,9 @@
+---
+lib: quasar
+langs: kotlin
+title: Quasar
+---
+Quasar - biblioteka dla języka Kotlin ,
+która umożliwia programowanie z użyciem włókien (ang. fiber ),
+kanałów jak w języku Go
+oraz aktoróœ w jak w języku Erlang .
diff --git a/_collections/_libs/quickcheck.html b/_collections/_libs/quickcheck.html
new file mode 100644
index 00000000..be259061
--- /dev/null
+++ b/_collections/_libs/quickcheck.html
@@ -0,0 +1,12 @@
+---
+lib: quickcheck
+title: QuickCheck
+langs: haskell eta
+tags: testing
+---
+QuickCheck - biblioteki do pisania testów dla języków Haskell i Eta .
+
diff --git a/_collections/_libs/readp.html b/_collections/_libs/readp.html
new file mode 100644
index 00000000..91323cd9
--- /dev/null
+++ b/_collections/_libs/readp.html
@@ -0,0 +1,27 @@
+---
+lib: readp
+title: ReadP
+langs: haskell eta
+tags: parser
+---
+ReadP - biblioteka do budowania parserów dla języków Haskell i Eta .
+
diff --git a/_collections/_libs/scala-guice.html b/_collections/_libs/scala-guice.html
new file mode 100644
index 00000000..57659beb
--- /dev/null
+++ b/_collections/_libs/scala-guice.html
@@ -0,0 +1,6 @@
+---
+lib: scala-guice
+title: Scala Guice
+langs: scala
+tags: di
+---
diff --git a/_collections/_libs/scala-optparse-applicative.html b/_collections/_libs/scala-optparse-applicative.html
new file mode 100644
index 00000000..8d537819
--- /dev/null
+++ b/_collections/_libs/scala-optparse-applicative.html
@@ -0,0 +1,5 @@
+---
+lib: scala-optparse-applicative
+title: scala-optparse-applicative
+langs: scala
+---
diff --git a/_collections/_libs/scalatest.html b/_collections/_libs/scalatest.html
new file mode 100644
index 00000000..68dff4b2
--- /dev/null
+++ b/_collections/_libs/scalatest.html
@@ -0,0 +1,7 @@
+---
+lib: scalatest
+title: ScalaTest
+langs: scala
+tags: testing
+---
+ScalaTest to biblioteka do testów jednostkowych i akceptacyjnych dla języka Scala .
diff --git a/_collections/_libs/scalatra.html b/_collections/_libs/scalatra.html
new file mode 100644
index 00000000..94303ab1
--- /dev/null
+++ b/_collections/_libs/scalatra.html
@@ -0,0 +1,6 @@
+---
+lib: scalatra
+title: Scalatra
+langs: scala
+tags: http
+---
diff --git a/_collections/_libs/scalawui.html b/_collections/_libs/scalawui.html
new file mode 100644
index 00000000..194fce38
--- /dev/null
+++ b/_collections/_libs/scalawui.html
@@ -0,0 +1,6 @@
+---
+lib: scalawui
+title: ScalaWUI
+langs: scala
+tags: http
+---
diff --git a/_collections/_libs/scalaz.html b/_collections/_libs/scalaz.html
new file mode 100644
index 00000000..327eef70
--- /dev/null
+++ b/_collections/_libs/scalaz.html
@@ -0,0 +1,8 @@
+---
+lib: scalaz
+title: Scalaz
+langs: scala
+tags: testing
+---
+Scalaz - biblioteka dla języka Scala ,
+która umożliwia programowanie czysto-funkcyjne znane z języka Haskell .
\ No newline at end of file
diff --git a/_collections/_libs/shocon.html b/_collections/_libs/shocon.html
new file mode 100644
index 00000000..c1545078
--- /dev/null
+++ b/_collections/_libs/shocon.html
@@ -0,0 +1,7 @@
+---
+lib: shocon
+title: SHocon
+langs: scala
+tags: hocon
+---
+SHocon
diff --git a/_collections/_libs/slogging.html b/_collections/_libs/slogging.html
new file mode 100644
index 00000000..a1c6cc54
--- /dev/null
+++ b/_collections/_libs/slogging.html
@@ -0,0 +1,7 @@
+---
+lib: slogging
+title: slogging
+langs: scala
+tags: logging
+---
+slogging to biblioteka do logowania dla języka Scala .
diff --git a/_collections/_libs/specs2.html b/_collections/_libs/specs2.html
new file mode 100644
index 00000000..e5067d98
--- /dev/null
+++ b/_collections/_libs/specs2.html
@@ -0,0 +1,7 @@
+---
+lib: specs2
+title: specs2
+langs: scala
+tags: testing
+---
+specs2 to biblioteka do testów jednostkowych i akceptacyjnych dla języka Scala .
diff --git a/_collections/_libs/sqlite.html b/_collections/_libs/sqlite.html
new file mode 100644
index 00000000..f693f66a
--- /dev/null
+++ b/_collections/_libs/sqlite.html
@@ -0,0 +1,5 @@
+---
+lib: sqlite
+title: SQLite
+tags: database
+---
diff --git a/_collections/_libs/stoml.html b/_collections/_libs/stoml.html
new file mode 100644
index 00000000..eb5bcdcc
--- /dev/null
+++ b/_collections/_libs/stoml.html
@@ -0,0 +1,8 @@
+---
+lib: stoml
+title: STOML
+langs: scala
+tags: toml
+---
+STOML
+toml-scala
diff --git a/_collections/_libs/trifecta.html b/_collections/_libs/trifecta.html
new file mode 100644
index 00000000..1337dfd1
--- /dev/null
+++ b/_collections/_libs/trifecta.html
@@ -0,0 +1,15 @@
+---
+lib: trifecta
+title: Trifecta
+langs: haskell
+tags: parser
+---
+Trifecta - biblioteka do budowania parserów dla języka Haskell .
+
diff --git a/_collections/_libs/udash.html b/_collections/_libs/udash.html
new file mode 100644
index 00000000..09115fb4
--- /dev/null
+++ b/_collections/_libs/udash.html
@@ -0,0 +1,6 @@
+---
+lib: udash
+title: Udash
+langs: scala
+tags: http
+---
diff --git a/_collections/_libs/utest.html b/_collections/_libs/utest.html
new file mode 100644
index 00000000..29cc70c5
--- /dev/null
+++ b/_collections/_libs/utest.html
@@ -0,0 +1,7 @@
+---
+lib: utest
+title: µTest
+langs: scala
+tags: testing
+---
+utest to biblioteka do testów jednostkowych dla języka Scala .
diff --git a/_collections/_libs/vavr-kotlin.html b/_collections/_libs/vavr-kotlin.html
new file mode 100644
index 00000000..d91bcbad
--- /dev/null
+++ b/_collections/_libs/vavr-kotlin.html
@@ -0,0 +1,10 @@
+---
+lib: vavr-kotlin
+title: vavr-kotlin
+langs: kotlin
+tags: fp
+---
+Vavr integration for Kotlin - biblioteka dla języka Kotlin ,
+która umożliwia programowanie funkcyjne znane z języków Scala i Ocaml .
+
+Twitter : @vavr_io
\ No newline at end of file
diff --git a/_collections/_libs/vavr.html b/_collections/_libs/vavr.html
new file mode 100644
index 00000000..b8d76420
--- /dev/null
+++ b/_collections/_libs/vavr.html
@@ -0,0 +1,10 @@
+---
+lib: vavr
+title: Vavr
+langs: java
+tags: fp
+---
+Vavr - biblioteka dla języka Java ,
+która umożliwia programowanie funkcyjne znane z języków Scala i Ocaml .
+
+Twitter : @vavr_io
\ No newline at end of file
diff --git a/_collections/_libs/zio.html b/_collections/_libs/zio.html
new file mode 100644
index 00000000..7f4fcc1d
--- /dev/null
+++ b/_collections/_libs/zio.html
@@ -0,0 +1,10 @@
+---
+lib: zio
+title: ZIO
+langs: scala
+tags: fp
+---
+ZIO - biblioteka dla języka Scala ,
+która umożliwia programowanie z użyciem włókien (ang. fiber ),
+kanałów jak w języku Go
+oraz lekkich aktorów w jak w języku Erlang .
diff --git a/_collections/_microblog/jezyk-fullstackowy.md b/_collections/_microblog/jezyk-fullstackowy.md
new file mode 100644
index 00000000..afca1b19
--- /dev/null
+++ b/_collections/_microblog/jezyk-fullstackowy.md
@@ -0,0 +1,115 @@
+W ciągu ostatnich 48h zarzucono mi to wiele rzeczy, ale nikt mi nie będzie zarzucać że nie wiem, że `nawet w WEB można się już obyć bez JS`, dlatego przeklejam tu swój stary artykuł z bloga. Mam nadzieję że przez rok się mocno nie zdezaktualizował.
+
+Nie jest to artykuł profesjonalisty, ale bardziej zapiski hobbysty i próba usystematyzowania nowych rzeczy. Proszę o konstruktywną krytykę. `Jesteś upośledzony` to nie jest konstruktywna krytyka, bo to już wiem (mam krótkowzroczność -8D, niezdiagnozowanego Aspergera i totalny brak gustu). BTW Podobno jest to najlepszy artykuł jaki mam na blogu, więc kolejne będą jeszcze gorsze :P
+
+Z pozdrowieniami dla frontendowców za to że piszą front i dzięki temu ja tego nie muszę robić.
+
+# Który język programowania wybrać na początek - język fullstackowy
+
+Wiele osób pyta się, **który język programowania wybrać na początek** jako pierwszy język do nauki. Wiele jednak zależy od tego do czego chcemy użyć tego języka programowania. Dlatego wybrałem zwycięzców w czterech kategoriach:
+1. [dynamicznie typowany język skryptowy ogólnego przeznaczenia](https://www.writeonly.pl/programming/jezyk-skryptowy/)
+2. [statycznie typowany język korporacyjny używany do pisania długowiecznych aplikacji klasy *enterprise*](https://www.writeonly.pl/programming/jezyk-korporacyjny/)
+3. język *fullstackowy*, który można używać do pisania frontendu i backendu
+4. [szybki język natywny działający bez maszyny wirtualnej i interpretera](https://www.writeonly.pl/programming/jezyk-natywny/)
+
+W tym artykule skupię się na zwycięzcy trzeciej kategorii, świętym Graalu programowania webowego, czyli języku *fullstackowy*, w którym można pisać zarówno frontend jak i backend.
+
+**Ważna uwaga!**
+Artykuł nie jest sponsorowany przez Google, mimo że każdy ze zwycięskich języków jest używany przez Google. Nie jest też sponsorowany przez JetBrains. Po prostu uważam, że JetBrains tworzy najlepsze IDE. Jest to tylko mój mały subiektywny ranking języków programowania na rok 2019.
+
+## JavaScript oraz jego problemy i dziwactwa
+**JavaScript** jest obecnie jedynym językiem programowania wspieranym przez przeglądarki bezpośrednio. Dlatego jesteśmy skazani na niego przy programowaniu frontendu działającego po stronie przeglądarki. Jednocześnie JS posiada sporo swoich problemów i dziwactw. Zaczynając od najważniejszych są to:
+1. Różne implementacje w różnych przeglądarkach
+2. Słabe typowanie, które pozwala robić takie rzeczy jak JSFuck
+3. Obiektowość oparta na [prototypach](https://pl.wikipedia.org/wiki/Prototyp_(oprogramowanie)).
+
+Ostatnie nie byłoby nawet problemem gdyby nie to, że w początkowej fazie istnienia rozdziału na frontend i backend programiści backendowi byli przymuszani do pisania frontendu. Bolało to zwłaszcza programistów języków korporacyjnych, gdzie obiektowość oparta jest na [klasach](https://pl.wikipedia.org/wiki/Klasa_(programowanie_obiektowe)).
+
+### Podejście zerowe
+Początkowo głównym problemem z JavaScryptem było to, że był różnie implementowany w różnych przeglądarkach. W niektórych przeglądarkach brakowało niektórych funkcji, w innych te same funkcje zachowywały się różnie. Spowodowało to powstawanie wielu różnych nakładek i bibliotek na JS, z czego jedna stała się *de facto* standardem - **JQuery**. Było to jednak w dawnych czasach, gdy programowanie JavaScripcie było proste, ponieważ służył on głownie do robienia bezsensownych animacji na strona oraz customowych menu kontekstowych.
+
+Obecnie głównym problemem pisania aplikacji webowych jest to, że potrzebujemy osobnych programistów do tworzenia frontendu (*frontendowców*) i osobnych do tworzenia backendu (*backendowców*). Teoretycznie istnieje święty Graal wszelakiej rekrutacji, człowiek orkiestra, Leonardo da Vinci swoich czasów, czyli fullstackowiec potrafiący pisać zarówno frontend jak i backend. W praktyce jest to jednak osoba znająca się na wszystkim, ale po trochu. Trochę jak np. internista w szpitalu. Rozwiązaniem jest dopiero język *fullstackowy*.
+
+### Podejście pierwsze - język backendowy transpilowany do JS
+
+Ponieważ programistów JavaScriptu było mało, a frontend stawał się coraz bardziej skomplikowany pojawił się pomysł, żeby już istniejące języki backendu transpilować do JS. Dzięki temu programiści backendu mogą z marszu stać się programistami frontendu. Tutaj są dwie grupy rozwiązań:
+* Biblioteki graficzne przeniesione do **JS**:
+ * RAP (ang. *Remote Aplication Platform*) - to implementacja SWT (ang. *Standard Widget Toolkit*). SWT to niestandardowy (sic!) zestaw bibliotek graficznych dla Javy, posiadający implementacje dla najpopularniejszych systemów operacyjnych (Mac, Linux, Windows).
+* GWT (ang. *Google Widget Toolkit*) - biblioteka graficzna zaprojektowana dla Javy specjalnie pod transpilację do JS
+ * Pyjs - Port GWT dla języka **Python**
+* Język backendu przeniesiony do frontendu jednocześnie nie narzucający frameworka widoku i biblioteki graficznej:
+ * **Scala.js** - posiada już dedykowane frameworki ja *Udash*
+ * Kotlin.js - dalej w procesie projektowania
+ * Ceylon.js - transpilowany do CommonJS
+ * ClojureScript* - używa Closure Compiler do optymalizacji kodu. Tutaj pojawia się gwiazdka ponieważ istnieją [różnice](https://clojurescript.org/about/differences) pomiędzy
+**Clojure** i ClojureScript
+ * Dla Javy:
+ * J2CL - transpilator od Google używający Closure Compiler i będący następcą GWT
+ * JSweet - transpilator do języka **TypeScript**, który następnie jest transpilowany do JS
+ * Programiści języka **Haskell** także podejmowali kilka prób stworzenia transpilatora z Haskella do JS. Są to Fay, GHCJS, Haste i uhc
+ * Dla języka **OCaml** jest kilka transpilatorów, ale aktualnie najbardziej obiecująco wygląda **BuckleScript.**
+ * Język **Racket** był jednym z pierwszych transpilowanych do JS, aktualnie jest rozwijany RacketScript
+
+### Podejście drugie - nowy język transpilowany do JS
+
+Według wielu programistów pierwsze podejście było niezadowalające. Istniało wiele problemów z językami backedowymi transpilowanymi do JS. Prawdopodobnie największym jest przetwarzanie współbieżne. Statycznie typowane języki korporacyjne posiadają wielowątkowość do przetwarzania współbieżnego. Interpretery JS posiadają jeden wątek i do przetwarzania współbieżnego używa konstrukcji `Promise` (*obietnicy*), której najbliżej do monady) `IO` z Haskella lub FlatMappable `Future` ze Scali. Ponieważ nie da się łatwo zamienić modelu `Promise` na wielowątkowość to jest to problemem.
+
+Ponieważ pierwsze podejście okazało się niezadowalające postanowiono stworzyć nowe języki programowania będące jak najbardziej podobne do JS, ale jednocześnie rozwiązujące znane w nim problemy. Te języki to m.in.:
+* **CoffeeScript** - pierwszy popularny, nowy język transpilowany do JS. Posiada klasy i *normalne* dziedziczenie, ale typowany dynamicznie. Promowany przez programistów **Ruby** we frameworku RoR
+* **LiveScript** - funkcyjny następca CoffeeScriptu
+* **TypeScript** - rozszeżenie **JS** o statyczne typowanie i klasy
+* **PureScript** - **Haskell**, ale wykonywany zachłannie, czyli jak *normalny* język programowania, a nie Haskell
+* **ReasonML** - **OCaml** ze zmienioną składnią w celu upodobnienia go do **JS**. Także transpilowany za pomocą **BuckleScript**.
+* **Elm** * - język będący połączeniem języków **Meta Language** i **Haskell** oraz będący już zintegrowany z frameworkami React i Redux (implementacja architektury Flux). Jest z gwiazdką, bo jest dedykowany tylko do pisania frontendu. Jednocześnie posiada ciekawą właściwość jaką jest usuwanie martwego kodu podczas transpilacji. Dlatego aplikacja napisana w Elmie może być mniejsza niż kod Reacta
+* **Dart** * - kolejny język z gwiazdką. Mimo że jest względnie młody przeszedł już historię dzielącą się na etapy:
+ 1. Natywny język przeglądarki - niestety wykonywany natywnie tylko przez Chroma. Inne przeglądarki miały posiadać maszynę wirtualną Darta napisaną w JS.
+ 2. Język do pisania frontendu, transpilowany do JS
+ 3. Język do pisania frontendu i aplikacji mobilnych za pomocą frameworku Flutter
+
+Ale jakim cudem w ogóle można mówić o JS jako o języku *fullstackowym*? Spójrzy na małe kalendarium:
+* 2007 - Qt dodaje Qt Script, własną implementacją EmcaScriptu, język jest dedykowany do tworzenia **GUI**. Teoretycznie nic to nie wnosi do tej historii, ale zainspirowało niektórych
+* 2008 - Gnome dodaje dwa [bindingi Javascriptu](https://wiki.gnome.org/JavaScript), Gjs i Seed. Są one dedykowane do tworzenia **GUI** w miejsce wcześniej stosowanego w tym celu języka **Python**, ale można ich używać jako główny język do pisania aplikacji oraz jako język skryptowy
+* 2009 - powstaje Node.js, wyciągnięty z przeglądarki interpreter] V8, który można używać z linii poleceń CLI
+* 2011 - powstaje Vert.x, framework do przetwarzania współbieżnego na JVM, który posiada API m.in. w JavaScripcie
+
+A więc wszystkie języki transpilowane do JS (i sam JS oczywiście) można wykonywać po stronie backendu!
+### Podejście wygrywające
+zwycięzcą kategorii *język fullstackowy* jest język transpilowany do JS i jest to ... JavaScript!
+
+Co?! Dlaczego JavaScript jest transpilowany do JavaScriptu? Wynika to z tego, że w międzyczasie tworzenia gigantycznej ilości nakładek do JavaScriptu sam Javascript też był rozwijany. Niestety dalej trzeba wspierać stare przeglądarki używające starszych wersji JavaScriptu. Dlatego jest potrzebny transpilator Babel zamieniający ECMAScript 6 do ECMAScript 5.
+
+A dlaczego JavaScript jest zwycięzcą?
+* Ewoluował i nie jest już tak brzydki jak kiedyś
+* Jest popularny - język roku 2014 według Tiobe
+* Nawet jeśli będziesz pisać frontend w innym języku programowania niż JS to prawdopodobnie i tak będziesz musiał znać podstawy JavaScriptu,
+* Niestety [WebStorm] od JetBains jest płatny, ale na szczęście istnieją inne dobre IDE dla JavaScriptu jak Atom lub VSC.
+* Chyba wreszcie zrozumieli JS w Google. Google długo miało problemy z JavaScriptem i dlatego m.in. stworzyło GWT. Jednak od pewnego czasu Google wspiera użycie JavaScriptu np w Google Cloud Functions, gdzie można używać tylko i wyłącznie JavaScriptu.
+
+Ale nie to jest największą zaletą JavaScriptu! Największą zaletą jest Node.js. A największą zaletą Node.js jest to, że jest jednowątkowy i zmusza do pisania aplikacji funkcyjnych, asynchronicznych i reaktywnych
+
+Node.js nie jest jedynym asynchronicznym serwerem. Istnieją także inne jak:
+* Vert.x - wielki framework dla języków JavaScript, Java, Scala, Kotlin, **Ceylon**, Groovy i **Ruby**
+* Lagom - kolejny wielki framework, dedykowany dla języka Java
+* Akka HTTP - biblioteka dedykowana dla języków **Scala** i Java
+* Spark - biblioteka dedykowana dla języków **Kotlin** i Java
+* Ratpack - biblioteka dedykowana dla języków Groovy i Java
+* WebFlux - reaktywa wersja Springa
+
+Wiele innych frameworków także zaczyna wspierać programowanie asynchroniczne, jak np. DropWizard.
+## Podsumowanie
+
+Trudno tutaj o dobre podsumowanie. Chyba nie mam odwagi polecić komuś JavaScript/TypeScript do nauki jako pierwszy język do programowania.
+Głównie obawiając się o zdrowie psychiczne tej osoby, która miałaby programować w JS.
+
+Osobiście jestem zwolennikiem statycznie typowanych języków backendu transpilowanych do JS, jak np. Scala.js lub Kotlin.js. Pozwala to współdzielić kod między frontendem i backendem, który teoretycznie może być nawet aplikacją natywną. Jednocześnie w tych językach programowania do rozwiązywania problemów asynchroniczności są preferowane konstrukcje `Future` oraz **monady** `IO`, które łatwo przetłumaczyć na `Promise` z JS.
+
+Równie ciekawy wydaje się także, pojawiącący w niektórych zagranicznych ogłoszeniach o pracę, stos technologiczny PHP, czyli:
+* **P**ureScript na frontendzie
+* **H**askell na backandzie
+* **P**ostgreSQL jako baza danych
+
+Są to co prawda dwa języki programowania do nauki, ale bardzo podobne do siebie. O wiele bardziej niż Java i JavaScript. Więc opanowanie jednego z nich, gdy umie się już drugi nie powinno być problemem.
+
+[Link do oryginalnego artykułu](https://www.writeonly.pl/programming/jezyk-fullstackowy/)
+
+#writeonly
diff --git a/_collections/_posts/2018-08-13-dlaczego-warto-prowadzic-bloga.md b/_collections/_posts/2018-08-13-dlaczego-warto-prowadzic-bloga.md
new file mode 100644
index 00000000..635837ba
--- /dev/null
+++ b/_collections/_posts/2018-08-13-dlaczego-warto-prowadzic-bloga.md
@@ -0,0 +1,66 @@
+---
+title: "Dlaczego warto prowadzić bloga o programowaniu"
+author: TheKamilAdam
+category: thoughts
+tags: blog
+langs: scala java
+tools: github
+libs:
+redirect_from:
+ - dlaczego-warto-prowadzic-bloga
+ - thoughts/dlaczego-warto-prowadzic-bloga
+ - thoughts/2018/08/13/dlaczego-warto-prowadzic-bloga.html
+---
+
+Ja znalazłem cztery powody, dlaczego warto prowadzić bloga o programowaniu.
+Natrafiałem na nie właśnie w tej kolejności.
+
+## Notatki dla siebie
+Nie wiem jak inni programiści,
+ale ja mam dobrą pamięć do rzeczy złożonych,
+jak np. składnia języka **[Scala]**,
+i słabą pamięć do rzeczy prostych, jak np. “z jakimi parametrami należy budować projekt w języku Scala, żeby otrzymać żądany efekt”.
+Rezultat tego był taki, że wielokrotnie przeszukiwałem internet w poszukiwaniu tych samych rzeczy.
+Pierwszą próbą rozwiązania mojego problemu był pomysł zapisywania wiedzy w pliku na dysku.
+Niestety po formacie dysku ta wiedza się traciła.
+Kolejnym krokiem było trzymanie wiedzy w chmurze np. w Dokumentach Googlowych.
+
+## Pomoc dla innych
+Nie tylko ja mam słabą pamięć.
+Poza tym do pracy przychodzą też nowi lub ludzie z innych zespołów, którzy chcą się czegoś dowiedzieć.
+Głupio mi było odpowiedzieć, że czegoś nie pamiętam, gdy wiedzą że robię to od roku.q
+Wycinanie fragmentów Dokumentów Googlowych i wysyłanie ich przez komunikator nie było najbardziej eleganckim rozwiązaniem.
+Więc założyłem repozytorium na **[GitHubie]** i odsyłałem linki jako odpowiedzi na pytania.
+Było to rozwiązanie lepsze, ale nie zadowalało mnie w pełni,
+ponieważ w ten sposób mogłem pomóc tylko osobom, które mnie bezpośrednio poprosiły o pomoc.
+
+## Dokumentowanie swojego postępu prac
+
+Repozytoria na GitHubie, bez dodatkowej dokumentacji szybko mogą przerodzić się w chaos.
+Tak było zarówno w przypadku mojego repozytorium zawierającego wiedzę, jak i moich projektów Scalowych.
+Blog będący Dziennikiem Postępów Prac pozwala temu przeciwdziałać i zaprezentować innym zastosowane rozwiązania.
+
+## Dostanie wymarzonej pracy
+Jest to ostatni powód, który odkryłem. Jest to także powód, który ostatecznie zmotywował mnie do założenia tego bloga.
+
+Jestem programistą **[Javy]**, a chcę być programistą **[Scali]**.
+Fascynuję się tym językiem programowania odkąd o nim usłyszałem, czyli dłużej niż pracuję w Javie.
+Niestety na Górnym Śląsku, gdzie mieszkam, jest mało pracy dla programistów Scali.
+Można pracować zdalnie, ale jest ciężko przekonać firmy programistyczne,
+że umie się Scalę, gdy pisało się w niej komercyjnie tylko pół roku.
+
+Mimo że hobbistycznie piszę w niej od pięciu lat.
+
+## Podsumowanie
+Mój plan jest taki,
+żeby umieszczać tu posty głównie związane z postępem prac nad moimi projektami opensoursowymi pisanymi dla wprawy.
+Dokumentować tutaj każdą większą zmianę wraz z uzasadnieniem.
+
+Mam nadzieję, że będzie to jasne i łatwe do zrozumienia zarówno dla mnie, gdy po roku wrócę do swojego kodu,
+jak i dla wszystkich innych, którzy chcieliby się nauczyć języka **[Scala]**.
+
+[Javy]: /langs/java
+[Scala]: /langs/scala
+[Scali]: /langs/scala
+
+[GitHubie]: /tools/github
diff --git a/_collections/_posts/2018-08-22-jekyll-i-ciasteczka-pliki-cookies.md b/_collections/_posts/2018-08-22-jekyll-i-ciasteczka-pliki-cookies.md
new file mode 100644
index 00000000..2cfc0217
--- /dev/null
+++ b/_collections/_posts/2018-08-22-jekyll-i-ciasteczka-pliki-cookies.md
@@ -0,0 +1,108 @@
+---
+title: "Jekyll i ciasteczka (pliki cookies)"
+author: TheKamilAdam
+category: jekyll
+tags: blog html jekyllcodex github-pages
+labels: cookies
+tools: jekyll
+libs: jquery
+redirect_from:
+ - jekyll-i-ciasteczka-pliki-cookies
+ - jekyll/jekyll-i-ciasteczka-pliki-cookies
+ - writeonlydoc/jekyll-i-ciasteczka-pliki-cookies
+ - writeonlydoc/2018/08/22/jekyll-i-ciasteczka-pliki-cookies.html
+---
+
+Przed założeniem bloga opartego na technologiach **[Jekyll]** i **[GitHub Pages]**
+przejrzałem sporo polskojęzycznych blogów z opisem “Jak to zrobić”.
+Wszyscy mówili, że jest to niesamowicie proste.
+Za wyjątkiem jednego malkontenta, Gutka ( ).
+
+Pierwszy wieczór spędziłem na nieudanej instalacji Jekylla i próbie uruchomienia przykładowego bloga opartego na motywie graficznym BlackDocs
+().
+Wieczór zakończyłem w momencie przeczytania porady na StackOverflow “usuń Rubiego i zainstaluj wszystko ponownie”.
+Wtedy stwierdziłem, że może jednak Gutek ma rację i Jekyll bywa problematyczny.
+
+Jednak nie poddałem się i po paru wieczorach miałem pusty blog z możliwością komentowania postów i skryptem raportującym statystyki
+(funkcjonalność dodana według )
+oraz nie do końca skonfigurowaną wyszukiwarką ().
+W tym momencie uznałem, że dalsze usprawnianie bloga, który nie zawiera żadnej treści, nie ma żadnego sensu.
+W związku z czym odłożyłem na czas późniejszy dodawanie tagów i kategorii “bez użycia pluginu”
+( i ).
+A nuż w międzyczasie plugin dla kategorii znajdzie się na liście pluginów wspieranych przez **[GitHub Pages]**
+(Aktualna lista wspieranych pluginów ).
+
+Po opublikowaniu pierwszego posta czułem jednak, że dalej czegoś brakuje. Wciśnięcie F12 i spojrzenie w kod strony było przerażające.
+Ujrzałem spaghetti w postaci naprzemiennie występujących fragmentów HTML, CSS i JS.
+Ale najgorsze było, gdy spojrzałem na zakładkę “Storage”.
+Okazało się, że moja prosta strona internetowa zapisuje, o zgrozo, ciasteczka.
+O ile ciasteczko dla systemu komentarzy Disqus można jeszcze obronić, że jest technicznie potrzebne do działania funkcjonalności,
+o tyle ciasteczko dla Google Analytics jest już jawnym śledzeniem użytkownika!
+
+Poszukiwanie rozwiązania mojego problemu doprowadziło mnie do strony ,
+a dokładniej do sekcji “Without plugins” ( ).
+Znalazłem tam skrypt wyświetlający banner informujący o plikach Cookies. Po moich przeróbkach wygląda on tak:
+
+```html
+
+
+
+
+```
+
+Czuję, że na stronie spędzę więcej czasu z czego wynikają dwie smutne informacje:
+* później zacznę pisać o języku **[Scala]**
+* istnieje niebezpieczeństwo, że nauczę się jQuery
+
+[Scala]: /langs/scala
+
+[Jekyll]: /tools/jekyll
+
+[GitHub Pages]: /tags/github-pages
diff --git a/_collections/_posts/2018-08-30-alias-komenda-powloki-bash.md b/_collections/_posts/2018-08-30-alias-komenda-powloki-bash.md
new file mode 100644
index 00000000..0831ac76
--- /dev/null
+++ b/_collections/_posts/2018-08-30-alias-komenda-powloki-bash.md
@@ -0,0 +1,105 @@
+---
+title: "Alias - polecenie powłoki Bash"
+author: TheKamilAdam
+category: cli
+tags: alias cli
+tools: bash git
+redirect_from:
+ - alias-komenda-powloki-bash
+ - cli/alias-komenda-powloki-bash
+ - cli/2018/08/30/alias-komenda-powloki-bash.html
+---
+
+Jeśli:
+* masz problemy z zapamiętywaniem skomplikowanych poleceń Basha lub innych programów wywoływanych przez wiersz poleceń
+* nie lubisz wpisywać w terminalu długich poleceń z podkomendami i przełącznikami
+
+istnieje rozwiązanie twoich problemów! Jest to polecenie powłoki Bash o nazwie `alias`.
+
+Polecenie `alias` można wywołać bez żadnego parametru:
+```bash
+alias
+```
+
+wyświetli wtedy listę wszystkich zdefiniowanych aliasów dostępnych w danym terminalu.
+
+## Tworzenie aliasów
+
+Żeby utworzyć nowy alias należy wywołać:
+```bash
+alias NAME=VALUE
+```
+
+gdzie:
+* `NAME` oznacza nazwę nowego "polecenia" do wywoływania w wierszu poleceń
+* `VALUE` jest poleceniem, lub ciągiem poleceń, które zostanie wywołana naprawdę.
+Jeśli chcemy, żeby `VALUE` zawierało spację należy wszystko umieścić w parze apostrofów (') lub cudzysłowów (")
+
+Przykłady użycia:
+```bash
+alias rf='fm -rf'
+alias ..='cd ..'
+alias cwd='cd `pwd`'
+```
+Od teraz :
+* polecenie `rf <ścieżka_do_folderu>` będzie usuwać foldery,
+* polecenie `..` przechodzić do folderu wyżej w drzewie hierarchii folderów,
+* polecenie `cwd` będzie odświeżać aktywny folder.
+
+## Tworzenie permanentnych aliasów
+Problem z aliasami jest tylko jeden. Działają tylko w ramach terminala w którym zostały zdefiniowane.
+Można to rozwiązać w prosty sposób poprzez stworzenie wszystkich aliasów w pliku, np. pod nazwą `~/.bash_aliases`,
+a następnie wczytywania go za pomocą polecenia `source`.
+Teraz po otwarciu nowego terminala wystarczy wywołać:
+```bash
+source ~/.bash_aliases
+```
+
+by cieszyć się swoimi aliasami w każdym terminalu.
+
+## Automatyczne wczytywanie aliasów
+Można to jednak jeszcze bardziej uprościć.
+Przy starcie każdego nowego terminala jest wczytywany plik `~/.bashrc`.
+Wystarczy na końcu tego pliku dodać:
+```bash
+source ~/.bash_aliases
+```
+lub bezpieczniej:
+```bash
+if [ -f ~/.bash_aliases ]; then
+ . ~/.bash_aliases
+fi
+```
+Dodatkowy `if` uchroni nas przed błędem, gdy plik `~/.bash_aliases` nie istnieje.
+Kropka na początku drugiej linii jest aliasem na `source`.
+
+Dodatkowo do pliku `~/.bash_aliases` warto dodać aliasy:
+```bash
+alias vish='vim ~/.bashrc'
+alias srcsh='source ~/.bashrc'
+```
+
+## Niezniszczalne aliasy
+Używanie aliasów nie jest niczym nowym.
+Możliwe, że w waszej dystrybucji będzie już istnieć plik `~/.bash_aliases` czekający na uzupełnienie
+lub nawet będzie już wczytywany w pliku `~/.bashrc`.
+Także cała powyższa procedura jest opisana na wielu stronach i blogach.
+
+Mój główny problem z aliasami polegał na tym,
+że gdy już miałem uzbierany pokaźny zestaw aliasów ułatwiających mi życie padł mi dysk w służbowym laptopie.
+Komputer poszedł do działu IT, wymienili mi dysk, ale ja straciłem wszystkie aliasy.
+
+Stwierdziłem wtedy "Moja wina, bo wszystko, co tylko można, należy trzymać w chmurze".
+Więc założyłem repozytorium na githubie [cli](https://github.com/writeonly/cli),
+gdzie w pliku [bash_aliases](https://github.com/writeonly/cli/blob/master/bash_aliases) ponownie zbieram potrzebne mi aliasy.
+Dodatkowo zrobiłem mały skrypt instalujący, tak by jedną linią
+```bash
+wget https://raw.githubusercontent.com/writeonly/cli/master/bash_aliases_install.sh | bash
+```
+móc odzyskać wszystko to, do czego przywykłem.
+
+A polecenie:
+```bash
+update_aliases
+```
+można zaktualizować aliasy.
\ No newline at end of file
diff --git a/_collections/_posts/2018-09-05-docker-usuwanie-obrazow.md b/_collections/_posts/2018-09-05-docker-usuwanie-obrazow.md
new file mode 100644
index 00000000..3de1475d
--- /dev/null
+++ b/_collections/_posts/2018-09-05-docker-usuwanie-obrazow.md
@@ -0,0 +1,56 @@
+---
+title: "Docker - usuwanie obrazów"
+author: TheKamilAdam
+category: cli
+tags: alias cli
+tools: docker
+redirect_from:
+ - docker-usuwanie-obrazow
+ - cli/docker-usuwanie-obrazow
+ - cli/2018/09/05/docker-usuwanie-obrazow.html
+---
+
+Dziesięć lat pracy na Linuksie nauczyło mnie,
+że jeśli Linuks zaczyna magicznie i bez ostrzeżenia sam z siebie nie działać
+to najprawdopodobniej skończyło się miejsce na dysku.
+Identycznie jest z Dockerem.
+Jeśli lokalnie stawiamy chmurę mikroserwisów,
+które często pojawiają się w nowych wersjach,
+to prędzej czy później zabraknie nam miejsca na dysku.
+W skrajnym wypadku, na laptopie zastępczym, musiałem dwa razy w tygodniu usuwać obrazy Dockerowe.
+
+## Procedura usuwania obrazów Dockerowych
+Szczęśliwie procedura usuwania obrazów Dockerowcyh nie jest czynnością skomplikowaną i składa się z trzech kroków.
+Na początek włączamy terminal i teraz kolejno wykonujemy kroki:
+
+Krok 1. Zatrzymujemy wszystkie kontenery:
+```bash
+docker kill $(docker ps -q)
+```
+
+Krok 2. Usuwamy wszystkie kontenery:
+```bash
+docker rm $(docker ps -a -q)
+```
+
+Krok 3. Usuwamy wszystkie obrazy:
+```bash
+docker rmi $(docker images -q)
+```
+
+## Wszystko razem
+Można także wykonać wszystko razem jako jedno, połączone polecenie w terminalu:
+
+```bash
+docker kill $(docker ps -q); docker rm $(docker ps -a -q); docker rmi $(docker images -q)
+```
+
+Lepiej jest jednak dodać wpis do pliku `~/.bash_aliases` :
+```bash
+alias docker_rmi_all='docker kill $(docker ps -q); docker rm $(docker ps -a -q); docker rmi $(docker images -q)'
+```
+
+I wtedy wystarczy z wywołać w terminalu:
+```bash
+docker_rmi_all
+```
diff --git a/_collections/_posts/2018-09-12-git-submoduly-i-aliasy.md b/_collections/_posts/2018-09-12-git-submoduly-i-aliasy.md
new file mode 100644
index 00000000..3c2fdf96
--- /dev/null
+++ b/_collections/_posts/2018-09-12-git-submoduly-i-aliasy.md
@@ -0,0 +1,124 @@
+---
+title: "Git - submoduły i aliasy"
+author: TheKamilAdam
+category: cli
+tags: cli alias interpreter
+labels: submodule
+langs: java javascript
+tools: git
+redirect_from:
+ - git-submoduly-i-aliasy
+ - cli/git-submoduly-i-aliasy
+ - cli/2018/09/12/git-submoduly-i-aliasy.html
+---
+
+*Post oparty na prawdziwych wydarzeniach i traumach*
+
+## Submoduły
+
+Zrobili to!
+Mimo że protestowałem.
+Do projektu przy którym pracowałem dodali submoduły.
+
+- Jak mogli to zrobić - zadaje pytanie oburzony.
+- Prosto - pada odpowiedź - za pomocą polecenia o składni:
+```bash
+git submodule add link-do-repozytorium opcjonalna-nazwa-folderu
+```
+A w tym wypadku było to dokładnie:
+```bash
+git submodule add https://github.com/paulp/sbt-extras.git sbtx
+```
+wykonane w folderze projektu.
+
+- Ale po co? - drążę dalej temat.
+- Żeby współdzielić kod.
+- Przecież do tego służą biblioteki! - moje oburzenie sięga zenitu.
+- Ale nie zawsze jest to łatwe i możliwe:
+ 1. Biblioteki trzeba wydawać i trzymać je w menedżerze repozytoriów binarnych (ang. *Binary Repository Manager*),
+a takiego menedżera trzeba gdzieś zainstalować.
+ 2. Menedżer repozytorium binarnych może kosztować, np. dla języka **[Java]** jest za darmo, a dla języka **[JavaScript]** już niekoniecznie.
+ 3. W językach skryptowych biblioteki są często instalowane do **[interpretera]**
+ co może utrudniać instalację programu klientowi
+(przykład z pierwszej wersji [Git-Tools-Submodules]()).
+ 4. Nie wszystko da się umieścić w bibliotece, w tym wypadku jest to skrypt do budowania projektu.
+
+## Dodatkowe polecenia
+Tak przekonany przestałem marudzić
+ i przejrzałem [Git-Tools-Submodules](),
+ [git-submodule]()
+ oraz [git-clone]().
+ Okazało się, że praca z submodułami nie jest taka straszna i sprowadza się głównie do dwóch poleceń:
+
+```bash
+git clone --recurse-submodules
+git submodule update --init --recursive
+```
+Pierwsze polecenie ściąga repozytorium ze wszystkimi submodułami.
+Drugie - aktualizuje submoduły po przełączeniu się na inną rewizję (ang. *commit*), gałąź lub po aktualizacji gałęzi.
+
+Niestety polecenia te wydłużają i tak długie już polecenia gita.
+
+## Aliasy Basha
+
+Szczęśliwie umiem rozwiązywać problem długich poleceń,
+bo znam [aliasy basha](/alias-komenda-powloki-bash).
+
+Pierwsza wersja moich aliasów wyglądała następująco:
+```bash
+alias g='git'
+alias gcl='git clone'
+alias gclr='gcl --recurse-submodules'
+alias gupdate='git submodule update --init --recursive'
+alias gpr='git pull --rebase'
+alias gpru='gpr && gupdate'
+alias master='git checkout master && gupdate'
+alias develop='git checkout develop && gupdate'
+```
+
+## Aliasy Gita
+
+Byłem bardzo zadowolony ze swoich aliasów, więc postanowiłem się nimi pochwalić koledze:
+- To bez sensu - odpowiedział zdziwiony -
+przecież git ma swój system [aliasów]().
+
+Po przeczytaniu [Git-Basics-Git-Aliases]()
+i [git-config]()
+mój zbiór aliasów zamienił się w zestaw poleceń gita do wykonania:
+
+```bash
+git config --global alias.cl 'clone'
+git config --global alias.clr 'cl --recurse-submodules'
+git config --global alias.update 'submodule update --init --recursive'
+git config --global alias.pr 'pull --rebase'
+git config --global alias.pru '!git pr && git update'
+git config --global alias.master '!git checkout master && git update'
+git config --global alias.develop '!git checkout develop && git update'
+git config --global alias.tig '!tig'
+```
+Widać tutaj, że podkomenda `alias` ma dwie składnie:
+```bash
+git config --global alias.nowa_komenda_gita 'stara_komenda_gita_z_parametrami'
+git config --global alias.nowa_komenda_gita '!dowolna_komenda_basha'
+```
+
+I od teraz:
+* `git cl` - klonuje repozytorium;
+* `git clr` - klonuje repozytorium razem z submodułami;
+* `git update` - aktualizuje submoduły;
+* `git pr` - pobiera zmiany ze zdalnego repozytorium;
+* `git pru` - pobiera zmiany ze zdalnego repozytorium i aktualizuje submoduły;
+* `git master` - przełącza na gałąź master i aktualizuje submoduły;
+* `git develop` - przełącza na gałąź develop i aktualizuje submoduły;
+* `git tig` - uruchamia program `tig` (o ile mamy go zainstalowany).
+
+Polecenia te zapisałem w pliku [git_config.sh]()
+i można je wykonać poleceniem:
+```bash
+curl -s https://raw.githubusercontent.com/writeonly/cli/master/git_config.sh | bash
+```
+
+[Java]: /langs/java
+[JavaScript]: /langs/javascript
+
+[interpretera]: /tags/interpreter
diff --git a/_collections/_posts/2018-09-26-jekyllcodex-org-czesc-druga.md b/_collections/_posts/2018-09-26-jekyllcodex-org-czesc-druga.md
new file mode 100644
index 00000000..9dcb051d
--- /dev/null
+++ b/_collections/_posts/2018-09-26-jekyllcodex-org-czesc-druga.md
@@ -0,0 +1,55 @@
+---
+title: "jekyllcodex.org - część druga"
+author: TheKamilAdam
+category: jekyll
+tags: blog jekyllcodex seo
+tools: jekyll
+redirect_from:
+ - jekyllcodex-org-czesc-druga
+ - jekyll/jekyllcodex-org-czesc-druga
+ - writeonlydoc/jekyllcodex-org-czesc-druga
+ - writeonlydoc/2018/09/26/jekyllcodex-org-czesc-druga.html
+---
+
+Ponad miesiąc temu, w panice, szukałem prostego skryptu, który by wyświetlał ostrzeżenie o plikach cookies.
+Skrypt odnalazłem na stronie [jekyllcodex.org]().
+Strona ta zawiera repozytorium skryptów, które rozszerzają możliwości generatora statycznych stron Jekyll.
+
+Dziś już na spokojnie postanowiłem przejrzeć to repozytorium skryptów.
+Przeszukiwanie prowadziłem pod kątem możliwości rozszerzenia funkcjonalności mojego bloga.
+
+## Skrypty, które użyłem
+Skrypty wykorzystane przeze mnie podzieliłem na trzy kategorie ze względu na miejsce dodania skryptu:
+
+### Skrypty ogólne
+Są to skrypty, które w większości trafiły do układu strony `default.html`:
+
+- [ostrzeżenie o plikach cookies]( )
+- [seo]( )
+- [kanał rss]( )
+- [przyciski linkujące do kont na portalach społecznościowych]( )
+- [czat na żywo]( ) - jeszcze nie wiem po co, ale dodałem.
+
+### Skrypty dla postów
+Są to skrypty, które trafiły do układu strony `post.html`:
+
+- [wskaźnik czasu czytania]( )
+- [przyciski udostępniania dla mediów społecznościowych]( )
+
+### Skrypty dla stron
+Jest to w zasadzie jeden skrypt, który trafił do układu strony `page.html`:
+
+- [okruszki chleba]( ) - dla bloga nie za bardzo nie ma sens,
+wydaje się przydatny tylko dla stron o zagnieżdżonej hierarchii
+
+## Skrypty, których jeszcze nie użyłem
+Niestety nie zdążyłem wypróbować wszystkich skryptów, które mnie ciekawią i które mogłyby być użyteczne na blogu.
+Te które pozostały do przetestowania dzielą się na dwie kategorie:
+
+### Skrypty robiące jakąś magię z menu
+- [proste menu]( )
+- [mobilne menu]( )
+
+### Skrypty dodające wyszukiwarki
+- wyszukiwarka oparta o [google]( )
+- wyszukiwarka oparta o [skrypt lunar]( )
diff --git a/_collections/_posts/2018-10-03-przenosna-scala.md b/_collections/_posts/2018-10-03-przenosna-scala.md
new file mode 100644
index 00000000..588602ad
--- /dev/null
+++ b/_collections/_posts/2018-10-03-przenosna-scala.md
@@ -0,0 +1,149 @@
+---
+title: "Przenośna Scala"
+author: TheKamilAdam
+category: scala-native
+tags: compiler native nojvm transpiler
+langs: crystal erlang haskell go javascript pony rust scala
+tools: clang jvm llvm node-js sbt scala-jvm scala-js scala-native
+libs: akka
+redirect_from:
+ - przenosna-scala
+ - scala-native/przenosna-scala
+ - resentiment/przenosna-scala
+ - resentiment/2018/10/03/przenosna-scala.html
+---
+
+Znajomy zajarał się językiem **[Rust]**.
+Opowiada mi jaki to wspaniały język i pokazuje przykłady kodu.
+**[Rust]** na pierwszy rzut oka wygląda jak skrzyżowanie **[C]** i języka **[Haskell]** plus kanały jak w języka **[Go]**.
+Czyni go to pretendentem do bycia najbardziej skomplikowanym językiem programowania na świecie.
+Pretendentem, bo istnieje wśród programistów JVM opinia, że najbardziej skomlikowanym językiem na świecie jest **[Scala]**.
+**[Scala]** jest skrzyżowaniem Javy i Haskella plus aktory z języka **[Erlang]**.
+
+Przykłady kodu coś mi przypominają.
+Wyglądają prawie jak w Scali tylko trochę mniej obiektowe, więc pytam:
+- Dlaczego nie Scala? Jest to w tej chwili jedyny funkcyjny język programowania, który odniósł sukces komercyjny.
+Nie licząc niszowego Erlanga - dodaję.
+- Bo ja nie lubię **[JVM]** - odpowiada. - Za dużo musiałem robić w apletach.
+
+Po tej rozmowie zacząłem się zastanawiać czy istnieje możliwość używania Scali poza JVM.
+Czy Scala jest językiem przenaszalnym na inne platformy?
+
+## Portable Scala - dwa razy tak i jeden raz nie
+
+### .Net Framework
+Podobno największą konkurencją dla JVM jest .Net.
+
+Z kilka lat temu, jak o Scali zaczynano dopiero mówić, podobno ruszyły prace nad przeniesieniem Scali na .Net.
+Podobno nawet M$ dofinansował ten projekt.
+
+Jednak do dziś nie ma języka Scala.NET ani S#.
+Podobno różnice między JVM a .Net są zbyt duże,
+żeby w sensowny sposób udało się przenieść statycznie typowany język programowania
+z jednego środowiska uruchomieniowego na drugie.
+
+Podobno istniał jeden statycznie typowany język programowania,
+który działał na obu platformach.
+Jednak było to zalane taką ilością warstw abstrakcyjnych,
+że czyniło go to bezużytecznym.
+
+### JavaScript
+**[JavaScript]** jest platformą docelową dla każdego,
+kto chce uruchamiać cokolwiek na stronie internetowej.
+Dlatego jeśliby posiadać **[transpilator]** Scali do JavaScriptu
+to w łatwy sposób można by z każdego programisty Scali stworzyć legendarnego Full-Stack Developera.
+Szczęśliwie taki **[transpilator]** istnieje i nazywa się **[Scala.js]**.
+Istnieje nawet [Akka.js], framework aktorów.
+
+Niestety **[Scala.js]** i Akka.js posiadają wszystkie wady **[Node.js]** to znaczy jednowątkowość,
+ale do front-endu wydają się idealne.
+
+### Native
+Największą zaletą języków
+**[Rust]**, **[Pony]**, **[Crystal]** czy **[Go]**,
+jest to,
+że są to języki kompilowane do postaci natywnej,
+a programy w nich pisane mogą być dostarczane do klienta pod postacią jednego pliku.
+
+To samo ze Scalą robi **[kompilator]** **[Scala Native]** oparty na **[LLVM]**.
+Niestety dalej jest w wersji eksperymentalnej i nie posiada np. wielowątkowości.
+Co czyni go na razie tylko zabawką dla nerdów i np. ... DevOpsów oraz QA.
+Bo o ile jednowątkowy program na produkcji zwykle nie ma sensu,
+to ScalaNative może zastąpić inne języki używane do wdrażania aplikacji i testowania.
+Zwłaszcza, że zwykle i tak są to języki jednowątkowe.
+
+## Portable Scala - wszystkie części mocy
+
+W łatwy sposób można stworzyć projekt, który będzie kompilowany na wszystkie trzy platformy,
+to znaczy JS, JVM i Native.
+
+Na początek instalujemy [zależności] dla **[Scala Native]**:
+
+```bash
+sudo apt install clang libunwind-dev
+sudo apt install libgc-dev libre2-dev
+```
+
+Następnie pobieramy przykładową [aplikację skośną] z portable-scala:
+```bash
+sbt new portable-scala/sbt-crossproject.g8
+```
+
+Kompilujemy:
+```bash
+sbt clean compile test
+```
+
+I uruchamiamy:
+```bash
+sbt barJS/run barJVM/run barNative/run
+```
+
+## Mój Resentiment
+
+Stworzyłem projekt na portalu [GitHub],
+gdzie będę starał się rozwijać aplikację kompilowaną na wszystkie trzy platformy.
+Na razie pod tagiem [portable-scala]
+znajduje się wersja z podniesionymi zależnościami i ze zmienioną konfiguracją projektu.
+
+Pobranie projektu:
+```
+git clone https://github.com/writeonly/resentiment.git
+```
+
+Kompilacja:
+```bash
+sbt clean compile test
+```
+
+I uruchomienie:
+```bash
+sbt re/run reJS/run reJVM/run
+```
+
+[Crystal]: /langs/crystal
+[Erlang]: /langs/erlang
+[Go]: /langs/go
+[Haskell]: /langs/haskell
+[JavaScript]: /langs/javascript
+[Pony]: /langs/pony
+[Rust]: /langs/rust
+[Scala]: /langs/scala
+
+[C]: /tools/clang
+[JVM]: /tools/jvm
+[LLVM]: /tools/llvm
+[Node.js]: /tools/node-js
+[Scala Native]: /tools/scala-native
+[Scala.js]: /tools/scala-js
+
+[Akka.js]: /libs/akka-js
+
+[Transpilator]: /tags/transpiler
+[Kompilator]: /tags/compiler
+
+[zależności]: http://www.scala-native.org/en/v0.3.8/user/setup.html#installing-clang-and-runtime-dependencies
+[aplikację skośną]: https://github.com/portable-scala/sbt-crossproject.g8
+
+[GitHub]: https://github.com/writeonly/resentiment
+[portable-scala]: https://github.com/writeonly/resentiment/tree/portable-scala
diff --git a/_collections/_posts/2018-10-10-git-flow-i-aliasy.md b/_collections/_posts/2018-10-10-git-flow-i-aliasy.md
new file mode 100644
index 00000000..0c818f5a
--- /dev/null
+++ b/_collections/_posts/2018-10-10-git-flow-i-aliasy.md
@@ -0,0 +1,79 @@
+---
+title: "Git-flow i aliasy"
+author: TheKamilAdam
+category: cli
+tags: alias cli
+labels: flow
+tools: git
+redirect_from:
+ - git-flow-i-aliasy
+ - cli/git-flow-i-aliasy
+ - cli/2018/10/10/git-flow-i-aliasy.html
+---
+
+Gitflow jest wspaniałą koncepcją pracy z gałęziami w repozytorium Git.
+Strategia ta jest świetnie opisana na
+[A successful Git branching model]( ).
+
+Jednak początkowo może wydawać się zbyt skomplikowana.
+Straszy zwłaszcza ilością poleceń, które trzeba wykonać, żeby scalić gałąź z nową funkcjonalnością:
+```bash
+$ git checkout develop
+$ git merge --no-ff myfeature
+$ git branch -d myfeature
+$ git push origin develop
+```
+
+Ilość poleceń, parametrów i przełączników może powodować niekończące się problemy i dyskusje
+ "czy na pewno potrzebujemy czegoś tak skomplikowanego?".
+
+Na szczęście istnieje 'git-flow'.
+
+## Narzędzie git-flow
+
+> git-flow jest zbiorem rozszerzeń gita dostarczającym wysokopoziomowe operacje na repozytorium,
+ wspierającym strategię rozgałęziania opracowaną przez Vincenta Driessena.
+Za [ściągawka do git-flow]()
+
+Tutaj już nie mogą toczyć się dyskusje czy powinniśmy scalać z przełącznikiem `--no-ff` czy bez niego.
+Możemy wziąć całe narzędzie ustandaryzowane i przetestowane przez społeczność i nie kroimy niczego własnego.
+
+Zalety tego są oczywiste:
+* programista, tester i/lub wdrożeniowiec,
+który raz nauczył się pracować z Gitflow ma jedną rzecz mniej do nauki przy przenoszeniu się do innego zespołu,
+gdzie będą stosować dokładnie ten sam Gitflow bez żadnych lokalnych modyfikacji
+* zamiast wpisywania długich wielolinijkowców w konsoli możemy używać pojedynczych poleceń.
+
+## Moje aliasy
+
+Jednak nawet te polecenia są dla mnie za długie.
+Dlatego przygotowałem [plik]() z [aliasami Basha](/git-submoduly-i-aliasy)
+
+```bash
+# git flow
+git config --global alias.fi 'flow init'
+# git flow feature
+git config --global alias.ffstart 'flow feature start'
+git config --global alias.fffinish 'flow feature finish '
+git config --global alias.ffpublish 'flow feature publish'
+git config --global alias.ffpull 'flow feature pull origin'
+git config --global alias.fftrack 'git flow feature track'
+# git flow release
+git config --global alias.frstart 'flow release start'
+git config --global alias.frpusblish 'flow release publish'
+git config --global alias.frfinish 'flow release finish'
+# git flow hotfix
+git config --global alias.fhstart 'flow hotfix start'
+git config --global alias.fhfinish 'flow hotfix finish'
+```
+
+Można go zastosować poleceniem
+```bash
+curl -s https://raw.githubusercontent.com/writeonly/cli/master/git_config.sh | bash
+```
+
+i cieszyć się krótkimi poleceniami jak:
+```bash
+git ffstart myfeature
+git fffinish myfeature
+```
diff --git a/_collections/_posts/2018-10-17-dynamiczna-analiza-kodu.md b/_collections/_posts/2018-10-17-dynamiczna-analiza-kodu.md
new file mode 100644
index 00000000..ea45d0ba
--- /dev/null
+++ b/_collections/_posts/2018-10-17-dynamiczna-analiza-kodu.md
@@ -0,0 +1,183 @@
+---
+title: "Dynamiczna analiza kodu dla SBT - testy jednostkowe"
+author: TheKamilAdam
+category: scala-native
+tags: code-analysis dynamic-code-analysis
+labels: minitest greenlight
+langs: scala
+tools: scala-jvm scala-js scala-native
+libs: specs2 scalatest utest
+redirect_from:
+ - dynamiczna-analiza-kodu
+ - scala-native/dynamiczna-analiza-kodu
+ - resentiment/dynamiczna-analiza-kodu
+ - resentiment/2018/10/17/dynamiczna-analiza-kodu.html
+---
+
+> Dynamiczna analiza programu to analiza oprogramowania komputerowego wykonywanego przez wykonywanie programów na rzeczywistym lub wirtualnym procesorze.
+> Korzystanie z metryk testów, takich jak pokrycie kodu, zapewnia, że przetestowano odpowiednią ilość możliwych zachować programu.
+> Aby analiza dynamiczna programu była skuteczna, program docelowy musi być wykonany z wystarczającą ilością danych wejściowych do testów, aby uzyskać interesujące zachowanie.
+> Testy jednostkowe, testy integracyjne, testy systemowe i testy akceptacyjne wykorzystują dynamiczną analizę programu.
+
+Za [wikipedią]().
+
+W tym poście skupię się tylko na frameworkach do testów, testach jednostkowych i mierzeniu pokrycia kodu testami.
+
+## Frameworki dla testów
+
+* [ScalaTest]() -
+jest to chyba najbardziej znany i rozbudowany framework dla testów do języka Scala.
+Wspiera Scala.js w wersji 0.6.x. Ostatnia wersja snapshot wspiera Scala Native.
+Posiada osiem różnych [stylów pisania testów](),
+jednak autorzy zachęcają do wybrania dwóch dla projektu.
+Jeden styl dla testów jednostkowo-integracyjnych, drugi - dla akceptacyjnych.
+Najciekawsze style to:
+ * `FunSuite` i `FlatSpec` - są to proste, płaskie style pisania testów podobne do JUnit.
+ Jeśli jednak są dla kogoś zbyt awangardowe jest możliwość pisania testów w Scali z użyciem [JUnit i assercji z ScalaTest]()
+ * `FunSpec`, `FreeSpec` i `WordSpec` - są to style testów umożliwiające pisanie zagnieżdżonych testów,
+ jednak zagnieżdżenia nie są wymagane (za wyjątkiem stylu `FunSpec`, gdzie trzeba użyć przynajmniej jeden poziom `Describe`)
+ * `FeatureSpec` - jest to zaawansowany styl dla pisania testów akceptacyjnych.
+* [specs2]( ) -
+jest to drugi najbardziej znany framework do pisania testów dla języka Scala.
+Od wersji czwartej wspiera Scala.js w wersji 0.6.x.
+Ma dwa style pisania testów:
+ * `org.specs2.mutable.Specificatio` - najbardziej przypomina `FreeSpec` i jest przewidziany do pisania testów jednostkowych i integracyjnych.
+ * `org.specs2.Specification` - styl testów przewidziany do pisania testów akceptacyjnych,
+* [uTest]() -
+czarny koń tego zestawienia.
+Wspiera Scala.js w wersji 0.6.x i 1.0.x oraz Scala Native.
+Autor frameworka skromnie chwali się, że wspiera wszystkie wersje języka Scala.
+Ma jeden styl pisania testów który wygląda jak `FreeTest`.
+* [MiniTest]() -
+stworzony przez [Monix]() do testowania swojej biblioteki.
+Wspiera Scala.js w wersji 0.6.x.
+Ma jeden styl pisania testów, który wygląda jak `FunSuite`.
+* [Greenlight]() -
+projekt niestety umarł.
+Wspiera Scala.js w wersji 0.6.x.
+Ma jeden styl pisania testów, który wygląda jak `FlatSpec`
+
+## Test jednostkowy w uTest
+
+W `build.sbt` dodajemy `uTest` do zależności projektu:
+```scala
+ libraryDependencies += "com.lihaoyi" %%% "utest" % "0.6.5" % "test"
+```
+
+i ustawiamy jako framework testowy:
+```scala
+ testFrameworks += new TestFramework("utest.runner.Framework"),
+```
+
+Tworzymy klasę `Calculator`, którą będziemy testować :
+```scala
+package pl.writeonly.re.shared
+
+class Calculator {
+ type T = Int
+
+ def add(a: T, b: T): T = a * b
+
+ def mul(a: T, b: T): T = a + b
+
+ def leq(a: T, b: T): Boolean = a < b
+
+}
+```
+
+Oraz testy dla niej:
+
+```scala
+package pl.writeonly.re.shared
+
+import utest._
+
+object CalculatorTest extends TestSuite {
+ override val tests: Tests = Tests {
+ val calculator = new Calculator()
+ 'addition - {
+ val addition: (Int, Int) => Int = (x, y) => calculator.add(x, y)
+ "0 + 0 == 0" - {
+ assert(addition(0, 0) == 0)
+ }
+ "2 + 2 == 4" - {
+ assert(addition(2, 2) == 4)
+ }
+ }
+ 'multiplication - {
+ val multiplication: (Int, Int) => Int = (x, y) => calculator.mul(x, y)
+ "0 + 0 == 0" - {
+ assert(multiplication(0, 0) == 0)
+ }
+ "2 + 2 == 4" - {
+ assert(multiplication(2, 2) == 4)
+ }
+ }
+ 'less_or_equal - {
+ val less_or_equal: (Int, Int) => Boolean = (x, y) => calculator.leq(x, y)
+ "0 <= 2 == true" - {
+ assert(less_or_equal(0, 2))
+ }
+ "2 <= 0 == false" - {
+ assert(!less_or_equal(2, 0))
+ }
+ }
+ }
+}
+```
+
+Wszystko kompilujemy i uruchamiamy testy za pomocą polecenia:
+```bash
+sbt clean compile test
+```
+
+Testy przeszły, jesteśmy szczęśliwi:
+```log
+[info] -------------------------------- Running Tests --------------------------------
+[info] + pl.writeonly.re.shared.CalculatorTest.addition.0 + 0 == 0 0ms
+[info] + pl.writeonly.re.shared.CalculatorTest.addition.2 + 2 == 4 0ms
+[info] + pl.writeonly.re.shared.CalculatorTest.multiplication.0 + 0 == 0 0ms
+[info] + pl.writeonly.re.shared.CalculatorTest.multiplication.2 + 2 == 4 0ms
+[info] + pl.writeonly.re.shared.CalculatorTest.less_or_equal.0 <= 2 == true 0ms
+[info] + pl.writeonly.re.shared.CalculatorTest.less_or_equal.2 <= 0 == false 0ms
+[info] Tests: 6, Passed: 6, Failed: 0
+```
+
+## Testowanie testów - mierzenie pokrycia kodu testami
+Skąd mamy mieć pewność, że przetestowaliśmy klasę `Calculator` w wystarczający sposób?
+Możemy to częściowo sprawdzić mierząc pokrycie kodu produkcyjnego (tj. klasy `Calculator`) testami.
+
+Jeśli chodzi o narzędzia do mierzenia pokrycia kodu testami to tutaj król jest jeden
+i jest nim [scoverage]().
+Posiada on wtyczki do:
+* [sbt]()
+* [maven]()
+* [gradle]()
+* [scalac]()
+* [sonarqube]()
+
+Przy czym użyjemy tutaj tylko pierwszej z nich.
+
+Dodajemy `sbt-scoverage` do `build.sbt`:
+```scala
+addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1")
+```
+I wykonujemy:
+```bash
+sbt clean coverage test && sbt coverageReport
+```
+gdzie:
+* `coverage` - wykonuje kompilacje z instrumentacją kodu
+* `coverageReport` - generuje raport
+
+Niestety powyższe polecenie działa tylko dla implementacji Scala/JVM i Scala.js.
+Scala Native nie wspiera instrumentacji kodu.
+Dlatego projekt [resentiment](https://github.com/writeonly/resentiment) trzeba kompilować za pomocą polecenia:
+```bash
+sbt clean compile re/test coverage reJVM/test reJS/test && sbt coverageReport
+```
+
+Teraz możemy otworzyć pliki `/re/js/target/scala-2.11/scoverage-report/index.html`
+oraz `/re/jvm/target/scala-2.11/scoverage-report/index.html`
+i zobaczyć, że klasa `Calculator` ma 100% pokrycia kodu testami.
+Lider nietechniczny i Product Owner powinni być z nas zadowoleni.
diff --git a/_collections/_posts/2018-10-24-statyczna-analiza-kodu-1.md b/_collections/_posts/2018-10-24-statyczna-analiza-kodu-1.md
new file mode 100644
index 00000000..bf1a928f
--- /dev/null
+++ b/_collections/_posts/2018-10-24-statyczna-analiza-kodu-1.md
@@ -0,0 +1,167 @@
+---
+title: "Statyczna analiza kodu dla języka Scala w SBT - część 1."
+author: TheKamilAdam
+category: scala-native
+tags: code-analysis static-code-analysis
+labels: scalafmt scalariform
+langs: scala
+tools: sbt scalafix
+redirect_from:
+ - statyczna-analiza-kodu-1
+ - scala-native/statyczna-analiza-kodu-1
+ - resentiment/statyczna-analiza-kodu-1
+ - resentiment/2018/10/24/statyczna-analiza-kodu-1.html
+---
+
+> Statyczna analiza programu to analiza oprogramowania komputerowego wykonywanego bez faktycznego uruchamiania programów,
+w przeciwieństwie do analizy dynamicznej,
+która jest analizą wykonywaną na programach podczas ich wykonywania.
+
+> Termin ten jest zwykle stosowany do analizy wykonywanej przez zautomatyzowane narzędzie,
+analiza wykonywana przez człowieka jest nazywana przeglądem kodu.
+
+Za [wikipedią]().
+
+Jest to moja ulubiona część konfigurowania projektu,
+ponieważ odpowiednio dobrany zestaw wtyczek do statycznej analizy kodu
+potrafi znacząco skrócić czas potrzebny do zrobienia przeglądu kodu.
+
+## Wtyczki modyfikujące kod źródłowy
+
+Z powodu ogromu różnego rodzaju wtyczek do statycznej analizy kodu dla języka Scala
+w tym poście skupię się tylko na wtyczkach modyfikujących kod źródłowy.
+
+### sbt-scalariform - sbt plugin adding support for source code formatting using Scalariform
+[sbt-scalariform]()
+to wtyczka sbt dodająca obsługę formatowania kodu źródłowego przy użyciu formatera kodu Scalariform
+
+Dodajemy `scalariform` do pliku `projektu/plugins.sbt`:
+```scala
+addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.2")
+```
+
+Konfiguracja jest możliwa za pomocą:
+* zmiennej `scalariformPreferences` w pliku `build.sbt`
+* pliku `.scalariform.conf`
+
+Formatowanie kodu jest wykonywane automatycznie podczas kompilacji:
+
+```bash
+sbt compile test:compile it:compile
+```
+
+### Scalafmt - Code formatter for Scala
+[Scalafmt]( ) to formater kodu dla języka Scala.
+
+Dodajemy `scalafmt` do pliku `projektu/plugins.sbt`:
+```scala
+addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.1")
+```
+
+Konfiguracja jest możliwa za pomocą pliku `.scalafmt.conf`, np.:
+```hocon
+style=IntelliJ
+maxColumn=80
+```
+
+Formatowanie domyślnie nie wykonuje się podczas kompilacji.
+Aby sformatować kod należy wykonać:
+```bash
+sbt scalafmtSbt scalafmt test:scalafmt it:scalafmt
+```
+Kolejno formatowany jest plik `build.sbt`, kod produkcyjny, testy jednostkowe i testy integracyjne.
+
+Możliwe jest także tylko sprawdzenie czy kod jest sformatowany poprawnie za pomocą polecenia:
+```bash
+sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck it:scalafmtCheck
+```
+
+### Scalafix - Refactoring and linting tool for Scala
+[Scalafix]( ) to narzędzie do analizy statycznej kodu w języku Scala.
+Jest to jedyne narzędzie, które potrafi znalezione błędy poprawić.
+
+Dodajemy `scalafix` do pliku `projektu/plugins.sbt`:
+```scala
+addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.0")
+```
+
+W pliku `build.sbt` dodajemy następujące linie:
+```scala
+ addCompilerPlugin(scalafixSemanticdb)
+ scalacOptions ++= Seq(
+ //"-Xfatal-warnings", // it should be disabled for scalafix
+ "-Ywarn-adapted-args", // for NoAutoTupling
+ "-Ywarn-unused", // for RemoveUnused
+ )
+```
+
+Konfiguracja jest możliwa za pomocą pliku `.scalafix.conf`.
+Poniższa konfiguracja włącza wszystkie istniejące obecnie reguły:
+```hocon
+rules = [
+
+// Semantic Rules - Reguły semantyczne
+ NoAutoTupling
+ RemoveUnused
+
+// Syntactic Rules - Reguły składniowe
+ DisableSyntax
+ LeakingImplicitClassVal
+ NoValInForComprehension
+ ProcedureSyntax
+]
+
+DisableSyntax.noVars = true
+DisableSyntax.noThrows = true
+DisableSyntax.noNulls = true
+DisableSyntax.noReturns = true
+DisableSyntax.noAsInstanceOf = true
+DisableSyntax.noIsInstanceOf = true
+DisableSyntax.noXml = true
+DisableSyntax.noDefaultArgs = true
+DisableSyntax.noFinalVal = true
+DisableSyntax.noFinalize = true
+DisableSyntax.noValPatterns = true
+DisableSyntax.noUniversalEquality = true
+DisableSyntax.noUniversalEqualityMessage = "== is unsafe since it allows comparing two unrelated types"
+DisableSyntax.regex = []
+```
+
+Aby naprawić kod należy wykonać:
+```bash
+sbt scalafix test:scalafix it:scalafix
+```
+Kolejno naprawiany jest kod produkcyjny, testy jednostkowe i testy integracyjne.
+
+Możliwe jest także tylko sprawdzenie czy kod nie zawiera błędów za pomocą polecenia:
+```bash
+sbt 'scalafix --check' 'test:scalafix --check' 'it:scalafix --check'
+```
+
+## Podsumowanie
+
+Wszystkie wymienione wyżej wtyczki dodałem do projektu
+[resentiment]().
+
+Na chwilę obecna moje polecenie do zbudowania tego projektu to:
+```bash
+sbt clean compile test:compile it:compile re/test && \
+sbt coverage reJVM/test reJS/test && \
+sbt coverageReport
+```
+
+Wcześniej jednak powinienem wywołać polecenie refaktoryzującą i formatującą kod:
+```bash
+sbt scalafix test:scalafix it:scalafix && \
+sbt scalafmtSbt scalafmt test:scalafmt it:scalafmt
+```
+
+Ewentualnie, gdy robię przegląd kodu mogę sprawdzić czy kod jest poprawny za pomocą polecenia:
+```bash
+sbt 'scalafix --check' 'test:scalafix --check' 'it:scalafix --check' && \
+sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck it:scalafmtCheck
+```
+
+Niestety ponieważ w testach używam porównania `==`
+musiałem zakomentować linię `DisableSyntax.noUniversalEquality` w pliku `.scalafix.conf`.
+Problem ten rozwiąże w następnym poście.
diff --git a/_collections/_posts/2018-10-31-statyczna-analiza-kodu-2.md b/_collections/_posts/2018-10-31-statyczna-analiza-kodu-2.md
new file mode 100644
index 00000000..c0a521c6
--- /dev/null
+++ b/_collections/_posts/2018-10-31-statyczna-analiza-kodu-2.md
@@ -0,0 +1,176 @@
+---
+title: "Statyczna analiza kodu dla języka Scala w SBT - część 2."
+author: TheKamilAdam
+category: scala-native
+tags: code-analysis static-code-analysis
+labels: scalastyle wartremover scapegoat linter scala-clippy sbt-cpd sbt-stats
+langs: scala
+tools: sbt scala-jvm scala-js scala-native
+redirect_from:
+ - statyczna-analiza-kodu-2
+ - scala-native/statyczna-analiza-kodu-2.html
+ - resentiment/statyczna-analiza-kodu-2.html
+ - resentiment/2018/10/31/statyczna-analiza-kodu-2.html
+---
+
+Jest to kontynuacja posta
+[Statyczna analiza kodu dla języka Scala w SBT - część 1](/statyczna-analiza-kodu-1.html).
+
+## Wtyczki nie modyfikujące kodu źródłowego.
+
+Jest to o wiele większy zestaw wtyczek niż poprzednio.
+
+### Scalastyle - Scala style checker
+
+[Scalastyle]()
+
+Dodajemy `Scalastyle` do pliku `project/plugins.sbt`:
+```scala
+addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0")
+```
+
+Generujemy domyślny plik konfiguracyjny `scalastyle-config.xml` zawierający reguły:
+```bash
+sbt scalastyleGenerateConfig
+```
+
+Wchodzimy do pliku `scalastyle-config.xml` i zmieniamy poziomy z `warning` na `error`.
+
+Następnie wyłączamy sprawdzanie nagłówka:
+```xml
+
+```
+A na końcu poprawiamy formatowanie dwuliniowej instrukcji `if`:
+```xml
+
+
+
+
+
+
+```
+
+Teraz analizujemy kod i testy za pomocą polecenia:
+```bash
+sbt scalastyle test:scalastyle it:scalastyle
+```
+
+Pełna lista reguł jest dostępna pod linkiem
+[rules-1.0.0]().
+
+Dla mnie najważniejszą funkcjonalnością jest liczenie [złożoności cyklomatycznej]():
+```xml
+
+
+
+
+
+```
+
+### WartRemover: a flexible scala linter
+[WartRemover]()
+jest to wtyczka do usuwania brodawek z kodu.
+Przez brodawkę autor rozumie brzydkie rzeczy, które można napisać w języku Scala,
+bo składnia języka jest zbyt liberalna.
+Nazwa wtyczki jest trochę na wyrost,
+ponieważ w tej chwili `WartRemover` pozwala tylko odnaleźć brodawki,
+a usunąć musimy je sami.
+
+Dodajemy `wartremover` do pliku `project/plugins.sbt`:
+```scala
+addSbtPlugin("org.wartremover" % "sbt-wartremover" % "2.3.7")
+```
+
+W pliku `build.sbt` włączamy `wartremover`:
+```scala
+wartremoverErrors ++= Warts.unsafe
+```
+
+Od teraz przy każdej kompilacji będą poszukiwane brodawki.
+Pełna lista [brodawkek]()
+
+### Scapegoat - Scala compiler plugin for static code analysis
+[Scapegoat]() to linter dla języka Scala.
+
+Dodajemy `scapegoat` do pliku `project/plugins.sbt`:
+```scala
+addSbtPlugin("com.sksamuel.scapegoat" %% "sbt-scapegoat" % "1.3.8")
+```
+
+Ustawiamy wersję `scapegoat` w `build.sbt`:
+```scala
+scapegoatVersion := "1.1.0"
+```
+
+Analizujemy kod za pomocą polecenia:
+```bash
+sbt scapegoat
+```
+
+### Linter - Static Analysis Compiler Plugin for Scala
+[Linter]()
+to niestety nie rozwijany już linter.
+
+Dodajemy `Linter` do pliku `project/plugins.sbt`:
+```scala
+addCompilerPlugin("org.psywerx.hairyfotr" %% "linter" % "0.1.17")
+```
+
+Linter uruchamia się automatycznie podczas kompilacji.
+
+### Scala clippy - Good advice for Scala compiler errors
+[Scala clippy]()
+to wtyczka dodająca porady jak poprawić błędy kompilacji.
+
+Dodajemy `clippy` do pliku `project/plugins.sbt`:
+```scala
+addSbtPlugin("com.softwaremill.clippy" % "plugin-sbt" % "0.5.3")
+```
+
+### sbt-cpd - Copy & Paste Detector plugin using PMD for sbt.
+[sbt-cpd]()
+to wtyczka do wykrywania duplikatów kodu za pomocą Copy/Paste Detector (CPD) z projektu PMD.
+
+Dodajemy `sbt-cpd` do pliku `project/plugins.sbt`:
+```scala
+addSbtPlugin("com.github.sbt" % "sbt-cpd" % "2.0.0")
+```
+
+I analizujemy kod za pomocą polecenia:
+```bash
+sbt cpd
+```
+
+### stats - An sbt plugin for source code statistics
+
+[sbt-stats]()
+to wtyczka licząca ilość plików, linii i znaków w projekcie.
+
+Dodajemy `stats` do pliku `project/plugins.sbt`:
+```scala
+addSbtPlugin("com.orrsella" % "sbt-stats" % "1.0.7")
+```
+
+Analizujemy kod za pomocą polecenia:
+```bash
+sbt stats
+```
+
+## Podsumowanie
+
+Wszystkie wymienione wyżej wtyczki dodałem do projektu
+[resentiment]()
+
+Moje polecenie generowania raportów wygląda następująco:
+```bash
+sbt scalastyle test:scalastyle it:scalastyle && \
+sbt scapegoat && \
+sbt cpd && \
+sbt stats
+```
+
+Niestety,
+ponieważ używam metody `println` w klasie `Core`,
+muszę obniżyć poziom raportowania błędów
+dla reguły `org.scalastyle.file.RegexChecker` w `ScalaStyle`
+z `error` na `warning`.
\ No newline at end of file
diff --git a/_collections/_posts/2018-11-07-flagi-kompilatora-scalac.md b/_collections/_posts/2018-11-07-flagi-kompilatora-scalac.md
new file mode 100644
index 00000000..2f7aa2e0
--- /dev/null
+++ b/_collections/_posts/2018-11-07-flagi-kompilatora-scalac.md
@@ -0,0 +1,156 @@
+---
+title: "Flagi kompilatora Scalac"
+author: TheKamilAdam
+category: scala-native
+tags: compiler
+labels: scalafix scalac
+langs: perl scala
+tools: sbt scalafix
+redirect_from:
+ - flagi-kompilatora-scalac
+ - scala-native/flagi-kompilatora-scalac
+ - resentiment/flagi-kompilatora-scalac
+ - resentiment/2018/11/07/flagi-kompilatora-scalac.html
+---
+
+Nie bójmy się tego powiedzieć, Scala to nowy **[Perl](/langs/perl)**.
+I tak jak w Perlu, w Scali obowiązuje zasada TIMTOWTDI (ang. There is more than one way to do it),
+czyli "Można to zrobić na różne sposoby".
+
+Jednak z biegiem czasu twórcy języka Scala uznali,
+że niektóre sposoby są lepsze od innych i powinna istnieć możliwość wyłączenia gorszych sposobów.
+Dodatkowo niektóre funkcjonalności języka są tak inne od tego co do tej pory widzieli programiści języków obiektowych,
+że nie powinny być domyślnie włączone.
+Oba te warunki, i pewnie jeszcze kilka innych, powodują, że Scalac, **[kompilator](/tags/compiler)** języka Scala,
+posiada [flagi kompilacji]().
+Dokładniej Scalac posiada ogromną ilość flag kompilacji.
+
+## Rekomendowana lista flag kompilatora
+
+Na szczęście istnieją tacy ludzie jak [tpolecat](),
+który na swoim blogu zebrał listę [rekomendowanych flag kompilatora](https://tpolecat.github.io/2017/04/25/scalac-flags.html)
+Są to:
+```scala
+scalacOptions ++= Seq(
+ "-deprecation", // Emit warning and location for usages of deprecated APIs.
+ "-encoding", "utf-8", // Specify character encoding used by source files.
+ "-explaintypes", // Explain type errors in more detail.
+ "-feature", // Emit warning and location for usages of features that should be imported explicitly.
+ "-language:existentials", // Existential types (besides wildcard types) can be written and inferred
+ "-language:experimental.macros", // Allow macro definition (besides implementation and application)
+ "-language:higherKinds", // Allow higher-kinded types
+ "-language:implicitConversions", // Allow definition of implicit functions called views
+ "-unchecked", // Enable additional warnings where generated code depends on assumptions.
+ "-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access.
+ "-Xfatal-warnings", // Fail the compilation if there are any warnings.
+ "-Xfuture", // Turn on future language features.
+ "-Xlint:adapted-args", // Warn if an argument list is modified to match the receiver.
+ "-Xlint:by-name-right-associative", // By-name parameter of right associative operator.
+ "-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error.
+ "-Xlint:delayedinit-select", // Selecting member of DelayedInit.
+ "-Xlint:doc-detached", // A Scaladoc comment appears to be detached from its element.
+ "-Xlint:inaccessible", // Warn about inaccessible types in method signatures.
+ "-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`.
+ "-Xlint:missing-interpolator", // A string literal appears to be missing an interpolator id.
+ "-Xlint:nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'.
+ "-Xlint:nullary-unit", // Warn when nullary methods return Unit.
+ "-Xlint:option-implicit", // Option.apply used implicit view.
+ "-Xlint:package-object-classes", // Class or object defined in package object.
+ "-Xlint:poly-implicit-overload", // Parameterized overloaded implicit methods are not visible as view bounds.
+ "-Xlint:private-shadow", // A private field (or class parameter) shadows a superclass field.
+ "-Xlint:stars-align", // Pattern sequence wildcard must align with sequence component.
+ "-Xlint:type-parameter-shadow", // A local type parameter shadows a type already in scope.
+ "-Xlint:unsound-match", // Pattern match may not be typesafe.
+ "-Yno-adapted-args", // Do not adapt an argument list (either by inserting () or creating a tuple) to match the receiver.
+ "-Ypartial-unification", // Enable partial unification in type constructor inference
+ "-Ywarn-dead-code", // Warn when dead code is identified.
+ "-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined.
+ "-Ywarn-inaccessible", // Warn about inaccessible types in method signatures.
+ "-Ywarn-infer-any", // Warn when a type argument is inferred to be `Any`.
+ "-Ywarn-nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'.
+ "-Ywarn-nullary-unit", // Warn when nullary methods return Unit.
+ "-Ywarn-numeric-widen", // Warn when numerics are widened.
+ "-Ywarn-unused:implicits", // Warn if an implicit parameter is unused.
+ "-Ywarn-unused:imports", // Warn if an import selector is not referenced.
+ "-Ywarn-unused:locals", // Warn if a local definition is unused.
+ "-Ywarn-unused:params", // Warn if a value parameter is unused.
+ "-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused.
+ "-Ywarn-unused:privates", // Warn if a private member is unused.
+ "-Ywarn-value-discard" // Warn when non-Unit expression results are unused.
+)
+```
+
+Lista jest długa i działa dla języka Scala w wersji 2.12.
+Jeśli używasz języka Scala w wersji wcześniejszej to część flag będziesz musiał wyłączyć.
+Dla wersji 2.11 jest to:
+```scala
+scalacOptions --= Seq(
+ "-Xlint:constant",
+ "-Ywarn-extra-implicit",
+ "-Ywarn-unused:implicits",
+ "-Ywarn-unused:imports",
+ "-Ywarn-unused:locals",
+ "-Ywarn-unused:params",
+ "-Ywarn-unused:patvars",
+ "-Ywarn-unused:privates",
+)
+```
+
+## .. i wtyczka do nich
+
+Lista opcji jest długa i może zaciemniać plik `build.sbt`.
+Na szczęście [DavidGregory084](https://github.com/DavidGregory084)
+stworzył wtyczkę [sbt-tpolecat](https://github.com/DavidGregory084/sbt-tpolecat)
+dodającą flagi kompilatora do projektu.
+
+W pliku ` project/plugins.sbt` dodajemy:
+```scala
+addSbtPlugin("io.github.davidgregory084" % "sbt-tpolecat" % "0.1.4")
+```
+i wtyczka automatycznie ustawia odpowiednie flagi dla wersji 2.10/2.11/2.12/2.13
+
+## Portable Scala & Multi-project
+
+Jeśli kompilujesz projekt w Scali na różne platformy (JVM/JS/Native)
+lub posiadasz [multi-project](),
+tak jak ja w projekcie [resentiment](https://github.com/writeonly/resentiment),
+to musisz ręcznie dodać flagi dla kompilatora.
+Flagi generuje metoda `scalacOptionsFor`, która jako parametr pobiera wersję języka Scala.
+Flagi dodajemy do każdego projektu z osobna lub do wydzielonych ustawień jak w moim przypadku:
+
+```scala
+val SharedSettings = Seq(
+ scalaVersion := "2.11.12",
+ scalacOptions ++= scalacOptionsFor(scalaVersion.value),
+ // ...
+)
+```
+
+### ScalaFix i modyfikacja domyślnych flag
+
+Właśnie ustawiliśmy ponad 30 różnych flag,
+ale pewnie w niektórych wypadkach chciałbyś zmodyfikować tę listę.
+Np. żeby móc używać wtyczki [ScalaFix](/statyczna-analiza-kodu-1.html).
+
+Wtyczka ta wymaga dodania dwóch flag (`-Ywarn-adapted-args`, `-Ywarn-unused"`) oraz usunięcia jednej (`-Xfatal-warnings`).
+Dla wygody, flagi przypisuję do zmiennych, a następnie dodaje do `scalacOptions`.
+```scala
+val ScalaFixScalacOptions = Seq(
+ "-Ywarn-adapted-args", // for NoAutoTupling
+ "-Ywarn-unused", // for RemoveUnused
+)
+
+val ScalaFixScalacOptionsOff = Seq(
+ "-Xfatal-warnings", // it should be disabled for scalafix
+)
+
+val SharedSettings = Seq(
+ scalaVersion := "2.11.12",
+ scalacOptions ++= scalacOptionsFor(scalaVersion.value),
+ scalacOptions ++= ScalaFixScalacOptions,
+ scalacOptions --= ScalaFixScalacOptionsOff,
+ // ...
+)
+```
+
+W identyczny sposób można włączać i wyłączać każdą inną flagę kompilatora Scalac.
diff --git a/_collections/_posts/2018-11-14-bardziej-dynamiczna-analiza-kodu.md b/_collections/_posts/2018-11-14-bardziej-dynamiczna-analiza-kodu.md
new file mode 100644
index 00000000..31e0ae64
--- /dev/null
+++ b/_collections/_posts/2018-11-14-bardziej-dynamiczna-analiza-kodu.md
@@ -0,0 +1,242 @@
+---
+title: "Bardziej dynamiczna analiza kodu dla języka Scala - Property-based testing"
+author: TheKamilAdam
+category: scala-native
+tags: code-analysis dynamic-code-analysis
+labels: property-based scalacheck scalaprops nyaya
+langs: scala haskell
+tools: scala-js scala-native
+libs: scalatest scalaz specs2
+redirect_from:
+ - bardziej-dynamiczna-analiza-kodu
+ - scala-native/bardziej-dynamiczna-analiza-kodu
+ - resentiment/bardziej-dynamiczna-analiza-kodu
+ - resentiment/2018/11/14/bardziej-dynamiczna-analiza-kodu.html
+---
+
+Testy modułowe (jednostkowe) napisane w poście
+[Dynamiczna analiza kodu](/dynamiczna-analiza-kodu.html)
+dla projektu [resentiment]()
+zawiodły.
+Mimo posiadania 100% pokrycia kodu dla klasy Calculator klasa ta nie działała w sposób poprawy.
+
+To dlatego, że skupiłem się na drugiej linii definicji
+> Korzystanie z metryk testów, takich jak pokrycie kodu, zapewnia,
+że przetestowano odpowiednią ilość możliwych zachować programu
+
+Zapominając jednocześnie o trzeciej:
+> Aby analiza dynamiczna programu była skuteczna,
+> program docelowy musi być wykonany z wystarczającą ilością danych wejściowych do testów,
+> aby uzyskać interesujące zachowanie.
+
+Problem można rozwiązać za pomocą *property-based testing*
+
+## Property-based testing (Testowanie oparte na właściwościach)
+
+Przy pisaniu normalnych testów, czyli modułowych (jednostkowych), integracyjnych i systemowych,
+wyznaczamy przypadki brzegowe i klasy równoważności.
+Chcemy by danych testowych było jak najmniej, tak by testy wykonywały się jak najszybciej.
+
+W przypadku *property-based testing* jest inaczej.
+Tutaj zamiast wyznaczać konkretne dane wejściowe definiujemy tylko ogólne ograniczenia jakie mają spełniać dane.
+Na podstawie ograniczeń generowane są dane wejściowe dla testów.
+Dużo danych wejściowych.
+Dlatego testy te są wolne, chociaż testują pojedyncze moduły i jednostki.
+
+## Biblioteki dla property-based testing w języku Scala
+
+* [ScalaCheck]( ) -
+pierwsza i najbardziej popularna biblioteka *property-based testing*.
+Wspiera Scala.js w wersji 0.6 i 1.0.0.
+Inspirowana biblioteką [QuickCheck]() dla języka **[Haskell]**.
+Jeden z projektów [typelevel]( ).
+Posiada integracje z [ScalaTest]()
+i [Specs2]().
+* [scalaprops]() -
+druga najbardziej popularna biblioteka *property-based testing*.
+Wspiera **[Scala.js]** w wersji 0.6 i **[Scala Native]** w wersji 0.3.
+Posiada integrację z biblioteką **[Scalaz]**.
+* [Nyaya]() -
+projekt niestety umarł.
+Wspierał Scala.js w wersji 0.6.
+
+## Testowanie oparte na właściwościach za pomocą ScalaProps
+Ponieważ chcę utrzymać możliwość kompilacji krzyżowej (cross compilation),
+wybieram bibliotekę `scalaprops` dla testów.
+
+Dodajemy wtyczkę `sbt-scalaprops` do pliku `project/plugins.sbt`:
+```
+addSbtPlugin("com.github.scalaprops" % "sbt-scalaprops" % "0.2.6")
+```
+
+Dodajemy wymagane zależności do `libraryDependencies`:
+```scala
+ libraryDependencies ++= Seq(
+ "com.github.scalaprops" %%% "scalaprops" % ScalaPropsVersion % "test,it",
+ "com.github.scalaprops" %%% "scalaprops-scalazlaws" % ScalaPropsVersion % "test,it",
+ ),
+```
+
+Ponieważ testy jednostkowe powinny być szybkie,
+konfigurujemy `scalaprops` jako testy integracyjne.
+
+Na początku musimy dodać do cross-projektu ustawienia dla `scalaprops` za pomocą linii:
+```scala
+lazy val re = crossProject(JSPlatform, JVMPlatform, NativePlatform)
+ // ...
+ .settings(scalapropsCoreSettings)
+```
+
+Następnie musimy wskazać folder, który będzie zawierać testy integracyjne:
+```scala
+lazy val re = crossProject(JSPlatform, JVMPlatform, NativePlatform)
+ // ...
+ .settings(
+ unmanagedSourceDirectories in IntegrationTest ++= CrossType.Full.sharedSrcDir(baseDirectory.value, "it").toSeq
+ )
+```
+
+Niestety Scala Native nie wspiera obecnie testów integracyjnych.
+Może kiedyś będzie wspierać,
+może jak będę miał czas sam ogarnę makra i napiszę stosownego pull-requesta.
+Do tego czasu będzie mi o tym przypominać zakomentowana linia:
+```scala
+lazy val re = crossProject(JSPlatform, JVMPlatform, NativePlatform)
+ // ...
+ //.nativeSettings(scalapropsNativeSettings)
+```
+
+Ostatecznie konfiguracja projektu wygląda następująco:
+```scala
+lazy val re = crossProject(JSPlatform, JVMPlatform, NativePlatform)
+ .withoutSuffixFor(NativePlatform)
+ .crossType(CrossType.Full)
+ .settings(SharedSettings)
+ .jsSettings(jsSettings)
+ .jvmSettings(jvmSettings)
+ .nativeSettings(nativeSettings)
+ // IntegrationTest
+ .configs(IntegrationTest)
+ .settings(Defaults.itSettings)
+ .settings(
+ inConfig(IntegrationTest)(scalafixConfigSettings(IntegrationTest)),
+ inConfig(IntegrationTest)(ScalafmtPlugin.scalafmtConfigSettings),
+ inConfig(IntegrationTest)(scalariformItSettings),
+ unmanagedSourceDirectories in IntegrationTest ++= CrossType.Full.sharedSrcDir(baseDirectory.value, "it").toSeq
+ )
+ .jsSettings(inConfig(IntegrationTest)(ScalaJSPlugin.testConfigSettings))
+ .nativeSettings(inConfig(IntegrationTest)(Defaults.testSettings))
+ // PropsTest
+ .settings(scalapropsCoreSettings)
+ //.nativeSettings(scalapropsNativeSettings)
+```
+
+W folderze `re/shared/src/it/scala/` tworzymy testy dla klasy `pl.writeonly.re.shared.Calculator`:
+```scala
+package pl.writeonly.re.shared
+
+import scalaprops.{ Property, Scalaprops }
+
+object CalculatorIT extends Scalaprops {
+ val calculator = new Calculator()
+
+ val addition: (Int, Int) => Int = (x, y) => calculator.add(x, y)
+ val additionTest = Property.forAll { (a: Int, b: Int) =>
+ addition(a, b) == a + b
+ }
+
+ val multiplication: (Int, Int) => Int = (x, y) => calculator.mul(x, y)
+ val multiplicationTest = Property.forAll { (a: Int, b: Int) =>
+ multiplication(a, b) == a * b
+ }
+
+ val lessOrEqual: (Int, Int) => Boolean = (x, y) => calculator.leq(x, y)
+ val lessOrEqualTest = Property.forAll { (a: Int, b: Int) =>
+ lessOrEqual(a, b) == (a <= b)
+ }
+}
+```
+
+Wywołujemy:
+```bash
+sbt clean coverage reJS/it:test reJVM/it:test
+```
+
+I naszym oczom powinien ukazać się piękny komunikat:
+```bash
+pl.writeonly.re.shared.CalculatorIT$
++- additionTest Falsified(0,0,[Arg(0, 18591416),Arg(0, 241819340)],LongSeed(1542137236582000128)) 4ms
++- lessOrEqualTest ................................................. Passed(50,0,LongSeed(1542137236604999936)) 11ms
+`- multiplicationTest Falsified(0,0,[Arg(0, -795557759),Arg(0, -1)],LongSeed(1542137236617999872)) 0ms
+[error] falsified CalculatorIT additionTest Falsified(0,0,[Arg(0, 18591416),Arg(0, 241819340)],LongSeed(1542137236582000128))
+[error] falsified CalculatorIT multiplicationTest Falsified(0,0,[Arg(0, -795557759),Arg(0, -1)],LongSeed(1542137236617999872))
+[info] pl.writeonly.re.shared.CalculatorIT$ 39 ms
+11 pl.writeonly.re.shared.CalculatorIT$.lessOrEqualTest 50 50
+4 pl.writeonly.re.shared.CalculatorIT$.additionTest 50 50
+0 pl.writeonly.re.shared.CalculatorIT$.multiplicationTest 50 50
+[info] 11 pl.writeonly.re.shared.CalculatorIT$.lessOrEqualTest 50 50
+[info] 4 pl.writeonly.re.shared.CalculatorIT$.additionTest 50 50
+[info] 0 pl.writeonly.re.shared.CalculatorIT$.multiplicationTest 50 50
+[error] Failed tests:
+[error] pl.writeonly.re.shared.CalculatorIT
+[error] (reJS / IntegrationTest / test) sbt.TestsFailedException: Tests unsuccessful
+```
+Testy nie przeszły, mamy błąd w kodzie. W związku z tym poprawiamy klasę `Calculator`:
+```scala
+package pl.writeonly.re.shared
+
+class Calculator {
+ type T = Int
+
+ def add(a: T, b: T): T = a + b
+
+ def mul(a: T, b: T): T = a * b
+
+ def leq(a: T, b: T): Boolean = a < b
+
+}
+```
+
+I ponownie wywołujemy:
+```bash
+sbt clean coverage reJS/it:test reJVM/it:test
+```
+
+Teraz dostajemy poprawną odpowiedź:
+```bash
+pl.writeonly.re.shared.CalculatorIT$
++- additionTest ................................................. Passed(50,0,LongSeed(1542137486777999872)) 12ms
++- lessOrEqualTest ................................................. Passed(50,0,LongSeed(1542137486793999872)) 5ms
+`- multiplicationTest ................................................. Passed(50,0,LongSeed(1542137486800999936)) 5ms
+[info] pl.writeonly.re.shared.CalculatorIT$ 31 ms
+12 pl.writeonly.re.shared.CalculatorIT$.additionTest 50 50
+5 pl.writeonly.re.shared.CalculatorIT$.lessOrEqualTest 50 50
+5 pl.writeonly.re.shared.CalculatorIT$.multiplicationTest 50 50
+[info] 12 pl.writeonly.re.shared.CalculatorIT$.additionTest 50 50
+[info] 5 pl.writeonly.re.shared.CalculatorIT$.lessOrEqualTest 50 50
+[info] 5 pl.writeonly.re.shared.CalculatorIT$.multiplicationTest 50 50
+```
+
+Ostatecznie moje pełne polecenie do kompilacji to:
+```bash
+sbt scalafix test:scalafix it:scalafix && \
+sbt scalafmtSbt scalafmt test:scalafmt it:scalafmt && \
+sbt clean compile test:compile it:compile re/test && \
+sbt coverage reJS/test reJVM/test reJS/it:test reJVM/it:test && \
+sbt coverageReport && \
+sbt scalastyle test:scalastyle it:scalastyle && \
+sbt scapegoat cpd stats
+```
+
+## Smutne podsumowania
+Klasyczne testy modułowe (jednostkowe) nie wystarczają,
+ponieważ poprawnie napisane testy modułowe,
+które pokrywają 100% kodu aplikacji,
+mogą być niepoprawne, jeśli dane wejściowe są źle dobrane.
+
+[Haskell]: /langs/haskell
+
+[Scalaz]: /libs/scalaz
+
+[Scala Native]: /tools/scala-native
+[Scala.js]: /tools/scala-js
diff --git a/_collections/_posts/2018-12-12-ciagla-intergracja.md b/_collections/_posts/2018-12-12-ciagla-intergracja.md
new file mode 100644
index 00000000..c428c41e
--- /dev/null
+++ b/_collections/_posts/2018-12-12-ciagla-intergracja.md
@@ -0,0 +1,275 @@
+---
+title: "Ciągła integracja, ciągła kontrola, ciągła Scala"
+author: TheKamilAdam
+category: scala-native
+labels: coveralls continuous-integration travis-ci
+langs: scala java rust
+tools: clang sbt scala-native ubuntu
+libs:
+redirect_from:
+ - ciagla-intergracja
+ - scala-native/ciagla-intergracja
+ - resentiment/ciagla-intergracja
+ - resentiment/2018/12/12/ciagla-intergracja.html
+---
+
+W poprzednich wpisach zbudowaliśmy ogromne polecenie
+do analizy statycznej i dynamicznej kodu projektu oraz generacji raportów.
+Jednak wykonanie tego polecenia trwa.
+A programiści nie lubią czekać.
+
+Istnieje podejrzenie graniczące z pewnością,
+że programiści pracujący przy projekcie będą wywoływać polecenie fragmentarycznie,
+a całe polecenie tylko przed wysłaniem kodu do repozytorium.
+O ile i tego nie zapomną lub zignorują.
+
+W scentralizowanych systemach kontroli wersji takich jak SVN lub CVS
+problem ten rozwiązywano za pomocą *hooków* po stronie klienta (tj programisty).
+Np. nie można było zrobić *commita*, jeśli kod nie był sformatowany,
+a pokrycie kodu testami na odpowiednio wysokim poziomie.
+Nie było to jednak dobre rozwiązanie ponieważ każdą walidację po stronie klienta można oszukać, obejść i/lub wyłączyć.
+
+Dziś istnieją zdecentralizowane systemy kontroli wersji jak Git czy Mercurial.
+Pozwalają one w łatwy sposób tworzyć *feature branche*,
+dzięki czemu kod nie jest wysyłany bezpośrednio do głównej gałęzi repozytorium.
+*Feature branche* nie muszą zawierać sformatowanego kodu, nie muszą się nawet kompilować.
+
+Jednocześnie chcielibyśmy mieć pewność, że w momencie łączenia *feature branch* z główną gałęzią repozytorium,
+kod zawarty w *feature branchy* działa poprawnie i spełnia standardy zdefiniowane w projekcie.
+Rozwiązaniem jest tutaj serwer ciągłej integracji.
+
+## Serwer ciągłej integracji i zamieszanie ze słownictwem
+
+Serwer ciągłej integracji jest to serwer konfigurowany skryptem, zwanym także *pipeline*.
+Większość serwerów, w zależności od konfiguracji jest wstanie robić trzy rzeczy:
+* ciągłą integrację
+* ciągłe dostarczanie
+* ciągłe wdrażanie
+
+**Ciągła integracja** (ang. *Continuous Integration*, *CI*) jest to proces,
+który powinien wykonać się po każdym *commicie* wysłanym do zdalnego repozytorium kodu źródłowego.
+W jego skład wchodzą:
+* sprawdzenie poprawności formatowania
+* analiza statyczna
+* kompilacja
+* analiza dynamiczna (testy jednostkowe i integracyjne)
+* generowanie raportów
+
+i wszystko inne co zostanie uznane za słuszne dla pojedynczego *commitu*.
+
+**Ciągłe dostarczanie** (ang. *Continuous Delivery*, *CD*) jest to proces,
+który powinien wykonać się po każdym *commicie* (zwykle *merge'u*) do gałęzi głównej (np. master/develop).
+Składa się ze wszystkich etapów ciągłej integracji plus dodatkowo:
+* nadania numeru wersji (głównie w przypadku bibliotek)
+* zbudowaniu paczki wykonywalnej (biblioteki, mikroserwisu, aplikacji)
+* wdrożeniu na serwer developerski (w przypadku mikroserwisów i aplikacji)
+i uruchomieniu testów systemowych oraz akceptacyjnych, a następnie wdrożeniu na serwer testowy/demonstracyjny
+* opublikowaniu w repozytorium artefaktów (głównie w przypadku bibliotek)
+
+Oczywiście jest to tylko jedna z wielu wersji procesu.
+Możliwe punkty zmiany to np.:
+* polityka firmy może zakładać, że numery wersji bibliotek powinny być nadawane ręcznie
+* aplikacja jest na tyle duża, że niemożliwością jest uruchamianie wszystkich testów po każdej zmianie
+
+**Ciągłe wdrażanie** (ang. *Continuous Deployment*) jest rozszerzeniem procesu ciągłego dostarczania dla aplikacji
+i zawiera tylko jeden dodatkowy punkt, zaufanie. Zaufanie, że:
+* aplikacja została odpowiednio przetestowana
+* jeśli włączy się alarm, sygnalizujący błąd w aplikacji, to ktoś się nim zajmie
+
+Dodatkowy krok polega na automatycznym wdrażaniu wydanej aplikacji na serwer produkcyjny.
+
+Teoretycznie możnaby wprowadzać podział na serwery CI i serwery CD.
+Jednak jeśli z poziomu konfiguracji serwera CI mamy dostęp do basha,
+lub możemy pisać wtyczki w innych językach programowania,
+to z łatwością możemy zamienić serwer CI w serwer CD.
+Łatwo więc zauważyć że granica jest tutaj bardzo płynna.
+
+## Wybór serwera CI/CD
+
+W świecie Javy jeśli ktoś mówi o serwerze CI zwykle ma na myśli Jenkinsa.
+Dostępnych jest jednak wiele serwerów ciągłej integracji.
+Chcąc jednak jak najszybciej (najprościej) pokazać zalety ciągłej integracji należy wybrać oprogramowanie darmowe
+i dodatkowo dostępne jako usługa (ang. *Software as a Service*, *SaaS*).
+Dobrze także, aby *po wyjęciu z pudełka* wspierało używane przez nas języki programowania.
+Przy takich założeniach wybór padł na dwa serwisy:
+* popularniejszy [Travis CI]() używający kontenerów z **[Ubuntu]**
+* młodszy [CircleCI]() używający kontenerów z Debianem
+
+Niestety nie udało mi się skonfigurować CircleCI dla języka **[ScalaNative]**.
+Problemem były zależności dla Debiana.
+
+Dodatkowo przydatne są także serwisy agregujące raporty z pokrycia kodu testami.
+Ja znalazłem dwa działające jako serwis:
+* [Code Coverage Done Right | Codecov]()
+* [Coveralls - Test Coverage History & Statistics]()
+
+oba są darmowe dla projektów opensource.
+
+## Konfiguracja generowania raportów
+
+Do pliku `project/plugins.sbt` dodajemy dwie wtyczki:
+```yaml
+addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1")
+addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7")
+```
+* [sbt-scoverage]( ) umożliwia generowanie raportów z pokrycia kodu testami,
+* [sbt-coveralls]() umożliwia wysłanie raportu
+do [Coveralls]( )
+
+## Konfiguracja projektu dla Travis Ci
+
+TravisCi jest konfigurowany za pomocą pliku `.travis.yml`.
+
+Najpierw wybieramy język programowania, jego wersję, wersję Ubuntu oraz wersję maszyny wirtualnej Javy:
+```yaml
+language: scala
+scala: 2.11.12
+dist: xenial
+jdk: openjdk8
+```
+
+Niestety `openjdk-8-jdk` nie jest domyślnie zainstalowane na Ubuntu w wersji `xenial`.
+Na szczęście możemy doinstalować potrzebną nam wersję Javy z pakietów Ubuntu.
+Pozostałe pakiety są dla ScalaNative
+```yaml
+addons:
+ apt:
+ packages:
+ - openjdk-8-jdk
+ - libunwind-dev
+ - libgc-dev
+ - libre2-dev
+ - clang-6.0
+```
+
+Niestety to nie wystarcza i musimy podmienić wersję Javy w zmiennej środowiskowej `PATH`:
+```yaml
+env:
+ global:
+ - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
+ - PATH=$JAVA_HOME/bin:$PATH
+```
+
+Włączamy cache dla folderów zawierających zależności:
+```yaml
+cache:
+ directories:
+ - $HOME/.sbt
+ - $HOME/.ivy2/cache
+```
+
+Uruchamiamy analizę statyczną i analizę dynamiczną kodu oraz generujemy raport z testów:
+```yaml
+script:
+ - sbt 'scalafix --check' 'test:scalafix --check' 'it:scalafix --check' &&
+ sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck it:scalafmtCheck &&
+ sbt clean re/compile re/test:compile re/it:compile &&
+ sbt coverage reJS/test reJVM/test reJS/it:test reJVM/it:test coverageReport &&
+ sbt coverageAggregate &&
+ sbt scalastyle test:scalastyle it:scalastyle &&
+ sbt scapegoat cpd stats
+```
+
+Przesyłamy raport do usług agregujących wyniki testów:
+```yaml
+after_success:
+ - sbt coveralls
+ - bash <(curl -s https://codecov.io/bash)
+```
+
+Pełny plik konfiguracyjny `.travis.yml`:
+```yaml
+language: scala
+scala: 2.11.12
+dist: xenial
+jdk: openjdk8
+
+addons:
+ apt:
+ packages:
+ - openjdk-8-jdk
+ - libunwind-dev
+ - libgc-dev
+ - libre2-dev
+ - clang-6.0
+
+env:
+ global:
+ - JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
+ - PATH=$JAVA_HOME/bin:$PATH
+
+cache:
+ directories:
+ - $HOME/.ivy2/cache
+ - $HOME/.sbt
+
+script:
+ - sbt 'scalafix --check' 'test:scalafix --check' 'it:scalafix --check' &&
+ sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck it:scalafmtCheck &&
+ sbt clean re/compile re/test:compile re/it:compile &&
+ sbt coverage reJS/test reJVM/test reJS/it:test reJVM/it:test coverageReport &&
+ sbt coverageAggregate &&
+ sbt scalastyle test:scalastyle it:scalastyle &&
+ sbt scapegoat cpd stats
+
+after_success:
+ - sbt coveralls
+ - bash <(curl -s https://codecov.io/bash)
+```
+
+## Podsumowanie
+
+Uważny czytelnik może zauważyć, że nie wywołuje testów dla **[ScalaNative]**.
+Mimo zainstalowania wszystkich pakietów wywołanie testów dla ScalaNative kończy się błędem:
+```bash
+[error] /usr/bin/ld: warning: libunwind.so.8, needed by /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../x86_64-linux-gnu/libunwind-x86_64.so, may conflict with libunwind.so.1
+[error] /usr/bin/ld: /home/travis/build/writeonly/resentiment/re/native/target/scala-2.11/native/lib/gc/immix/Heap.c.o: undefined reference to symbol '_Ux86_64_getcontext'
+[error] //usr/lib/x86_64-linux-gnu/libunwind.so.8: error adding symbols: DSO missing from command line
+[error] clang: error: linker command failed with exit code 1 (use -v to see invocation)
+[info] Linking native code (immix gc) (184 ms)
+[info] Starting process '/home/travis/build/writeonly/resentiment/re/native/target/scala-2.11/re-out' on port '32951'.
+Exception in thread "Thread-386" java.io.IOException: Cannot run program "/home/travis/build/writeonly/resentiment/re/native/target/scala-2.11/re-out": error=2, No such file or directory
+ at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
+ at scala.sys.process.ProcessBuilderImpl$Simple.run(ProcessBuilderImpl.scala:71)
+ at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.run(ProcessBuilderImpl.scala:102)
+ at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.$anonfun$runBuffered$1(ProcessBuilderImpl.scala:150)
+ at scala.runtime.java8.JFunction0$mcI$sp.apply(JFunction0$mcI$sp.java:12)
+ at scala.sys.process.ProcessLogger$$anon$1.buffer(ProcessLogger.scala:99)
+ at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.runBuffered(ProcessBuilderImpl.scala:150)
+ at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.$bang(ProcessBuilderImpl.scala:116)
+ at scala.scalanative.testinterface.ComRunner$$anon$1.run(ComRunner.scala:31)
+Caused by: java.io.IOException: error=2, No such file or directory
+ at java.lang.UNIXProcess.forkAndExec(Native Method)
+ at java.lang.UNIXProcess.(UNIXProcess.java:247)
+ at java.lang.ProcessImpl.start(ProcessImpl.java:134)
+ at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
+ ... 8 more
+```
+
+Jest to kolejny problem **[ScalaNative])**. po braku możliwości wygenerowania pokrycia kodu
+oraz braku możliwości uruchomienia testów integracyjnych.
+Dowodzi to że ScalaNative niestety dalej jest zabawką
+i jeśli chce się pisać monady w języku kompilowanym natywnie należy wybrać **[Rust]**.
+
+## Postscriptum
+
+Poszukując serwisów CI natrafiłem na jeszcze jeden termin z kategorii *Continuous cośtam*.
+
+**Ciągła analiza statyczna** (ang. *Continuous static analysis*) jest to proces podobny do ciągłej integracji, ale ograniczony tylko do jednego kroku,
+analizy statycznej.
+Cechą charakterystyczną serwerów ciągłej analizy statycznej jest posiadanie ogromnej ilości reguł według których sprawdzany jest kod.
+Klasycznym przykładem oprogramowania w świecie Javy jest tutaj [SonarQube]( ).
+Ja oczywiście poszukiwałem oprogramowania działającego jako darmowa usługa dla projektów opensorsowych i znalazłem:
+* [Codacy: Automated code reviews & code analytics]()
+* [Rocro INSPECODE - Code review without the hassle.]()
+
+## Postscriptum 2
+
+Termin **ciągła analiza statyczna** ułożyłem sam,
+jednak występujący w jego miejscu termin **ciągła kontrola jakości kodu** (ang. *Continuous Inspection of Code Quality*)
+jest według mnie zbyt ogólny.
+
+[Rust]: /langs/rust
+
+[Ubuntu]: /tools/ubuntu
+[ScalaNative]: /tools/scala-native
diff --git a/_collections/_posts/2019-01-09-biblioteki-do-logowania.md b/_collections/_posts/2019-01-09-biblioteki-do-logowania.md
new file mode 100644
index 00000000..dbd27711
--- /dev/null
+++ b/_collections/_posts/2019-01-09-biblioteki-do-logowania.md
@@ -0,0 +1,370 @@
+---
+title: "Biblioteki do logowania dla języka Scala"
+author: TheKamilAdam
+category: scala-native
+tags: library cli factory logging
+labels: scala-logging scribe
+langs: scala java
+tools: scala-js scala-native
+lisb: utest slogging
+redirect_from:
+ - biblioteki-do-logowania
+ - scala-native/biblioteki-do-logowania
+ - resentiment/biblioteki-do-logowania
+ - resentiment/2019/01/09/biblioteki-do-logowania.html
+---
+
+Chcąc dowiedzieć się co dzieje się wewnątrz naszej aplikacji mamy dwie drogi.
+Pierwszym sposobem jest debugowanie.
+Jednak im więcej wątków w aplikacji i im bardziej komunikują się one w sposób asynchroniczny tym trudniej jest debugować.
+Drugim sposobem jest logowanie informacji.
+Najprostszym sposobem logowania informacji w Javie jest `System.out.println`, a w Scali upraszcza się to do `println`.
+Ale jest to złe z dwóch powodów:
+* Po pierwsze, jeśli piszemy aplikację "konsolową" (ang. *command line interface*, **[CLI]**)
+to użytkownik będzie niepotrzebnie widział nieinteresujące go informacje z wewnętrznego procesu przetwarzania.
+* Tak wypisanych informacji nie można zapisać w bazie danych ani wysłać do innego systemu.
+
+Dlatego powstały biblioteki do logowania.
+Biblioteki takie pozwalają przekierować logi do pliku, zapisać je w bazie danych oraz wysłać je do dowolnego innego systemu.
+
+## Przegląd bibliotek
+
+* [scala-logging]() -
+wygodna i wydajna biblioteka logowania opakowywująca bibliotekę `SLF4J` dla języka Scala.
+Niestety działa tylko dla Scala/JVM
+* [util-logging]() -
+jest małym opakowaniem wbudowanego logowania Javy, aby uczynić go bardziej przyjaznym dla Scali.
+Niestety także, działa tylko dla Scala/JVM
+* [scalajs-java-logging]() -
+implementacja `java.logging` dla **[Scala.js]**.
+Wspiera **[Scala.js]** w wersji 0.6.x i 1.0.x
+* [airframe-log]() -
+biblioteka do ulepszania logowania aplikacji Scala z kolorami i lokalizacjami kodów źródłowych.
+Wspiera Scala.js w wersji 0.6.x i 1.0.x
+* [slogging]() -
+biblioteka logowania zgodna z `scala-logging` (i `SLF4J`) oparta na makrach
+dla Scala/JVM, **[Scala.js]** (wersja 0.6.x) i **[Scala Native]**
+* [scribe]() -
+praktyczny szkielet logowania, który nie wymaga żadnej innej struktury logowania
+i może być w pełni skonfigurowany programowo.
+Wspiera **[Scala.js]** w wersji 0.6.x oraz **[Scala Native]**.
+
+## I konkretne próby zastosowania
+
+### scala-logging
+Jest to najprawdopodobniej najpopularniejsza biblioteka do logowania w języku Scala.
+Niestety jej wadą jest to, że działa tylko dla JVM.
+
+W pliku `build.sbt` dodajemy bibliotekę do wspólnych zależności:
+```scala
+ libraryDependencies ++= Seq(
+ "com.typesafe.scala-logging" %% "scala-logging" % "3.9.0",
+ ),
+```
+
+`Scala-logging` można używać na dwa sposoby.
+Za pomocą traitów `StrictLogging` i `LazyLogging`.
+Oba traity tworzą zmienną `logger`, która jest loggerem.
+
+Trait `StrictLogging` inicjalizuje `logger` w momencie utworzenia klasy:
+```scala
+package com.typesafe.scalalogging
+
+import org.slf4j.LoggerFactory
+
+trait StrictLogging {
+ protected val logger: Logger = Logger(LoggerFactory.getLogger(getClass.getName))
+}
+```
+
+```scala
+package pl.writeonly.re.shared
+
+import com.typesafe.scalalogging.StrictLogging
+
+object StrictLoggingCore extends Core with StrictLogging {
+ def apply(arg: String): Unit = {
+ logger.info(s"Hello Scala $arg!")
+ }
+}
+```
+
+Trait `LazyLogging` inicjalizuje `logger` w momencie pierwszego użycia loggera:
+```scala
+package com.typesafe.scalalogging
+
+import org.slf4j.LoggerFactory
+
+trait LazyLogging {
+ @transient
+ protected lazy val logger: Logger = Logger(LoggerFactory.getLogger(getClass.getName))
+}
+```
+
+```scala
+package pl.writeonly.re.shared
+
+import slogging.LazyLogging
+
+object LazyLoggingCore extends Core with LazyLogging {
+ def apply(arg: String): Unit = {
+ logger.info(s"Hello Scala $arg!")
+ }
+}
+```
+
+Łączymy wszystko w obiekcie `Core`:
+```scala
+package pl.writeonly.re.shared
+
+trait Core {
+ def apply(arg: String): Unit
+}
+
+object Core extends Core {
+ override def apply(arg: String): Unit = {
+ StrictLoggingCore(arg)
+ LazyLoggingCore(arg)
+ }
+}
+```
+
+Tworzymy test jednostkowy we frameworku **[uTest]**:
+```scala
+package pl.writeonly.re.shared
+
+import utest._
+
+object CoreTest extends TestSuite {
+ override val tests: Tests = Tests {
+ 'core - {
+ Core("Awesome")
+ }
+ }
+}
+```
+
+Wywołujemy:
+```bash
+sbt clean re/test
+```
+
+I wszystko się wysypuje, bo `scala-logging` wspiera tylko JVM.
+
+### slogging
+Jest to przepisana biblioteka `scala-logging`,
+która działa dla Scala Native, Scala.js oraz oczywiście Scala/JVM.
+
+W pliku `build.sbt` dodajemy bibliotekę do wspólnych zależności:
+```scala
+ libraryDependencies ++= Seq(
+ "biz.enef" %%% "slogging" % SloggingVersion,
+ ),
+```
+
+`Slogging` używa się identycznie jak `scala-logging`.
+
+Trait `StrictLogging` inicjalizuje `logger` w momencie utworzenia klasy:
+```scala
+package slogging
+
+trait StrictLogging extends LoggerHolder {
+ protected val logger : Logger = LoggerFactory.getLogger(loggerName)
+}
+```
+
+```scala
+package pl.writeonly.re.shared
+
+import slogging.StrictLogging
+
+object StrictLoggingCore extends Core with StrictLogging {
+ def apply(arg: String): Unit = {
+ logger.info(s"Hello Scala $arg!")
+ }
+}
+```
+
+Trait `LazyLogging` inicjalizuje `logger` w momencie pierwszego użycia loggera:
+```scala
+package slogging
+
+trait LazyLogging extends LoggerHolder {
+ protected lazy val logger = LoggerFactory.getLogger(loggerName)
+}
+```
+
+```scala
+package pl.writeonly.re.shared
+
+import slogging.LazyLogging
+
+object LazyLoggingCore extends Core with LazyLogging {
+ def apply(arg: String): Unit = {
+ logger.info(s"Hello Scala $arg!")
+ }
+}
+```
+
+Łączymy wszystko w obiekcie `Core`:
+```scala
+package pl.writeonly.re.shared
+
+trait Core {
+ def apply(arg: String): Unit
+}
+
+object Core extends Core {
+ override def apply(arg: String): Unit = {
+ StrictLoggingCore(arg)
+ LazyLoggingCore(arg)
+ }
+}
+```
+
+Tworzymy test jednostkowy we frameworku **[uTest]**:
+```scala
+package pl.writeonly.re.shared
+
+import utest._
+
+object CoreTest extends TestSuite {
+ override val tests: Tests = Tests {
+ 'core - {
+ Core("Awesome")
+ }
+ }
+}
+```
+
+Wywołujemy:
+```bash
+sbt clean re/test
+```
+
+I wszystko działa!
+
+### Scribe
+
+W pliku `build.sbt` dodajemy bibliotekę do wspólnych zależności:
+```scala
+ libraryDependencies ++= Seq(
+ "com.outr" %%% "scribe" % ScribeVersion,
+ ),
+```
+
+`Scribe` można używać na dwa sposoby.
+Za pomocą traitu `Logging` oraz za pomocą obiektu pakietu `scribe`.
+
+Trait `Logging` w prostu sposób tworzy `logger` dla każdej instancji klasy:
+```scala
+trait Logging {
+ protected def loggerName: String = getClass.getName
+
+ protected def logger: Logger = Logger(loggerName)
+}
+```
+
+```scala
+package pl.writeonly.re.shared
+
+import scribe.Logging
+
+object LoggingCore extends Core with Logging {
+ override def apply(arg: String): Unit = {
+ logger.info(s"Hello Scala $arg!")
+ }
+}
+```
+
+Obiekt pakietu `scribe` zawiera magię opartą na makrach, dlatego dziedziczenie nie jest potrzebne:
+```scala
+package object scribe extends LoggerSupport {
+ lazy val lineSeparator: String = System.getProperty("line.separator")
+
+ protected[scribe] var disposables = Set.empty[() => Unit]
+
+ override def log[M](record: LogRecord[M]): Unit = Logger(record.className).log(record)
+
+ def dispose(): Unit = disposables.foreach(d => d())
+
+ implicit class AnyLogging(value: Any) {
+ def logger: Logger = Logger(value.getClass.getName)
+ }
+
+ def async[Return](f: => Return): Return = macro Macros.async[Return]
+
+ def future[Return](f: => Return): Future[Return] = macro Macros.future[Return]
+
+ object Execution {
+ implicit def global: ExecutionContext = macro Macros.executionContext
+ }
+}
+```
+
+```scala
+package pl.writeonly.re.shared
+
+object ScribeCore extends Core {
+ def apply(arg: String): Unit = {
+ scribe.info(s"Hello Scala $arg!")
+ }
+}
+```
+
+Łączymy wszystko obiektem `Core`:
+```scala
+package pl.writeonly.re.shared
+
+trait Core {
+ def apply(arg: String): Unit
+}
+
+object Core extends Core {
+ override def apply(arg: String): Unit = {
+ LoggingCore(arg)
+ ScribeCore(arg)
+ }
+}
+```
+
+Tworzymy test:
+```scala
+package pl.writeonly.re.shared
+
+import utest._
+
+object CoreTest extends TestSuite {
+ override val tests: Tests = Tests {
+ 'core - {
+ Core("Awesome")
+ }
+ }
+}
+```
+
+Wywołujemy:
+```bash
+sbt clean re/test
+```
+
+Niestety pojawia się błąd:
+```
+[error] cannot link: @java.util.Calendar$::getInstance_java.util.Calendar
+[error] cannot link: @java.util.Calendar::setTimeInMillis_i64_unit
+[error] unable to link
+[error] (re / Nativetest / nativeLink) unable to link
+```
+
+## Podsumowanie
+
+Jak zwykle składnia Scali pozwala zapisać te same rzeczy prościej niż w Javie,
+jednocześnie dzięki temu można wymusić konwencję tworzenia loggerów na etapie kompilacji.
+Dzięki temu nie mamy w kodzie loggerów o nazwach innych niż `loggger` jak np. `LOGGER` lub `LOG`.
+
+[Scala Native]: /tools/scala-native
+[Scala.js]: /tools/scala-js
+
+[uTest]: /libs/utest
+
+[CLI]: /tags/cli
diff --git a/_collections/_posts/2019-01-16-kategorie-i-tagi.md b/_collections/_posts/2019-01-16-kategorie-i-tagi.md
new file mode 100644
index 00000000..c0105a5a
--- /dev/null
+++ b/_collections/_posts/2019-01-16-kategorie-i-tagi.md
@@ -0,0 +1,247 @@
+---
+title: "Jekyll - kategorie i tagi"
+author: TheKamilAdam
+category: jekyll
+tags: blog
+tools: jekyll
+redirect_from:
+ - kategorie-i-tagi
+ - jekyll/kategorie-i-tagi
+ - writeonlydoc/kategorie-i-tagi
+ - writeonlydoc/2019/01/16/kategorie-i-tagi.html
+---
+
+Opublikowałem już kilka artykułów na blogu i chciałem je w jakiś sposób pogrupować.
+Najlepiej za pomocą kategorii i tagów.
+
+## Metadane
+
+Dla każdego postu oprócz zawartości zapisywałem także metadane,
+w tym kategorie i tagi.
+W przypadku tego artykułu są to:
+
+{%raw%}
+```yaml
+---
+#layout: post
+title: "Jekyll - kategorie i tagi"
+author: TheKamilAdam
+category: jekyll
+tags: jekyll blog
+---
+```
+{%endraw%}
+
+Artykuł może zawierać wiele tagów, ale musi mieć dokładnie jedną kategorię.
+
+## Strony pomocnicze
+
+Jest to najprawdopodobniej największa wada Jekylla.
+Dla każdej kategorii i dla każdego taga trzeba utworzyć stronę pomocniczą.
+Strony pomocnicze kategorii muszą znajdować się w folderze `_categories`,
+a strony pomocnicze tagów w folderze `_tags`.
+
+Przykładowy strona pomocnicza dla kategorii:
+
+{%raw%}
+```yaml
+---
+permalink: /categories/resentiment
+labelcategory: "resentiment"
+---
+Opis powstawania projektu resentiment .
+```
+{%endraw%}
+
+Przykładowy strona pomocnicza dla tagu:
+
+{%raw%}
+```yaml
+---
+permalink: /tools/scala-native
+#layout: page-tag
+tag: "scala-native"
+---
+```
+{%endraw%}
+
+## Kolekcje
+
+Ponieważ stron pomocniczych jest dużo,
+dlatego źle jest je trzymać w przestrzeni głównej projektu.
+Problem ten można rozwiązać za pomocą kolekcji.
+W pliku `_config.yml` dodajemy:
+
+```yaml
+collections:
+ categories:
+ output: true
+ tags:
+ output: true
+```
+Od tej pory strony dla kategorii będą znajdować się w katalogu `_categories`,
+a strony dla tagów w katalogu `_tags`.
+
+Ale dla mnie nawet to było za dużo.
+Dlatego kolekcje przeniosłem do folderu `data`.
+W pliku `_config.yml` dodajemy:
+```yaml
+collections_dir: data
+```
+
+Od tej pory:
+* w katalogu `data/_categories` znajdują się kategorie artykułów
+* w katalogu `data/_posts` znajdują się artykuły
+* w katalogu `data/_tags` znajdują się tagi
+
+## Layouts - układy stron
+
+W stronach pomocniczych użyliśmy layoutów `page-categories` i `page-tags`.
+Teraz trzeba je zdefiniować.
+
+Układ strony `_layout/page-category.html` zawierający wszystkie artykuły z danej kategorii:
+
+{%raw%}
+```yaml
+---
+#layout: default
+title: {{ page.category }}
+---
+
+ {% include breadcrumbs.html %}
+
Kategoria: {{ page.title }}
+
+ {{ posts.content }}
+
+
+ {% for post in site.posts %}
+ {% if post.category == page.category %}
+
+
+ {{ post.title }}
+
+
+ {{ post.date | date: "%Y-%m-%d" }}
+
+
+
+
+
+ {% assign tags = post.tags | sort %}
+ Tagi:
+ {% for tag in tags %}
+ {{ tag }}
+ {% endfor %}
+
+ {% endif %}
+ {% endfor %}
+
+
+```
+{%endraw%}
+
+Układ strony `_layout/page-tag.html` zawierający wszystkie artykuły z danym tagiem:
+{%raw%}
+```yaml
+---
+#layout: default
+title: {{ page.tag }}
+---
+
+ {% include breadcrumbs.html %}
+
Tag: {{ page.tag | capitalize }}
+
+
+ {% for post in site.posts %}
+ {% if post.tags contains page.tag %}
+
+
+ {{ post.title }}
+
+
+ {{ post.date | date: "%Y-%m-%d" }}
+
+
+
+
+
+ Kategoria :
+ {{ post.category | capitalize }}
+
+
+ {% endif %}
+ {% endfor %}
+
+
+```
+{%endraw%}
+
+W obu przypadkach iterujemy po liście wszystkich artykułów i prostym `if`em wybieramy te które nas interesują.
+
+## Pages - strony specjalne
+
+Potrzebujemy jeszcze jednej rzeczy.
+
+Strona `pages/categories.html` zawierająca listę wszystkich kategorii:
+{%raw%}
+```yaml
+---
+#layout: posts
+title: Kategorie
+permalink: /categories/
+description: Kategorie artykułów
+---
+
+ {% assign categories = site.categories | sort: "title" %}
+
+ {% for node in categories %}
+ {% if node.title != null and node.layout == "page-category" %}
+
+ {{ node.title }}
+
+
+ {{ node.content }}
+
+ {% endif %}
+ {% endfor %}
+
+
+```
+{%endraw%}
+
+Strona `pages/tags.html` zawierająca listę wszystkich tagów:
+{%raw%}
+```yaml
+---
+#layout: posts
+title: Tagi
+permalink: /tags/
+description: Tagi artykułów
+---
+
+
+ {% assign tags = site.tags | sort: "title" %}
+ {% for node in tags %}
+ {% if node.title != null and node.layout == "page-tag" %}
+
+ {{ node.title }}
+
+ {% endif %}
+ {% endfor %}
+
+
+```
+{%endraw%}
+
+W obu przypadkach pobieramy listę wszystkich kategorii/tagów i sortujemy po tytułach.
+A następnie odrzucamy te które nie są poprawne do wyświetlenia,
+czyli zawierają błędny `layout` lub nie posiadają tytułu.
+
+## Podsumowanie
+
+Żeby wszystko działało trzeba było napisać trochę kodu.
+Łącznie 17 stron pomocniczych dla tagów, 3 - dla kategorii,
+dwa układy stron i dwie strony specjalne do agregacji kategorii i tagów.
+Ale oczywiście nie to zajeło najwięcej czasu.
+Największym problemem była wolność jaką daje jekyll,
+czyli możliwość zbudowania układów stron w dowolny sposób.
diff --git a/_collections/_posts/2019-01-30-no-universal-equality.md b/_collections/_posts/2019-01-30-no-universal-equality.md
new file mode 100644
index 00000000..4ee26774
--- /dev/null
+++ b/_collections/_posts/2019-01-30-no-universal-equality.md
@@ -0,0 +1,179 @@
+---
+title: "Scala - No Universal Equality"
+author: TheKamilAdam
+category: scala-native
+tags: compiler library monad operator type-class
+labels: scalatic
+langs: haskell java scala
+tools: scala-jvm scala-js scala-native scalafix
+libs: cats scalatest scalaz utest
+projects: resentiment
+redirect_from:
+ - no-universal-equality
+ - scala-native/no-universal-equality
+ - resentiment/no-universal-equality
+ - resentiment/no-universal-equality.html
+---
+
+Ostatnim błędem zgłaszanym w kodzie projektu **[resentiment]** przez **[scalafix]**
+jest "No Universal Equality" wynikający z użycia operatora `==`.
+
+W języku **[Scala]** obiekty domyślnie porównuje się za pomocą operatora `==`.
+Operator ten wywołuje pod spodem znaną z Javy metodę `equals`.
+Operator `==` pozwala jednak na bezsensowne porównywanie obiektów, które są różnych klas.
+Mimo że poprawnie napisana metoda `equals` zawsze zwróci w takim przypadku `false`.
+Np. porównanie `"A" == 'A'` zawsze zwróci `false`,
+ponieważ `"A"` jest klasy `String`, a `'A'` jest klasy `Char`.
+Umieszczenie czegoś takiego w kodzie zawsze jest błędem programisty i powinno spowodować nieskompilowanie się kodu.
+Jest to nazywane problemem `Universal Equality`.
+Można ten problem rozwiązać na kilka sposobów.
+
+## Dotty - Multiversal Equality
+
+Najprostszym sposobem rozwiązania problemu `Universal Equality` jest poczekać.
+Nowa wersja **[kompilator]** Scala - *[Dotty]( )* będzie posiadać
+[Multiversal Equality]()
+co rozwiązuje problem.
+
+## Biblioteki zewnętrzne
+Jeśli jednak jesteście niecierpliwi istnieje kilka bibliotek rozwiązujących ten problem.
+Wykorzystują one to,
+że Scala pozwala implementować metody,
+których wywołanie wygląda jak wywołanie operatora i zwykle tym nowym operatorem jest `===`.
+
+### Scalactic
+**[Scalactic]()**
+jest to zestaw utilsów/narzędzi wydzielony ze **[ScalaTest]**,
+który może być przydatny także w kodzie produkcyjnym.
+
+**Scalactic** posiada wiele klas do porównywania wartości,
+między innymi klasę `org.scalactic.TypeCheckedTripleEquals`,
+która wymaga by oba porównywane obiekty były tej samej klasy.
+
+Największą zaletą biblioteki **Scalactic** jest to,
+że nie zagłębia się w teorię czystego programowania funkcyjnego (ang. *pure functional programming*)
+i nie pojawiają się tam takie straszne terminy jak **[monada]** czy **[klasy typów]**.
+
+### Scalaz i Cats
+*Kolejność chronologiczna.*
+
+Są to dwie wspaniałe biblioteki, które robią ze Scali język funkcyjny przypominający język **[Haskell]**.
+
+Biblioteki te dzielą się na dwie główne części:
+* *Data types* - tutaj znajdują się monady, które są w Haskellu, ale nie ma ich w bibliotece standardowej języka Scala
+* *Type classes* - typ konstruktu systemowego, który obsługuje polimorfizm *ad hoc*.
+
+Zarówno **[Scalaz]** jak i **[Cats]** posiadają klasę `Equal`,
+która pozwala porównywać obiekty za pomocą operatora `===`.
+
+Dobre porównanie obu bibliotek można znaleźć na [githubie](),
+chociaż różnice są bardzo małe.
+Obie biblioteki wspierają **[scala.js])**,
+ale tylko **Scalaz** - **[scala native]**.
+
+## "No Universal Equality" z Scalaz w projekcie Resentiment
+
+W `build.sbt` do `SharedSettings` dodajemy bibliotekę `Scalaz`:
+```scala
+ libraryDependencies += "org.scalaz" %%% "scalaz-core" % "7.2.27",
+```
+
+Jeśli używamy scalafix w pliku `.scalafix.conf` można dodać/odkomentować linię:
+```conf
+DisableSyntax.noUniversalEquality = true
+```
+
+Teraz należy poprawić cały kod zamieniając `==` na `===`.
+W przypadku projektu **[resentiment]** są to klasy `CalculatorTest` i `CalculatorIT`
+
+```scala
+package pl.writeonly.re.shared
+
+import scalaz.Scalaz._
+import utest._
+
+object CalculatorTest extends TestSuite {
+ override val tests: Tests = Tests {
+ val calculator = new Calculator()
+ 'addition - {
+ val addition: (Int, Int) => Int = (x, y) => calculator.add(x, y)
+ "0 + 0 == 0" - {
+ assert(addition(0, 0) === 0)
+ }
+ "2 + 2 == 4" - {
+ assert(addition(2, 2) === 4)
+ }
+ }
+ 'multiplication - {
+ val multiplication: (Int, Int) => Int = (x, y) => calculator.mul(x, y)
+ "0 + 0 == 0" - {
+ assert(multiplication(0, 0) === 0)
+ }
+ "2 + 2 == 4" - {
+ assert(multiplication(2, 2) === 4)
+ }
+ }
+ 'less_or_equal - {
+ val less_or_equal: (Int, Int) => Boolean = (x, y) => calculator.leq(x, y)
+ "0 <= 2 == true" - {
+ assert(less_or_equal(0, 2))
+ }
+ "2 <= 0 == false" - {
+ assert(!less_or_equal(2, 0))
+ }
+ }
+ }
+}
+```
+
+```scala
+package pl.writeonly.re.shared
+
+import scalaprops.{Property, Scalaprops}
+import scalaz.Scalaz._
+
+object CalculatorIT extends Scalaprops {
+ val calculator = new Calculator()
+
+ val addition: (Int, Int) => Int = (x, y) => calculator.add(x, y)
+ val additionTest = Property.forAll { (a: Int, b: Int) =>
+ addition(a, b) === a + b
+ }
+
+ val multiplication: (Int, Int) => Int = (x, y) => calculator.mul(x, y)
+ val multiplicationTest = Property.forAll { (a: Int, b: Int) =>
+ multiplication(a, b) === a * b
+ }
+
+ val lessOrEqual: (Int, Int) => Boolean = (x, y) => calculator.leq(x, y)
+ val lessOrEqualTest = Property.forAll { (a: Int, b: Int) =>
+ lessOrEqual(a, b) === (a <= b)
+ }
+}
+
+```
+
+## Podsumowanie
+Język Scala posiada kilka mniejszych lub większych błedów projektowych.
+Część z nich zostanie poprawiona w nowej wersji kompilatora Dotty.
+Jeśli jednak nie chcemy czekać do tego czasu warto się rozejrzeć w internecie,
+ponieważ prawdopodobnie istnieją już rozwiązania naszych problemów.
+"Universal Equality" jest jednym z problemów,
+które w prosty sposób mogą być rozwiązane już dziś.
+
+[Haskell]: /langs/haskell
+[Scala]: /langs/scala
+
+[Cats]: /libs/cats
+[ScalaTest]: /libs/scalatest
+[Scalaz]: /libs/scalaz
+
+[scala native]: /tools/scala-native
+[scalafix]: /tools/scalafix
+[scala.js]: /tools/scala-js
+
+[resentiment]: /projects/resentiment
+
+[klasy typów]: /tags/type-class
+[kompilator]: /tags/compiler
+[monada]: /tags/monad
diff --git a/_collections/_posts/2019-02-13-setxkbmap.md b/_collections/_posts/2019-02-13-setxkbmap.md
new file mode 100644
index 00000000..eb1fe957
--- /dev/null
+++ b/_collections/_posts/2019-02-13-setxkbmap.md
@@ -0,0 +1,74 @@
+---
+title: "setxkbmap - Jak szybko zmienić układ klawiatury z konsoli na Ubuntu?"
+author: TheKamilAdam
+category: cli
+tags: cli
+langs:
+tools: bash ubuntu
+libs:
+redirect_from:
+ - setxkbmap
+ - cli/setxkbmap
+ - cli/2019/02/13setxkbmap.html
+---
+
+Po długiej przerwie prosty artykuł "Jak szybko zmienić układ klawiatury z konsoli na **[Ubuntu]**?".
+
+## Problem
+
+Podczas pracy na Xubuntu zainstalowanym na wirtualnej maszynie często zmienia mi się układ klawiatury z polskiej na amerykańską.
+Na **[Ubuntu]** można odwrócić ten proces w łatwy sposób za pomocą ikonki na pasku zadań,
+jednak już w Xubuntu ta opcja jest ukryta głęboko w trzewiach ustawień systemowych.
+Dlatego prościej jest to zrobić z linii poleceń.
+
+## Rozwiązanie - setxkbmap
+
+Aby szybko zmienić układ klawiatury, wystarczy zainstalować 'setxkbmap' za pomocą polecenia:
+```bash
+sudo apt-get install x11-xkb-utils
+```
+
+Następnie można łatwo zmieniać układ klawiatury za pomocą polecenia:
+```bash
+setxkbmap pl
+```
+
+Pomoc można wyświetlić za pomocą polecenia:
+```bash
+setxkbmap -help
+```
+
+Pomoc polecenia w wersji 'setxkbmap 1.3.1' :
+```
+Usage: setxkbmap [options] [ [ [ ... ]]]
+Options:
+ -?, -help Print this message
+ -compat Specifies compatibility map component name
+ -config Specifies configuration file to use
+ -device Specifies the device ID to use
+ -display Specifies display to use
+ -geometry Specifies geometry component name
+ -I Add to list of directories to be used
+ -keycodes Specifies keycodes component name
+ -keymap Specifies name of keymap to load
+ -layout Specifies layout used to choose component names
+ -model Specifies model used to choose component names
+ -option Adds an option used to choose component names
+ -print Print a complete xkb_keymap description and exit
+ -query Print the current layout settings and exit
+ -rules Name of rules file to use
+ -symbols Specifies symbols component name
+ -synch Synchronize request with X server
+ -types Specifies types component name
+ -v[erbose] [] Sets verbosity (1..10); higher values yield more messages
+ -version Print the program's version number
+ -variant Specifies layout variant used to choose component names
+```
+
+Aby przełączać się na polski układ klawiatury za każdym razem,
+gdy jest otwierany nowy terminal wystarczy dodać wywołanie polecenia `setxkbmap` do pliku `~/.bashrc` za pomocą polecenia:
+```bash
+echo "setxkbmap pl" >> ~/.bashrc
+```
+
+[Ubuntu]: /tools/ubuntu
diff --git a/_collections/_posts/2019-02-27-scalapipe.md b/_collections/_posts/2019-02-27-scalapipe.md
new file mode 100644
index 00000000..a8987c82
--- /dev/null
+++ b/_collections/_posts/2019-02-27-scalapipe.md
@@ -0,0 +1,243 @@
+---
+title: 'Problem wywołań cebulowych w Scali'
+author: TheKamilAdam
+category: scala-native
+tags: operator
+langs: clojure elixir elm fsharp julia kotlin lisp livescript meta-language ocaml perl racket scala
+tools: bash jekyll
+libs: scalaz
+redirect_from:
+ - scalapipe
+ - scala-native/scalapipe
+ - resentiment/scalapipe
+ - resentiment/2019/02/27/scalapipe.html
+---
+
+## Problem: wywołania cebulowe
+
+### Przypadek pierwszy - języki nieobiektowe
+
+Jeśli mamy dane wejściowe, które chcemy przetworzyć za pomoca kilku funkcji po kolej, np:
+```scala
+third_function(second_function(first_function(data)))
+```
+Powstaje nam brzydkie i nieczytelne **wywołanie cebulowe**.
+* Cebulowe, ponieważ nawiasy układają się jak warstwy w cebuli wokół rdzenia, którym są tu dane wejściowe.
+* Nieczytelne, ponieważ przy czytaniu wzrok podąża od lewej do prawej.
+W tym wypadku jednak, żeby zrozumieć sens linijki wzrok musi zawrócić i ponownie czytać od prawej do lewej.
+* Brzydkie, ponieważ rozwiązanie to się nie *skaluje*,
+jeśli mielibyśmy trzydzieści takich funkcji musielibyśmy w końcu złamać linię lub przepisać kod na taki:
+
+```scala
+val data1 = first_function(data)
+val data2 = second_function(data1)
+val data3 = third_function(data2)
+// (...)
+val data30 = thirty_function(data29)
+```
+Dlaczego uważam, że ten kod jest zły?
+Ponieważ zawiera wiele niepotrzebnego szumu.
+Szumem jest tutaj tworzenie pomocniczych zmiennych,
+które często trudno nazwać w sensowny sposób.
+
+Dlatego powinniśmy unikać *wywołań cebulowych*
+Chyba, że piszemy w języku **[Clojure]**, **[Racket]** lub innym **[Lispie]**.
+Wtedy formatujemy kod:
+```clojure
+(third_function
+ (second_function
+ (first_function data)))
+```
+i mówimy że wszystko jest w porządku.
+
+### Przypadek drugi - języki obiektowe
+
+Gdybyśmy programowali w języku obiektowym moglibyśmy zapisać:
+```scala
+data.first_function().second_function().third_function()
+```
+lub bardziej czytelnie:
+```scala
+data
+ .first_function()
+ .second_function()
+ .third_function()
+```
+
+Oczywiście o ile `first_function` jest metodą obiektu `data`,
+`second_function` jest metodą obiektu zwracanego przez `first_function` i tak dalej.
+Jeśli nie, to musimy użyć haków
+jak [implicit classes]() w języku **[Scala]**
+lub [extensions]() w języku **[Kotlin]**.
+
+Jeśli nasz język programowania nie wspiera haków to pozostaje nam kod z tworzeniem wielu pomocniczych zmiennych:
+```scala
+val data1 = first_function(data)
+val data2 = second_function(data1)
+val data3 = third_function(data2)
+// (...)
+val data30 = thirty_function(data29)
+```
+
+### Prawdopodobna inspiracja - potoki w Bash i Jekyll
+
+W powłoce systemowej **[Bash]** przesyłanie danych między jednym poleceniem,
+a drugim jest realizowane przez potoki, np:
+```bash
+ps -a | sort | uniq | grep -v sh
+```
+Dwa lub więcej poleceń można połączyć w jedno polecenie za pomocą operatora pionowej kreski `|` (ang. *pipe*).
+
+**[Jekyll]** także posiada potoki, ale dla utrudnienia nazywają się filtrami.
+Precyzyjniej to Jekyll używa języka szablonów Liquid, a Liquid posiada Filtry.
+Kod :
+```jekyll
+{% raw %}
+{{ "scala!" | capitalize | prepend: "Hello " }}
+{% endraw %}
+```
+daje na wyjściu:
+```
+{{ "scala!" | capitalize | prepend: "Hello " }}
+```
+
+## Rozwiązanie - operator potoku
+
+Jednym z możliwych rozwiązań **wywołań cebulowych** jest operator potoku (ang. *pipe operator* lub *pipeline operator*) `|>`.
+Pozwala on na zapis:
+```elixir
+data |> first_function |> second_function |> third_function
+```
+lub czytelniej:
+```elixir
+data
+ |> first_function
+ |> second_function
+ |> third_function
+```
+
+Został spopularyzowany przez język [Elixir](),
+ale wcześniej był już używany w odmianach języka **[Meta Language]** jak [OCaml](http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html#VAL%28%7C%3E%29)
+oraz [F#](https://en.wikibooks.org/wiki/F_Sharp_Programming/Higher_Order_Functions#The_.7C.3E_Operator).
+W tym ostatnim istnieje nawet możliwość samodzielnego zdefiniowania operatora potoku za pomocą linii:
+```F#
+let inline (|>) x f = f x
+```
+
+Na fali popularności *operator potoku* został dodany także do wielu innych języków programowania takich jak
+[Elm](),
+[LiveScript](),
+[Julia]() czy
+[Hack]().
+
+Część z nich zawiera także drugi podobny operator zwany *back pipe operator* zapisywany `<|` lub `|>>`.
+Ten drugi zapis prawdopodobnie inspirowany jest językiem [Clojure]().
+
+Tak, **[Clojure]** posiada dużo lukru składniowego,
+żeby poprawić standardową nieczytelność **[Lispa]** dzięki czemu możemy zapisać:
+
+```clojure
+(-> data (first_function) (second_function) (third_function))
+```
+**lub**
+```clojure
+(--> data (first_function) (second_function) (third_function))
+```
+
+Po co nam dwa operatory potoku, tj `|>` i `<|`?
+
+Otóż `|>` dodaje argument na początku listy parametrów, a `<|` - na końcu listy.
+Czyli jeśli w języku **[Perl]** 5 wprowadzonoby oba operatory to moglibyśmy wywołać:
+
+```perl
+(0, 1, 2, 3) <| grep { $_ != 2} <| map { $_ * 2})
+```
+
+## Rozwiązanie w Scali - ScalaPipe i operator drozda
+
+Język **[Scala]** nie posiada operatora potoku,
+ale posiada możliwość definiowania operatorów.
+W internecie pod hasłem *ScalaPipe* można znaleść wiele możliwych implementacji.
+Moja ulubiona to:
+```scala
+package pl.writeonly.re.shared.scalapipe
+
+trait ScalaPipeOps {
+ implicit def toPipe[A](a: A): ScalaPipe[A] = ScalaPipe(a)
+
+ class ScalaPipe[A](a: A) {
+ def |>[B](f: A => B): B = f(a)
+ }
+
+ object ScalaPipe {
+ def apply[A](v: A): ScalaPipe[A] = new ScalaPipe(v)
+ }
+
+}
+
+object ScalaPipeOps extends ScalaPipeOps
+```
+
+Na szczęście nie musimy sami implementować operatora *ScalaPipe*,
+ponieważ istnieje on już w bibliotece **[Scalaz]**
+ale dla utrudnienia nazywa się **operator drozda** (ang. *Thrush combinator* lub *Thrush combinator*).
+Używając tego operatora z łatwością możemy zapisać:
+```scala
+import scalaz.Scalaz._
+
+data |> firstFunction |> secondFunction |> threeFunction
+```
+
+Niestety Scala to nie **[Elixir]** i nie możemy zapisać:
+```scala
+data
+ |> firstFunction
+ |> secondFunction
+ |> threeFunction
+```
+
+Wywołanie zdefiniowanego przez nas operatora nie może znajdować się bezpośrednio na początku linii.
+Ale może znajdować się na końcu linii:
+```scala
+data |>
+ firstFunction |>
+ secondFunction |>
+ threeFunction
+```
+
+Lub, co wygląda jeszcze gorzej, na początku linii poprzedzony kropką:
+```scala
+data
+ .|>(firstFunction)
+ .|>(secondFunction)
+ .|>(threeFunction)
+```
+
+Jednak w takim wypadku lepiej użyć aliasu `into`:
+```scala
+data
+ .into(firstFunction)
+ .into(secondFunction)
+ .into(threeFunction)
+```
+
+## Podsumowanie
+
+Składnia języka **[Scala]** jest elastyczna, ale czasem nie aż tak bardzo jak była by potrzeba.
+Mimo to, łatwo definiować nowe operatory oraz składnię, która może znacząco skrócić i uprościć kod.
+Warto jednak wcześnie sprawdzić czy nasz operator nie jest zdefiniowany w istniejącej i popularnej bibliotece.
+
+[Clojure]: /langs/clojure
+[Elixir]: /langs/elixir
+[Kotlin]: /langs/kotlin
+[Lispa]: /langs/lisp
+[Lispie]: /langs/lisp
+[Meta Language]: /langs/meta-language
+[Perl]: /langs/perl
+[Racket]: /langs/racket
+[Scala]: /langs/scala
+
+[Scalaz]: /libs/scalaz
+
+[Bash]: /tools/bash
+[Jekyll]: /tools/jekyll
diff --git a/_collections/_posts/2019-03-13-biblioteki-do-parserowania.md b/_collections/_posts/2019-03-13-biblioteki-do-parserowania.md
new file mode 100644
index 00000000..9342714f
--- /dev/null
+++ b/_collections/_posts/2019-03-13-biblioteki-do-parserowania.md
@@ -0,0 +1,216 @@
+---
+title: "Biblioteki do parsowania dla języka Scala"
+author: TheKamilAdam
+category: scala-native
+tags: ast compiler dsl interface json lexer library parser properties xml
+labels: BNF parboiled2
+langs: scala
+libs: fastparse shocon stoml utest
+redirect_from:
+ - biblioteki-do-parserowania
+ - scala-native/biblioteki-do-parserowania
+ - resentiment/biblioteki-do-parserowania
+ - resentiment/2019/03/13/biblioteki-do-parserowania.html
+---
+
+## Co to jest parser?
+
+**[Parser]** to program dokonujący procesu analizy składniowej na ciągu leksemów (tokenach z typami),
+czyli sprawdzeniu ich zgodności z określoną gramatyką formalną.
+Wynikiem pracy parsera jest **[drzewo składniowe]** (ang. *abstract syntax tree*, *AST*),
+na którym są przeprowadzane dalsze operacje.
+
+Programem pomocniczym, często działającym równolegle do parsera, jest **[lekser]**.
+Dokonuje on procesu analizy leksykalnej,
+czyli dzieli wejściowy tekst na leksemy.
+
+## Po co nam parser?
+Parsery są używane do różnych celów:
+
+### Parsowanie danych strukturalnych
+* Parsowanie języka programowania -
+jest to pierwsza rzecz jaka nasuwa się na myśl, przynajmniej mi.
+Parsery są pierwszą (wejściową) częścią **[kompilatora]**.
+Oczywiście mało prawdopodobne, że będziesz tworzył nowy język programowania.
+Czasem jednak istnieje potrzeba napisania parsera już istniejącego języka,
+gdy np. piszesz własny tool do formatowania kodu.
+* Parsowanie z serializowanych danych -
+z serializowane dane można przesyłać i przechowywać w formatach tekstowych takich jak
+**[JSON]**, CSV, JSON Lines (połączenie zalet formatów JSON i CSV), **[XML]** i wielu innych.
+Ale możliwe, że chciałbyś napisać parser własnego formatu zoptymalizowany pod pewne konkretne wymagania.
+Jak np. [Rison],
+JSON zmodyfikowany w taki sposób by móc go przesyłać bezpośrednio w adresie url.
+* Parsowanie konfiguracji -
+teoretycznie każdą konfigurację można zapisać w Javowych plikach **[Properties]** lub formacie JSON,
+ewentualnie Yamlu (nadzbiorze formatu JSON) albo XMLu.
+Powstają jednak cały czas nowe formaty dedykowane do przechowywania konfiguracji jak
+[Hocon]) ([Shocon])
+lub
+[Toml]) ([Stoml]).
+* Parsowanie języka domenowego (ang. *domain-specific language*, **[DSL]** -
+czasem prosta konfiguracja nie wystarcza i potrzebujemy czegoś więcej.
+Jeśli potrzebujesz prostych wyrażeń (np. relacji) wczytywanych z pliku możesz spróbować zaadoptować jeden z języków wyrażeń (ang. *Expression Language*, *EL*) jak
+SpEL,
+[MVFLEX Expression Language (MVEL)](),
+[Object-Graph Navigation Language (OGNL)]().
+Jeśli potrzeba czegoś więcej można użyć jednego z istniejących silników reguł biznesowych.
+Problemem jest to że są to wielkie kobyły.
+Jeśli potrzebujemy prostego DSL możliwe że najlepiej będzie zaimplementować go samodzielnie.
+
+### Parsowanie danych niestrukturalnych
+
+Tutaj najbardziej znanym zastosowaniem jest przetwarzanie języków naturalnych,
+ale proste parsery mogą być używane do przeszukiwania dowolnych danych tekstowych w celu odnalezienia
+wszystkich adresów mailowych, numerów telefonów i tak dalej.
+
+## Biblioteki
+
+W pradawnych czasach parsery pisało się całkowicie ręcznie, były to zwykle parsery zejść rekurencyjnych.
+Zużywały mało pamięci, co było ważne w czasach procesorów ośmiobitowych, ale działały wolno.
+Dodatkowo, ponieważ drzewo AST było na bierząco konsumowane,
+utrodniona była wieloetapowa optymalizacja wynikowego kodu
+i wynikowy kod także był wolny.
+W ciemnych wiekach średnich parsery generowało się za pomocą narzędzi Yacc i Lex lub podobnych ze zbliżonym **[interfejsem]**.
+Były one konfigurowane we własnym języku,
+podobnym do notacja Backusa-Naura (ang. **Backus-Naur Form**, **BNF**)
+oraz generowane przed właściwą kompilacją.
+
+Dziś istnieją biblioteki przy pomocy których można napisać parser o akceptowalnej wydajności.
+Dla języka **[Scala]** są to:
+
+* [Scala Parser Combinators]() -
+Wspiera Scala.js w wersji 0.6.x.
+Biblioteka należała do Scala Standard Library (Standardowa Biblioteka Scali), ale wyleciała do modułów.
+Podobno za to, że jest powolna
+* [parboiled2]() -
+*A macro-based PEG parser generator for Scala 2.10+*
+Wspiera Scala.js w wersji 0.6.x.
+Podobno najszybszy z parserów w działaniu, ale ma trudną składnię i zgłasza niezrozumiałe błędy
+* [FastParse]( ) -
+*Fast to write, Fast running Parsers in Scala*.
+Wspiera Scala.js w wersji 0.6.x.
+Wersja FastParse 1.0.0 wspierała Scala Native.
+
+## FastParse w akcji
+
+Prosty parser wyrażeń arytmetycznych zaimplementowany przy pomocy **[FastParse]**:
+```scala
+package pl.writeonly.re.shared.calculator
+
+class CalculatorParser {
+ def eval(tree: (Int, Seq[(String, Int)])): Int = {
+ val (base, ops) = tree
+ ops.foldLeft(base) {
+ case (left, (op, right)) => evalOp(op, left, right)
+ }
+ }
+
+ private def evalOp(op: String, left: Int, right: Int): Int = op match {
+ case "+" => left + right
+ case "-" => left - right
+ case "*" => left * right
+ case "/" => left / right
+ }
+
+ import fastparse.all._
+
+ val number: P[Int] = P(CharIn('0' to '9').rep(1).!.map(_.toInt))
+ val parens: P[Int] = P("(" ~/ addSub ~ ")")
+ val factor: P[Int] = P(number | parens)
+
+ val divMul: P[Int] = P(factor ~ (CharIn("*/").! ~/ factor).rep).map(eval)
+ val addSub: P[Int] = P(divMul ~ (CharIn("+-").! ~/ divMul).rep).map(eval)
+ val expr: P[Int] = P(addSub ~ End)
+}
+```
+I proste testy do tego w frameworku **[utest]**:
+```scala
+package pl.writeonly.re.shared.calculator
+
+import fastparse.core.Parsed
+import utest._
+
+@SuppressWarnings(Array("org.wartremover.warts.Any"))
+object CalculatorParserTest extends TestSuite {
+ override val tests: Tests = Tests {
+
+ val parser = new CalculatorParser()
+ val expr = parser.expr
+ "2+3" - {
+ val result = expr.parse("2+3")
+ val Expected = 2 + 3
+ assertMatch(result) {
+ case Parsed.Success(Expected, _) =>
+ }
+ }
+ "2-3" - {
+ val result = expr.parse("2-3")
+ val Expected = 2 - 3
+ assertMatch(result) {
+ case Parsed.Success(Expected, _) =>
+ }
+ }
+ "2*3" - {
+ val result = expr.parse("2*3")
+ val Expected = 2 * 3
+ assertMatch(result) {
+ case Parsed.Success(Expected, _) =>
+ }
+ }
+ "2/3" - {
+ val result = expr.parse("2/3")
+ val Expected = 2 / 3
+ assertMatch(result) {
+ case Parsed.Success(Expected, _) =>
+ }
+ }
+ "1+1*" - {
+ val result = expr.parse("1+1*")
+ assertMatch(result) {
+ case _: Parsed.Failure[_, _] =>
+ }
+ }
+ "(1+1*2)+3*4" - {
+ val result = expr.parse("(1+1*2)+3*4")
+ val Expected = (1 + 1 * 2) + 3 * 4
+ assertMatch(result) {
+ case Parsed.Success(Expected, _) =>
+ }
+ }
+ "((1+1*2)+3*4*5)/3" - {
+ val result = expr.parse("((1+1*2)+3*4*5)/3")
+ val Expected = ((1 + 1 * 2) + 3 * 4 * 5) / 3
+ assertMatch(result) {
+ case Parsed.Success(Expected, _) =>
+ }
+ }
+ }
+}
+```
+
+## Podsumowanie
+
+Dzięki bibliotekom do parsowania możliwe jest pisanie parserów w językach ogólnego przeznaczenia jak **[Scala]**.
+Nie są potrzebne dodatkowe narzędzia, ani dodatkowe fazy kompilacji.
+Dodatkowo dzięki możliwości dodawania operatorów do składni języka **[Scala]**,
+możliwe jest używanie notacji podobnej do BNF.
+
+[Scala]: /langs/scala
+
+[FastParse]: /libs/fastparse
+[SHocon]: /libs/shocon
+[STOML]: /libs/stoml
+[utest]: /libs/utest
+
+[DSL]: /tags/dsl
+[drzewo składniowe]: /tags/ast
+[interfejsem]: /tags/interface
+[JSON]: /tags/json
+[HOCON]: /tags/hocon
+[kompilatora]: /tags/compiler
+[lekser]: /tags/lexer
+[Properties]: /tags/properties
+[Parser]: /tags/parser
+[Rison]: /tags/rison
+[TOML]: /tags/toml
+[XML]: /tags/xml
diff --git a/_collections/_posts/2019-03-27-arrow-asserts.md b/_collections/_posts/2019-03-27-arrow-asserts.md
new file mode 100644
index 00000000..8056d3d4
--- /dev/null
+++ b/_collections/_posts/2019-03-27-arrow-asserts.md
@@ -0,0 +1,108 @@
+---
+title: "uTest - operator Arrow Asserts"
+author: TheKamilAdam
+category: scala-native
+tags: operator
+langs: scala
+libs: utest
+redirect_from:
+ - arrow-asserts
+ - scala-native/arrow-asserts
+ - resentiment/arrow-asserts
+ - resentiment/2019/03/27/arrow-asserts.html
+---
+
+Dziś krótki wpis o tym, że warto czytać dokumentację. Zapraszam.
+
+## Arrow Asserts
+
+Framework **[uTest]** do testów jednostkowych dla języka **[Scala]** udostępnia **[operator]** `a ==> b` zwany po angielsku **Arrow Asserts**
+(po polsku *Asercja Strzałkowa* ?). Jest on skrótem od `assert(a == b)`. Dzięki niemu kod :
+
+```scala
+package pl.writeonly.re.shared
+
+import scalaz.Scalaz._
+import utest._
+
+object CalculatorTest extends TestSuite {
+ override val tests: Tests = Tests {
+ val calculator = new Calculator()
+ 'addition - {
+ val addition: (Int, Int) => Int = (x, y) => calculator.add(x, y)
+ "0 + 0 == 0" - {
+ assert(addition(0, 0) === 0)
+ }
+ "2 + 2 == 4" - {
+ assert(addition(2, 2) === 4)
+ }
+ }
+ 'multiplication - {
+ val multiplication: (Int, Int) => Int = (x, y) => calculator.mul(x, y)
+ "0 + 0 == 0" - {
+ assert(multiplication(0, 0) === 0)
+ }
+ "2 + 2 == 4" - {
+ assert(multiplication(2, 2) === 4)
+ }
+ }
+ 'less_or_equal - {
+ val less_or_equal: (Int, Int) => Boolean = (x, y) => calculator.leq(x, y)
+ "0 <= 2 == true" - {
+ assert(less_or_equal(0, 2))
+ }
+ "2 <= 0 == false" - {
+ assert(!less_or_equal(2, 0))
+ }
+ }
+ }
+}
+
+```
+
+może zostać zastąpiony swoją czytelniejszą wersją:
+
+```scala
+package pl.writeonly.re.shared.calculator
+
+import utest._
+
+object CalculatorTest extends TestSuite {
+ override val tests: Tests = Tests {
+ val calculator = new Calculator()
+ 'addition - {
+ val addition: (Int, Int) => Int = (x, y) => calculator.add(x, y)
+ "0 + 0 == 0" - {
+ addition(0, 0) ==> 0
+ }
+ "2 + 2 == 4" - {
+ addition(2, 2) ==> 4
+ }
+ }
+ 'multiplication - {
+ val multiplication: (Int, Int) => Int = (x, y) => calculator.mul(x, y)
+ "0 + 0 == 0" - {
+ multiplication(0, 0) ==> 0
+ }
+ "2 + 2 == 4" - {
+ multiplication(2, 2) ==> 4
+ }
+ }
+ 'less_or_equal - {
+ val less_or_equal: (Int, Int) => Boolean = (x, y) => calculator.leq(x, y)
+ "0 <= 2 == true" - {
+ less_or_equal(0, 2) ==> true
+ }
+ "2 <= 0 == false" - {
+ less_or_equal(2, 0) ==> false
+ }
+ }
+ }
+}
+```
+
+[Scala]: /langs/scala
+
+[uTest]: /libs/utest
+
+[operator]: /tags/operator
diff --git a/_collections/_posts/2019-04-10-jekyllcodex-org-head-seo.md b/_collections/_posts/2019-04-10-jekyllcodex-org-head-seo.md
new file mode 100644
index 00000000..d8b68e0d
--- /dev/null
+++ b/_collections/_posts/2019-04-10-jekyllcodex-org-head-seo.md
@@ -0,0 +1,105 @@
+---
+title: "jekyllcodex.org - problem ze skryptem seo"
+author: TheKamilAdam
+category: jekyll
+tags: blog html jekyllcodex seo
+tools: jekyll
+redirect_from:
+ - jekyllcodex-org-head-seo
+ - jekyll/jekyllcodex-org-head-seo
+ - writeonlydoc/jekyllcodex-org-head-seo
+ - writeonlydoc/2019/04/10/jekyllcodex-org-head-seo.html
+---
+
+Wyszukiwując swój blog w google trafiłem na brzydki opis w rodzaju:
+{%raw%}
+```html
+for post in paginator. posts %} {{ post. title }} {{ post. date | date:
+```
+{%endraw%}
+
+wynika to z tego, że skrypt dla **[seo]**
+ze strony [jekyllcodex]( )
+generuje skrócony opis nawet dla stron używających liquiidu.
+Dokładnie problematyczna jest linia:
+
+{%raw%}
+```html
+
+```
+{%endraw%}
+
+i dwie podobne dla niej.
+
+## Pomysł rozwiązania problemu ...
+Żeby rozwiązać problem podzieliłem wszystkie wygenerowane strony na trzy grupy:
+* strony nie używające liquidu, można dla nich przygotować skrócony opis - są to artykuły, kategorie, tagi i inne kolekcje
+* strony używające liquidu i posiadające własny opis - są to strony statyczne
+* strony używające liquidu i nie posiadające własnego opisu, tylko używające domyślnego opis - w moim przypadku jest to tylko jedna strona,
+`index.html` zawierająca paginację artykułów
+
+## ... i implementacja algorytmu
+Ładnie sformatowany kod rozwiązujący ten problem wygląda następująco:
+{%raw%}
+```html
+{% if page.description %} {% comment %} jeśli strona posiada opis {% endcomment %}
+ {{ page.description }} {% comment %} to wyświetl go {% endcomment %}
+{% elsif page.use_default_description %} {% comment %} w przeciwnym wypadku jeśli strona posiada zmienną use_default_description {% endcomment %}
+ {{ site.description }} {% comment %} to wyświetl domyślny opis {% endcomment %}
+{% else %} {% comment %} w przeciwnym wypadku {% endcomment %}
+ {{ pagecontent_description }} {% comment %} wyświelt przygotowany skrót {% endcomment %}
+{% endif %}
+```
+{%endraw%}
+
+Co produkcyjnie wygląda
+{%raw%}
+```html
+
+```
+{%endraw%}
+
+A cały skrypt dla **[seo]** ostateczie wygląda:
+{%raw%}
+```html
+
+
+
+
+ {% if page.title %}{{ page.title }} | {% endif %}{{ site.title }}
+ {% assign pagecontent_description = page.content | markdownify | replace: '.', '. ' | replace: '', ': ' | replace: '', ': ' | replace: '', ': ' | strip_html | strip_newlines | replace: ' ', ' ' | truncate: 160 %}
+
+
+
+
+
+
+
+
+ {% if page.image %} {% endif %}
+
+
+
+
+
+
+
+
+ {% if page.image %} {% endif %}
+
+
+
+
+
+
+```
+{%endraw%}
+
+Aktualny skrypt do pobrania pod linkiem znajduje się dpo linkiem
+[head-seo.html]().
+Należy umieścić go wewnątrz znaczników ` ` za pomocą kodu `{%raw%}{% include head-seo.html %}{%endraw%}`.
+
+## Podsumowanie
+Nalezy sprawdzać i testować cudze skrypty. Zawsze.
+
+[seo]: /tags/seo
\ No newline at end of file
diff --git a/_collections/_posts/2019-04-17-git-rebase-i.md b/_collections/_posts/2019-04-17-git-rebase-i.md
new file mode 100644
index 00000000..4994e14d
--- /dev/null
+++ b/_collections/_posts/2019-04-17-git-rebase-i.md
@@ -0,0 +1,183 @@
+---
+title: 'Prosty sposób na zmianę historii Gita'
+author: TheKamilAdam
+category: cli
+tools: git ubuntu
+tags: tui
+redirect_from:
+ - git-rebase-i
+ - cli/git-rebase-i
+---
+
+Każdy z nas czasem zatwierdza (ang. *commit*) coś brzydkiego do repozytorium.
+Dlaczego tak robimy?
+Czasem przypadkiem,
+ale często dlatego, że trzeba przełączyć się na inną gałąź,
+a posiadamy już jakieś zmiany na gałęzi aktualnej.
+Co prawda można niezatwierdzone zmiany, tylko schować w schowku za pomocą polecenia `git stash`,
+ale dane ze schowka strasznie łatwo stracić.
+Poza tym schowek jest jeden wspólny dla wszystkich gałęzi.
+
+Zatwierdzanie brzydkich rzeczy na osobną gałąź (ang. *feature branch*) nie jest niczym złym,
+o ile posprzątamy wszystko przed złączeniem z główną gałęzią.
+
+Sposobów na sprzątanie w historii gita jest kilka,
+ale moim ulubiony,
+bo nie wymagającym zewnętrznych narzędzi,
+jest polecenie:
+```bash
+git rebase -i HEAD~LICZBA_ZATWIERDZEN_WSTECZ
+```
+
+## Usuwanie, łączenie i zmiana opisu rewizji za pomocą polecenia `git rebase -i`
+Wyobraźmy sobie,
+że mamy repozytorium w którym kilka ostatnich rewizji (ang. *commit*) było robionych w zbytnim pośpiechu i chcemy to teraz naprawić.
+Wywołujemy:
+
+```bash
+git rebase -i HEAD~5
+```
+
+i zobaczymy edytor dla gita (domyślnie jest to vim) z następującą treścią:
+```bash
+pick 2222222 dobry commit
+pick 3333333 dobry commit, ale ze złym opisem
+pick 4444444 zły komit robiony na szybko
+pick 5555555 commit poprawiający poprzedni
+pick 6666666 błędny commit do skasowania
+
+# Rebase 1111111..6666666 onto 1111111 (5 commands)
+#
+# Commands:
+# p, pick = use commit
+# r, reword = use commit, but edit the commit message
+# e, edit = use commit, but stop for amending
+# s, squash = use commit, but meld into previous commit
+# f, fixup = like "squash", but discard this commit's log message
+# x, exec = run command (the rest of the line) using shell
+# d, drop = remove commit
+#
+# These lines can be re-ordered; they are executed from top to bottom.
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+#
+# However, if you remove everything, the rebase will be aborted.
+#
+# Note that empty commits are commented out
+```
+
+Najpierw mamy listę rewizji w kolejności chronologicznej,
+a następnie listę możliwych poleceń do użycia.
+
+*Oczywiście hashe rewizji zostały zmyślone by łatwiej było się skupić na tym co ważne.*
+
+W naszym przypadku użyjemy:
+* `pick` - żeby pozostawić rewizje niezmienioną
+* `reword` - żeby zmienić opis rewizji. Po użyciu tego polecenia pojawi nam się kolejny ekran edytora do wprowadzenia nowego opisu
+* `squash` lub `fixup` - żeby połączyć to rewizję z poprzednim. Ja wolę `fixup`, bo nie zostawia żadnych śladów w historii
+* `drop` - żeby pozbyć się niepotrzebnego rewizji
+
+Po naszych zmianach lista wygląda następująco:
+```bash
+pick 2222222 dobry commit
+r 3333333 dobry commit ze złym opisem
+pick 4444444 zły comit robiony na szybko
+f 5555555 commit poprawiający poprzedni
+d 6666666 błędny commit do skasowania
+```
+
+Teraz wychodzimy z edytora (jeśli używamy vima jest to `:x`) i pokazuje nam się edytor do zmiany treści opisu:
+```bash
+dobry commit, ze z złym opisem
+
+# Please enter the commit message for your changes. Lines starting
+# with '#' will be ignored, and an empty message aborts the commit.
+#
+# Date: DATA_REWIZJI_Z_OPISEM
+#
+# OPIS AKTUALNEGO STANU
+#
+# Changes to be committed:
+
+```
+Kasujemy stary opis (*dobry commit ze złym opisem*) i wprowadzamy nowy np. *dobry commit z poprawionym opisem*.
+Ponownie wychodzimy z edytora
+i jeśli teraz wywołamy w konsoli:
+```bash
+git rebase -i HEAD~3
+```
+to zobaczymy:
+```bash
+pick 2222222 dobry commit
+pick 3333333 dobry commit z poprawionym opisem
+pick 4545454 zły komit robiony na szybko
+```
+i jeśli nie chcemy nic już zmieniać to wystarczy wyjść z edytora.
+Nie spowoduje to żadnych zmian,
+ponieważ dla każdego zatwierdzenia domyślnie jest ustawione polecenie `pick`,
+które go nie zmienia.
+
+### Zmienianie kolejności rewizji za pomocą polecenia `git rebase -i`
+
+Polecenie `git rebase -i` pozwala także zmienić kolejność rewizji.
+
+Może się zdarzyć, że pracując dłużej na osobnej gałęzi dokonamy więcej zmian w kodzie.
+Takiej ilości, że dokonanie przeglądu kodu stanie się *niemożliwe*.
+Co to znaczy *niemożliwe* zależy od definicji w zespole, ale przeglądy powyżej 500 linii są naprawdę trudne.
+
+Często wystarczającym rozwiązaniem jest wydzielenie refaktoryzacji przygotowywującego kod pod dodanie nowej funkcjonalnosci do osobnej gałęzi.
+Niestety zwykle moje zatwierdzenia wyglądają następująco:
+
+```bash
+pick 1111111 refaktoring i formatowanie klasy A
+pick 2222222 dodanie funkcjonalności w klasie A
+pick 3333333 refaktoring i formatowanie klasy B
+pick 4444444 dodanie funkcjonalności w klasie B
+pick 5555555 refaktoring i formatowanie klasy C
+pick 6666666 dodanie funkcjonalności w klasie C
+```
+
+*Oczywiście są to tylko przykładowe opisy zatwierdzeń :)*
+
+Gdybyśmy mogli łatwo doprowadzić historię rewizji do postaci:
+```bash
+pick 1111111 refaktoring i formatowanie klasy A
+pick 3333333 refaktoring i formatowanie klasy B
+pick 5555555 refaktoring i formatowanie klasy C
+pick 2222222 dodanie funkcjonalności w klasie A
+pick 4444444 dodanie funkcjonalności w klasie B
+pick 6666666 dodanie funkcjonalności w klasie C
+```
+Czyli takiej, że najpierw znajdują się wszystkie rewizje zawierające refaktoryzacje,
+a dopiero później całe dodawanie nowej funkcjonalności,
+to łatwo moglibyśmy podzielić to na dwie gałęzie.
+
+Na szczęście nie ma nic prostszego.
+Wystarczy wpisać tylko w konsoli `git rebase -i HEAD~6` i zmienić kolejność rewizji na taką jak potrzebujemy!
+Należy tylko uważać na to by nie skasować żadnej linii,
+ponieważ skasowanie linii działa jak polecenie `drop`,
+czyli usuwa rewizję.
+
+Uwaga!
+Zmiana kolejności rewizji może wymagać od nas użycia poleceń `git add` i `git rebase --continue`,
+podobnie jak przy używaniu polecenia `git rebase NAZWA_GAŁĘZI`
+
+### Widzieć więcej
+Czasem by móc podjąć decyzję, które rewizje zmodyfikować, musimy widzieć ich zawartość.
+Są do tego różne programy
+ale ja polecam **Tig:** *text-mode interface for Git*,
+które na **[Ubuntu]** można zainstalować za pomocą:
+```bash
+sudo apt-get install tig
+```
+Jego główną zaletą jest to,
+że jest aplikacją konsolową z przyjaznym interfejsem tekstowym (ang. *text-based user interface*, **[TUI]**)
+
+## Podsumowanie
+Widać że `git rebase -i` to potężne narzędzie z wieloma możliwościami w rękach dobrego programisty.
+Polecenie `edit` jest opisane w kolejnym [artykule](/git-rebase-i-edit).
+
+[git]: /tools/git
+[Ubuntu]: /tools/ubuntu
+
+[TUI]: /tags/tui
diff --git a/_collections/_posts/2019-04-24-git-rebase-i-edit.md b/_collections/_posts/2019-04-24-git-rebase-i-edit.md
new file mode 100644
index 00000000..d53f662e
--- /dev/null
+++ b/_collections/_posts/2019-04-24-git-rebase-i-edit.md
@@ -0,0 +1,92 @@
+---
+title: 'Prosty sposób na zmianę historii Gita - polecenie edit'
+author: TheKamilAdam
+category: cli
+tools: git ubuntu
+redirect_from:
+ - git-rebase-i-edit
+ - cli/git-rebase-i-edit
+ - cli/2019/04/24/git-rebase-i.html
+---
+
+Jest to kontynuacja artykuły na temat możliwości polecenia `get rebase`.
+Tym razem skupie się na podziele istniejących rewizji (ang. *commits*).
+
+### Podział rewizji
+O ile łączenie rewizji omówione w poprzednim [artykule](/git-rebase-i) jest banalnie proste
+i wymaga tylko użycia polecenia `fixup` lub `squash`
+o tyle podział rewizji (ang. *split commit*) jest już trudniejszy.
+
+Najpierw musimy ustalić jak daleko w historii znajduje się rewizja do podziału,
+której szukamy,
+a następnie wywołać polecenie `git rebase -i HEAD~` z odpowiednią liczbą, np.:
+```bash
+git rebase -i HEAD~8
+```
+
+I zobaczymy:
+```bash
+pick 2222222 gigantyczne coś, z tydzień pracy z nadgodzinami
+pick 3333333 dobre zatwierdzenie, bo małe
+pick 4444444 dobre zatwierdzenie, bo małe
+pick 5555555 dobre zatwierdzenie, bo małe
+pick 6666666 dobre zatwierdzenie, bo małe
+pick 7777777 dobre zatwierdzenie, bo małe
+pick 8888888 dobre zatwierdzenie, bo małe
+pick 9999999 dobre zatwierdzenie, bo małe
+```
+
+Następnie interesującą nas rewizję oznaczamy poleceniem `edit`
+```bash
+e 2222222 gigantyczne coś, z tydzień pracy z nadgodzinami
+pick 3333333 dobre zatwierdzenie, bo małe
+pick 4444444 dobre zatwierdzenie, bo małe
+pick 5555555 dobre zatwierdzenie, bo małe
+pick 6666666 dobre zatwierdzenie, bo małe
+pick 7777777 dobre zatwierdzenie, bo małe
+pick 8888888 dobre zatwierdzenie, bo małe
+pick 9999999 dobre zatwierdzenie, bo małe
+```
+i zamykamy edytor.
+
+Teraz jesteśmy w historii rewizji zaraz po zatwierdzeniu dużej rewizji, która nas interesuje.
+Dlatego trzeba jeszcze zresetować gita do poprzedniej rewizji za pomocą polecenia:
+```bash
+git reset HEAD^
+```
+Teraz za pomocą pary poleceń `git add ...` i `git commit -m OPIS_REWIZJI` dzielimy pliki na atomowe części, np.:
+
+```bash
+git add *.elm
+git commit -m 'dodanie frontendu w języku Elm, dialekcie języka Haskell transpilowanym do JS'
+git add *.ps
+git commit -m 'dodanie backend-for-frontend w języku PureScript, dialekcie języka Haskell transpilowanym do JS'
+git add *.fr
+git commit -m 'dodanie backendu w języku Frege, dialekcie języka Haskell na JVM'
+git add *.eta
+git commit -m 'dodanie backendu w języku Eta, dialekcie języka Haskell na JVM'
+```
+Następnie zatwierdzamy wszystko za pomocą polecenia:
+```bash
+git rebase --continue
+```
+I za pomocą polecenia `git rebase -i HEAD~9` możemy zobaczyć wynik:
+```bash
+pick 1234567 dodanie frontendu w języku Elm, dialekcie języka Haskell transpilowanym do JS
+pick 2345678 dodanie backendu w języku PureScript, dialekcie języka Haskell transpilowanym do JS
+pick 3456789 dodanie backendu w języku Frege, dialekcie języka Haskell na JVM
+pick 4567891 dodanie backendu w języku Eta, dialekcie języka Haskell na JVM
+pick 3333333 dobre zatwierdzenie, bo małe
+pick 4444444 dobre zatwierdzenie, bo małe
+pick 5555555 dobre zatwierdzenie, bo małe
+pick 6666666 dobre zatwierdzenie, bo małe
+pick 7777777 dobre zatwierdzenie, bo małe
+pick 8888888 dobre zatwierdzenie, bo małe
+pick 9999999 dobre zatwierdzenie, bo małe
+```
+
+## Podsumowanie
+Nic nie napisałem na temat działania polecenia `exec`, ponieważ nigdy nie miałem potrzeby go użyć.
+
+[git]: /tools/git
+[Ubuntu]: /tools/ubuntu
diff --git a/_collections/_posts/2019-05-01-github-pages.md b/_collections/_posts/2019-05-01-github-pages.md
new file mode 100644
index 00000000..3e1a6da4
--- /dev/null
+++ b/_collections/_posts/2019-05-01-github-pages.md
@@ -0,0 +1,160 @@
+---
+title: 'Lokalne uruchamianie strony hostowanej na GitHub Pages'
+author: TheKamilAdam
+category: jekyll
+tags: json alias github-pages
+lang: go ruby
+tools: jekyll github
+libs:
+redirect_from:
+ - github-pages
+ - jekyll/github-pages
+ - writeonlydoc/github-pages
+ - writeonlydoc/2019/05/01/github-pages.html
+---
+
+Jedną z największych zalet generator statycznych stron **[Jekyll]** jest to,
+że jest wspierany przez portal *[Github]( )*
+za pomocą **[Github Pages]**.
+Gdyby nie *Github Pages* prawdopodobnie wybrałbym *[Hugo]()*
+napisane w języku **[Go]**
+do budowania tego bloga.
+Największą wadą *Github Pages* jest to,
+że posiada ograniczony zbiór dozwolonych wtyczek i nie wolno instalować własnych wtyczek.
+Listę dozwolonych wtyczek (wraz z wersjami) można znaleźć na stronie [Dependency versions](https://pages.github.com/versions/)
+lub pod postacią pliku **[json]** na stronie [versions.json]().
+
+Chcąc budować i uruchamiać stronę lokalnie (poza *GitHub Pages*) za pomocą poleceń:
+```bash
+jekyll build
+jekyll serve
+```
+
+należy posiadać w pliku `Gemfile.lock` dokładnie te same wersje wtyczek jakie są w pliku [versions.json]().
+Dlaczego dokładnie te same?
+Ponieważ w przeciwnym wypadku możemy mieć trudne do odtworzenia błędy na produkcji,
+a komunikaty przychodzące z *GitHub Pages* nie są zbyt wiele mówiące.
+
+Wersje wtyczek można synchronizować ręcznie.
+Można także napisać skrypt,
+który będzie parsować plik [versions.json]()
+i na tej podstawie budował plik `Gemfile.lock`.
+Brzmi strasznie.
+
+Na szczęście żadne z tych rozwiązań nie jest potrzebne,
+ponieważ *GitHub* udostępnia gem `github-pages` (bibliotekę języka **[Ruby]**) zawierający wersję wszystkich wspieranych wtyczek dla Jekylla.
+Także wtyczki są zwykłymi gemami (bibliotekami) języka **[Ruby]**.
+Więc jedyne co potrzebujemy to program `bundle` do zarządzania zależnościami w języku **[Ruby]**.
+
+## Ukryta strona dokumentacji
+
+**[Jekyll]** posiada informację o integracji z *GitHub Pages*.
+Niestety znajduje się to na [ukrytej stronie dokumentacji]( ),
+tzn. nie znajdującej się w menu nawigacyjnym dokumentacji.
+Informuje ona jak zainstalować i używać gem `github-pages`.
+
+## Instalacja `github-pages`
+
+W pliku `Gemfile` umieszczamy:
+```bash
+source "https://rubygems.org"
+
+gem "github-pages", group: :jekyll_plugins
+```
+Od teraz plik `Gemfile.lock` nigdy nie będzie nam potrzebny,
+więc możemy dodać go do ignorowanych.
+
+Do pliku `.gitignore` dodajemy:
+```bash
+Gemfile.lock
+```
+
+I budujemy oraz uruchamiamy stronę lokalnie:
+```bash
+jekyll build
+jekyll serve
+```
+
+## Problemy Jekylla
+
+niestety uruchomienie polecenia `jekyll build` powoduje błąd:
+```bash
+Traceback (most recent call last):
+ 10: from /home/kamil-adam/gems/bin/jekyll:23:in `'
+ 9: from /home/kamil-adam/gems/bin/jekyll:23:in `load'
+ 8: from /var/lib/gems/2.5.0/gems/jekyll-3.8.5/exe/jekyll:11:in `'
+ 7: from /var/lib/gems/2.5.0/gems/jekyll-3.8.5/lib/jekyll/plugin_manager.rb:50:in `require_from_bundler'
+ 6: from /var/lib/gems/2.5.0/gems/bundler-2.0.1/lib/bundler.rb:107:in `setup'
+ 5: from /var/lib/gems/2.5.0/gems/bundler-2.0.1/lib/bundler/runtime.rb:26:in `setup'
+ 4: from /var/lib/gems/2.5.0/gems/bundler-2.0.1/lib/bundler/runtime.rb:26:in `map'
+ 3: from /var/lib/gems/2.5.0/gems/bundler-2.0.1/lib/bundler/spec_set.rb:148:in `each'
+ 2: from /var/lib/gems/2.5.0/gems/bundler-2.0.1/lib/bundler/spec_set.rb:148:in `each'
+ 1: from /var/lib/gems/2.5.0/gems/bundler-2.0.1/lib/bundler/runtime.rb:31:in `block in setup'
+/var/lib/gems/2.5.0/gems/bundler-2.0.1/lib/bundler/runtime.rb:319:in `check_for_activated_spec!': You have already activated addressable 2.6.0, but your Gemfile requires addressable 2.5.2. Prepending `bundle exec` to your command may solve this. (Gem::LoadError)
+```
+
+Z niewiadomych dla mnie powodów Jekyll ma problem,
+ale zasugerowane przez niego rozwiązanie działa.
+Od teraz budujemy i uruchamiamy generator Jekyll za pomocą poleceń:
+```bash
+bundle exec jekyll build
+bundle exec jekyll serve
+```
+
+lub krócej:
+
+```bash
+bundle exec jekyll b
+bundle exec jekyll s
+```
+
+## Aliasy
+
+Polecenie `bundle exec jekyll` aż prosi się zastąpienie jakimś **[aliasem]**,
+np. `bejekyll`.
+
+W konsoli wpisujemy:
+```bash
+echo "alias bejekyll='bundle exec jekyll'" >> ~/.bashrc
+```
+
+lub
+```bash
+echo "alias bejekyll='bundle exec jekyll'" >> ~/.bash_aliases
+```
+jeśli używamy pliku `~/.bash_aliases`.
+
+Następnie w konsolę wpisujemy:
+```bash
+. ~/.bashrc
+```
+
+lub
+```bash
+srcsh
+```
+jeśli używamy [niezniszczalnych aliasów](/alias-komenda-powloki-bash).
+
+I od teraz możemy budować i uruchamiać naszą stronę lokalnie za pomocą:
+
+```bash
+bejekyll b
+bejekyll s
+```
+
+## Podsumowanie
+*GitHub Pages* z generatorem stron **[Jekyll]**
+są ciekawą i darmową alternatywą dla klasycznych sposobów prowadzenia bloga lub strony.
+Możliwość uruchamiania strony w takiej samej konfiguracji lokalnie jak na produkcji
+czyni z tego połączenia rozwiązanie skierowane nie tylko do hobbystów,
+ale także dla rozwiązań biznesowych.
+
+[Go]: /langs/go
+[Ruby]: /langs/ruby
+
+[Jekyll]: /tools/jekyll
+[git]: /tools/git
+
+[aliasem]: /tags/alias
+[Github Pages]: /tags/github-pages
+[json]: /tags/json
diff --git a/_collections/_posts/2019-05-08-gcc-llvm-clang.md b/_collections/_posts/2019-05-08-gcc-llvm-clang.md
new file mode 100644
index 00000000..d04ab2b4
--- /dev/null
+++ b/_collections/_posts/2019-05-08-gcc-llvm-clang.md
@@ -0,0 +1,334 @@
+---
+title: 'Krótki opis konstrukcji kompilatorów GCC, LLVM i Clang'
+author: TheKamilAdam
+category: programming
+tags: api assembler ast bytecode cli compiler interface interpreter lexer parser
+labels: gcc ir r
+langs: haskell kotlin lua python ruby crystal julia pony rust go lisp wasm webassembly
+tools: clang jvm llvm scala-native
+redirect_from:
+ - gcc-llvm-clang
+ - programming/gcc-llvm-clang
+ - onions/gcc-llvm-clang
+ - onions/2019/05/08/gcc-llvm-clang.html
+---
+
+W dawnych czasach każdy dobry programista chciał napisać swój własny **[kompilator]** języka C.
+Co prawda te czasy już minęły i dziś większość z nas programuje w językach o wiele bardziej złożonych niż C.
+Dzięki czemu jesteśmy w stanie pisać szybciej kod.
+Ale nadal warto znać podstawy budowy kompilatorów.
+Na szczęście konstrukcja kompilatora jest prosta jak konstrukcja dzidy bojowej.
+Dzida bojowa składa się z:
+1. przeddzidzia dzidy bojowej
+2. śróddzidzia dzidy bojowej
+3. zadzidzia dzidy bojowej.
+
+## Konstrukcja kompilatora
+Podobnie jest z kompilatorem.
+**[Kompilator]** języka programowania składa się z:
+1. front-endu, zależnego od języka wejściowego
+2. middle-endu, clou kompilatora
+3. back-endu, zależnego od architektury docelowej
+
+Zgadza się.
+Dobrze widzicie.
+Pojęcia front-end i back-end są starsze niż aplikacje jednostronicowe (ang. *single-page application*, *SPA*).
+### Front-end
+Front-end kompilatora składa się z:
+1. analizatora leksykalnego (**[leksera]**) - wynikiem działania jest ciąg leksemów (tokenów z typami)
+2. analizatora składniowego (**[parsera]**) - wynikiem jest drzewo **[AST]**
+3. analizatora semantycznego - wynikiem jest zmodyfikowane drzewo AST z tablicą symboli.
+Analizator semantyczny zajmuje się:
+ * kontrolą nazw
+ * kontrolą typów
+ * kontrolą poprawności instrukcji
+4. optymalizatora drzewa AST - wykonuje optymalizacje zależne od języka wejściowego
+5. generatora reprezentacji pośredniej (ang. *Intermediate representation*, *IR*) -
+drzewo zostaje spłaszczone do uniwersalnego kodu bajtowego lub uniwersalnego języka asemblerowego czytelnego dla człowieka
+
+### Middle-end
+Zwany też optymalizatorem reprezentacji pośredniej.
+Dokonuje optymalizacji uniwersalnych,
+czyli wszystkie optymalizacje niezależne od języka wejściowego i architektury docelowej.
+Z jednej strony jest to najmniej potrzebna część kompilatora.
+Z drugiej to właśnie rozbudowany optymalizator decyduje o tym,
+który **[kompilator]** jest najlepszy.
+
+### Back-end
+Back-end kompilatora składa się z:
+1. optymalizator kodu wynikowego, wykonuje optymalizacje zależne od architektury docelowej
+2. generacja kodu binarnego lub asemblera architektury docelowej
+
+Poziom skomplikowania back-endu zależy od architektury docelowej.
+
+Architektury *RISC* (ang. *Reduced Instruction Set Computing*),
+*MISC* (ang. *Minimal Instruction Set Computer*)
+oraz *OISC* (ang *One Instruction Set Computer*)
+posiadają zwykle prosty i przejrzysty język asemblera,
+dlatego back-end dla nich także jest prosty.
+Przykładem architektury *RISC* jest architektura ARM oraz AVR.
+
+Architektura *CISC* (ang. *Complex Instruction Set Computing*)
+jest skomplikowana, a więc także back-end dla niej będzie zawierać wiele hacków.
+Przykładem tej architektury jest architektura x86 oraz rodzina mikrokontrolerów MCS-51.
+
+## GCC i LLVM
+
+Przez lata najbardziej znanym opensoursowym i najlepszym kompilatorem o tej budowie był GCC
+(kiedyś *GNU C Compiler* , dziś *GNU Compiler Collection*).
+Jednak dziś powoli palmę pierwszeństwa odbiera mu **[LLVM]**
+(kiedyś *Low Level Virtual Machine*, dziś nazwa się nie rozwija ponieważ jest to **[kompilator]**, a nie maszyna wirtualna).
+
+LLVM powstał z projektu badawczego na temat kompilacji.
+Naukowcy wzięli frond-end z GCC i dopisali własny middle-end i back-end.
+Później gdy firma Apple sypneła kasą projekt rozrósł się do prawdziwego kompilatora,
+ale dalej na otwartej licencji.
+
+Dlaczego naukowcy nie użyli middle-endu z GCC?
+Każdy kto spojrzał w kod GCC wie dlaczego.
+Ponieważ GCC jest napisany w języku C oraz języku **[Lisp]**,
+dwóch ulubionych językach [rms].
+Dzięki temu połączeniu w GCC jest osiągany polimorfizm.
+
+Kompilacja GCC składa się z kilku etapów.
+Pierwszym jest skompilowanie własnej wersji interpretera Lispa napisanego w C.
+Następnie wczytywany jest deklaratywny kod w Lispie opisujący docelową architekturę.
+Na podstawie kodu w Lispie generowany jest kod w C dla docelowej architektury.
+Kompilowany jest kod dla docelowej architektury.
+Niestety tego etapu nigdy nie udało mi się przejść więc nie wiem co dzieje się dalej.
+
+**[LLVM]** jest napisany w C++, języku który jako język obiektowy posiada polimorfizm out-of-the-box.
+
+## Główne programy/polecenia LLVM
+
+W skład LLVM wchodzi wiele bibliotek dostępnych także jako [polecenia standalone].
+Są to:
+* [llvm-as] - **[Asembler]** LLVM,
+konwertuje kod czytelny dla człowieka w języku asemblera LLVM (pliki *.ll) do bitkodu LLVM (pliki *.bc)
+* [llvm-dis] - Disasembler LLVM,
+konwertuje bitkod LLVM (pliki *.bc) do kodu czytelnego dla człowieka w języku asemblera LLVM (pliki *.ll)
+* [opt] - Optimizer LLVM,
+optymalizuje kod w języku asemblera LLVM
+* [llc] - **[Kompilator]** LLVM,
+kompiluje kod w języku asemblera LLVM na kod w języku asemblera docelowej architektury
+* [lli] - **[Interpreter]** (sic!) LLVM,
+wykonuje kod
+* i wiele innych...
+
+... ale żeby móc używać LLVM potrzebujemy jeszcze front-endu.
+
+### Clang ...
+
+Technicznie **[Clang]** to front-end dla projektu **[LLVM]**
+kompilujący języki z rodziny C
+(C, C ++, Objective C, OpenCL, CUDA i RenderScript).
+
+W praktyce Clang to kompilator maksymalnie zgodny z **[API]** GCC
+
+Można w swoim projekcie podmienić GCC na Clang i cieszyć się szybszą i lepszą kompilacją kodu.
+
+### ... i inne języki programowania
+
+Nie tylko języki C, C++ i Objective-C posiadają swój kompilator oparty na LLVM.
+Wiele innych języków natywnych posiada swój kompilator oparty na LLVM jak np.
+Ada, D, Delphi, Fortran.
+Także języki nienatywne zyskały swoją wersję natywną jak np.
+ActionScript,
+C#,
+**[Common Lisp]**,
+**[Haskell]**,
+**[Kod bajtowy]** Javy,
+**[Kotlin]**,
+**[Lua]**,
+**[Python]**,
+R,
+**[Ruby]**,
+**[Scala]**.
+Kompilatory wielu innych języków programowania powstały odrazu przy pomocy LLVM jak np.
+**[Crystal]**,
+**[Julia]**,
+**[Pony]**,
+**[Rust]**,
+Swift.
+
+Co ciekawe nie ma wśród nich języka **[Go]**.
+Plotki mówią że jest to spowodowane tym,
+że głównym sponsorem LLVM jest Apple.
+Ale LLVM jest używany przez Google w wielu innych projektach,
+jak chociażby w Chromium/Chrom do kompilowania języka **[JavaScript]**.
+Oficjalnym wytłumaczeniem jest to, że LLVM nie pozwalał na zarządzanie włóknami (ang. *fiber*), lekkimi procesami,
+potrzebnymi do implementacji gorutyn (ang. *goroutines*).
+
+### Przykładowa kompilacja za pomocą GCC i Clang
+
+Jako przykład skompilujemy interpreter języka **[Lua]**.
+Najpierw za pomocą kompilatora GCC,
+a później za pomocą LLVM.
+
+Ściągamy repozytorium z kodem interpretera języka **[Lua]**:
+```bash
+https://github.com/lua/lua.git
+```
+
+Przechodzimy do folderu `lua`:
+```bash
+cd lua
+```
+
+I kompilujemy:
+```bash
+make all
+```
+
+Może brakować wam kilku bibliotek potrzebnych do kompilacji.
+U mnie było to:
+```bash
+sudo apt-get install libreadline-dev
+```
+
+Jeśli kompilacja przeszła uruchamiamy interpreter języka **[Lua]**:
+```bash
+./lua
+```
+I żeby sprawdzić czy wszystko działa wpisujemy:
+```lua
+print("Hello World")
+```
+
+Jeśli wszystko jest wporządku to kasujemy wszystkie nowe pliki:
+```bash
+rm -f *.o *.a lua
+```
+
+Wchodzimy do pliku `makefile` i zamieniamy kompilator GCC na LLVM,
+czyli linię:
+```bash
+CC= gcc
+```
+na linię:
+```bash
+CC= clang
+```
+
+Ponownie wszystko kompilujemy:
+```bash
+make all
+```
+Prawdopodobnie kompilacja się nie uda ponieważ nie posiadacie kompilatora `clang`.
+Więc instalujemy kompilator i ponawiamy kompilację:
+```bash
+sudo apt install clang
+```
+
+Jeśli kompilacja przeszła uruchamiamy interpreter języka **[Lua]**:
+```bash
+./lua
+```
+I żeby sprawdzić czy wszystko działa wpisujemy:
+```lua
+print("Hello World")
+```
+
+Widać,
+że GCC może zostać bezproblemowo zastąpiony przez Clang,
+ponieważ oba kompilatory mają zgodny interfejs **[CLI]**.
+### Clang w szczegółach
+
+Za pomocą kompilatora Clang możemy...
+
+... skompilować pojedynczy plik:
+```bash
+clang lua.c
+```
+
+... uruchomić tylko preprocesor:
+```bash
+clang lua.c -E
+```
+
+... sprawdzić składnię:
+```bash
+clang lua.c -fsyntax-only
+clang lua.c -fsyntax-only -pedantic
+```
+
+... sformatowakoć kod:
+```bash
+clang -cc1 lua.c -ast-print
+```
+
+... wygenerować reprezentację pośrednią (ang. *Intermediate representation*, *IR*):
+```bash
+clang lua.c -S -emit-llvm -o -
+```
+
+... wygenerować asembler maszyny docelowej:
+```bash
+clang lua.c -S -o -
+clang lua.c -S -fomit-frame-pointer -o -
+```
+
+### WebAssembly
+
+Za pomocą clanga możeby też wygenerować webassembly
+
+Kompilujemy plic C do bitkodu:
+```bash
+clang -emit-llvm --target=wasm32 -Oz main.c -c -o math.bc
+```
+
+Kompilujemy bitkod do s-assembly:
+
+```bash
+llc -asm-verbose=false -o main.s main.bc
+```
+
+używamy narzędzia s2wasm, żeby stworzyć plik .wast:
+```bash
+s2wasm main.s > main.wast
+```
+
+Używamy narzędzia wast2wasm, żeby przetłumaczyć plik tekstowy .wast do postaci binarnej .wasm:
+```bash
+wast2wasm -o main.wasm main.wast
+```
+
+## Podsumowanie
+**[LLVM]** jest przyszłością i głównie ten projekt jest odpowiedzialny za wysyp nowych języków natywnych.
+
+[Common Lisp]: /langs/common-lisp
+[Crystal]: /langs/crystal
+[Go]: /langs/go
+[Haskell]: /langs/haskell
+[JavaScript]: /langs/javascript
+[Julia]: /langs/julia
+[Kotlin]: /langs/kotlin
+[Lisp]: /langs/lisp
+[Lua]: /langs/lua
+[Pony]: /langs/pony
+[Python]: /langs/python
+[Ruby]: /langs/ruby
+[Rust]: /langs/rust
+[Scala]: /tools/scala-native
+
+[Clang]: /tools/clang
+[LLVM]: /tools/llvm
+
+[API]: /tags/api
+[Asembler]: /tags/assembler
+[AST]: /tags/ast
+[CLI]: /tags/cli
+[Interpreter]: /tags/interpreter
+[Kod bajtowy]: /tags/bytecode
+[Kompilator]: /tags/compiler
+[leksera]: /tags/lexer
+[parsera]: /tags/parser
+
+[rms]: https://pl.wikipedia.org/wiki/Richard_Stallman
+
+[polecenia standalone]: http://llvm.org/docs/CommandGuide/
+[llvm-as]: http://llvm.org/docs/CommandGuide/llvm-as.html
+[llvm-dis]: http://llvm.org/docs/CommandGuide/llvm-dis.html
+[opt]: http://llvm.org/docs/CommandGuide/opt.html
+[llc]: http://llvm.org/docs/CommandGuide/llc.html
+[lli]: http://llvm.org/docs/CommandGuide/lli.html
diff --git a/_collections/_posts/2019-05-15-slogging.md b/_collections/_posts/2019-05-15-slogging.md
new file mode 100644
index 00000000..7a7de69b
--- /dev/null
+++ b/_collections/_posts/2019-05-15-slogging.md
@@ -0,0 +1,251 @@
+---
+title: 'Konfiguracja fabryki loggerów z biblioteki slogging w Scali'
+author: TheKamilAdam
+category: scala-native
+tags: library factory logging native
+langs: scala
+tools: docker jvm node-js scala-js scala-jvm scala-native
+libs: slogging logback
+redirect_from:
+ - slogging
+ - scala-native/slogging
+ - resentiment/slogging
+ - konfiguracja-fabryki-slogging
+ - resentiment/konfiguracja-fabryki-slogging
+ - resentiment/2019/05/15/konfiguracja-fabryki-slogging.html
+---
+
+W poście
+**[Biblioteki do logowania dla języka Scala](/biblioteki-do-logowania)**
+skonfigurowałem logger **[slogging]**.
+Zapomniałem tylko wybrać fabrykę loggerów.
+Bez tego logger w ogóle nie działa.
+
+Przy okazji, tu rodzi się pytanie-zagadka "jak przetestować loggera w testach jednostkowych"?
+
+## Rozwiązanie uniwersalne
+Uniwersalną fabryką loggerów jest `PrintLoggerFactory`.
+Działa ona dla wszystkich platform docelowych.
+Jej działanie jest oparte na metodzie/funkcji/procedurerze `println`.
+
+Do pliku `build.sbt` dodajemy zależność i ustawiamy wersję biblioteki :
+```scala
+val SloggingVersion = "0.6.1"
+// ...
+val SharedSettings = Seq(
+ // ...
+ libraryDependencies ++= Seq(
+ "biz.enef" %%% "slogging" % SloggingVersion,
+ ),
+)
+```
+
+A w pliku `Main.scala` ustawiamy `PrintLoggerFactory` jako implementację:
+```scala
+package pl.writeonly.re.main
+
+import pl.writeonly.re.shared.core.Core
+import slogging._
+
+object Main extends App {
+ LoggerConfig.factory = PrintLoggerFactory()
+
+ LoggerConfig.level = LogLevel.TRACE
+ Core.apply("Goodbye to the World")
+}
+```
+Wszystko działa i można by zakończyć na tym artykuł.
+Zwłaszcza jeśli dockeryzujemy swoją aplikację
+i kto inny zajmuje się zapisywaniem logów do plików i baz danych.
+Jeśli jednak nasza aplikacja ma działać poza dockerem przydatne mogą być bardziej zaawanasowane funkcjonalności loggera.
+
+## Rozwiązania dedykowane dla platformy
+Aktualnie język **[Scala]**
+można [kompilować skrośnie](/przenosna-scala) (ang. *cross compiler*) na trzy platformy
+**[JVM](/tools/scala-jvm)**, **[JS](/tools/scala-js)** i **[Native](/tools/scala-native)**
+Każda z platform posiada inne możliwości konfiguracyjne loggera.
+
+### Scala JVM
+
+Dla platformy **[JVM]** nie ma dużego wyboru.
+Jest jedna dedykowana fabryka `SLF4JLoggerFactory`.
+Jest ona opakowaniem [slf4j](https://www.slf4j.org/),
+dzięki czemu możemy wybrać dowolny logger implementujący tą fasadę.
+Ja wybrałem *[logback](https://logback.qos.ch/)*.
+
+Do pliku `build.sbt` dodajemy zależności:
+```scala
+val jvmSettings = Seq(
+ // ...
+ libraryDependencies ++= Seq(
+ "biz.enef" %% "slogging-slf4j" % SloggingVersion,
+ "ch.qos.logback" % "logback-classic" % "1.2.3",
+ ),
+)
+```
+
+A w pliku `Main.scala` ustawiamy `PrintLoggerFactory` jako implementację:
+```scala
+package pl.writeonly.re.main
+
+import pl.writeonly.re.shared.core.Core
+import slogging._
+
+object Main extends App {
+ LoggerConfig.factory = SLF4JLoggerFactory()
+
+ LoggerConfig.level = LogLevel.TRACE
+ Core.apply("JVM")
+}
+```
+
+I uruchamiamy projekt w **[Scala JVM]** za pomocą polecenia:
+```bash
+sbt clean reJVM/run
+```
+
+Warto przeczytać jeszcze [sposób konfiguracji loggera logback](https://logback.qos.ch/manual/configuration.html).
+
+### Scala.js
+
+Jeśli używamy **[transpilatora]** **[Scala.js]**
+to mamy do wyboru trzy możliwości :
+* `ConsoleLoggerFactory` - podobny do `PrintLoggerFactory`, ale używa `console.log()` zamiast `println()`.
+* `WinstonLoggerFactory` - opakowanie wokół biblioteki do logowania `winston` dla **[Node.js]**.
+* `HttpLoggerFactory` - ten backend wysyła komunikaty dziennika do serwera HTTP za pośrednictwem żądań POST Ajax.
+Należy zauważyć,
+że ta sama zasada pochodzenia zazwyczaj wymaga,
+aby serwer,
+do którego wysyłane są komunikaty,
+był tym samym serwerem,
+z którego załadowano źródło javascript.
+
+Ja chcę zbudować aplikację konsolową **[CLI]**, więc wybierałem `ConsoleLoggerFactory`.
+
+Do pliku `build.sbt` dodajemy... nic:
+```scala
+val jsSettings = Seq(
+ // ...
+// scalaJSModuleKind := ModuleKind.CommonJSModule,
+ libraryDependencies ++= Seq(
+// "biz.enef" %%% "slogging-winston" % SloggingVersion,
+// "biz.enef" %%% "slogging-http" % SloggingVersion,
+ ),
+)
+```
+Gdybyśmy wybrali `WinstonLoggerFactory` musielibyśmy:
+* dodać `"biz.enef" %%% "slogging-winston" % SloggingVersion` do zależności
+* ustawić `scalaJSModuleKind := ModuleKind.CommonJSModule`
+
+Gdybyśmy wybrali `HttpLoggerFactory` musielibyśmy dodać `"biz.enef" %%% "slogging-http" % SloggingVersion` do zależności.
+
+A w pliku `Main.scala` ustawiamy `ConsoleLoggerFactory` jako implementację:
+```scala
+package pl.writeonly.re.main
+
+import pl.writeonly.re.shared.core.Core
+import slogging._
+
+object Main extends JSApp {
+ override def main(): Unit = {
+ LoggerConfig.factory = ConsoleLoggerFactory()
+
+ LoggerConfig.level = LogLevel.TRACE
+ Core.apply("JS")
+ }
+}
+```
+
+I uruchamiamy projekt w **[Scala.js]** za pomocą polecenia:
+```bash
+sbt clean reJS/run
+```
+
+### Scala Native
+
+Jeśli używamy **[kompilatora]** **[Scala Native]**
+to mamy do wyboru trzy możliwości :
+* `TerminalLoggerFactory` - rejestruje wszystkie komunikaty na `stderr` za pomocą `fprintf()`.
+Komunikaty są zawarte w kodach kontrolnych terminala ANSI, które można skonfigurować oddzielnie dla każdego poziomu.
+Dzięki czemu możemy mieć tęczowe logi.
+* `GLibLoggerFactory` - ten backend używa *[GLib's g_log()]()*
+do rejestrowania wiadomości, np. do użytku z *[skalan-gtk]()*.
+* `SyslogLoggerFactory` - ten backend używa standardowego narzędzia `syslog`.
+
+Ja chcę zbudować aplikację konsolową **[CLI]**, więc wybierałem `TerminalLoggerFactory`.
+
+W pliku `build.sbt` dodajemy... nic:
+```scala
+val nativeSettings = Seq(
+ // ...
+ // nativeLinkingOptions += "-lglib-2.0",
+ libraryDependencies ++= Seq(
+ // "biz.enef" %%% "slogging-glib" % SloggingVersion,
+ // "biz.enef" %%% "slogging-syslog" % SloggingVersion,
+ ),
+)
+```
+Gdybyśmy wybrali `GLibLoggerFactory` to musielibyśmy:
+* dodać do zależności `"biz.enef" %%% "slogging-glib" % SloggingVersion,`
+* ustawiamu opcję kompilatora `nativeLinkStubs := true`
+
+Gdybyśmy wybrali `SyslogLoggerFactory` musielibyśmy dodać `"biz.enef" %%% "slogging-syslog" % SloggingVersion` do zależności.
+
+A w pliku `Main.scala` ustawiamy `TerminalLoggerFactory` jako implementację:
+```scala
+package pl.writeonly.re.main
+
+import pl.writeonly.re.shared.core._
+import slogging._
+import slogging.TerminalLoggerFactory.TerminalControlCode
+
+object Main extends App {
+ LoggerConfig.factory = TerminalLoggerFactory()
+ TerminalLoggerFactory.infoCode = TerminalControlCode.green
+ TerminalLoggerFactory.debugCode = TerminalControlCode.cyan
+ TerminalLoggerFactory.traceCode = TerminalControlCode.blue
+
+ LoggerConfig.level = LogLevel.TRACE
+ Core.apply("Native")
+
+ StrictLoggingCore.rainbow()
+}
+```
+
+Implementacja metody `StrictLoggingCore.rainbow()` to:
+```scala
+ def rainbow(): Unit = {
+ logger.error("rainbow error")
+ logger.warn("rainbow warn")
+ logger.info("rainbow info")
+ logger.debug("rainbow debug")
+ logger.trace("rainbow trace")
+ }
+```
+
+Uruchamiamy projekt w **[Scala Native]** za pomocą polecenia:
+```bash
+sbt clean re/run
+```
+
+I oglądamy tęczę XD
+
+## Podsumowanie i wnioski
+Kod jest dostępny pod adresem [resentiment]().
+Co do wniosków to:
+* warto czytać dokumentację
+* trudno testować logowanie
+
+[Scala]: /langs/scala
+
+[JVM]: /tools/jvm
+[kompilatora]: /tags/compiler
+[Node.js]: /tools/node-js
+[Scala JVM]: /tools/scala-jvm
+[Scala Native]: /tools/scala-native
+[Scala.js]: /tools/scala-js
+
+[slogging]: /libs/slogging
+
+[CLI]: /tags/cli
+[transpilatora]: /tags/transpiler
diff --git a/_collections/_posts/2019-05-22-czy-nadaje-sie-na-programiste.md b/_collections/_posts/2019-05-22-czy-nadaje-sie-na-programiste.md
new file mode 100644
index 00000000..8be81917
--- /dev/null
+++ b/_collections/_posts/2019-05-22-czy-nadaje-sie-na-programiste.md
@@ -0,0 +1,210 @@
+---
+title: 'Czy nadaję się na programistę? Inne możliwości w IT'
+author: TheKamilAdam
+category: thoughts
+tags: blog api gui
+langs: perl python ruby
+tools: bash
+redirect_from:
+ - czy-nadaje-sie-na-programiste
+ - thoughts/czy-nadaje-sie-na-programiste
+ - thoughts/2019/05/22/czy-nadaje-sie-na-programiste.html
+---
+
+Wiele osób pyta "Czy nadaję się na programistę?".
+Złośliwi mówią,
+że jeśli się pytacie,
+zamiast siedzieć w piwnicy i rozwiązywać tutoriale z programowania,
+ewentualnie dopytywać się co jeszcze się nauczyć,
+to niestety się nie nadajecie.
+Niezłośliwi podają [Test na programistę]().
+
+Ale niezależnie od wyniku testu nie przejmujcie się!
+W IT istnieje wiele innych dobrze płatnych stanowisk,
+na które często o wiele łatwiej się dostać,
+więc nic straconego.
+
+Zanim omówimy pozostałe często występujące stanowiska w typowej firmie IT jeszcze jedno ważne wprowadzenie.
+Czyli fałszywi przyjaciele języka angielskiego `engineer != inżynier`:
+* angielskie *engineer* oznacza po polsku *technika*
+* najbliższym odpowiednikiem polskiego
+*inżynier (w znaczeniu tytułu zawodowego)*
+jest
+*[Bachelor of Science]()*
+czyli dosłownie *licencjat techniczny*.
+Tak przynajmniej mam w angielskojęzycznym odpisie dyplomu.
+
+Podsumowując, żeby pracować na stanowisku *cośtam engineer* nie trzeba mieć skończonych studiów technicznych,
+ani jakichkolwiek innych.
+
+### Zespół do spraw rozwoju produktu
+
+**Zespoł ds. rozwoju** (ang. *Developer Team*) jest rdzeniem firmy wytwarzającej oprogramowanie.
+Bywa nazywany *Zespołem deweloperski* chociaż nie wszystkie osoby wewnątrz tego zespołu to *deweloperzy*
+oraz *zespołem technicznym* chociaż nie wszystkie osoby wewnątrz tego zespołu są techniczne.
+
+Zespół ten jest odpowiedzialny za wytworzenie produktu,
+czyli oprogramowania,
+które zostanie sprzedane klientowi.
+Klasyczny zespoł ds. rozwoju składa się z trzech rodzajów stanowisk:
+* Analityk biznesowy
+* Tester
+* Programista
+
+#### Analityk biznesowy
+**Analityk biznesowy** (ang. *Business Analyst*, *BA*)
+jest to osoba która zamienia *słowno-muzyczny* opis dostarczony przez klienta *jak ma działać aplikacja* na **Historyjki** (ang. *Stories*).
+Historyjki te są zwykle umieszczane w Jirze lub innym narzędziu do zarządzania zadaniami oraz są podstawą do dalszych prac pozostałej części zespołu.
+
+#### Tester
+
+**Tester** na podstawie historyjek opracowanych przez *Analityka biznesowego* przygotowuje **Przypadki testowe** (ang. *Test Cases*).
+Różnica między *historyjką* a *przypadkiem testowym* polega na tym, że *historyjka* opisuje funkcjonalność ogólnie bez podania poszczególnych parametrów,
+a *przypadek testowy* zawiera konkretne parametry (przypadki brzegowe, klasy równoważności).
+Tak więc jedna *historyjka* może wygenerować wiele *przypadków testowych*.
+
+Ogólnie *testerzy* dzielą się na dwie grupy:
+* *Software Quality Control Engineer* - szuka błędów w istniejącym oprogramowaniu,
+zwykle *manualnie*,
+czyli klikając po aplikacji.
+Dlatego często nazywani są *testerami manualnymi* lub *klikaczami*.
+Z racji tego,
+że umiejętność klikania posiada prawie każdy stanowisko testera manualnego jest często polecane dla osób które chcą rozpocząć pracę w IT.
+* *Software Quality Assurance Engineer* (w skrócie *QA Engineer*) - osoba zapewniająca jakość oprogramowania,
+zwykle poprzez pisanie **automatycznych testów akceptacyjnych** na podstawie *przypadków testowych*.
+Dlatego często nazywani są *testerami automatycznymi*
+
+Oczywiście istnieją stanowiska łączące obie funkcje.
+Np. najważniejsze funkcjonalności systemu posiadają testy automatyczne,
+a reszta systemu jest przeklikiwana ręcznie.
+
+Co ciekawe umiejętność pisania dobrych przypadków testowych potrafi być wyżej ceniona niż umiejętność pisania testów akceptacyjnych.
+
+Czasem w ofertach pracy pojawia się stanowisko **Programista testów automatycznych/akceptacyjnych**,
+które *de facto* oznacza *QA Engineer*.
+Skąd taka nazwa?
+Otóż jest to optymalizacja podatkowa polegająca na tym,
+że bycie programistą pozwala na stosowanie podwyższonego kosztu uzyskania przychodu, a testerem - nie.
+
+#### Programista
+
+**Programista** (ang. *Software Developer* lub żargonowo *deweloper*) tworzy kod oprogramowania na podstawie *historyjek* dostarczonych przez analityków biznesowych.
+
+*Programista* bywa nazywany w różny sposób:
+* **Programista** - taki zwykły
+* **Koder** - można powiedzieć, że pojęcie to jest już archaiczne i przestarzałe.
+Prawdopodobnie pochodzi z czasów,
+gdy program trzeba było najpierw napisać na kartce,
+a potem zakodować na kartach perforowanych.
+Obecnie jest używane też jako określenie obraźliwe na *klepacza kodu*,
+programistę, który tylko koduje, a nie myśli.
+* **Inżynier oprogramowania** (ang. *Software Engineer*) - lepszy programista.
+Wręcz *programista++*.
+Od zwykłego programisty różni się tym, że zna się także na inżynierii wytwarzania oprogramowania,
+co w wielu wypadkach oznaczało,
+że wykuł UMLa i umie rozmawiać z klientem.
+Jak pisałem wcześniej, nie trzeba być inżynierem, żeby być *engineer*.
+* **Architekt oprogramowania** (ang. *Software Architect*) - lepszy inżynier oprogramowania,
+zna się także na architekturze.
+W realnym życiu można spotkać dwa typy architektów.
+ * programujący architekt - programista tak dobry, że nie można mu było dać więcej pieniędzy,
+więc dano mu tytuł,
+dzięki czemu ma szacun na dzielni.
+ * nie programujący architekt - dziwny osobnik, który kiedyś był programistą,
+a dziś prawdopodobnie odleciał wysoko i daleko od kodu. Rysuje dzidy w UMLu i programiści go nienawidzą.
+
+#### Mistrz młyna
+
+**Mistrz młyna** (ang. *Scrum Master*, *SM*) nie jest osobą należącą do *zespołu ds. rozwoju*,
+ale odpowiadającą za poprawny przepływ pracy w zespole i uczestniczy we wszystkich spotkaniach tego zespołu.
+Stanowisko to jest prawdopodobnie najlepiej płatne z nietechnicznych i niekierowniczych stanowisk.
+Jednocześnie *SM* jest najbardziej znienawidzoną osobą w zespole/firmie
+i bywa nazywany **B**ardzo **D**zielnym **S**crum **M**asterem.
+Na *Scrum Mastera* są robione szkolenia.
+
+### Właściciel produktu, Kierownik projektu
+
+**Właściciel produktu** (ang. *Product Owner*, *PO*) jest to osoba spoza teamu developerskiego,
+która jest adwokatem klienta.
+To ona dostarcza opisów *słowno-muzycznych* jak powinna działać aplikacja,
+które później starają się zrozumieć analitycy biznesowi.
+Powinna bardzo dobrze znać dziedzinę biznesu dla której powstaje oprogramowanie,
+żeby móc wyjaśnić *co klient miał na myśli*.
+W przeciwnym wypadku staje się tylko niepotrzebnym pośrednikiem między klientem a *zespołem ds. rozwoju produktu*.
+
+Czasem zamiast lub obok *PO* jest jeszcze **Kierownik projektu** (ang. *Project Manager*, *PM*).
+Zwykle w firmach typu korpo o niepłaskiej hierarchii.
+Jako że jest to stanowisko kierownicze, zwykle trzeba na niego awansować z stanowiska analityka, testera lub programisty.
+O takiej osobie mówi się później
+"10 lat pracował jako programista i nie nauczył się programować, więc został awansowany na PM".
+
+### Wdrożenie aplikacji
+Gdy aplikacja zostanie już napisana trzeba wdrożyć ją u klienta.
+
+Najmniej techniczną osobą pracującą przy wdrożeniu jest *Wdrożeniowiec* lub *Konsultant-Wdrożeniowiec*.
+Jego zadaniem jest jechać do klienta na delegację
+i wdrażać przyszłych użytkowników w działanie aplikacji prowadząc im szkolenia.
+Powinna być to osoba która ma dobry kontakt z ludźmi i umie przekazywać wiedzę.
+Wdrożeniem samej aplikacji zajmują się dwa kolejne stanowiska:
+* **SysOps Engineer** (ang. *Systems Operations Engineer*) kiedyś nazywany *SysAdmin* (ang. *Systems Administration*) -
+wdraża *manualnie*, albo klikając po aplikacjach, albo wpisując polecenia w terminalu, czasem pisząc skrypty w **[Bashu](/tools/bash )**.
+* **DevOps Engineer** (ang. *Development and Operations*) często zwany także *Cloud Engineer* jeśli pracuje z chmurą -
+wdraża automatycznie za pomocą skryptów w **[Bashu]**, **[Perlu]**, **[Pythonie]**, **[Ruby]** lub innym języku skryptowym.
+
+W uproszczeniu różnica między *SysOps Engineer* a *DevOps Engineer* jest taka jak między *Testerem manualnym* a *Testerem automatycznym*.
+W ostatnim czasie spada zapotrzebowanie na *SysOps Engineerów* a rośnie na *DevOps Engineerów*,
+ponieważ z jednej strony aplikacje składają się z coraz większej liczby modułów,
+a z drugiej coraz częściej są wydawane nowe wersja.
+Samo pojęcie *DevOps* nawiązuje do tego że dział wdrażający oprogramowanie (*Operations*)
+powinien ściśle współpracować z działem rozwoju oprogramowania (*Development*).
+Co jednak nie zawsze jest możliwe, np. dlatego że klient posiada swój własny dział wdrożeniowy.
+
+### Dokumentalista, Dokumentalista techniczny
+Gdy aplikacja jest już wdrożona,
+prawdopodobnie będzie przekazywana z jakąś **dokumentacją**.
+Dokumentację tę ktoś musi napisać i często w tym celu zatrudnia się osobne osoby,
+czyli **dokumentalistów**.
+
+Osobną kategorią jest **dokumentacja techniczna**, pisana przez **dokumentalistów technicznych**.
+Pod tą nazwą kryją się co najmniej dwa rodzaje dokumentacji:
+* Dokumentacja kierowana do *SysOpsów* i *DevOpsów* opisująca jak zainstalować aplikację.
+* Dokumentacja opisująca zewnętrzne **[API]** aplikacji skierowana do Testerów i Programistów
+
+Co ciekawe, często w ramach oszczędności, jest ona pisana także przez osoby nietechniczne.
+
+### UI Designer i UX Designer
+
+W teorii **UI Designer** rysuje jak ma wyglącać graficzny interfejs użytkownika (ang. *graphical user interface*, **[GUI]**),
+a *UX Designer* - jak ma się zachowywać.
+W praktyce wiele zależy od firmy.
+Często jest to stanowisko łączone, czyli *UI/UX Designer*.
+Czasem *UI/UX Designer* pracuje tylko w programach graficznych,
+a w innych firmach dostarcza też pliki *.CSS oraz przykłady plików *.HTML
+Trudno powiedzieć, ale na pewno żeby pracować na tym stanowisku trzeba wiedzieć co jest ładne a co brzydkie.
+### Sprzedawca i Marketingowiec
+Sprzedawcy i Marketingowcy będą potrzebni zawsze.
+Wiele startupów informatycznych upadło ponieważ ich prezesi uważali,
+że wystarczy stworzyć świetny produkt,
+ale nie umieli go sprzedać,
+bo nie mieli sprzedawców.
+Dokładnie nie wiadomo ile,
+bo nie mieli też marketingowców i nikt się o nich nie dowiedział.
+
+## Podsumowanie
+
+Podsumowując nietechniczne stanowiska w typowej firmie IT na które najłatwiej aplikować to:
+* Analityk biznesowy - w zasadzie nie wiem co trzeba umieć żeby zostać BA
+* Tester - ale często chcą studia techniczne na to stanowisko
+* Scrum Master - potrzebne jest szkolenie i twarda psychika
+* Product Owner - ale trzeba znać dziedzinę biznesową oprogramowania
+* Dokumentalista - umiejętność Worda
+* UI/UX Designer - trzeba mieć zmysł artystyczny
+* Sprzedawca i Marketingowiec - tak samo jak wszędzie, IT nie jest tu w żaden sposób wyjątkowe.
+
+[Perlu]: /langs/perl
+[Pythonie]: /langs/python
+[Ruby]: /langs/ruby
+
+[Bashu]: /tools/bash
+[API]: /tags/api
+[GUI]: /tags/gui
\ No newline at end of file
diff --git a/_collections/_posts/2019-05-29-logback.md b/_collections/_posts/2019-05-29-logback.md
new file mode 100644
index 00000000..0f9469ec
--- /dev/null
+++ b/_collections/_posts/2019-05-29-logback.md
@@ -0,0 +1,148 @@
+---
+title: 'Biblioteki do logowania dla języka Java i platformy JVM'
+author: TheKamilAdam
+category: scala-native
+tags: api gui interface library logging properties xml
+labels: adapter design-pattern facade
+langs: java rust scala
+tools: docker jvm
+libs: logback
+redirect_from:
+ - logback
+ - scala-native/logback
+ - resentiment/logback
+ - resentiment/2019/05/29/logback.html
+---
+
+W artykule *[Konfiguracja fabryki loggerów z biblioteki Slogging w Scali](/slogging)*
+autorytarnie stwierdziłem,
+że **[Logback]** dla **[JVM]** jest najlepszym silnikiem do logowania.
+Czytając artykuł
+[Programowanie w Rust: The Good, The Bad and The Ugly]()
+zszokowała mnie informacja,
+że programista nie wie która biblioteka logowania dla **[Javy]** jest najlepsza.
+Prawdziwa klęska urodzaju.
+I programista nie wie co wybrać
+
+## Opowieść w pięciu aktach o najlepszym rejestratorze logów dla Javy
+To jest opowieść o bohaterze Ceki Gülcü i jego drużynie,
+którzy razem wyruszyli pokonać chaos,
+a spotkali hydrę standaryzacji oraz smoka.
+W roli smoka - *Apache Software Foundation* (*ASF*)
+
+### Prolog - `System.out` i `System.err`
+Na początku był chaos.
+Dedykowane rejestratory logów jeszcze nie istniały.
+Aplikacje logowały do `System.out` (informacje) oraz `System.err` (błędy)
+W aplikacjach konsolowych **[CLI]** oraz z **[GUI]** to jest złe.
+W aplikacjach serwerowych też.
+Chyba że używa się **[Dockera]**.
+Wtedy wszystkie logi i tak są wyrzucane na standardowe wyjście.
+Ale Dockera jeszcze nie wymyślono.
+Problemem była też mała ilość poziomów logowania,
+brak możliwości zapisu logów do pliku i bazy danych oraz to,
+że `System.out` buforuje wyjście.
+
+### Akt pierwszy: rok 1999 - Apache Log4j (Log4j)
+Powstaje pierwszy popularny silnik logowania [Apache Log4j]( ).
+Stworzony pod dowództwem naszego bohatera.
+Początkowo biblioteka zwana jest *Log4j*,
+a później *Apache Log4j*,
+gdy smok *ASF* przejmuje opiekę nad nią.
+
+Posiada sześć poziomów logowania (`TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR` i `FATAL`) oraz
+możliwość konfigurowania poziomów logowania programowo,
+plikami **[XML]**
+lub plikami **[properties]**.
+Konfiguracja jest hierarchiczna i dla każdego pakietu, a nawet klasy, może być inna.
+Dodatkowo można zdefiniować wiele wyjść logów.
+Tzn. można jednocześnie logować do wiersza poleceń, pliku oraz bazy danych.
+Oczywiście z różnymi poziomami logowania dla różnych pakietów i klas.
+
+Chaos pokonany.
+Problem rozwiązany.
+Żyć nie umierać.
+
+### Akt drugi: rok 2002 - `java.util.logging` (JUL)
+Po trzech latach spokoju,
+hydra standaryzacji podnosi głowy
+i do Javy 1.4 zostaje dodany domyślny silnik logowania zwana *JUL*.
+Nazwa pochodzi od pakietu `java.util.logging`,
+w którym się znajduje.
+Posiada mniejsze możliwości niż *Log4j*,
+ale ponieważ znajduje się w standardowej bibliotece **[Javy]**,
+zyskuje sobie zwolenników.
+
+Zaczynają się problemy.
+
+### Akt trzeci: rok 2002 - Jakarta Commons Logging (JCL)
+
+Istnienie dwóch dobrych silników logowania narodziło problem.
+Niektóre biblioteki zależne używały *Log4j*,
+a inne *JUL*.
+Rozwiązaniem miała być wspólna fasada logowania -
+[Jakarta Commons Logging]( ).
+Ponieważ ładowała silniki logowania przez `classloader` powodowała często więcej problemów niż rozwiązywała.
+
+### Akt czwarty: rok 2005 - Simple Logging Facade for Java (SLF4J)
+Po trzech latach niekończących się problemów z *JCL* do akcji ponownie wkracza bohater.
+Powstaje kolejna wspólna fasada logowania [Simple Logging Facade for Java]( ).
+Tym razem stworzona przez naszego bohatera i jego dzielną drużynę.
+Bohater rozwiązał problem ładowania silnika logowania w banalnie prosty sposób.
+W danej aplikacji może istnieć tylko jedna implementacja fasady.
+Wystarczy, że znajduje się w ścieżce przeszukiwania (ang. *classpath*) podczas uruchomienia aplikacji.
+Dzięki takiemu pomysłowi rozwiązano problemy czasu uruchomienia (ang. *runtime*),
+które występowały dla *JCL*.
+
+*SLF4J* posiada wiele bindingów,
+będących adapterami istniejących interfejsów silników logowania do interfejsu *SLF4J*:
+* `slf4j-log4j12` dla *Log4j* w wersji 1.2
+* `slf4j-jdk14` dla *JUL*
+* `slf4j-jcl` dla *JCL*
+* `slf4j-simple` dla `System.err`
+* `slf4j-nop` - domyślna implementacja, która nic nie robi
+
+Część bibliotek samodzielnie dostarcza binding jak np. *Log4j* w wersji 2.
+
+Dzięki temu biblioteki zależne używają tylko *SLF4J*,
+a twórca aplikacji może zdecydować samodzielnie,
+który rejestrator logów użyje.
+
+### Akt piąty: rok 2006 - Logback
+
+Wydawać by się mogło,
+że wszystkie problemy zostały już rozwiązanie.
+Bohatera dręczyło jednak to,
+że utrzymuje trzy biblioteki dla rozwiązania polecanego przez siebie,
+czyli:
+* interfejs fasady do logowania - `slf4j-api`
+* silnik logowania - `log4j`
+* binding - `slf4j-log4j12`, zmianiający interfejs `log4j` do interfejsu `slf4j-api`
+
+Postanowił więc on połączyć silnik logowania z bindingiem.
+Tak powstał [Logback]( ).
+Nie posiada on własnego interfejsu i implementuje tylko i wyłącznie interfejs `slf4j-api`.
+Jest nowym kodem napisanym od początku i jednocześnie naprawia błędy istniejące w `log4j`,
+jak np. brak posiadania domyślnej konfiguracji.
+
+A dlaczego pod inną nazwą?
+Ponieważ smok *ASF* sprawuje kontrolę nad silnikiem *Log4j*.
+
+### Epilog
+
+Jest rok 2019.
+Nadal istnieją programiści,
+którzy nie potrafią wybrać właściwego rejestratora logów dla **[Javy]**.
+To smutne.
+
+[Javy]: /langs/java
+
+[Dockera]: /tools/docker
+[JVM]: /tools/jvm
+
+[Logback]: /libs/logback
+
+[CLI]: /tags/cli
+[GUI]: /tags/gui
+[properties]: /tags/properties
+[XML]: /tags/xml
diff --git a/_collections/_posts/2019-06-05-fun-miners-programownnie-funkcyjne-dla-kazdego.md b/_collections/_posts/2019-06-05-fun-miners-programownnie-funkcyjne-dla-kazdego.md
new file mode 100644
index 00000000..1e794699
--- /dev/null
+++ b/_collections/_posts/2019-06-05-fun-miners-programownnie-funkcyjne-dla-kazdego.md
@@ -0,0 +1,103 @@
+---
+title: 'Functional Miners - Programowanie Funkcyjne dla Każdego'
+author: TheKamilAdam
+category: relationships
+tags: compiler interpreter lambda-calculus monad monoid transpiler
+labels: brainfuck subleq
+langs: elixir clojure scala java haskell
+redirect_from:
+ - programownnie-funkcyjne-dla-kazdego
+ - relationships/programownnie-funkcyjne-dla-kazdego
+ - fun-miners-programownnie-funkcyjne-dla-kazdego
+ - relationships/fun-miners-programownnie-funkcyjne-dla-kazdego
+ - relationships/2019/06/05/fun-miners-programownnie-funkcyjne-dla-kazdego.html
+---
+
+2019-05-21 odbyło się spotkanie *Functional Miners* (@fun_miners)
+w *HackerSpace Silesia* (@hs_silesia)
+o tematyce *Programowanie Funkcyjne dla Każdego*.
+Wydarzyły się dwie prezentacje:
+* Wojciech Gawroński - Functional Programming in the Wild
+* Andrzej Spiess - From \x.x to Facebook - Introduction to Lambda Calculus
+
+## Wojciech Gawroński - Functional Programming in the Wild
+
+Wojtek (@afronski) przygotował [prezentację]()
+próbującą przekonać,
+że deklaratywne programowanie czysto funkcyjne jest lepsze od imperatywnego.
+Było to o tyle łatwe,
+że na spotkanie przyszli tylko fani programowania funkcyjnego.
+Dla mnie,
+głównym wnioskiem z prezentacji jest to,
+że nie należy w prezentacji umieszczać żadnych skomplikowanych definicji matematycznych,
+np. **[monad]**.
+Zwłaszcza jeśli są to pierwsze dwa slajdy.
+Nawet jeśli jest to tylko żart.
+
+Pozwólcie, że powtórzę: **nie należy ludziom pokazywać matematycznej definicji monady**, bo uciekną.
+
+W prezentacji Wojtek stara się odpowiedzieć na pytania:
+* Dlaczego uczyć się funkcyjnych języków programowania?
+ * Bo jest totalnie inne od programowania imperatywnego, więc ćwiczy nasz mózg
+ * Bo jest przejrzystrze, więc trudniej popełnić błąd
+* Z czego składa się funkcyjny język programowania?
+ * *Patern Maching* - dopasowywanie do wzorca
+ * *Macros* - prawdziwe makra,
+takie jak są w językach **[Elixir]**, **[Clojure]** lub **[Scala]**
+* *Correctness* - *poprawność*, święty graal matematyków-programistów,
+ która miała pozwolić na automatyczne stwierdzać poprawność programu
+ * *Immutability* - *niezmienność*, zmienne są stałymi,
+ referencje są finalne,
+ wartości są niemodyfikowalne
+ * *Referential Transparency* - *reguła podstawienia*,
+wywołanie funkcji zawsze można zamienić na wartość przez nią zwracaną,
+ nie używa się efektów ubocznych
+* *Advanced Type Systems* - *zaawansowane systemy typów*,
+ o wiele bardziej rozbudowany parametryczny polimorfizm
+* Jak uczyć się funkcyjnego języka programowania?
+ * Warto mieć jeden mały programik,
+ trochę większy niż *Hello Wolrd* i implementować go w wielu językach.
+Np **[interpreter]**, **[transpilator]** lub **[kompilator]** ezoterycznego języka Brainfuck
+
+Oprócz tego Wojtek rozprawiał się z mitami na temat programowania funkcyjnego,
+jak np. to że zasady SOLID stosują się także do funkcji i programowania funkcyjnego i deklaratywnego.
+
+## Andrzej Spiess - From \x.x to Facebook - Introduction to Lambda Calculus
+
+Andrzej (@ninjazoete) przygotował [prezentację]()
+będącą bardzo teoretycznym i historycznym wprowadzeniem do [rachunku lambda].
+
+Najważniesze punkty, które zrozumiałem to:
+* Problemowi stopu z Maszyny Turinga w **[rachunku lambda]** odpowiada problem nieredukowalnych lambd do postaci normalnej.
+* **[Haskell]** jest kompilowany do HSC CORE,
+który składa się 26 rodzajów konstruktorów (rachunek lambda + systemu F + kowersja + parametryczny polimorfizm)
+* W typowanych lambdach problem stopu nie istnieje,
+ale nie da się wyrazić rekurencji,
+więc dodaje się nowe operatory i traci się kompletność w sensie turinga.
+
+Jeśli ktoś chciałby zobaczyć rachunek lambda w bardziej przystępnej formie,
+czyli interaktywnie w języku **[Java]** to polecam prezentacje Jarosława Ratajskiego (@jarek000000):
+* W warszawie - *[WJUG #183 - Lambda Core: Hardcore - Jarosław Ratajski]()*
+* W Łodzi - *[Lambda Core - Hardcore - Jarek Ratajski]()*
+
+Najważniejsza rzecz z tego wykładu to to, że:
+> Wszystko to co robicie da się zrobić czysto funkcyjnie,
+to jest udowodnione przez [Turinga]()
+
+Repozytorium z kodem do analizy lambd - *[Lambda analysis package]()*.
+
+## Podsumowanie
+
+Z niecierpliwością czekam na kolejne wykłady w ramach *Functional Miners* (@fun_miners)
+
+[Clojure]: /langs/clojure
+[Elixir]: /langs/elixir
+[Haskell]: /langs/haskell
+[Java]: /langs/java
+[Scala]: /langs/scala
+
+[kompilator]: /tags/compiler
+[interpreter]: /tags/interpreter
+[rachunku lambda]: /tags/lambda-calculus
+[monad]: /tags/monad
+[transpilator]: /tags/transpiler
diff --git a/_collections/_posts/2019-06-12-jezyk-skryptowy.md b/_collections/_posts/2019-06-12-jezyk-skryptowy.md
new file mode 100644
index 00000000..75c3f0f5
--- /dev/null
+++ b/_collections/_posts/2019-06-12-jezyk-skryptowy.md
@@ -0,0 +1,165 @@
+---
+title: 'Który język programowania wybrać na początek - język skryptowy'
+author: TheKamilAdam
+category: programming
+tags: bdd cst dsl script
+langs: awk clojure common-lisp crystal elixir lisp perl python racket ruby scheme
+tools: bash sed
+redirect_from:
+ - jezyk-skryptowy
+ - programming/jezyk-skryptowy
+ - onions/jezyk-skryptowy
+ - onions/2019/06/12/jezyk-skryptowy.html
+ - onions/2019/06/12/ktory-jezyk-programowania-wybrac-jezyk-skryptowy.html
+---
+
+Wiele osób pyta się,
+**który język programowania wybrać na początek** jako pierwszy język do nauki.
+Wiele jednak zależy od tego do czego chcemy użyć tego języka programowania.
+Dlatego wybrałem zwycięzców w czterech kategoriach:
+1. dynamicznie typowany język skryptowy ogólnego przeznaczenia
+2. [statycznie typowany język korporacyjny używany do pisania długowiecznych aplikacji klasy *enterprise*](/jezyk-korporacyjny)
+3. [fullstack język, który można używać do pisania frontendu i backendu](/jezyk-fullstackowy)
+4. [szybki język natywny działający bez maszyny wirtualnej i interpretera](/jezyk-natywny)
+
+W tym artykule skupię się na zwyciężcy pierwszej kategorii,
+czyli języku skryptowym ogólnego przeznaczenia.
+
+**Ważna uwaga!**
+Artykuł nie jest sponsorowany przez Google,
+mimo że każdy z tych języków jest używany przez Google.
+Nie jest też sponsorowany przez JetBrains.
+Po prostu uważam,
+że JetBrains tworzy najlepsze IDE.
+Jest to tylko mój mały subiektywny ranking języków programowania na rok 2019.
+
+## Język skryptowy ogólnego przeznaczenia - definicja
+[Język skryptowy]() (ang. *script language*)
+powinien być prostym językiem programowania,
+czyli być dynamicznie typowany i mieć prostą składnie.
+Dzięki temu można w nim szybko skryptować, testować, prototypować.
+Łatwo i szybko można go zrozumieć i jest polecany tym którzy *programują, ale nie są programistami*.
+
+Wzorcowy język skryptowy jest idealny dla:
+* eksploratorów danych i naukowców -
+ale tu jest mała gwiazdka,
+bo zwykle pod spodem są biblioteki napisane w szybkim języku natywnym
+* SysAdminów (*SysOps Engenerów*, *DevOpsów Engenerów*) - do pisania skryptów zarządzających i administrujących
+* testerów (*QA Engenerów*) - do pisania testów akceptacyjnych
+* hobbystów - do zabawy i np. oprogramowywania Raspberry Pi
+* programistów:
+ * do [prototypowania]()
+ * pisania małych aplikacji, zwykle webowych
+
+Dużych aplikacji w językach skryptowych się nie pisze,
+bo są trudno utrzymywalne.
+Oczywiście w językach skryptowych powstawały duże aplikacje,
+ale wiele z nich zostało już przepisanych do korpo języków ze statycznym typowaniem.
+
+## Język skryptowy ogólnego przeznaczenia - zwycięzca
+Zwycięzcą w kategorii *język skryptowy* jest **[Python]**.
+Główne przesłanki przemawiające za tym,
+że jest najlepszy to:
+* Język roku 2008, 2010 i 2018 według [Tiobe]
+* Pierwszy język według [IEEE]
+* Darmowe IDE [PyCharm] od JetBrains
+* Jest używany w Google do prototypowania
+* Prosta składnia - niektórzy jednak nie zgadzają się z tym,
+że [składnia Pythona jest prosta]()
+
+Niestety jest też parę minusów:
+* Rakiem,
+który toczy Pythona najbardziej,
+jest problem z wersjami,
+czyli rozłam na wersję 2 oraz wersję 3.
+Powoduje to przymus poznania takich narzędzi jak [pipenv], [pyenv] i [virtualenv].
+Dodatkowo nie pomagają różne implementacje jak [PyPy],
+lub [Stackless Python].
+* Statystyki informujące o wspaniałej przyszłości Pythona dotyczą zbiorczo całego świata.
+A niestety różnica między USA a Europą,
+jeśli chodzi o popularność poszczególnych języków programowania,
+zawsze była duża.
+Różnice są także spore,
+jeśli chodzi o poszczególne miasta w Polsce.
+
+## ... i pokonani
+Python powstał jako konkurencja dla języka **[Perl]** z prostszą składnią.
+**[Perl]** posiadał mocno niespójną i trudną do nauki składnię.
+Wynika to z tego,
+że inspiracją dla Perla były narzędzia **[Bash]**, **[AWK]** i [Sed].
+
+Jednocześnie Python ciągle wygrywa z **[Ruby]**,
+ponieważ ma prostszą składnię i [działa szybciej]().
+Jednak Ruby pozostaje bardzo ciekawym językiem programowania w którym powstały takie rzeczy jak:
+* [Sinatra] - wzorcowy mały framework webowy przeniesiony do wielu innych języków programowania,
+jak np. [Scalatra] lub [Spark]
+* [RoR] - duży framework webowy będący inspiracją dla wielu innych, jak np. [Play Framework] lub [Phoenix]
+* [RSpec] - framework popularyzujący nowy **[DSL]** dla testów,
+zaimplementowany także wielu innych frameworkach testowych jak np. **[ScalaTest]** i **[Specs2]**
+* [Cucumber] - framework do testów akceptacyjnych,
+używany podczas *rozwoju opartego o zachowanie* (ang *behavior-driven development*, **[BDD]**),
+który stał się *de facto* standardem i został przeportowany dla wielu innych języków programowania
+* [Capybara] - narzędzie to testów stron internetowych i aplikacji webowych
+
+Sama składnia języka **[Ruby]** była inspiracją dla języków **[Crystal]** i **[Elixir]**.
+Prawdopodobnych następców powolnego Rubiego.
+
+## Podsumowanie
+Czy warto uczyć się języka skryptowego i Pythona w szczególności?
+Tu nastąpi standardowa odpowiedź w informatyce, *to zależy*.
+* Jeśli chcesz zostać *osobą która programuje, ale nie jest to jej głównych zajęciem* to polecam.
+* Jeśli jednak chcesz zostać programistą to polecam wcześniej przejrzeć oferty pracy
+czy w twojej okolicy jest zapotrzebowanie na ten język programowania.
+**[Python]** jest aktualnie na trzecim miejscu w rankingu [Tiobe],
+ale bardzo możliwe,
+że w twojej okolicy jest więcej ofert na np. programistę języka **[Ruby]**.
+## Postscriptum
+
+Nie lubię języków skryptowych.
+Kiedyś lubiłem Perla, ale wyrosłem.
+Z języków dynamicznie typowanych interesujący dla mnie jest tylko **[Lisp]**
+ze wszystkimi swoimi dialektami (**[Clojure]**, **[Racket]**, **[Scheme]**, **[Common Lisp]**).
+Jest coś szalonego w języku, którego zapis jest od razu jego drzewem **[CST]**.
+
+[AWK]: /langs/awk
+[Clojure]: /langs/clojure
+[Common Lisp]: /langs/common-lisp
+[Crystal]: /langs/crystal
+[Elixir]: /langs/elixir
+[Lisp]: /langs/lisp
+[Perl]: /langs/perl
+[Python]: /langs/python
+[Racket]: /langs/racket
+[Ruby]: /langs/ruby
+[Scheme]: /langs/scheme
+
+[Bash]: /tools/bash
+[ScalaTest]: /libs/scalatest
+[Specs2]: /libs/specs2
+
+[BDD]: /tags/bdd
+[CST]: /tags/cst
+[DSL]: /tags/dsl
+
+[Język skryptowy]: https://pl.wikipedia.org/wiki/J%C4%99zyk_skryptowy
+[Tiobe]: https://www.tiobe.com/tiobe-index/
+
+[IEEE]: https://spectrum.ieee.org/at-work/innovation/the-2018-top-programming-languages
+[PyCharm]: https://www.jetbrains.com/pycharm/
+[virtualenv]: https://pypi.org/project/virtualenv/
+[pipenv]: https://pypi.org/project/pipenv/
+[pyenv]: https://github.com/pyenv/pyenv
+[PyPy]: https://pypy.org/
+[Stackless Python]: https://github.com/stackless-dev/stackless/wiki
+
+[Sed]: https://pl.wikipedia.org/wiki/Sed_(program)
+
+[Sinatra]: https://en.wikipedia.org/wiki/Sinatra_(software)
+[Scalatra]: https://en.wikipedia.org/wiki/Scalatra
+[Spark]: https://en.wikipedia.org/wiki/Spark_(software)
+[RoR]: https://pl.wikipedia.org/wiki/Ruby_on_Rails
+[Play Framework]: https://pl.wikipedia.org/wiki/Play_(framework)
+[Phoenix]: https://en.wikipedia.org/wiki/Phoenix_(web_framework)
+[RSpec]: https://en.wikipedia.org/wiki/RSpec
+[Cucumber]: https://en.wikipedia.org/wiki/Cucumber_(software)
+[Capybara]: https://en.wikipedia.org/wiki/Capybara_(software)
diff --git a/_collections/_posts/2019-06-19-jezyk-korporacyjny.md b/_collections/_posts/2019-06-19-jezyk-korporacyjny.md
new file mode 100644
index 00000000..4e976ae7
--- /dev/null
+++ b/_collections/_posts/2019-06-19-jezyk-korporacyjny.md
@@ -0,0 +1,164 @@
+---
+title: 'Który język programowania wybrać na początek - język korporacyjny'
+author: TheKamilAdam
+category: programming
+langs: java scala kotlin clojure frege eta go python ruby lisp haskell ocaml fsharp
+tools: jvm
+redirect_from:
+ - jezyk-korporacyjny
+ - programming/jezyk-korporacyjny
+ - onions/jezyk-korporacyjny
+ - onions/2019/06/19/jezyk-korporacyjny
+ - onions/2019/06/19/ktory-jezyk-programowania-wybrac-jezyk-korporacyjny.html
+---
+
+Wiele osób pyta się,
+**który język programowania wybrać na początek** jako pierwszy język do nauki.
+Wiele jednak zależy od tego do czego chcemy użyć tego języka programowania.
+Dlatego wybrałem zwycięzców w czterech kategoriach:
+1. [dynamicznie typowany język skryptowy ogólnego przeznaczenia](/jezyk-skryptowy)
+2. statycznie typowany język korporacyjny używany do pisania długowiecznych aplikacji klasy *enterprise*
+3. [fullstack język, który można używać do pisania frontendu i backendu](/jezyk-fullstackowy)
+4. [szybki język natywny działający bez maszyny wirtualnej i interpretera](/jezyk-natywny)
+
+W tym artykule skupię się na zwycięzcy drugiej kategorii,
+czyli statycznie typowanym języku korporacyjnym używanym do pisania długowiecznych aplikacji klasy enterprise.
+Wbrew nazwie języki z tej kategorii są używane nie tylko w korporacjach,
+ale często są przez korpo preferowane.
+
+**Ważna uwaga!**
+Artykuł nie jest sponsorowany przez Google,
+mimo że każdy ze zwycięskich języków jest używany przez Google.
+Nie jest też sponsorowany przez JetBrains.
+Po prostu uważam,
+że JetBrains tworzy najlepsze IDE.
+Jest to tylko mój mały subiektywny ranking języków programowania na rok 2019.
+
+## Język korporacyjny - definicja
+
+Główne cechy dobrego języka korporacyjnego to:
+1. statyczne typowanie - aplikacje będą pisane w nim latami,
+a utrzymywane dziesiątki lat,
+dlatego potrzebne jest by kompilator był jak najbardziej radykalny
+2. bycie daleko od sprzętu - programista powinien jak najmniej zajmować się niskopoziomowymi technikaliami,
+a jak najwięcej uwagi poświęcać na pisanie wysokopoziomowej logiki biznesowek
+3. prosta składnia - bo programistów wciąż brakuje i trzeba cały czas przyuczać nowych
+4. wydajność/skalowalność - często aplikacje klasy enterprise mają dużo klientów naraz,
+więc muszą być wydajne i skalowalne
+
+Co ciekawe 1. kłóci się z 3. a 2. kłóci się z 4.
+Widać więc, że potrzebny jest *zgniły kompromis*.
+
+Kiedyś były dwa główne języki korporacyjne:
+* prosty język Cobol używany dla programów będących daleko od sprzętu
+* skomplikowany język C++ używany dla programów będących blisko sprzętu
+
+## Język korporacyjny - zwycięzca
+
+Była potrzeba na stworzenie języka będącego pomiędzy językami Cobol i C++.
+Tym językiem jest **[Java]**.
+
+Główne zalety pozajęzykowe Javy to:
+* Najbardziej popularny język programowania według [Tiobe]
+* Język roku 2005 i 2015 według [Tiobe]
+* Darmowe IDE *[IntelliJ IDEA]* od JetBrains
+* Główny język używany w Google do pisania aplikacji,
+a przynajmniej do niedawna tak było
+
+Pradopodobnie największą wadą Javy jest to,
+że jej rozwój mocno zamarł po wydaniu Javy 6 przez co inne języki mocno ją przegoniły.
+Co prawda ostatnio nowe wersje wydawane są częściej,
+jednak dodają one mało nowych funkcjonalności.
+Z tego powodu składnia Javy jest niesamowicie rozwlekłą i bywa nazywana barokową,
+tzn. trzeba napisać dużo kodu by osiągnąć ten sam efekt co w nowszych językach programowania.
+
+## Korpo platforma - JVM
+
+Java to nie tylko język,
+ale także platforma **[JVM]** (ang. *Java Virtual Machine*) odcinająca język od sprzątu.
+Java jest kompilowana do *[kodu bajtowego Javy](https://pl.wikipedia.org/wiki/Kod_bajtowy_Javy)*
+(and. *Java bytecode*),
+który jest następnie wykonywany przez JVM,
+a dokładniej przez **JRE** (ang. *Java Runtime Environment*).
+Do kodu bajtowego Javy są też kompilowane inne języki programowania,
+które w łatwy i przyjazny sposób można integrować z Javą.
+Języki te posiadają o wiele zwięźlejszą składnie i można je podzielić z grubsza na trzy kategorie:
+* Nowe języki programowania:
+ * **[Scala]** - wielki worek na *feature'y*,
+dzięki czemu w Scali da się zaimplementować wszystkie paradygmaty programowania
+ * **[Kotlin]** - Scala-- plus pare innych *feature'ów*,
+zdrowy kompromis między *wszystkomaniem* Scali i prostotą Javy,
+ale powoli zmierza do języka w którym także można używać wszystkich paradygmatów programowania
+ * **Groovy** - skryptowy język oparty składniowo o Javę.
+W skrócie *Java z opcjonalnymi typami*,
+co jest oczywiście **wadą**
+* Dialekty istniejących języków (niekompatybilne na poziomie kodu źródłowego):
+ * **[Clojure]** - dialekt języka **[Lisp]**, posiada opcjonalny system @TypedClojure
+ * **[Frege]** - dialekt języka **[Haskell]**, kompilowany do klas Javy, posiadający imperatywne wejście-wyjście
+* Nowe implementacje istniejących języków (kompatybilne na poziomie kodu źródłowego):
+ * **Jython** -> **[Python]**
+ * **JRuby** -> **[Ruby]**
+ * **[Eta]** -> **[Haskell]**
+
+## Główna konkurencja - język C# i platforma .Net
+
+Powiedzieć o Javie, a nie powiedzieć o C# to jak powiedzieć o Wizygotach, a nie wspomnieć o Ostrogotach.
+Język C# jest odpowiedzią Micro$oftu na Javę.
+Ponieważ te języki programowania są bardzo podobne do siebie,
+to od powstania C# istnieje niekończąca się wojna ideologiczna,
+który język programowania jest lepszy do pisania aplikacji korporacyjnych.
+W sporze tym przypadkowo wygrała Java,
+ponieważ jest darmowa i już prawie całkiem Open Source.
+Jednocześnie Java posiada bardziej rozwlekłą składnie i mniejszą bibliotekę standardową.
+
+C# identycznie jak Java jest kompilowany do kodu bajtowego,
+który nazywany jest
+[Wspólnym Językiem Pośredni](https://en.wikipedia.org/wiki/Common_Intermediate_Language)
+(ang. *Common Intermediate Language*, **CLI**).
+CLI następnie jest wykonywany przez maszynę wirtualną nazywaną platformą .NET.
+
+Podobnie jak dla kodu bajtowego Javy i JVM,
+tak dla CLI i platformy .Net także istnieją inne języki programowania,
+które można z grubsza podzielić na dwie kategorie:
+* Nowe języki programowania inspirowane istniejącymi już językami:
+ * **[C++/CLI]** - *ulepszona* wersja C++
+ * **[VB.NET]** - **[Visual Basic]** dostosowany do platformy .Net
+ * **[F#]** - dialekt języka **[OCaml]**
+* Nowe implementacje istniejących języków (kompatybilne na poziomie kodu źródłowego):
+ * **IronPython** -> **[Python]**
+ * **IronRuby** -> **[Ruby]**
+
+## Podsumowanie
+
+Czy warto uczyć się języków Java i C#?
+Biorąc pod uwagę,
+że pojawiają się nowe języki z lepszą składnią (Scala, Kotlin, F#, Go)?
+
+Według mnie warto.
+Dziesięcioletnie aplikacje napisane w Javie i C# nie znikną z dnia na dzień.
+Dodatkowo menedżerowie nie lubią często eksperymentować,
+dlatego nowe aplikacje także powstają w Javie i C#.
+Poza tym trudno pracować w nowych językach jak Scala, Kotlin czy F# nie znając starych języków jak Javy czy C#,
+ponieważ nowe języki używają bibliotek napisanych w swoich starszych kuzynach.
+
+[Clojure]: /langs/clojure
+[Eta]: /langs/eta
+[Frege]: /langs/frege
+[F#]: /langs/fsharp
+[Go]: /langs/go
+[Haskell]: /langs/haskell
+[Java]: /langs/java
+[Kotlin]: /langs/kotlin
+[Lisp]: /langs/lisp
+[OCaml]: /langs/ocaml
+[Python]: /langs/python
+[Ruby]: /langs/ruby
+[Scala]: /langs/scala
+
+[JVM]: /tools/jvm
+
+[C++/CLI]: https://pl.wikipedia.org/wiki/C%2B%2B/CLI
+[VB.NET]: https://pl.wikipedia.org/wiki/Visual_Basic_.NET
+[Visual Basic]: https://pl.wikipedia.org/wiki/Visual_Basic
+[Tiobe]: https://www.tiobe.com/tiobe-index/
+[IntelliJ IDEA]: https://www.jetbrains.com/idea/download/
diff --git a/_collections/_posts/2019-07-03-jezyk-fullstackowy.md b/_collections/_posts/2019-07-03-jezyk-fullstackowy.md
new file mode 100644
index 00000000..61cfc792
--- /dev/null
+++ b/_collections/_posts/2019-07-03-jezyk-fullstackowy.md
@@ -0,0 +1,312 @@
+---
+title: 'Który język programowania wybrać na początek - język fullstackowy'
+author: TheKamilAdam
+category: programming
+tags: api cli flatmappable interpreter io gui monad transpiler
+langs: ceylon clojure coffeescript dart elm java javascript haskell kotlin livescript meta-language ocaml purescript python racket reasonml ruby scala typescript
+tools: bucklescript clojurescript kotlin-js node-js postgresql scala-js
+libs: akka-http dropwizard jquery udash
+redirect_from:
+ - jezyk-fullstackowy
+ - programming/jezyk-fullstackowy
+ - onions/jezyk-fullstackowy
+ - onions/2019/07/03/jezyk-fullstackowy.html
+ - onions/2019/07/03/ktory-jezyk-programowania-wybrac-jezyk-fullstackowy.html
+---
+
+Wiele osób pyta się,
+**który język programowania wybrać na początek** jako pierwszy język do nauki.
+Wiele jednak zależy od tego do czego chcemy użyć tego języka programowania.
+Dlatego wybrałem zwycięzców w czterech kategoriach:
+1. [dynamicznie typowany język skryptowy ogólnego przeznaczenia](/jezyk-skryptowy)
+2. [statycznie typowany język korporacyjny używany do pisania długowiecznych aplikacji klasy *enterprise*](/jezyk-korporacyjny)
+3. język *fullstackowy*, który można używać do pisania frontendu i backendu
+4. [szybki język natywny działający bez maszyny wirtualnej i interpretera](/jezyk-natywny)
+
+W tym artykule skupię się na zwycięzcy trzeciej kategorii,
+świętym Graalu programowania webowego,
+czyli języku *fullstackowy*,
+w którym można pisać zarówno frontend jak i backend.
+
+**Ważna uwaga!**
+Artykuł nie jest sponsorowany przez Google,
+mimo że każdy ze zwycięskich języków jest używany przez Google.
+Nie jest też sponsorowany przez JetBrains.
+Po prostu uważam,
+że JetBrains tworzy najlepsze IDE.
+Jest to tylko mój mały subiektywny ranking języków programowania na rok 2019.
+
+## JavaScript oraz jego problemy i dziwactwa
+**[JavaScript]** jest obecnie jedynym językiem programowania wspieranym przez przeglądarki bezpośrednio.
+Dlatego jesteśmy skazani na niego przy programowaniu frontendu działającego po stronie przeglądarki.
+Jednocześnie JS posiada sporo swoich problemów i dziwactw. Zaczynając od najważniejszych są to:
+1. Różne implementacje w różnych przeglądarkach
+2. [Słabe typowanie], które pozwala robić takie rzeczy jak [JSFuck]
+3. Obiektowość oparta na [prototypach]().
+
+Ostatnie nie byłoby nawet problemem gdyby nie to,
+że w początkowej fazie istnienia rozdziału na frontend i backend
+programiści backendowi byli przymuszani do pisania frontendu.
+Bolało to zwłaszcza programistów języków korporacyjnych,
+gdzie obiektowość oparta jest na [klasach]().
+
+### Podejście zerowe
+Początkowo głównym problemem z JavaScryptem było to,
+że był różnie implementowany w różnych przeglądarkach.
+W niektórych przeglądarkach brakowało niektórych funkcji,
+w innych te same funkcje zachowywały się różnie.
+Spowodowało to powstawanie wielu różnych nakładek i bibliotek na JS,
+z czego jedna stała się *de facto* standardem - **[JQuery]**.
+Było to jednak w dawnych czasach,
+gdy programowanie JavaScripcie było proste,
+ponieważ służył on głownie do robienia bezsensownych animacji na strona oraz customowych menu kontekstowych.
+
+Obecnie głównym problemem pisania aplikacji webowych jest to,
+że potrzebujemy osobnych programistów do tworzenia frontendu (*frontendowców*)
+i osobnych do tworzenia backendu (*backendowców*).
+Teoretycznie istnieje święty Graal wszelakiej rekrutacji,
+człowiek orkiestra,
+Leonardo da Vinci swoich czasów,
+czyli fullstackowiec potrafiący pisać zarówno frontend jak i backend.
+W praktyce jest to jednak osoba znająca się na wszystkim, ale po trochu.
+Trochę jak np. internista w szpitalu.
+Rozwiązaniem jest dopiero język *fullstackowy*.
+
+### Podejście pierwsze - język backendowy transpilowany do JS
+
+Ponieważ programistów JavaScriptu było mało,
+a frontend stawał się coraz bardziej skomplikowany pojawił się pomysł,
+żeby już istniejące języki backendu transpilować do JS.
+Dzięki temu programiści backendu mogą z marszu stać się programistami frontendu.
+Tutaj są dwie grupy rozwiązań:
+* Biblioteki graficzne przeniesione do **[JS]**:
+ * [RAP] (ang. *Remote Aplication Platform*) -
+to implementacja [SWT] (ang. *Standard Widget Toolkit*).
+ SWT to niestandardowy (sic!) zestaw bibliotek graficznych dla Javy,
+ posiadający implementacje dla najpopularniejszych systemów operacyjnych (Mac, Linux, Windows).
+* [GWT] (ang. *Google Widget Toolkit*) -
+biblioteka graficzna zaprojektowana dla Javy specjalnie pod transpilację do JS
+ * [Pyjs] - Port GWT dla języka **[Python]**
+* Język backendu przeniesiony do frontendu jednocześnie nie narzucający frameworka widoku i biblioteki graficznej:
+ * **[Scala.js]** - posiada już dedykowane frameworki ja *[Udash]*
+ * [Kotlin.js] - dalej w procesie projektowania
+ * [Ceylon.js] - transpilowany do CommonJS
+ * [ClojureScript]* - używa [Closure Compiler] do optymalizacji kodu.
+Tutaj pojawia się gwiazdka ponieważ istnieją [różnice]() pomiędzy
+**[Clojure]** i ClojureScript
+ * Dla Javy:
+* [J2CL] - [transpilator] od Google używający [Closure Compiler] i będący następcą [GWT]
+ * [JSweet] - [transpilator] do języka **[TypeScript]**, który następnie jest transpilowany do [JS]
+ * Programiści języka **[Haskell]** także podejmowali kilka prób stworzenia transpilatora z Haskella do JS.
+Są to [Fay], [GHCJS], [Haste] i [uhc]
+ * Dla języka **[OCaml]** jest kilka transpilatorów,
+ale aktualnie najbardziej obiecująco wygląda **[BuckleScript].**
+ * Język **[Racket]** był jednym z pierwszych transpilowanych do JS, aktualnie jest rozwijany [RacketScript]
+
+### Podejście drugie - nowy język transpilowany do JS
+
+Według wielu programistów pierwsze podejście było niezadowalające.
+Istniało wiele problemów z językami backedowymi transpilowanymi do JS.
+Prawdopodobnie największym jest przetwarzanie współbieżne.
+Statycznie typowane języki korporacyjne posiadają wielowątkowość do przetwarzania współbieżnego.
+Interpretery JS posiadają jeden wątek
+i do przetwarzania współbieżnego używa konstrukcji `Promise` (*obietnicy*),
+której najbliżej do [monady]) `IO` z Haskella lub [FlatMappable] `Future` ze Scali.
+Ponieważ nie da się łatwo zamienić modelu `Promise` na wielowątkowość to jest to problemem.
+
+Ponieważ pierwsze podejście okazało się niezadowalające postanowiono
+stworzyć nowe języki programowania będące jak najbardziej podobne do JS,
+ale jednocześnie rozwiązujące znane w nim problemy.
+Te języki to m.in.:
+* **[CoffeeScript]** - pierwszy popularny, nowy język transpilowany do JS. Posiada klasy i *normalne* dziedziczenie,
+ale typowany dynamicznie. Promowany przez programistów **[Ruby]** we frameworku RoR
+* **[LiveScript]** - funkcyjny następca CoffeeScriptu
+* **[TypeScript]** - rozszeżenie **[JS]** o statyczne typowanie i klasy
+* **[PureScript]** - **[Haskell]**, ale wykonywany zachłannie,
+czyli jak *normalny* język programowania, a nie Haskell
+* **[ReasonML]** - **[OCaml]** ze zmienioną składnią w celu upodobnienia go do **[JS]**.
+ Także transpilowany za pomocą **[BuckleScript]**.
+* **[Elm]*** - język będący połączeniem języków **[Meta Language]** i **[Haskell]**
+oraz będący już zintegrowany z frameworkami React i Redux (implementacja architektury Flux).
+Jest z gwiazdką, bo jest dedykowany tylko do pisania frontendu.
+Jednocześnie posiada ciekawą właściwość jaką jest usuwanie martwego kodu podczas transpilacji.
+Dlatego aplikacja napisana w Elmie może być mniejsza niż kod Reacta
+* **[Dart]*** - kolejny język z gwiazdką. Mimo że jest względnie młody przeszedł już historię dzielącą się na etapy:
+ 1. Natywny język przeglądarki - niestety wykonywany natywnie tylko przez Chroma.
+Inne przeglądarki miały posiadać maszynę wirtualną Darta napisaną w JS.
+ 2. Język do pisania frontendu, transpilowany do JS
+ 3. Język do pisania frontendu i aplikacji mobilnych za pomocą frameworku Flutter
+
+Ale jakim cudem w ogóle można mówić o JS jako o języku *fullstackowym*?
+Spójrzy na małe kalendarium:
+* 2007 - Qt dodaje Qt Script, własną implementacją EmcaScriptu, język jest dedykowany do tworzenia **[GUI]**.
+Teoretycznie nic to nie wnosi do tej historii, ale zainspirowało niektórych
+* 2008 - Gnome dodaje dwa [bindingi Javascriptu](), [Gjs] i [Seed].
+Są one dedykowane do tworzenia **[GUI]** w miejsce wcześniej stosowanego w tym celu języka **[Python]**,
+ale można ich używać jako główny język do pisania aplikacji oraz jako język skryptowy
+* 2009 - powstaje [Node.js], wyciągnięty z przeglądarki [interpreter] V8,
+który można używać z linii poleceń [CLI]
+* 2011 - powstaje [Vert.x], framework do przetwarzania współbieżnego na [JVM],
+który posiada [API] m.in. w JavaScripcie
+
+A więc wszystkie języki transpilowane do JS (i sam JS oczywiście) można wykonywać po stronie backendu!
+### Podejście wygrywające
+zwycięzcą kategorii *język fullstackowy* jest język transpilowany do JS i jest to ... JavaScript!
+
+Co?! Dlaczego JavaScript jest transpilowany do JavaScriptu?
+Wynika to z tego,
+że w międzyczasie tworzenia gigantycznej ilości nakładek do JavaScriptu sam Javascript też był rozwijany.
+Niestety dalej trzeba wspierać stare przeglądarki używające starszych wersji JavaScriptu.
+Dlatego jest potrzebny [transpilator] [Babel] zamieniający ECMAScript 6 do ECMAScript 5.
+
+A dlaczego JavaScript jest zwycięzcą?
+* Ewoluował i nie jest już tak brzydki jak kiedyś
+* Jest popularny - język roku 2014 według [Tiobe]
+* Nawet jeśli będziesz pisać frontend w innym języku programowania niż JS to prawdopodobnie
+i tak będziesz musiał znać podstawy JavaScriptu,
+* Niestety [WebStorm] od JetBains jest płatny,
+ale na szczęście istnieją inne dobre IDE dla JavaScriptu jak [Atom] lub [VSC].
+* Chyba wreszcie zrozumieli JS w Google.
+Google długo miało problemy z JavaScriptem i dlatego m.in. stworzyło [GWT].
+Jednak od pewnego czasu Google wspiera użycie JavaScriptu np w [Google Cloud Functions],
+gdzie można używać tylko i wyłącznie JavaScriptu.
+
+Ale nie to jest największą zaletą JavaScriptu!
+Największą zaletą jest [Node.js].
+A największą zaletą [Node.js] jest to,
+że jest jednowątkowy i zmusza do pisania aplikacji funkcyjnych, asynchronicznych i reaktywnych.
+Dlaczego warto pisać takie aplikacje?
+Zobacz:
+* [Funkcyjne Serwery w Javie, Jarek Ratajski ]()
+* [SegFault Łódź, 18 maja 2018. Jarek Ratajski: "Nadeszła era funkcyjnego serwera, to nie tylko NodeJS"]()
+
+[Node.js] nie jest jedynym asynchronicznym serwerem. Istnieją także inne jak:
+* [Vert.x] - wielki framework dla języków JavaScript, Java, Scala, Kotlin, **[Ceylon]**, Groovy i **[Ruby]**
+* [Lagom] - kolejny wielki framework, dedykowany dla języka Java
+* [Akka HTTP] - biblioteka dedykowana dla języków **[Scala]** i Java
+* [Spark] - biblioteka dedykowana dla języków **[Kotlin]** i Java
+* [Ratpack] - biblioteka dedykowana dla języków Groovy i Java
+* [WebFlux] - reaktywa wersja Springa
+
+Wiele innych frameworków także zaczyna wspierać programowanie asynchroniczne,
+jak np. [DropWizard].
+## Podsumowanie
+
+Trudno tutaj o dobre podsumowanie.
+Chyba nie mam odwagi polecić komuś JavaScript/TypeScript do nauki jako pierwszy język do programowania.
+Głównie obawiając się o zdrowie psychiczne tej osoby,
+która miałaby programować w JS.
+
+Osobiście jestem zwolennikiem statycznie typowanych języków backendu transpilowanych do JS,
+jak np. Scala.js lub Kotlin.js.
+Pozwala to współdzielić kod między frontendem i backendem,
+który teoretycznie może być nawet aplikacją natywną.
+Jednocześnie w tych językach programowania
+do rozwiązywania problemów asynchroniczności
+są preferowane konstrukcje `Future` oraz **[monady](/tags/monad)** `IO`,
+które łatwo przetłumaczyć na `Promise` z JS.
+
+Równie ciekawy wydaje się także,
+pojawiącący w niektórych zagranicznych ogłoszeniach o pracę,
+stos technologiczny PHP,
+czyli:
+* **P**ureScript na frontendzie
+* **H**askell na backandzie
+* **P**ostgreSQL jako baza danych
+
+Są to co prawda dwa języki programowania do nauki,
+ale bardzo podobne do siebie.
+O wiele bardziej niż Java i JavaScript.
+Więc opanowanie jednego z nich,
+gdy umie się już drugi nie powinno być problemem.
+
+## Ciekawe linki
+
+[Lista języków kompilowanych do JS]()
+
+[Ceylon]: /langs/ceylon
+[Clojure]: /langs/clojure
+[CoffeeScript]: /langs/coffeescript
+[Dart]: /langs/dart
+[Elm]: /langs/elm
+[Java]: /langs/java
+[JavaScript]: /langs/javascript
+[JS]: /langs/javascript
+[Haskell]: /langs/haskell
+[Kotlin]: /langs/kotlin
+[LiveScript]: /langs/livescript
+[Meta Language]: /langs/meta-language
+[OCaml]: /langs/ocaml
+[PureScript]: /langs/purescript
+[Python]: /langs/python
+[Racket]: /langs/racket
+[ReasonML]: /langs/reasonml
+[Ruby]: /langs/ruby
+[Scala]: /langs/scala
+[TypeScript]: /langs/typescript
+
+[BuckleScript]: /tools/bucklescript
+[ClojureScript]: /tools/clojurescript
+[JVM]: /tools/jvm
+[Kotlin.js]: /tools/kotlin-js
+[Node.js]: /tools/node-js
+[PosgreSQL]: /tools/postgresql
+[Scala.js]: /tools/scala-js
+
+[Akka HTTP]: /libs/akka-http
+[DropWizard]: /libs/dropwizard
+[JQuery]: /libs/jquery
+
+[API]: /tags/api
+[CLI]: /tags/cli
+[FlatMappable]: /tags/flatmappable
+[GUI]: /tags/gui
+[interpreter]: /tags/interpreter
+[monady]: /tags/monad
+[transpilator]: /tags/transpiler
+
+[Słabe typowanie]: https://pl.wikipedia.org/wiki/Typowanie_s%C5%82abe
+[JSFuck]: https://github.com/aemkei/jsfuck
+
+[RAP]: https://www.eclipse.org/rap/
+[SWT]: https://www.eclipse.org/swt/
+[GWT]: http://www.gwtproject.org
+[Pyjs]: http://pyjs.org/
+
+[Ceylon.js]: https://ceylon-lang.org/documentation/1.3/reference/interoperability/js/
+[ClojureScript]: https://clojurescript.org/
+
+[Closure Compiler]: https://github.com/google/closure-compiler
+[J2CL]: https://github.com/google/j2cl
+[JSweet]: https://github.com/cincheo/jsweet
+
+[Fay]: https://github.com/faylang/fay/wiki
+[GHCJS]: https://github.com/ghcjs/ghcjs
+[Haste]: https://github.com/valderman/haste-compiler
+[uhc]: https://github.com/uhc/uhc
+
+[RacketScript]: https://github.com/vishesh/racketscript
+
+[udash]: https://udash.io/
+
+[babeljs]: https://babeljs.io/
+
+[Tiobe]: https://www.tiobe.com/tiobe-index/
+[WebStorm]: https://www.jetbrains.com/webstorm/
+[Atom]: https://ide.atom.io/
+[VSC]: https://vscodium.com/
+[Google Cloud Functions]: https://cloud.google.com/functions/
+
+[Gjs]: https://gitlab.gnome.org/GNOME/gjs/blob/master/README.md
+[Seed]: https://gitlab.gnome.org/GNOME/seed
+[V8]: https://pl.wikipedia.org/wiki/V8_(silnik_JavaScript)
+[Npm]: https://pl.wikipedia.org/wiki/Npm_(manager_pakiet%C3%B3w)
+[Vert.x]: https://en.wikipedia.org/wiki/Vert.x
+
+[Babel]: https://babeljs.io/
+[Programowanie sterowane zdarzeniami]: https://pl.wikipedia.org/wiki/Programowanie_sterowane_zdarzeniami
+
+[Lagom]: https://github.com/lagom/lagom
+[Spark]: https://github.com/perwendel/spark
+[Ratpack]: https://github.com/ratpack/ratpack
+[WebFlux]: https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html
diff --git a/_collections/_posts/2019-07-10-jezyk-natywny.md b/_collections/_posts/2019-07-10-jezyk-natywny.md
new file mode 100644
index 00000000..9956cac4
--- /dev/null
+++ b/_collections/_posts/2019-07-10-jezyk-natywny.md
@@ -0,0 +1,248 @@
+---
+title: 'Który język programowania wybrać na początek - język natywny'
+author: TheKamilAdam
+category: programming
+tags: bytecode monad native type-class
+langs: common-lisp crystal dart erlang fsharp go haskell java javascript julia lua meta-language ocaml pony racket rust scala scheme smalltalk typescript
+tools: clang docker kotlin-native llvm node-js scala-native
+redirect_from:
+ - jezyk-natywny
+ - programming/jezyk-natywny
+ - onions/jezyk-natywny
+ - onions/2019/07/03/jezyk-natywny.html
+ - onions/2019/07/03/ktory-jezyk-programowania-wybrac-jezyk-natywny.html
+---
+
+Wiele osób pyta się,
+**który język programowania wybrać na początek** jako pierwszy język do nauki.
+Wiele jednak zależy od tego do czego chcemy użyć tego języka programowania.
+Dlatego wybrałem zwycięzców w czterech kategoriach:
+1. [dynamicznie typowany język skryptowy ogólnego przeznaczenia](/jezyk-skryptowy)
+2. [statycznie typowany język korporacyjny używany do pisania długowiecznych aplikacji klasy *enterprise*](/jezyk-korporacyjny)
+3. [język *fullstackowy*, który można używać do pisania frontendu i backendu](/jezyk-fullstackowy)
+4. szybki język natywny działający bez maszyny wirtualnej i interpretera
+
+W tym artykule skupię się na zwycięzcy czwartej kategorii,
+czyli języku natywnym.
+
+**Ważna uwaga!**
+Artykuł nie jest sponsorowany przez Google,
+mimo że każdy ze zwycięskich języków jest używany przez Google.
+Nie jest też sponsorowany przez JetBrains.
+Po prostu uważam,
+że JetBrains tworzy najlepsze IDE.
+Jest to tylko mój mały subiektywny ranking języków programowania na rok 2019.
+
+## Język natywny - definicja
+Roboczo przyjmiemy następujące definicje:
+1. Język natywny jest to język, który pozwala pisać aplikacje natywne.
+2. Aplikacja natywna jest to aplikacja, która jest skompilowana do kodu natywnego.
+3. Kod natywny jest to najbliższa sprzętowo implementacja kodu jaka jest możliwa.
+Czyli:
+ * Dla Androida będzie to **[kod bajtowy]** Javy
+ * Dla przeglądarki będzie to **[JavaScript]**
+ * Dla Maszyny Pascala był to PCode
+ * Gdyby Micro$oft skończył prace nad systemem operacyjnym Midori byłby to kod bajtowy CIL
+ * W pozostałych wypadkach będzie to najprawodpodobniej kod maszynowy
+
+## Zalety języków natywnych
+Języki natywne posiadają wiele zalet.
+Dla mnie najważniejszymi są:
+* możliwość spakowania programu/aplikacji do jednego pliku wykonywalnego
+razem ze wszystkimi bibliotekami trzecimi i plikami konfiguracyjnymi
+* mała zajętość zasobów, głównie pamięci RAM
+* szybkość działania
+
+### Jedna paczka ze wszystkim jako plik wykonywalny
+Jeśli piszemy aplikację desktopową prawdopodobnie chcielibyśmy dostarczyć klientowi jeden plik wykonywalny.
+Tak żeby nie musiał instalować żadnych maszyn wirtualnych, interpreterów i dodatkowych bibliotek współdzielonych.
+Tak właśnie jest w przypadku języków kompilowanych do kodu natywnego.
+
+Jeśli piszemy w języku skryptowym czasem można oszukać.
+Niektóre języki skryptowe pozwalają spakować skrypty i interpreter w jeden wykonywalny plik.
+Przykładem może tu być [Electron],
+który posłużył do napisania edytorów [Atom] oraz [VSC].
+
+Gorzej jest w przypadku języków korporacyjnych kompilowanych do kodu bajtowego.
+Ich maszyny wirtualne, jak JVM, są często zbyt duże, by móc je dołączać do każdego programu z osobna.
+Prawdziwy problem zaczyna się,
+gdy różne programy wymagają różnych wersji maszyny wirtualych np. JRE 6 i JRE 11.
+### Niska zajętość RAMu
+[Electron] jest wspaniałym narzędziem,
+które pozwoliło programistom frontendu pisać aplikacje desktopowe.
+Ale jest to okupione dużym kosztem.
+Zwykle koszt ten przelicza się na duże zużycie pamięci RAM.
+Koszt ten wynika z tego,
+że każda aplikacja oparta na Electronie musi uruchomić zawarty w sobie
+interpreter JavaScriptu V8 oraz silnik do renderowania HTMLu i CSSów.
+
+W przypadku języków natywnych możemy użyć bibliotek graficznych wbudowanych w system operacyjny.
+Lub przenośnych bibliotek graficznych jak GTK (Gnome) oraz Qt (KDE).
+Nie musimy uruchamiać także zewnętrznych interpreterów, maszyn wirtualnych i kompilatorów JIT.
+
+### Szybkość działania
+Szybkość poszczególnych języków programowania jest tematem drażliwym.
+Często testy porównawcze (ang. *benchmarks*) szybkości działania poszczególnych języków programowania
+są pisane w taki sposób,
+żeby potwierdziły tezę piszącego.
+Potem można spotkać raporty z których wynika,
+że [JavaScript jest szybszy od C++]().
+
+Drugim problemem jest to, że wydajność języków zmienia się w czasie.
+Np. początkowo kod bajtowy Javy był tylko interpretowany.
+Obecnie jest kompilowany podczas uruchomienia (ang. *just-in-time compilation*, **JIT**)
+Przydałby się niezależny zestaw testów nie sponsorowany przez żaden z języków.
+Szczęśliwie taki zestaw istnieje i nazywa się [Benchmarks Game].
+
+Na podstawie tego zestawu testów możemy podzielić języki programowania na kilka grup pod względem szybkości działania:
+1. Top - trzy prawie idealnie tak samo szybkie języki programowania:
+ * C gcc
+ * C++ g++
+ * **[Rust]** - kompilowany do kodu natywnego język z systemem typów inspirowanych językiem **[Haskell]**
+2. Około dwa razy wolniejsze niż C:
+ * Ada 2012 Gnat - kompilowany do kodu natywnego
+ * Fortran Intel - kompilowany do kodu natywnego
+ * Swift - kompilowany do kodu natywnego
+ * C# .NET Core - kompilowany do kodu bajtowego CIL
+ * **[Java]** - kompilowany do kodu bajtowego maszyny wirtualnej Javy
+ * FreePascal - kompilowany do kodu natywnego
+3. Około trzy razy wolniejsze niż C:
+ * **[Julia]** - kompilowany do kodu natywnego
+ * Chapel
+ * **[F#]**.NET Core - kompilowany do kodu bajtowego CIL
+ * **[OCaml]** - obiektowa werjsa **[Meta Language]** kompilowany do kodu natywnego
+ * LispSBCL - implementacja **[Common Lisp]**
+ * **[Go]** - kompilowany do kodu natywnego
+4. Trzy do dziesięciu razy wolniejsze niż C:
+ * **[TypeScript]** - kompilowany do **[JS]** i uruchamiany na **[Node.js]**
+ * **[Dart]** - prawdopodobnie kompilowany do **[JS]** i uruchamiany na **[Node.js]**
+ * **[Haskell]** GHC - prawdopodobnie kompilowany do C
+ * **[Node.js]** - prawdopodobnie chodzi o **[JavaScript]**
+ * **[Racket]** - dialekt **[Scheme]**
+5. Ponad dziesięć razy wolniejsze niż C:
+ * reszta [języków skryptowych](/jezyk-skryptowy) w tym **[Erlang]** i **[Lua]**
+
+Moje największe zaskoczenia,
+gdy analizowałem wykresy:
+1. Do niedawna nikomu nieznany **[Rust]** znalazł się w pierwszej trójce najszybszych jezyków programowania.
+2. Kompilowany do kodu bajtowego **[F#]** wyprzedził kompilowany do kodu natywnego **[OCaml]**.
+3. Dynamicznie typowany **[Common Lisp]** wyprzedził statycznie typowany **[Go]**.
+4. **[TypeScript]** wyprzedził język **[Haskell]** - nie mam pojęcia jak oni to zrobili.
+Widocznie leniwość i **[monady]** są drogie.
+5. **[JavaScript]** (i **[TypeScript]**) niesamowicie wyprzedzają pozostałe języki skryptowe.
+Nawet język **[Erlang]**, w którym, z powodu niezmienności, powinny być możliwe bardzo agresywne optymalizacje.
+
+Oczywiście z powodu istnienia kompilatora **[LLVM]** kolejność,
+jak i sama lista,
+może w najbliższej przyszłości się zmienić.
+
+## Język natywny - wady
+Przez wiele lat jako najbardziej popularny natywny język programowania królował C++.
+Dlatego wady języków natywnych są to głównie wady języka C++.
+A lista rzeczy które można zarzucić C++ jest długa:
+* trudna składnia i bycie zbyt blisko sprzętu
+* długi czas kompilacji
+* duża ilość narzędzi potrzebnych do poprawnej kompilacji (kompilator/transpilator, konsolidator/linker, preprocesor/makroprocesor)
+* przestarzałe narzędzia
+* archaiczne podejście do zarządzania zależnościami, czyli jego brak
+* często biblioteki wymagane do kompilacji instaluje się wprost do systemu operacyjnego,
+dlatego istnieje żart że linux nie jest systemem operacyjnym tylko środowiskiem do programowania w C/C++
+
+Na pewno nie jest to prosty język programowania.
+A niestety on jest często polecany jako pierwszy język do nauki programowania.
+
+## Język natywny - zwycięzcy ...
+Język C++ z pozycji lidera próbowały wygryźć inne języki jak D oraz **[Vala]**
+(język transpilowany do C i oparty na bibliotece [GObject] ze składnią wzorowaną na językach **[Java]** i C#).
+Jednak nie stała za tymi językami programowania żadna duża korporacja.
+Inaczej jest w przypadku języka **[Go]**,
+który jest zwycięzcą w kategorii.
+Główne cechy języka:
+* Język roku 2009 i 2016 według [Tiobe]
+* Pierwszy język stworzony przez Google,
+który przebił się do mainstreamu
+* Niestety [GoLand]( ) od JetBains jest płatny,
+ale na szczęście istnieją inne dobre IDE dla **[Go]** jak [Atom] lub [VSC]
+* Mimo że to język względnie nowy powstała w nim już ogromna ilość oprogramowania jak np. **[Docker]** i Kubernetes.
+* Dzięki temu, że posiada ~~upośledzoną~~ prostą składnię prawdopodobnie będzie to też nowy [język korporacyjny](/jezyk-korporacyjny).
+
+Dodatkowo problemy znane z C++ są rozwiązane w **[Go]** za pomocą wszystkomającego kompilatora,
+który także formatuje kod i zarządza zależnościami.
+Co prawda nie jest superszybki,
+co widać po testach,
+ale za to szybko się kompiluje.
+
+## ... i trudne alternatywy
+Co jednak jeśli nie chcemy pisać w języku z ~~upośledzoną~~ prostą składnią,
+który nie zawiera nawet generyków?
+Lub chcemy pisać szybko działające oprogramowanie?
+W takim przypadku istnieje kilka alternatyw,
+ale żadna z nich nie jest łatwa:
+* **[Rust]** - posiada zaawansowany system typów,
+domyślną niezmienność (ang. *immutable*),
+prawie **[klasy typów]** (ang. *type class*) i wiele innych cech deklaratywno funkcyjnych języków programowania.
+Jednocześnie pozwalając na imperatywne optymalizacje tam gdzie ważna jest wydajność.
+* **[Pony]** - posiada typowany system aktorów inspirowany językiem **[Erlang]**,
+i podobnie jak **[Rust]**,
+rozbudowany system własności zmiennych.
+* **[Crystal]** - język bazujący składniowo na języku **[Ruby]**,
+a więc kolejny spadkobierca języka **[Smalltalk]**
+
+Oprócz tego część języków nienatywnych stara się zostać językami natywnymi.
+Przykładami mogą tu być **[Scala Native]** i **[Kotlin Native]**.
+Jest to dziś łatwiejsze dzięki istnieniu kompilatora **[LLVM]**.
+
+## Podsumowanie
+W tej chwili trudno doradzać komuś naukę języków **[Go]** lub **[Rust]** jako pierwszego języka programowania.
+Ponieważ aktualnie ilość ofert pracy dla Go jest mniejsza niż dla języka **[Scala]**.
+Np. na Górnym Śląsku jest jedna firma zatrudniająca do Go.
+Z drugiej strony ilość i jakość narzędzi,
+które powstają w Go jest niesamowita.
+I to może odwrócić trend w najbliższych latach.
+
+[Common Lisp]: /langs/common-lisp
+[Crystal]: /langs/crystal
+[Dart]: /langs/dart
+[Erlang]: /langs/erlang
+[F#]: /langs/fsharp
+[Go]: /langs/go
+[Haskell]: /langs/haskell
+[Java]: /langs/java
+[JavaScript]: /langs/javascript
+[Julia]: /langs/julia
+[JS]: /langs/javascript
+[Lua]: /langs/lua
+[Meta Language]: /langs/meta-language
+[OCaml]: /langs/ocaml
+[Pony]: /langs/pony
+[Racket]: /langs/racket
+[Ruby]: /langs/ruby
+[Rust]: /langs/rust
+[Scala]: /langs/scala
+[Scheme]: /langs/scheme
+[Smalltalk]: /langs/smalltalk
+[TypeScript]: /langs/typescript
+
+[Docker]: /tools/docker
+[Kotlin Native]: /tools/kotlin-native
+[LLVM]: /tools/llvm
+[Node.js]: /tools/node-js
+[Scala Native]: /tools/scala-native
+
+[klasy typów]: /tags/type-class
+[kod bajtowy]: /tags/bytecode
+[monady]: /tags/monad
+
+[maszyny P-code]: https://en.wikipedia.org/wiki/P-code_machine
+
+[Electron]: https://pl.wikipedia.org/wiki/Electron_(oprogramowanie)
+[Atom]: https://ide.atom.io/
+[VSC]: https://vscodium.com/
+
+[Benchmarks Game]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/which-programs-are-fastest.html
+
+[Vala]: https://pl.wikipedia.org/wiki/Vala_(j%C4%99zyk_programowania)
+[GObject]: https://en.wikipedia.org/wiki/GObject
+
+[Tiobe]: https://www.tiobe.com/tiobe-index/
+[IEEE]: https://spectrum.ieee.org/at-work/innovation/the-2018-top-programming-languages
diff --git a/_collections/_posts/2019-07-24-paradygmaty-programowania.md b/_collections/_posts/2019-07-24-paradygmaty-programowania.md
new file mode 100644
index 00000000..8a64adaf
--- /dev/null
+++ b/_collections/_posts/2019-07-24-paradygmaty-programowania.md
@@ -0,0 +1,250 @@
+---
+title: 'Kolejny język programowania do nauki - paradygmaty programowania'
+author: TheKamilAdam
+category: programming
+tags: lambda-calculus
+langs: clojure coffeescript common-lisp elm emacs-lisp fsharp go haskell java javascript kotlin lisp livescript meta-language ocaml perl purescript python racket reasonml ruby rust scala scheme smalltalk typescript
+tools: jvm node-js
+redirect_from:
+ - paradygmaty-programowania
+ - programming/paradygmaty-programowania
+ - onions/paradygmaty-programowania
+---
+
+[Zdecydowaliśmy się nauczyć programować](/jezyk-skryptowy).
+[I zostać programistami](/czy-nadaje-sie-na-programiste).
+Może nawet dostaliśmy pierwszą pracę.
+I w tej pracy ktoś nam powiedział, że uczy się nowego, a więc i kolejnego, języka programowania.
+Czemu się uczy?
+Bo np. usłyszał/przeczytał cytat:
+
+> Warto uczyć się przynajmniej jednego **nowego języka** rocznie.
+**Różne języki** programowania pozwalają rozwiązywać te **same problemy** na **różne sposoby**.
+Stałe poznawanie nowych rozwiązań ułatwia szersze postrzeganie rozwiązywanych problemów
+i zmniejsza ryzyko wybierania utartych sposobów postępowania.
+
+Andrew Hunt, David Thopmas *[Pragmatyczny programista]. Od czeladnika do mistrza.* Pogrubienia moje.
+
+Jest to prawdopodobnie najsławniejszy cytat z tej książki.
+I może się wydawać dość dziwny.
+Przeanalizujmy go, więc zdanie po zdaniu.
+
+> Warto uczyć się przynajmniej jednego **nowego języka** rocznie.
+
+Ale po co?
+Na co?
+Przecież mamy dobrze płatną pracę i nic się nie zmieni.
+Bo przecież w informatyce nic się nie zmienia.
+Za wyjątkiem takich wypadków jak to że:
+* C zmiażdżyło Pascala oraz zastąpiło większość języków asemblerowych,
+stając się podstawowym językiem niskokoziomowym do pisania systemów operacyjnych i systemów wbudowanych.
+* **[Java]** (z pomocą C#) wygryzła C++ i Cobola stając się głównym [językiem korporacyjnym](/jezyk-korporacyjny).
+* **[Python]** wygryzł języki **[Perl]** oraz **[TCL]** i dalej spycha pozostałe [języki skryptowe](/jezyk-skryptowy) do coraz głębszej niszy.
+* **[Python]** wygryzł języki **[Scheme]** i **[Racket]** z zastosowań naukowych.
+Aktualnie:
+* **[Rust]** stara się zostać głównym [językiem natywnym](/jezyk-natywny).
+* **[Go]** stara się zostać głównym [językiem korporacyjnym](/jezyk-korporacyjny)
+i może także głównych [językim natywnym](/jezyk-natywny).
+
+Tak więc warto się uczyć **nowych języków** programowania.
+Pytanie tylko których.
+Tu odpowiedź podsuwa nam kolejne zdanie:
+
+> **Różne języki** programowania pozwalają rozwiązywać te **same problemy** na **różne sposoby**.
+
+Drugie zdanie cytatu już lepiej precyzuje których języków programowania się uczyć.
+Jednak o wiele trudniej je przeanalizować.
+
+## Różne języki programowania -> różne sposoby programowania -> różne paradygmaty programowania
+
+Powinniśmy uczyć się **różnych języków**,
+które pozwalają programować na **różne sposoby**.
+Różne sposoby programowania są popularnie nazywane paradygmatami programowania.
+Ile tych paradygmatów jest?
+Tutaj najlepiej sięgnąć do literatury.
+
+### Czysta architektura
+
+W książce [Czysta Architektura] Robert C. Martin zapewnia,
+że są tylko trzy paradygmaty programowania i z tego co można wyczytać w jego książce są to:
+1. **Programowanie strukturalne** - wymyślone w 1968 przez Edsger Dijkstra.
+Edsger Dijkstra skrytykował używanie instrukcji `goto`
+i zalecał używanie instrukcji sterujących selekcji (`if`/`then`/`else`) oraz iteracji (`for`/`while`/`until`).
+2. **Programowanie obiektowe** - wymyślone w roku 1966 przez Ole-Johan Dahl i Kristen Nygaard
+przy tworzeniu języków do symulacji SIMULA I i SIMULA-67.
+Rozwiązuje problem polimorfizmu.
+3. **Programowanie funkcyjne** - wymyślone w roku 1936 przez Alonzo Church jako [rachunek lambda].
+Zaimplementowany w roku 1958 w języku **[LISP]** przez John McCarthy.
+Polega na niezmienności (ang. *immutable*).
+
+Warto od razu wspomnieć,
+że o ile Robert C. Martin jest jedną z ważniejszych osób dla informatyki biznesowej
+i jego książka [Czysty kod] wpłynęła niesamowicie pozytywnie na sposób pisania oprogramowania,
+to często żyje w swoim wyidealizowanym świecie.
+Widać to zwłaszcza w książce [Mistrz czystego kodu].
+
+Spróbujmy zderzyć z rzeczywistością to co napisał:
+1. **Programowanie strukturalne** zostało zdefiniowane dopiero w 1968 jako nie używanie instrukcji `goto`,
+ale przypadkiem zaimplementowane już w 1958 w języki **[LISP]**.
+2. **Programowanie obiektowe** było definiowane co najmniej trzy razy
+ plus jeszcze dwa inne systemy podszywają się pod programowanie obiektowe:
+ 1. Dla języka SIMULA, a właściwie SIMULA-67 w 1967 roku.
+ Bardzo specyficzne i na potrzeby tworzenia symulacji zachowania statków.
+ 2. Dla języka **[Smalltalk]** w 1972 roku.
+ Jest totalne programowanie obiektowe,
+ gdzie wszystko jest obiektem,
+ a obiekty komunikują się wiadomościami.
+ Dziś tę definicję spełnia tylko **[Ruby]**.
+ 3. Dla języka C++ w 1985 roku.
+ Jest to obecnie najpopularniejsza definicja obiektowości.
+ Oparta na dziedziczeniu (czasem nazywanym rozszerzanie lub implementowaniem) klas, interfejsów i/lub protokołów.
+ 4. Duck typing i systemy typu strukturalnego,
+gdzie nie implementuje się interfejsów,
+ale obiekty po prostu mają posiadać pewien zestaw metod.
+Używane głównie w [językach skryptowych](/jezyk-skryptowy),
+ ale od niedawna także w statycznie typowanym jezyku **[Go]** oraz **[TypeScript]**.
+ 5. CLOS (Common Lisp Object System) -
+ system obiektowy oparty o multimetody używany w **[Common Lisp]**.
+3. **Programowanie funkcyjne** zostało zdefiniowane w 1936 jako [rachunek lambda].
+Od tej pory były trzy główne próby stworzenia języka funkcyjnego:
+ 1. Dynamicznie typowany język z rekurencją ogonową i leniwymi listami (strumieniami),
+ czyli **[LISP]** stworzony w roku 1958.
+Ustandaryzowany jako **[Scheme]** w 1975 roku.
+ Alternatywny standard **[Common Lisp]** jest bardziej podobny do zwykłych (imperatywnych) języków programowania,
+ ponieważ nie gwarantuje rekurencji ogonowej.
+ 2. Statycznie typowany, generyczny język programowania z rekurencją i strumieniami,
+ czyli **[Meta Language]** stworzony w 1973 roku.
+Ustandaryzowany jako **Standard ML** w 1990 roku.
+Co ciekawe **[OCaml]** z 1996 roku jest prawdopodobnie pierwszym [językiem wszystkomającym](/jezyk-wszystkomajacy),
+czyli obiektowo-funkcyjnym.
+ 3. W pełni funkcyjny język programowania kompilowany do rachunku lambda,
+ czyli **[Haskell]** stworzony w roku 1990.
+ Ponieważ nie zbudowano jeszcze komputera wykonującego natywnie [rachunek lambda]
+ to jest on dalej kompilowany do imperatywnych rozkazów procesora.
+### Scala. Nauka programowania
+
+W książce [Scala. Nauka programowania] Vikash Sharma
+wymienia za to cztery paradygmaty programowania:
+* **Programowanie imperatywne** - *najpierw zrób to, potem zrób tamto*.
+* **Programowanie funkcyjne** - *oceń i zrób*.
+* **Programowanie logiczne** - *odpowiedź za pomocą rozwiązania*.
+* **Programowanie zorientowane obiektowo** - przekazuje **komunikaty** między obiektami,
+aby w ten sposób symulować ewolucję faktycznie używanego podejścia.
+Z czego programowanie logiczne jest dedykowane do specyficznej klasy problemów matematycznych.
+
+### http://wazniak.mimuw.edu.pl
+
+Na stronie ę
+w kursie [Paradygmaty programowania](http://wazniak.mimuw.edu.pl/index.php?title=Paradygmaty_programowania)
+autor zgadza się co do czterech głównych paradygmatów z Vikash Sharma,
+ale dodaje jeszcze cztery [inne paradygmaty]():
+* **Programowanie strukturalne**.
+* **Programowanie sterowane przepływem danych**.
+* **Programowanie sterowane zdarzeniami**.
+* **Programowanie współbieżne**.
+
+Czyli łącznie osiem paradygmatów.
+
+### Wikipedia
+Wikipedia nie jest może najpewniejszym źródłem informacji,
+ale na [polskojęzycznej]() wikipedii paradygmatów jest więcej.
+A na [anglojęzycznej]() - jeszcze więcej.
+
+## Rozwiązywać te same problemy na różne sposoby
+
+Kolejny język programowania powinien być na tyle inny by pozwalać programować w sposób różny od tych sposobów które już znamy.
+Jednocześnie powinien być na tyle podobny by móc w nim rozwiązywać tą samą klasę problemów.
+Np. jeśli piszemy korpo aplikację zawsze w Javie/C# to możemy spróbować napisać ją w tym drugim języku programowania.
+Ale jest to przykład zły.
+I to z dwóch powodów:
+* Bo korpo aplikacje są duże i sami takiej nie napiszemy.
+* Java i C# są chyba najbardziej podobnymi do siebie językami programowania, więc za dużo się nie nauczymy.
+
+Co prawda będzie to przydatna umiejętność do wpisania w CV,
+ale nie pogłębi naszego podejścia do *różnych sposobów* pisania aplikacji.
+
+Trochę prościej jest jeśli pracujemy w software house robiącym strony internetowe w [językach skryptowych](/jezyk-skryptowy).
+Po pierwsze strony internetowe są zwykle mniejsze niż korpo aplikacja,
+więc jest szansa wykonania zadania samodzielnie w czasie wolnym.
+Po drugie języki skryptowe jak **[Perl]**, **[Python]** i **[Ruby]** różnią się od siebie bardziej niż C# od Javy.
+
+Jednak i tutaj stracimy pewnie dużo czasu na pisanie plików html i css.
+Lepszym zadaniem jest stworzenie jakiegoś mikroserwisu (ang. microservice).
+Ponieważ większość aplikacji jest obecnie przepisywana na mikroserwisy to w uproszczeniu można uznać,
+że jeśli w danym języku programowania można napisać mikroserwis to można używać go na produkcji.
+
+Ale tu znów będziemy kopać się z nieznanym sobie frameworkiem do RESTów w nieznanym sobie języku programowania.
+Możliwe także,
+że z nieznaną sobie bazą danych.
+Potrzebne jest lepsze zadanie.
+Nie używające http, kolejek wiadomości i baz danych,
+ale pozwalające wykorzystać jak najwięcej funkcjonalności (ang. *features*) poznawanego języka programowania.
+
+Nawet jeśli znajdziemy takie zadanie, tj. używające dużo funkcjonalności języka bez nauki frameworków
+to poświęcimy dużo czasu na przebijanie się przez instalowanie tego języka,
+zwłaszcza jeśli będzie to [język natywny](/jezyk-natywny),
+oraz pisanie prostych `"Hello world!"` w tym języku.
+Oczywiście jeśli mamy dużo czasu nie jest to problemem.
+Jeśli jednak mamy mało czasu to pewnie chcielibyśmy od razu siąść i kodować.
+Pewnym rozwiązaniem mogą być strony try-online jak:
+*
+*
+*
+*
+
+Innym rozwiązaniem jest nauka nowych języków na platformę którą już mamy zainstalowaną.
+Czyli:
+* jeśli programujemy w C# na .NET możemy zacząć używać **[F#]**;
+* jeśli programujemy w Javie na **[JVM]** możemy zacząć używać jednego z języków **[Scala]**, **[Kotlin]**, **[Clojure]** lub **[Eta]**;
+* jeśli programujemy w **[JS]**/**[CS]**/**[LS]**/**[TS]** na **[node.js]**
+możemy zacząć używać jednego z funkcyjnych transpilowanych do **[JS]** jak **[Elm]**, **[PureScript]** lub **[ReasonML]**.
+## Podsumowanie
+
+Jednak idealniebyłoby, gdyby istniał jeden język programowania,
+który zawierałby wszystkie paradygmaty programowania.
+Na nasze szczęście język taki istnieje.
+Tylko nie da się go nauczyć w jeden rok.
+
+Ciąg dalszy nastąpił jako artykuł [Kolejny język programowania - język wszystkomający](/jezyk-wszystkomajacy).
+
+[Clojure]: /langs/clojure
+[CS]: /langs/coffeescript
+[Common Lisp]: /langs/common-lisp
+[Elm]: /langs/elm
+[Eta]: /langs/eta
+[F#]: /langs/fsharp
+[Go]: /langs/go
+[Haskell]: /langs/haskell
+[Java]: /langs/java
+[JS]: /langs/javascript
+[Kotlin]: /langs/kotlin
+[LISP]: /langs/lisp
+[LS]: /langs/livescript
+[Meta Language]: /langs/meta-language
+[OCaml]: /langs/ocaml
+[Perl]: /langs/perl
+[PureScript]: /langs/purescript
+[Python]: /langs/python
+[Racket]: /langs/racket
+[ReasonML]: /langs/reasonml
+[Ruby]: /langs/ruby
+[Rust]: /langs/rust
+[Scheme]: /langs/scheme
+[Smalltalk]: /langs/smalltalk
+[Scala]: /langs/scala
+[TCL]: /langs/tcl
+[TS]: /langs/typescript
+
+[JVM]: /tools/jvm
+[node.js]: /tools/node-js
+
+[rachunek lambda]: /tags/lambda-calculus
+
+[Czysta architektura]: /books/czysta-architektura
+[Czysty kod]: /books/czysty-kod
+[Mistrz czystego kodu]: /books/mistrz-czystego-kodu
+[Pragmatyczny programista]: /books/pragmatyczny-programista
+[Scala. Nauka programowania]: /books/scala-nauka-programowania
+
+[Squeak]: https://pl.wikipedia.org/wiki/Squeak
+[Tiobe]: https://www.tiobe.com/tiobe-index/
diff --git a/_collections/_posts/2019-08-07-jezyk-wszystkomajacy.md b/_collections/_posts/2019-08-07-jezyk-wszystkomajacy.md
new file mode 100644
index 00000000..3c60aa04
--- /dev/null
+++ b/_collections/_posts/2019-08-07-jezyk-wszystkomajacy.md
@@ -0,0 +1,183 @@
+---
+title: 'Kolejny język programowania - język wszystkomający'
+author: TheKamilAdam
+category: programming
+tags: lambda-calculus fp type-class
+langs: clojure eiffel elm emacs-lisp fsharp go haskell java javascript kotlin lisp meta-language ocaml perl python racket reasonml ruby rust sather scala scheme smalltalk tcl
+tools: jvm node-js
+libs: akka arrow cats pulsar quasar scalaz vavr zio
+redirect_from:
+ - jezyk-wszystkomajacy
+ - programming/jezyk-wszystkomajacy
+---
+
+**Język wszystkomający** jest to język w którym można programować
+[imperatywnie], [funkcyjnie], [obiektowo], [proceduralnie] oraz [strukturalnie].
+Prawdopodobnie jest to język zły do nauki jako pierwszy język programowania.
+Może też być złym językiem do nauki pojedynczych paradygmatów programowania,
+jeśli nie mamy odpowiedniej dyscypliny.
+Jeśli jednak mamy tę dyscyplinę jest to genialny język do nauki nowych paradygmatów programowania.
+Po co uczyć się nowych paradygmatów programowania starałem się wyjaśnić w artykule
+[Kolejny język programowania do nauki - paradygmaty programowania](/paradygmaty-programowania).
+
+## Pierwszy język wszystkomający
+Chyba najpopularniejszym językiem wszystkomającym jest **[Scala]**.
+Jednak to nie ten język programowania chciałbym Tobie polecić.
+A język będący pierwowzorem Scali.
+
+Istnieje popularna legenda,
+że Martin Odersky tworząc język **[Scala]** połączył świat obiektowy, czyli język **[Java]**,
+ze światem funkcyjnym, czyli z językiem **[Haskell]**.
+Jednak gdyby była to prawda to nie byłyby potrzebne dodatkowe biblioteki jak **[Scalaz]** lub **[Cats]** robiące z Scali Haskella.
+Tak naprawdę Martin Odersky dostał zlecenie dodania typów polimorficznych (nazywanych w Javie generykami)
+umożliwiających metaprogramowanie (nazywane w Javie programowaniem generycznym) do Javy 1.4.
+
+Ponieważ praca nad dodaniem typów generycznych do Javy była trudna,
+Martin Odersky stworzył nowy język programowania na **[JVM]** nazwany przez niego Generic Java.
+Wzorowany był on na innym do metaprogramowania,
+czyli funkcyjnym **[Meta Language]**.
+A dokładniej jego obiektowo-funkcyjnej wersji,
+czyli język **[OCaml]**.
+Później Generic Java dostała nową nazwę i tak powstał język programowania Scala.
+
+Chyba największą zmianą jaką zrobił Martin Odersky była zamiana znaczących wcięć na wąsate nawiasy,
+dzięki czemu **[Scala]** nie wygląda jak **[Python]**.
+Ale podobno co wersje Scali zastanawia się czy postąpił słusznie
+i czy nie przywrócić znaczących wcięć w miejsce wąsatych nawiasów.
+
+Ale dlaczego nikt o tym nie mówi i powszechnie uważa się,
+że **[Scala]** była pierwszym językiem obiektowo-funkcyjnym?
+Może dlatego,
+że z trzech rodzin funkcyjnych języków programowania **[OCaml]** jest najmniej znany.
+Na dowód tego mam przykładowe zapytania do wyszukiwarki google.
+* `scheme tutorial` - 1 770 000 000 wyników
+* `haskell tutorial` - 1 220 000 wyników
+* `ocaml tutorial` -233 000 wyników
+
+**[OCaml]** jest tak mało znany,
+że nie pojawia się nawet w rankingu [Tiobe],
+a **[Meta Language]** pojawia się w drugiej 50.
+
+Mimo tego to właśnie język **[OCaml]** chciałbym Tobie polecić jako kolejny język do nauki.
+Zwłaszcza jeśli nie lubisz składni języka **[Scala]** lub maszyny wirtualnej **[JVM]**.
+
+Ważne jest też to,
+że składnia języków **[OCaml]** powoli zaczyna być doceniana
+i przeżywa swój renesans pod postacią nowych języków programowania jak:
+* **[F#]** - dialekt języka OCaml na platformę .Net
+* **[ReasonML]** - dialekt języka OCaml transpiloway do **[JS]**
+* **[Elm]** - język transpilowany do **[JS]** inspirowany składnią języków **[Meta Language]** i **[Haskell]**
+
+## Język funkcyjny a pragmatyczny programista
+
+Dlaczego jednak autorzy książki nie wspomnieli o języku **[Ocaml]** powstałym w roku 1996?
+Nie wspomnieli też o językach
+**[LISP]** (1958), **[Meta Language]** (1973), **[Scheme]** (1975), **[Haskell]** (1990) oraz **[Racket]** (1995).
+Ani nawet o **[Emacs Lisp]** używanym do skryptowania w polecanym przez nich edytorze kodu Emacs!
+
+Książka [Pragmatyczny programista] powstała w 2000 roku.
+Świat informatyki i języków programowania wyglądał wtedy inaczej.
+Istniały trzy główne grupy języków programowania (przynajmniej według autorów książki [Pragmatyczny programista]):
+1. Niskopoziomowe, rozwlekłe [języki korporacyjne](/jezyk-korporacyjny) i [języki natywne](/jezyk-natywny) -
+ ciężko się w nich pisało, były rozwlekłe i wszystkie były podobne do siebie.
+2. Wysokopoziomowe, dynamicznie typowane [języki skryptowe](/jezyk-skryptowy) -
+**[TCL]**, **[Perl]**, **[Python]**.
+ **[Ruby]** był jeszcze nieznany poza Japonią.
+3. Języki eksperymentalne w których pokładano przyszłość, czyli:
+ * **[Smalltalk]** i jego implementacja [Squeak].
+Język totalnie obiektowy (zwany reflektywnym) w którym można było wszystko przedefiniować.
+ Odbijało się to jednak negatywnie na jego szybkości.
+ * **[Eiffel]** oraz wzorujący się na nim **[Sather]**,
+ promujące programowanie kontraktowe.
+Żaden z języków eksperymentalnych nie przebił się do mainstreamu.
+Jednocześnie autorzy nie zająkneli się na temat programowania funkcyjnego wierząc,
+że języki dynamicznie typowane i totalnie obiektowe (reflektywne)
+oraz programowanie kontraktowe rozwiążą wszystkie nasze problemy.
+Dziś wiadomo że nie rozwiązały.
+
+Część winy za to ponoszą naukowcy,
+tworzący języki funkcyjne,
+siedzący w swoich wysokich wieżach i z góry spoglądający na zwykłych programistów aplikacji biznesowych.
+
+## Postscriptum
+
+Jeśli jednak chcesz uczyć się języka,
+który jest używany w celach biznesowych,
+polecam Scalę.
+Jeśli jednak nie chcesz uczyć się Scali polecam małe porównanie języków programowania na **[JVM]**
+i które paradygmaty można osiągnąć w nich przy użyciu zewnętrznych bibliotek.
+
+| Paradygmat | [Java] | [Scala] | [Kotlin] | [Clojure] |
+| ------ | ------ | ------ | ------ | ------ |
+| Programowanie imperatywne/proceduralne/obiektowe z listami mutowalnymi | Java | *Sclava, ale nie ma imperatywnej pętli `for`* | Kotlin, *ale nie ma imperatywnej pętli `for`* | *Nie można, listy w Clojure z założenia są niemutowalne* |
+| Programowanie obiektowo-funkcyjne, jak w języku **[OCaml]**, plus niemutowalne listy | Java + **[Vavr]** | Scala | *Scotlin*, czyli Kotlin + Vavr-kotlin | Clojure |
+| Programowanie czysto funkcyjne jak w języku **[Haskell]** z typami wyższych rzędów | Java + **[Functional Java]** | Scala + **[Scalaz]** lub Scala + **[Cats]** | Kotlin + **[ARROW]** | *Nie można, Clojure jest dynamicznie typowany. Ale trwają prace nad @TypedClojure* |
+| Programowanie Aktorowe z *ciężkimi* aktorami | Java + **[Akka]** | Scala + **[Akka]** | Kotlin + **[Akka]** | *Nie widziałem. Autor języka Clojure ceni wyżej pamięć transakcyjną niż model aktorów* |
+| Programowanie z włóknami (ang. *fiber*), kanałami (ang. *channel*) i *lekkimi* aktorami | prawdopodobnie można użyć bibliotek **[ZIO]** lub **[Quasar]** | Scala + **[ZIO]** | Kotlin + **[Quasar]** | Clojure + **[Pulsar]** |
+
+Tu należy się małe wyjaśnienie:
+* *Sclava* jest to określenie imperatywnego kodu napisanego w Scali przez programistę Javy 6,
+ który tylko zerknął na dokumentację składni Scali
+ i swoje imperatywne przyzwyczajenia do nowopoznanego języka.
+* *Scotlin* lub *Skotlin* jest to określenie tego czym powoli staje się język Kotlin,
+ który początkowo miał być pragmatycznym i prostym do nauki językiem ogólnego przeznaczenia.
+ A powoli zbiera wszystkie pomysły ze Scali.
+Aktualnie trwają [dyskusje]()
+ nad wprowadzeniem **[klas typów]** (ang. *type class*) do tego pragmatycznego i prostego języka programowania.
+
+Z książek polecam [Java. Programowanie funkcyjne].
+Nawet jeśli nie programujesz w Javie warto przeczytać tę książkę.
+Ponieważ pokazuje ona jak niesamowicie elastyczne są języki obiektowe.
+Dzięki czemu można w łatwy sposób zaimplementować bibliotekę,
+która umożliwia programować funkcyjnie w języku obiektowym.
+
+[Clojure]: /langs/clojure
+[Eiffel]: /langs/eiffel
+[Elm]: /langs/elm
+[Emacs Lisp]: /langs/emacs-lisp
+[F#]: /langs/fsharp
+[Haskell]: /langs/haskell
+[Java]: /langs/java
+[JS]: /langs/javascript
+[Kotlin]: /langs/kotlin
+[LISP]: /langs/lisp
+[Meta Language]: /langs/meta-language
+[OCaml]: /langs/ocaml
+[Perl]: /langs/perl
+[Python]: /langs/python
+[Racket]: /langs/racket
+[ReasonML]: /langs/reasonml
+[Ruby]: /langs/ruby
+[Sather]: /langs/sather
+[Scala]: /langs/scala
+[Scheme]: /langs/scheme
+[Smalltalk]: /langs/smalltalk
+[TCL]: /langs/tcl
+
+[JVM]: /tools/jvm
+[node.js]: /tools/node-js
+
+[Akka]: /libs/akka
+[ARROW]: /libs/arrow
+[Cats]: /libs/cats
+[Functional Java]: /libs/functionaljava
+[Pulsar]: /libs/pulsar
+[Quasar]: /libs/quasar
+[Scalaz]: /libs/scalaz
+[Vavr]: /libs/vavr
+[ZIO]: /libs/zio
+
+[rachunek lambda]: /tags/lambda-calculus
+[klas typów]: /tags/type-class
+
+[Java. Programowanie funkcyjne]: /books/java-programowanie-funkcyjne
+[Pragmatyczny programista]: /books/pragmatyczny-programista
+
+[Squeak]: https://pl.wikipedia.org/wiki/Squeak
+[Tiobe]: https://www.tiobe.com/tiobe-index/
+
+[imperatywnie]: https://pl.wikipedia.org/wiki/Programowanie_imperatywne
+[funkcyjnie]: https://pl.wikipedia.org/wiki/Programowanie_funkcyjne
+[obiektowo]: https://pl.wikipedia.org/wiki/Programowanie_obiektowe
+[proceduralnie]: https://pl.wikipedia.org/wiki/Programowanie_proceduralne
+[strukturalnie]: https://pl.wikipedia.org/wiki/Programowanie_strukturalne
diff --git a/_collections/_posts/2019-09-25-no-exceptions.md b/_collections/_posts/2019-09-25-no-exceptions.md
new file mode 100644
index 00000000..bd8fa085
--- /dev/null
+++ b/_collections/_posts/2019-09-25-no-exceptions.md
@@ -0,0 +1,441 @@
+---
+title: 'No Exceptions - o problemach z wyjątkami'
+author: TheKamilAdam
+category: scala-jvm
+tags: no-exceptions monad tco
+langs: haskell java ocaml racket scala scheme smalltalk
+projects: linkchecker
+redirect_from:
+ - no-exceptions
+ - scala-jvm/no-exception
+---
+
+Wyjątki bywają problematyczne,
+ale przez swoich obrońców, są często przedstawiane jako jedna z fundamentalnych części programowania obiektowego.
+Co ciekawe wyjątków nie ma w [podstawowych założeniach paradygmatu obiektowego].
+Nie ma też nic o wyjątkach w definicji programowania obiektowego podanej przez Alana Kaya,
+lider zespołu tworzącego język **[Smalltalk]** uznawany za twórcę tego terminu.
+Za to jest o komunikowaniu się obiektów za pomocą wiadomości.
+
+Dlaczego wyjątki są problematyczne?
+Prześledźmy to na przykładzie prostego skryptu do testowania linków w ramach domeny.
+
+## Problem martwych linków
+
+Mam na blogu wiele linków.
+Wiem że część z nich jest martwa i prowadzi nigdzie, a ja chciałbym to naprawić.
+Niestety nie wiem, które są to linki.
+Więc postanowiłem napisać skrypt, który je wszystkie zagreguje.
+
+Mówiąc skrypt mam na myśli mały program do którego nie warto pisać testów jednostkowych.
+
+## Algorytm działania skryptu
+
+Algorytm działania skryptu jest prosty:
+1. Budowanie stanu początkowego - zaczynamy od jednoelementowego zbioru zawierającego URL będący domeną
+2. Komunikacja ze światem zewnętrznym - dla każdego URL ze zbioru pobieramy źródło strony.
+W rezultacie mamy zbiór źródeł stron
+3. Budowa kolejnego stanu - Każde źródło ze zbioru parsujemy w poszukiwaniu linków wewnętrznych.
+ W rezultacie mamy zbiór zbiorów linków wewnętrznych.
+ Spłaszczamy zbiór zbiorów i zamieniamy linki wewnętrzne na URL
+4. Iteracja - Jeśli zbiór jest niepusty skaczemy do kroku 2.
+
+## Pierwsza wersja skryptu, ze standardowymi wyjątkami
+
+> Każda dobra przygoda zaczyna się od `main`
+
+@jarek000000
+
+```scala
+object StandardExceptionHyde {
+
+ private val domain = "https://www.writeonly.pl"
+
+ def main(args: Array[String]): Unit = apply().showResult()
+
+ def apply(): AbstractOOState = StandardExceptionState(domain)
+}
+```
+Obiekt singletonowy wydaje się w takiej postaci nie mieć sensu,
+ale metoda `apply` przyda się do późniejszych testów wydajności.
+
+### Punkt 1. Budowa stanu początkowego
+
+```scala
+trait AbstractOOStateObject {
+
+ final def apply(domain: String): AbstractOOState = fromDomain(new Domain(domain)) |> AbstractOOState.run
+
+ def fromDomain(implicit d: Domain): AbstractOOState
+}
+
+object StandardExceptionState extends AbstractOOStateObject {
+
+ override def fromDomain(implicit d: Domain): AbstractOOState = new StandardExceptionState(Urls.fromDomain)
+}
+```
+Na początku jest wywoływana metoda `apply` obiektu singletonowego `StandardExceptionState`.
+Obiekt `StandardExceptionState` tworzy stan początkowy w metodzie `fromDomain`, który jest następnie przekazywany do metody `run`.
+
+### Punkt 4. Iteracja czyli rekurencja
+
+W programowaniu imperatywnym uczymy się,
+że iteracja jest dobra (bo wydajna),
+a rekurencja jest zła (bo niewydajna).
+Niestety większość algorytmów jest rekurencyjna.
+Dlatego programiści opanowali do perfekcji zamianę algorytmów rekurencyjnych na implementacje iteracyjne.
+
+Matematycy byli sprytniejsi.
+Stworzyli funkcyjne języki programowania,
+takie jak **[Scheme]**, **[Ocaml]**, **[Haskell]**, **[Racket]**,
+w których rekurencja jest tak samo wydajna jak iteracja (czyli jest dobra).
+
+Jednak nie każdy rodzaj rekurencji jest dobry (wydajny).
+Ten rodzaj, który jest dobry jest nazywany rekurencja ogonową.
+Rekurencja ogonowa (ang. *tail call*) zwana też rekurencją prawostronną,
+jest to odmiana rekurencji,
+gdzie ostatnią operacją w funkcji jest wywołanie samej siebie.
+Dzięki czemu kompilator może w łatwy sposób przeprowadzić optymalizację (ang. *tail call optimization*, **[TCO]**)
+
+Rekurencji jednak nie należy nadużywać.
+Przez autora książki [Java. Programowanie funkcyjne] jest porównywana do instrukcji `goto`.
+Jednak czasem rekurencja jest potrzebna bezpośrednio.
+Są to te wypadki w których nie znamy ilości iteracji do wykonania,
+a posiadamy tylko warunek stopu iteracji.
+
+Tak właśnie jest w obiekcie `AbstractOOState`
+```scala
+object AbstractOOState {
+ @tailrec
+ def run(state: AbstractOOState): AbstractOOState = if (state.isEmptyNextInternalUrls) state else run(state.next)
+}
+```
+Metoda `run` jest rekurencyjna, czyli wywołuje samą siebie.
+Za każdym razem z nową wersję stanu.
+Metoda `isEmptyNextInternalUrls` jest warunkiem stopu.
+A adnotacja `tailrec` gwarantuje,
+że kompilacja się nie powiedzie,
+jeśli rekurencji nie będzie dało się zoptymalizować.
+
+### Punkt 3. Budowa kolejnego stanu
+
+```scala
+abstract class AbstractOOState(urls: Urls)(implicit d: Domain) extends State {
+
+ final def next: AbstractOOState = getWrappedUrlSet |> NewUrls.apply |> urls.next |> nextState
+
+ final def getWrappedUrlSet: WrappedUrlSet =
+ urls.nextInternalUrls
+ .map(impureFunction)
+ .flatMap(_.getWrappedUrlSet)
+
+ override final def showResult(): Unit = urls.showResult()
+
+ override final def showStep(): Unit = urls.showStep()
+
+ override final def isEmptyNextInternalUrls: Boolean = urls.isEmptyNextInternalUrls
+
+ def nextState(urls: Urls): AbstractOOState
+
+ def impureFunction: InternalUrlToSourcePage
+}
+
+class StandardExceptionState(urls: Urls)(implicit d: Domain) extends AbstractOOState(urls) {
+
+ override def nextState(urls: Urls): AbstractOOState = new StandardExceptionState(urls)
+
+ override def map: InternalUrl => SourcePage = SourcePageFromInternalUrl.apply
+}
+```
+
+Cały algorytm budowania kolejnego kroku znajduje się w metodzie `next`.
+Z czego najważniejszy jest etap pierwszy,
+czyli wywołanie metody `getWrappedUrlSet`.
+`WrappedUrlSet` to alias dla `Set[WrappedUrl]`.
+Na podstawie każdego linka ze zbioru jest pobierane źródło strony.
+Następnie każde źródło strony jest parsowane i są wyodrębniane nowe linki.
+Przy okazji jest wykorzystywane to że w Scali zbiory są monadami.
+
+### Pubkt 2. Komunikacja ze światem zewnętrznym, czyli nieczysta funkcja (ang. impure function)
+
+```scala
+object SourcePageFromInternalUrl extends InternalUrlToSourcePage {
+
+ def apply(internalUrl: InternalUrl): SourcePage = Source.fromURL(internalUrl.toURL).mkString |> SourcePage.apply
+}
+
+ type InternalUrlToSourcePage = InternalUrlTo[SourcePage]
+
+type InternalUrlTo[A] = InternalUrl => A
+```
+
+Funkcja `HtmlFromInternalRef` pobiera źródło strony na podstawie linku.
+Jest jedynym miejscem,
+gdzie łączymy się ze światem zewnętrznym.
+Jest to też jedyne miejsce w kodzie,
+gdzie spodziewamy się wyjątku.
+A skoro coś złego może się wydarzyć to na pewno się wydarzy.
+
+### Wynik
+
+Po uruchomieniu obiektu singletonowego `StandardExceptionHyde` szybko w konsoli pojawi się Stacktrace:
+
+```log
+Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
+ at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
+ at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
+ at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
+ at java.io.InputStreamReader.read(InputStreamReader.java:184)
+ at java.io.BufferedReader.read1(BufferedReader.java:210)
+ at java.io.BufferedReader.read(BufferedReader.java:286)
+ at java.io.Reader.read(Reader.java:140)
+ at scala.io.BufferedSource.mkString(BufferedSource.scala:98)
+ at pl.writeonly.scala.hyde.htmlpage.oo.SourcePageFromInternalUrl$.apply(SourcePageFromInternalUrl.scala:11)
+ at pl.writeonly.scala.hyde.impl.oo.oo1.StandardExceptionState.$anonfun$impureFunction$1(StandardExceptionState.scala:12)
+ at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:238)
+ at scala.collection.immutable.RedBlackTree$._foreachKey(RedBlackTree.scala:111)
+ at scala.collection.immutable.RedBlackTree$._foreachKey(RedBlackTree.scala:110)
+ at scala.collection.immutable.RedBlackTree$._foreachKey(RedBlackTree.scala:110)
+ at scala.collection.immutable.RedBlackTree$._foreachKey(RedBlackTree.scala:110)
+ at scala.collection.immutable.RedBlackTree$.foreachKey(RedBlackTree.scala:107)
+ at scala.collection.immutable.TreeSet.foreach(TreeSet.scala:170)
+ at scala.collection.TraversableLike.map(TraversableLike.scala:238)
+ at scala.collection.TraversableLike.map$(TraversableLike.scala:231)
+ at scala.collection.immutable.TreeSet.scala$collection$SetLike$$super$map(TreeSet.scala:53)
+ at scala.collection.SetLike.map(SetLike.scala:104)
+ at scala.collection.SetLike.map$(SetLike.scala:104)
+ at scala.collection.immutable.TreeSet.map(TreeSet.scala:53)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOState.getWrappedUrlSet(AbstractOOState.scala:18)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOState.next(AbstractOOState.scala:14)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOState$.run(AbstractOOState.scala:34)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOStateObject.$anonfun$apply$1(AbstractOOStateObject.scala:8)
+ at scalaz.syntax.IdOps$.$bar$greater$extension(IdOps.scala:13)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOStateObject.apply(AbstractOOStateObject.scala:8)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOStateObject.apply$(AbstractOOStateObject.scala:8)
+ at pl.writeonly.scala.hyde.impl.oo.oo1.StandardExceptionState$.apply(StandardExceptionState.scala:15)
+ at pl.writeonly.scala.hyde.impl.oo.oo1.StandardExceptionHyde$.apply(StandardExceptionHyde.scala:11)
+ at pl.writeonly.scala.hyde.impl.oo.oo1.StandardExceptionHyde$.main(StandardExceptionHyde.scala:9)
+ at pl.writeonly.scala.hyde.impl.oo.oo1.StandardExceptionHyde.main(StandardExceptionHyde.scala)
+```
+
+Niestety Stacktrace w żaden sposób nie mówi nam dla jakiego URLa wyjątek został rzucony.
+
+### Wrapping Exceptions
+
+Z powyższego Stacktrace'u wynika jedna prosta nauka.
+Zwykle nie powinniśmy pozwalać na to by wyjątki rzucone przez zewnętrzny kod,
+tj. bibliotekę standardową języka [Java],
+przechodziły przez całą aplikację.
+O wiele lepszym rozwiązaniem jest owinąć taki wyjątek wpisując do pola `message` parametry wejściowe pomagające rozpoznać powód wyjątku.
+
+```scala
+object SourcePageOrThrowExceptionFromInternalUrl extends InternalUrlToSourcePage {
+
+ @SuppressWarnings(Array("org.wartremover.warts.Throw"))
+ override def apply(internalUrl: InternalUrl): SourcePage =
+ try {
+ SourcePageFromInternalUrl(internalUrl)
+ } catch {
+ case e: RuntimeException => throw internalUrl.toException(e)
+ case e: IOException => throw internalUrl.toException(e)
+ case e: URISyntaxException => throw internalUrl.toException(e)
+ }
+}
+```
+Czemu ta lista zawiera aż trzy przypadki?
+Otóż nie potrafiłem się zdecydować czy używam klasy `java.net.URL` czy `java.net.URI`, a żeby było trudniej:
+* konstruktor klasy `java.net.URL` rzuca `MalformedURLException` dziedziczący po `IOException`
+* metoda `openStream` klasy `java.net.URL` rzuca `IOException`
+* konstruktor klasy `java.net.URI` rzuca `URISyntaxException`
+* statyczna metoda `create` klasy `java.net.URI` rzuca wyjątek `IllegalArgumentException` dziedziczący po `RuntimeException`
+
+Możnaby łapać zawsze `Exception` po którym dziedziczą wszystkie pozostałe wyjątki, ale w Javie nie jest to zalecane.
+Do tego dziwnego zalecenia jeszcze wrócę.
+
+Teraz po uruchomieniu klasy `WrappingExceptionHyde` zobaczymy:
+
+```log
+Exception in thread "main" pl.writeonly.scala.hyde.common.url.exception.UrlException: https://www.writeonly.pl/assets/favicon.ico
+ at pl.writeonly.scala.hyde.common.url.WrappedUrl.toException(WrappedUrl.scala:20)
+ at pl.writeonly.scala.hyde.common.url.typed.InternalUrl.toException(InternalUrl.scala:14)
+ at pl.writeonly.scala.hyde.htmlpage.oo.SourcePageOrThrowExceptionFromInternalUrl$.apply(SourcePageOrThrowExceptionFromInternalUrl.scala:17)
+ at pl.writeonly.scala.hyde.impl.oo.oo2.WrappingExceptionState.$anonfun$impureFunction$1(WrappingExceptionState.scala:12)
+ at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:238)
+ at scala.collection.immutable.RedBlackTree$._foreachKey(RedBlackTree.scala:111)
+ at scala.collection.immutable.RedBlackTree$._foreachKey(RedBlackTree.scala:110)
+ at scala.collection.immutable.RedBlackTree$._foreachKey(RedBlackTree.scala:110)
+ at scala.collection.immutable.RedBlackTree$._foreachKey(RedBlackTree.scala:110)
+ at scala.collection.immutable.RedBlackTree$.foreachKey(RedBlackTree.scala:107)
+ at scala.collection.immutable.TreeSet.foreach(TreeSet.scala:170)
+ at scala.collection.TraversableLike.map(TraversableLike.scala:238)
+ at scala.collection.TraversableLike.map$(TraversableLike.scala:231)
+ at scala.collection.immutable.TreeSet.scala$collection$SetLike$$super$map(TreeSet.scala:53)
+ at scala.collection.SetLike.map(SetLike.scala:104)
+ at scala.collection.SetLike.map$(SetLike.scala:104)
+ at scala.collection.immutable.TreeSet.map(TreeSet.scala:53)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOState.getWrappedUrlSet(AbstractOOState.scala:18)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOState.next(AbstractOOState.scala:14)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOState$.run(AbstractOOState.scala:34)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOStateObject.$anonfun$apply$1(AbstractOOStateObject.scala:8)
+ at scalaz.syntax.IdOps$.$bar$greater$extension(IdOps.scala:13)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOStateObject.apply(AbstractOOStateObject.scala:8)
+ at pl.writeonly.scala.hyde.common.states.oo.AbstractOOStateObject.apply$(AbstractOOStateObject.scala:8)
+ at pl.writeonly.scala.hyde.impl.oo.oo2.WrappingExceptionState$.apply(WrappingExceptionState.scala:15)
+ at pl.writeonly.scala.hyde.impl.oo.oo2.WrappingExceptionHyde$.apply(WrappingExceptionHyde.scala:11)
+ at pl.writeonly.scala.hyde.impl.oo.oo2.WrappingExceptionHyde$.main(WrappingExceptionHyde.scala:9)
+ at pl.writeonly.scala.hyde.impl.oo.oo2.WrappingExceptionHyde.main(WrappingExceptionHyde.scala)
+Caused by: java.nio.charset.MalformedInputException: Input length = 1
+ at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
+ at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
+ at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
+ at java.io.InputStreamReader.read(InputStreamReader.java:184)
+ at java.io.BufferedReader.read1(BufferedReader.java:210)
+ at java.io.BufferedReader.read(BufferedReader.java:286)
+ at java.io.Reader.read(Reader.java:140)
+ at scala.io.BufferedSource.mkString(BufferedSource.scala:98)
+ at pl.writeonly.scala.hyde.htmlpage.oo.SourcePageFromInternalUrl$.apply(SourcePageFromInternalUrl.scala:11)
+ at pl.writeonly.scala.hyde.htmlpage.oo.SourcePageOrThrowExceptionFromInternalUrl$.apply(SourcePageOrThrowExceptionFromInternalUrl.scala:14)
+ ... 25 more
+```
+
+Dzięki dodatkowym informacjom zawartym w polu `message` możemy pracować w sposób interaktywny w pętli:
+* Jedno uruchomienie programu
+* Jeden złapany wyjątek
+* Jeden poprawiony link
+
+### Try No Exception
+
+I wszystko byłoby dobrze gdyby nie to,
+że często potrzebujemy raport ze wszystkimi błędami.
+Chociażby dlatego, żeby oszacować ilość pracy do zrobienia.
+W takim wypadku potrzebujemy konstrukcji,
+która pozwoli nam zapisać wyjątek z niedziałania konkretnego linku i iść ze sprawdzeniem dalej,
+nie przerywając głównej pętli programu.
+
+Rozwiązaniem jest tutaj [monada] `Try`.
+Nie powinniśmy się jednak przejmować tym brzydkim słowem na `M` ponieważ ta właściwość nie zostanie tutaj użyta.
+Obiekt singletonowy `Try` ma jedną metodę `apply` pozwalającą konstruować nowe instancje klasy `Try`:
+```scala
+object Try {
+ def apply[T](r: => T): Try[T] =
+ try Success(r) catch {
+ case NonFatal(e) => Failure(e)
+ }
+}
+```
+
+W tym krótkim kodzie warto zwrócić uwagę na dwie rzeczy.
+Po pierwsze metoda `apply` pobiera parametr przez nazwę ([by-name]) dzięki czemu wartość parametru zostanie wyliczona dopiero w konstrukcji `try`.
+Po drugie są łapane wszystkie wyjątki za wyjątkiem tych *fatalnych*.
+Które wyjątki są fatalne?
+To można zobaczyć wewnątrz obiektu singletonowego `NonFatal`:
+```scala
+object NonFatal {
+ def apply(t: Throwable): Boolean = t match {
+ case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
+ case _ => true
+ }
+// ...
+}
+```
+Otóż łapane są nie tylko wszystkie wyjątki,
+ale także spora część błędów,
+czyli klas dziedziczących po klasie `Error`.
+Zupełnie inaczej niż zwykle zleca się w świecie Javy.
+
+Teraz gdy już wiemy jak działa monada `Try` możemy napisać nową wersję funkcji do pobierania dokumentu HTML:
+```scala
+object SourcePageTryFromInternalUrl extends InternalUrlTo[SourcePageTry] {
+
+ def apply(internalUrl: InternalUrl): SourcePageTry = Try { internalUrl |> SourcePageFromInternalUrl.apply }
+}
+
+type SourcePageTry = Try[SourcePage]
+```
+
+Ten kod nigdy nie rzuci wyjątku, za to zamiast prostej wartości `SourcePageTry` dostaniemy `Try[SourcePage]`.
+
+Teraz już możemy napisać algorytm przetwarzania zbioru `Try[SourcePage]` na zbiór nowych linków do odwiedzenia.
+
+```scala
+class TryState(data: UrlsWithThrowableList)(implicit d: Domain) extends AbstractAPIState(data) with AbstractFunctionState {
+
+ override def nextState(data: UrlsWithThrowableList): AbstractNextState = new TryState(data)
+
+ override def impureFunction: HPFromInternalUrl = SourcePageTryFromInternalUrl.apply
+
+ override type HP = SourcePageTry
+
+ def nextData(set: SourcePageTrySet): UrlsWithThrowableList = {
+
+ val partitioned = set.partition(_.isSuccess)
+
+ val newWrappedUrls: WrappedUrlSet = partitioned._1
+ .flatMap(TryState.sourcePageTryToWrappedUrlSet)
+
+ val newThrowableList: ThrowableList = partitioned._2.toList
+ .flatMap(_.failed.toOption.toList)
+
+ val newUrls = NewUrls(newWrappedUrls)
+
+ data.next(newUrls, newThrowableList)
+ }
+}
+
+object TryState extends AbstractNextStateObject {
+
+ override def fromDomain(implicit d: Domain): AbstractNextState = new TryState(UrlsWithThrowableList.fromDomain)
+
+ val sourcePageTryToWrappedUrlSet: SourcePageTry => WrappedUrlSet = _.map(_.getWrappedUrlSet).toOption.toSet.flatten
+}
+
+trait AbstractNextStateObject {
+
+ final def apply(domain: String): AbstractNextState = fromDomain(new Domain(domain)) |> AbstractNextState.run
+
+ def fromDomain(implicit d: Domain): AbstractNextState
+}
+```
+
+Przy czym najważniejsza jest tutaj metoda `nextData`, która:
+* Najpierw dzielimy zbiór pobranych dokumentów SourcePage na krotkę `partitioned` na wartości poprawne (`Success`) i niepoprawne (`Failure`)
+* Następnie na podstawie poprawnych wartości budujemy zmienną `newWrappedUrls` zawierający nowe linki wewnętrzne
+* Z drugiej części krotki tworzymy zmienną `newThrowableList` będącą listą wszystkich niepoprawnych linków
+* Na podstawie otrzymanych danych tworzymy nowy stan, który zwracamy
+
+## Podsumowanie - trzy nauki o wyjątkach
+
+1. No Three-Part Exceptions
+2. No Checked Exceptions
+3. No Exceptions
+
+A na poważnie:
+* **Żadnych cudzych wyjątków - cudze wyjątki nie zawierają kontekstu**.
+Każdy wyjątek należy opakować i dodać jak najwięcej informacji z kontekstu dlaczego został rzucony
+* **Żadnych weryfikowalnych wyjątków - wyjątki niszczą interfejs**.
+Należy rzucać tylko wyjątki dziedziczące po RuntimeException.
+W Scali ten punkt nie jest problemem, ponieważ w Scali wszystkie wyjątki są `unchecked`.
+* **Żadnych wyjątków - wyjątki nie są funkcyjne**.
+Jeśli tylko to możliwe zamiast wyjątków należy używać klas
+`Option`, `Validation`, `Either`, `Try`.
+
+Kod jest dostępny na [Githubie](https://github.com/writeonly/linkchecker/tree/v1.0).
+
+[haskell]: /langs/haskell
+[java]: /langs/java
+[ocaml]: /langs/ocaml
+[racket]: /langs/racket
+[scala]: /langs/scala
+[scheme]: /langs/scheme
+[smalltalk]: /langs/smalltalk
+
+[linkchecker]: /projects/linkchecker
+
+[no-exceptions]: /tags/no-exceptions
+[TCO]: /tags/tco
+
+[Java. Programowanie funkcyjne]: /books/java-programowanie-funkcyjne
+
+[podstawowych założeniach paradygmatu obiektowego]: https://pl.wikipedia.org/wiki/Programowanie_obiektowe#Podstawowe_za%C5%82o%C5%BCenia_paradygmatu_obiektowego
+
+[by-name]: https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_name
diff --git a/_collections/_posts/2019-10-30-no-exceptions-std-lib.md b/_collections/_posts/2019-10-30-no-exceptions-std-lib.md
new file mode 100644
index 00000000..25de4cfa
--- /dev/null
+++ b/_collections/_posts/2019-10-30-no-exceptions-std-lib.md
@@ -0,0 +1,261 @@
+---
+title: 'No Exceptions - problemy z wyjątkami i biblioteka standardowa'
+author: TheKamilAdam
+category: scala-jvm
+tags: io no-exceptions monad
+langs: haskell java rust scala
+libs: vavr
+projects: linkchecker
+redirect_from:
+ - no-exceptions-std-lib
+ - scala-jvm/no-exception-std-lib
+---
+
+To jest druga część cyklu o walce z wyjątkami w Scali. Zobacz [część pierwszą](/no-exceptions).
+
+## Try vs Either
+`Try` nie jest jedynym sposobem w bibliotece standardowej Scali na radzenie sobie z wyjątkami w kodzie.
+W ostatnim przykładzie poprzedniej części użyliśmy monady `Try`.
+Ogólnie `Try` nie jest zalecane w nowym kodzie.
+Chociażby dlatego, że nie możemy zamiast `Throwable` używać bardziej specyficznego błędu.
+W naszym przypadku `UrlException`.
+
+Rozwiązaniem jest [monada] `Either`.
+[Monada] `Either` podobnie jak [monada] `Try` posiada dwie wartości.
+Jednak w jego przypadku nazywają się one `right` i `left`:
+* `right` jest prawa - czyli poprawny
+* `left` jest lewa - czyli niepoprawny
+
+Chociaż w przypadku monady `Either` ze standardowej biblioteki Scali jest to głównie tylko konwencja.
+
+```scala
+object SourcePageEitherFromInternalUrl extends InternalUrlTo[SourcePageEither] {
+
+ override def apply(internalUrl: InternalUrl): SourcePageEither = applyWithThrowable(internalUrl).left.map(internalUrl.toException)
+
+ private def applyWithThrowable(internalUrl: InternalUrl) = nonFatalCatch either { internalUrl |> SourcePageFromInternalUrl.apply }
+}
+
+type SourcePageEither = Either[UrlException, SourcePage]
+```
+
+Metoda `nonFatalCatch` z obiektu singletonowego `scala.util.control.Exception` jest ładnym wrapperem na obiekt singletonowy `NonFatal` użyty w poprzedniej części cyklu.
+
+Jaka jest wyższość monady `Either` nad monadą `Try`?
+W monadzie `Try` możemy sparametryzować tylko warość poprawną.
+W monadzie `Eiher` - także błąd.
+Ogólnie to szkoda, że [monada] `Try` nie jest zdefiniowany jako:
+```scala
+type Try[A] = Either[Throwable, A]
+```
+Bo taką funkcję właśnie pełni w kodzie
+
+Reszta kodu po przeróbkach:
+```scala
+object EitherState extends AbstractNextStateObject {
+
+ override protected def fromDomain(implicit d: Domain): AbstractNextState = new EitherState(UrlsWithThrowableList.fromDomain)
+}
+
+class EitherState(data: UrlsWithThrowableList)(implicit d: Domain) extends EitherAPIState(data) with AbstractFunctionState {
+
+ override protected def nextState(data: UrlsWithThrowableList): AbstractNextState = new EitherState(data)
+
+ override protected def impureFunction: HPFromInternalUrl = SourcePageEitherFromInternalUrl.apply
+}
+```
+
+```scala
+abstract class EitherAPIState(data: UrlsWithThrowableList)(implicit d: Domain) extends AbstractAPIState(data) {
+ override protected type HP = SourcePageEither
+
+ protected def nextData(set: SourcePageEitherSet): UrlsWithThrowableList = {
+
+ val partitioned = set.partition(_.isRight)
+
+ val newWrappedUrls: WrappedUrlSet = partitioned._1
+ .flatMap(EitherAPIState.sourcePageEitherToWrappedUrlSet)
+
+ val newThrowableList: ThrowableList = partitioned._2.toList
+ .flatMap(_.left.toOption.toList)
+
+ val newUrls = NewUrls(newWrappedUrls)
+
+ data.next(newUrls, newThrowableList)
+ }
+}
+
+object EitherAPIState {
+ val sourcePageEitherToWrappedUrlSet: SourcePageEither => WrappedUrlSet =
+ _.right.map(_.getWrappedUrlSet).right.toOption.toSet.flatten
+}
+```
+Podobnie jak w przypadku `Try` dzielimy listę pobranych źródeł na elementy dobre lub nie,
+jednak teraz są to elementy `right` lub `left`.
+
+## Future
+
+Poprzednie wersje skryptu miały jedną bardzo ważną wadę.
+Interakcje ze światem zewnętrznym były wykonywane po kolej (sekwencyjnie).
+Pobieranie źródła strony jest akcją angażującą urządzenia wejścia-wyjścia (**[IO]**) jest to akcja powolna.
+Procesor w tym czasie czeka i nic nie robi.
+
+Można to rozwiązać za pomocą (prawie) monady,
+czyli **[FlatMappable]** `Future`.
+Jej nazwa pochodzi od tego że wynik dostaniemy w przyszłości, a w międzyczasie procesor może wykonywać inne rzeczy jak:
+* budować kolejne monady `Future`
+* przeliczać wartości które już otrzymał z monady `Future`
+
+Konstrukcje podobne to `Future` w różnych bibliotekach i językach są zwane także zadaniami (ang. `Task`),
+obietnicami (ang. `Promise`) lub po prostu **[IO]**.
+```scala
+object SourcePageFutureFromInternalUrl {
+
+ def apply(internalUrl: InternalUrl)(implicit ec: ExecutionContext): SourcePageFuture =
+ Future { internalUrl |> SourcePageEitherFromInternalUrl.apply }
+}
+```
+
+`implicit ec: ExecutionContext` jest potrzebny do tworzenia i przekształcania monady `Future`.
+
+## Short Future
+
+Reszta kodu po dostosowaniu do monady `Future`:
+
+```scala
+object EitherBeginState {
+
+ def apply(domain: String)(implicit ec: ExecutionContext): AbstractNextState = fromDomain(new Domain(domain)) |> AbstractNextState.run
+
+ private def fromDomain(domain: Domain)(implicit ec: ExecutionContext): AbstractNextState = fromDomainAllImplicit(domain, ec)
+
+ private def fromDomainAllImplicit(implicit d: Domain, ec: ExecutionContext): AbstractNextState =
+ new EitherBeginState(UrlsWithThrowableList.fromDomain)
+}
+
+class EitherBeginState(data: UrlsWithThrowableList)(implicit d: Domain, ec: ExecutionContext) extends EitherAPIState(data) with AbstractNewSetState {
+
+ override protected def nextState(data: UrlsWithThrowableList): AbstractNextState = new EitherBeginState(data)
+
+ override protected def newSet: SourcePageEitherSet = {
+
+ val set: Set[Future[SourcePageEither]] = nextUrls
+ .map(SourcePageFutureFromInternalUrl.apply)
+
+ val future: Future[SourcePageEitherSet] = Future.sequence(set)
+
+ Await.result(future, 1.minute)
+}
+```
+
+Metoda `Future.sequence` trawersuje zbiór,
+czyli zbiór monad `Future` zamienia na jedną monadę `Future` zawierającą zbiór.
+Następnie metoda `Await.result(future, 1.minute)` wypakowywuje zawartość monady,
+czyli oczekuje blokująco maksymalnie jedną minutę aż wszystkie zadania zostaną zakończone.
+
+## Long Future
+
+Ponieważ wypakowywanie monady `Future` jest operacją blokującą powinniśmy odwlec ten moment maksymalnie w czasie.
+Niestety tutaj bez zmiany interfejsu można przesunąć tylko jedno mapowanie wyniku:
+
+```scala
+object EitherEndState {
+
+ def apply(domain: String)(implicit ec: ExecutionContext): AbstractNextState = fromDomain(new Domain(domain)) |> AbstractNextState.run
+
+ private def fromDomain(domain: Domain)(implicit ec: ExecutionContext): AbstractNextState = fromDomainAllImplicit(domain, ec)
+
+ private def fromDomainAllImplicit(implicit d: Domain, ec: ExecutionContext): AbstractNextState =
+ new EitherEndState(UrlsWithThrowableList.fromDomain)
+}
+
+class EitherEndState(data: UrlsWithThrowableList)(implicit d: Domain, ec: ExecutionContext) extends EitherAPIState(data) with AbstractNextState {
+
+ override protected def nextState(data: UrlsWithThrowableList): AbstractNextState = new EitherEndState(data)
+
+ override def next: AbstractNextState = {
+
+ val set: Set[Future[SourcePageEither]] = nextUrls
+ .map(SourcePageFutureFromInternalUrl.apply)
+
+ val monad: Future[NextState] = Future
+ .sequence(set)
+ .map(newState)
+
+ Await.result(monad, 1.minute)
+ }
+}
+```
+
+## Future forever
+
+Jak już pisałem monadę `Future` należy wypakowywać jak najpóźniej,
+a w idealnym świecie nigdy nie powinniśmy wypakowywać monady `Future`.
+
+Niestety w tym celu musimy porzucić wywołania ogonowe i zadowolić się zwykłą rekurencją
+```scala
+object FutureState {
+
+ def apply(domain: String)(implicit ec: ExecutionContext): ParallelStateFuture = fromDomain(new Domain(domain)) |> run
+
+ private def fromDomain(domain: Domain)(implicit ec: ExecutionContext): FutureState = fromDomainAllImplicit(domain, ec)
+
+ private def fromDomainAllImplicit(implicit d: Domain, ec: ExecutionContext): FutureState =
+ new FutureState(UrlsWithThrowableList.fromDomain)
+
+ private def run(state: FutureState)(implicit executor: ExecutionContext): Future[EitherAPIState] =
+ if (state.isEmptyNextInternalUrls) Future.successful(state) else state.nextMonad.flatMap(run)
+}
+
+class FutureState(data: UrlsWithThrowableList)(implicit d: Domain, ec: ExecutionContext) extends EitherAPIState(data) {
+
+ override protected def nextState(data: UrlsWithThrowableList): NextState = new FutureState(data)
+
+ override type NextState = FutureState
+
+ def nextMonad: Future[FutureState] = {
+
+ val set: Set[Future[SourcePageEither]] = nextUrls
+ .map(SourcePageFutureFromInternalUrl.apply)
+
+ val monad: Future[SourcePageEitherSet] = Future
+ .sequence(set)
+
+ monad.map(newState)
+ }
+}
+```
+
+## Podsumowanie
+
+Monady pozwalają nie tylko rozwiązywać problem wyjątków w kodzie,
+ale także ułatwiają programowanie asynchroniczne oraz równoległe.
+
+Skąd pewność,
+że cokolwiek z tego co tu opisałem ma sens i jest przydatne w codziennej pracy programisty,
+a nie jest tylko wymysłem twórców języka **[Haskell]**?
+Ponieważ nowoczesny i wysokowydajny natywny język programowania **[Rust]**,
+zwany przez twórców językiem systemowym, nie posiada wyjątków.
+Dla błędów naprawialnych posiada klasę `Result` będącą odpowiednikiem klasy `Either` ze Scali.
+A dla błędów nie naprawialnych posiada makro `panic!` będące odpowiednikiem klasy `Error`,
+ale niemożliwej do złapania.
+Każde makro `panic!` zabija wątek w którym zostało zastosowane.
+Mimo tego **[Rust]** jest szybki jak C i C++.
+
+Monad `Option`, `Either`, `Try` oraz `Future` można używać także w języku programowania **[Java]** za pomocą biblioteki **[vavr]**.
+
+Kod jest oczywiście dostępny na [Githubie](https://github.com/writeonly/linkchecker/tree/v2.0).
+
+[haskell]: /langs/haskell
+[java]: /langs/java
+[rust]: /langs/rust
+[scala]: /langs/scala
+
+[vavr]: /libs/vavr
+
+[linkchecker]: /projects/linkchecker
+
+[io]: /tags/io
+[FlatMappable]: /tags/flatmappable
+[monada]: /tags/monad
+[no-exceptions]: /tags/no-exceptions
diff --git a/_collections/_posts/2019-11-27-no-exceptions-thridparty-lib.md b/_collections/_posts/2019-11-27-no-exceptions-thridparty-lib.md
new file mode 100644
index 00000000..dfc25a73
--- /dev/null
+++ b/_collections/_posts/2019-11-27-no-exceptions-thridparty-lib.md
@@ -0,0 +1,255 @@
+---
+title: 'No Exceptions - problemy z biblioteką standardową i biblioteki zewnętrzne'
+author: TheKamilAdam
+category: scala-jvm
+tags: api applicative for-comprehensions monad no-exceptions
+langs: scala haskell
+tools: clang
+libs: scalaz
+projects: linkchecker
+redirect_from:
+ - no-exceptions-thridparty-lib
+ - scala-jvm/no-exceptions-thridparty-lib
+---
+
+To jest trzecia część cyklu o walce z wyjątkami w Scali.
+Zobacz część [pierwszą](/no-exceptions) i [drugą](/no-exceptions-std-lib).
+
+## Problemy bibliotek standardowych
+
+Biblioteka standardowa Scali nie jest idealna.
+Ma swoje problemy.
+Ale **[Scala]** jako język programowania nie jest tu wyjątkiem.
+
+Biblioteki standardowe często mają błędy i niedoskonałości.
+Twórcy języków mają mało chęci by łamać istniejące **[API]**.
+Przykładem może być funkcja [gets](https://pl.wikibooks.org/wiki/C/gets) z języka **[C]** o sygnaturze:
+```c
+char *gets(char *str);
+```
+Funkcja nie sprawdza, czy jest miejsce do zapisu w tablicy `str`.
+Z tego powodu funkcja ta jest niebezpieczna.
+A mogłaby mieć zmienioną sygnaturę na:
+```c
+char *gets(char *str, int size);
+```
+Co rozwiązałoby problem.
+Jednak po wielu latach twórcy standardu **[C]** zamiast poprawić funkcję `gets` stwierdzili,
+że wolą ją usunąć.
+
+Co to ma wspólnego ze Scalą?
+Otóż niektórzy programiści,
+wiedząc że są marne szanse na naprawę błędów projektowych ze standardowej biblioteki Scali,
+napisali własne, poprawione wersje.
+
+Jedną z takich poprawionych wersji biblioteki standardowej Scali jest biblioteka **[Scalaz]**.
+Biblioteka ta jest inspirowana językiem **[Haskell]**.
+Język **[Haskell]** jest w pełni funkcyjny.
+Ale co ważniejsze jest też, według mnie, w pełni funkcjonalnym językiem.
+Co to oznacza?
+Że posiada te wszystkie rzeczy,
+które są potrzebne,
+żeby używać go jako język produkcyjny w korpoaplikacjach,
+takie jak statyczne typowanie, polimorfizm i obsługa błędów.
+Jednak w języku **[Haskell]** obsługa błędów jest zrobiona za pomocą konstrukcji takich jak **[monady]** i **[aplikatywy]**.
+
+## Disjunction vs Either
+
+Monada `Disjunction` z biblioteki **[Scalaz]** jest lepszą wersję `Either` ze standardowej biblioteki Scali.
+I tak jak `Either` posiada dwie podklasy:
+```scala
+/** A left disjunction
+ *
+ * Often used to represent the failure case of a result
+ */
+final case class -\/[+A](a: A) extends (A \/ Nothing)
+
+/** A right disjunction
+ *
+ * Often used to represent the success case of a result
+ */
+final case class \/-[+B](b: B) extends (Nothing \/ B)
+```
+Powyższy kod może wydawać się dziwny,
+do momentu gdy nie uświadomimy sobie,
+że klasa `Disjunction` nawet nie istnieje w kodzie biblioteki Scalaz.
+`Disjunction` jest tylko aliasem na klasę `\/`
+(czytane jako "Wściekły Zając", ale ja wymawiam to jako "Hail Hydra"):
+```scala
+ type Disjunction[+A, +B] = \/[A, B]
+ val Disjunction = \/
+```
+No dobrze, po tej informacji dalej jest to dziwne.
+Osobiście nie przepadam za nazwami klas składającymi się z samych symboli jak `\/`, `\/-` i `-\/`.
+
+W czym monada `Disjunction` jest lepsza od monady `Either`?
+W przypadku monady `Either` rozróżnienie między wartościami `right` i `left` było tylko konwencją.
+Powodowało to,
+że musieliśmy `explicit` wybierać,
+którą wartość chcemy użyć.
+W przypadku monady `Disjunction` wartość poprawna jest używana domyślnie.
+Jest to przydatne zwłaszcza w konstrukcji [For Comprehensions]
+
+Co do kodu skryptu nie ma tu Rocket Science.
+Użycie monady `Disjunction` jest prostsze od `Either` ponieważ domyślnie dla metod `map` i `flatMap` jest używana strona z poprawnym wynikiem.
+```scala
+abstract class DisjunctionAPIState(data: UrlsWithThrowableList)(implicit d: Domain) extends AbstractAPIState(data) {
+ override type HP = SourcePageDisjunction
+
+ def nextData(set: SourcePageDisjunctionSet): UrlsWithThrowableList = {
+
+ val partitioned = set.partition(_.isRight)
+
+ val newWrappedUrls: WrappedUrlSet = partitioned._1
+ .flatMap(DisjunctionAPIState.sourcePageDisjunctionToWrappedUrlSet)
+
+ val newThrowableList: ThrowableList = partitioned._2.toList
+ .flatMap(_.swap.toOption.toList)
+
+ val newUrls = NewUrls(newWrappedUrls)
+
+ data.next(newUrls, newThrowableList)
+ }
+
+}
+
+object DisjunctionAPIState {
+ val sourcePageDisjunctionToWrappedUrlSet: SourcePageDisjunction => WrappedUrlSet =
+ _.map(_.getWrappedUrlSet).toOption.toSet.flatten
+}
+```
+
+## Validation vs Disjunction
+
+Klasa `Validation` także posiada dwie podklasy,
+ale w tym przypadku nie mamy dziwnych symboli,
+tylko intuicyjne nazwy:
+
+```scala
+final case class Success[A](a: A) extends Validation[Nothing, A]
+final case class Failure[E](e: E) extends Validation[E, Nothing]
+```
+
+Jaka jest różnica pomiędzy `Disjunction` a `Validation`?
+Z technicznego punktu widzenia `Disjunction` jest **[monadą]**, a `Validation` jest tylko **[aplikatywem]**.
+Tak, też mi to za dużo nie mówi.
+Z logicznego punktu widzenia `Disjunction` przerywa działanie na pierwszym błędzie,
+a `Validation` używa się, gdy chce się kumulować błędy np. podczas walidacji danych.
+Stąd nazwa klasy.
+
+```scala
+abstract class ValidationAPIState(data: UrlsWithThrowableList)(implicit d: Domain) extends AbstractAPIState(data) {
+ override type HP = SourcePageValidation
+
+ def nextData(set: SourcePageValidationSet): UrlsWithThrowableList = {
+
+ val partitioned = set.partition(_.isSuccess)
+
+ val newWrappedUrls: WrappedUrlSet = partitioned._1
+ .flatMap(ValidationAPIState.sourcePageValidationToWrappedUrlSet)
+
+ val newThrowableList: ThrowableList = partitioned._2.toList
+ .flatMap(_.swap.toOption.toList)
+
+ val newUrls = NewUrls(newWrappedUrls)
+
+ data.next(newUrls, newThrowableList)
+ }
+
+}
+
+object ValidationAPIState {
+ val sourcePageValidationToWrappedUrlSet: SourcePageValidation => WrappedUrlSet =
+ _.map(_.getWrappedUrlSet).toOption.toSet.flatten
+}
+```
+
+Niestety w kodzie tym nie widać przewagi `Validation` nad `Disjunction`,
+ponieważ agregację błędów oraz poprawnych wyników robię ręcznie w kodzie.
+Myślę że po prostu nie lubię monady `\/` z powodu jej niewymawialnej nazwy.
+
+## Task vs Future
+
+Co jest złego w `Future`?
+Po pierwsze nie jest monadą, jest tylko **[FlatMappable]** - z tym oczywiście można żyć.
+Większość swojego zawodowe życia piszę kod bez monad i on działa i zarabia na siebie i ja zarabiam na siebie.
+Więc bez monad na produkcji można żyć.
+O wiele większym problemem jest to,
+że parametr `implicit ec: ExecutionContext` jest potrzebny do tworzenia i przekształcania konstrukcji `Future`.
+
+Tego problemu nie ma w przypadku monady `Task`.
+
+Monadzie `Task` można łatwo przekazać fragment kodu do wykonania w przyszłości:
+```scala
+object SourcePageTaskFromInternalUrl {
+
+ def apply(internalUrl: InternalUrl): SourcePageTask =
+ Task { internalUrl |> SourcePageValidationFromInternalUrl.apply }
+}
+```
+
+Także wykonywanie obliczeń i przekształceń na monadzie `Task` nie sprawia problemów:
+```scala
+object TaskState {
+
+ def apply(domain: String): ParallelStateTask = fromDomain(new Domain(domain)) |> TaskState.run
+
+ def fromDomain(implicit d: Domain): TaskState = new TaskState(UrlsWithThrowableList.fromDomain)
+
+ def run(state: TaskState): Task[ValidationAPIState] =
+ if (state.isEmptyNextInternalUrls) Task.now(state) else state.nextMonad.flatMap(run)
+}
+
+class TaskState(refsWithThrowable: UrlsWithThrowableList)(implicit d: Domain) extends ValidationAPIState(refsWithThrowable) {
+
+ override type NextState = TaskState
+
+ override def nextState(data: UrlsWithThrowableList): TaskState = new TaskState(data)
+
+ def nextMonad: Task[TaskState] = {
+
+ val set: Set[Task[SourcePageValidation]] = refsWithThrowable.nextUrls
+ .map(SourcePageTaskFromInternalUrl.apply)
+
+ val monad: Task[SourcePageValidationSet] = Task
+ .gatherUnordered(set.toSeq)
+ .map(_.toSet)
+
+ monad.map(newState)
+ }
+
+}
+```
+
+A kod nie posiada nadmiarowych parametrów `implicit` jest o wiele czystszy i łatwiejszy w utrzymaniu.
+
+## Podsumowanie
+
+Język **[Scala]** posiada rozbudowaną bibliotekę standardową,
+ale nie wszystko wewnątrz niej jest idealne.
+Dlatego dobrze jest znać alternatywy.
+Zwłaszcza,
+gdy chodzi o tak trudny temat jak przejrzysta obsługa błędów i programowanie równoległe.
+Warto więc na bieżąco obserwować zmiany w ekosystemie Scali.
+
+Kod jest oczywiście dostępny na [Githubie](https://github.com/writeonly/linkchecker/tree/v3.0).
+
+[haskell]: /langs/haskell
+[scala]: /langs/scala
+
+[scalaz]: /libs/scalaz
+
+[c]: /tools/clang
+
+[linkchecker]: /projects/linkchecker
+
+[api]: /tags/api
+[aplikatywem]: /tags/applicative
+[aplikatywy]: /tags/applicative
+[FlatMappable]: /tags/flatmappable
+[for comprehension]: /tags/for-comprehension
+[monad]: /tags/monad
+[monada]: /tags/monad
+[monad]: /tags/monad
+[monady]: /tags/monad
+[no-exceptions]: /tags/no-exceptions
diff --git a/_collections/_posts/2019-12-25-no-exceptions-io-monad.md b/_collections/_posts/2019-12-25-no-exceptions-io-monad.md
new file mode 100644
index 00000000..fdae6375
--- /dev/null
+++ b/_collections/_posts/2019-12-25-no-exceptions-io-monad.md
@@ -0,0 +1,317 @@
+---
+title: 'No Exceptions - IO, królowa monad'
+author: TheKamilAdam
+category: scala-jvm
+tags: alias api applicative for-comprehensions io monad no-exceptions task
+langs: scala haskell
+tools: clang
+libs: scalaz zio
+projects: linkchecker
+redirect_from:
+ - no-exceptions-io
+ - scala-jvm/no-exceptions-io
+---
+
+Czasem słyszy się opinie,
+że programowanie funkcyjne jest bez sensu,
+ponieważ czyste funkcje (ang. *pure functions*) nie pozwalają na pisanie efektów ubocznych.
+A przecież każdy działający program potrzebuje efektów ubocznych.
+Dla wyjaśnienia efektem ubocznym jest:
+* Komunikacja ze światem zewnętrznym, zarówno odczyt jak i zapis
+* Komunikacja między wątkami
+* Zmienny stan (ang. *mutable state*) i zmienne kolekcje (ang. *mutable collections*)
+
+Wszystkich tych rzeczy można używać w czystofunkcyjnych językach programowania, takich jak **[Haskell]**.
+Trzeba tylko je opakować w odpowiednią monadę.
+Najczęściej monadą to jest `IO`.
+Co ciekawe monada `IO` powstała przypadkiem,
+ponieważ twórcy języka **[Haskell]** chcieli stworzyć język programowania,
+który maksymalnie odracza w czasie wykonywanie obliczeń.
+Jednak przeszkodą były właśnie operacje wejścia/wyjścia (ang. *input/output*)
+Rozwiązaniem było użycie monady jako kontekstu do obliczeń.
+Stąd też nazwa monady `IO` (ang. *input/output*).
+
+W Scali, dzięki bibliotekom, mamy do wyboru kilka implementacji monady `IO`:
+* `scalaz.effect.IO` - pierwotnie należąca do rdzenia biblioteki **[Scalaz]**
+* `scalaz.ioeffect.IO` - znajdująca się także poza rdzeniem biblioteki **[Scalaz]**
+* `zio.IO` - pochodząca z biblioteki **[ZIO]**
+
+## `scalaz.effect.IO`
+
+Monada `scalaz.effect.IO` pierwotnie należała do `scalaz-core`,
+ale obecnie jest przeniesiona do biblioteki `scalaz-effect`.
+Posiada jeden parametr generyczny określający zwracany typ.
+
+Logika programu [linkchecker] pisana przy wykorzystaniu `scalaz.effect.IO` wygląda następująco:
+```scala
+object IOState {
+
+ def fromDomain(implicit d: Domain): IOState = new IOState(UrlsWithThrowableList.fromDomain)
+
+ def run(state: IOState): IO[ValidationAPIState] =
+ if (state.isEmptyNextInternalUrls) IO.apply(state) else state.nextMonad.flatMap(run)
+
+ private def sequence(set: Set[IO[SourcePageValidation]]): IO[SourcePageValidationSet] =
+ set
+ .foldLeft(IO.apply(Set.empty[SourcePageValidation])) { (b, a) =>
+ for {
+ bb <- b
+ aa <- a
+ } yield bb + aa
+ }
+}
+
+class IOState(data: UrlsWithThrowableList)(implicit d: Domain) extends ValidationAPIState(data) {
+
+ override type NextState = IOState
+
+ def nextState(data: UrlsWithThrowableList): IOState = new IOState(data)
+
+ def nextMonad: IO[IOState] = {
+
+ val set: Set[IO[SourcePageValidation]] = data.nextUrls
+ .map(SourcePageIOFromInternalUrl.apply)
+ val monad: IO[SourcePageValidationSet] = IOState.sequence(set)
+
+ monad.map(newState)
+ }
+}
+```
+
+Niestety nie znalazłem jak w łatwy sposób trawersować typ `C[IO[_]]` na `IO[C[_]]`,
+dlatego napisałem to samodzielnie za pomocą **[for comprehension]**.
+
+```scala
+object IOApp extends SafeApp {
+
+ private val domain = "https://www.writeonly.pl"
+
+ override def run(args: ImmutableArray[String]): IO[Unit] = applyIO().map(_.showResult())
+
+ def apply(): ValidationAPIState = applyIO().unsafePerformIO()
+
+ def applyIO(): IO[ValidationAPIState] = IOState.fromDomain(new Domain(domain)) |> IOState.run
+}
+```
+
+Biblioteka dostarcza także cechę `SafeApp` której można przekazać sterowanie.
+Dzięki czemu nie trzeba wypakowywać najbardziej zewnętrzne monady za pomocą metody `unsafePerformIO`.
+Tutaj jednak nie skorzystałem z tej opcji.
+
+Aktualnie monada `scalaz.effect.IO` jest tylko ciekawostką historyczną ponieważ
+została zdeprecjonowane i zastąpiona przez monadę `scalaz.ioeffect.IO`.
+
+## `scalaz.ioeffect.IO` - Monada IO po raz drugi
+
+Monada `scalaz.ioeffect.IO` jest ulepszoną wersję monady `scalaz.effect.IO` i posiada dwa typy generyczne.
+Lewy na wartość niepoprawną, prawy na wartość poprawną.
+
+Logika programu [linkcheckera] nie zmienia się za wiele po zmianie wersji monady `IO`:
+```scala
+object IO2State {
+
+ def fromDomain(implicit d: Domain): IO2State = new IO2State(UrlsWithThrowableList.fromDomain)
+
+ def run(state: IO2State): ParallelStateIO2 =
+ if (state.isEmptyNextInternalUrls) IO.now(state) else state.nextMonad.flatMap(run)
+
+ private def sequence(set: Set[IO[Throwable, SourcePageValidation]]): IO[Throwable, SourcePageValidationSet] =
+ set.foldLeft(IO.point[Throwable, SourcePageValidationSet](Set.empty)) {
+ (b: IO[Throwable, SourcePageValidationSet], a: IO[Throwable, SourcePageValidation]) =>
+ b.flatMap(bb => a.map(aa => bb + aa))
+ }
+}
+
+class IO2State(data: UrlsWithThrowableList)(implicit d: Domain) extends ValidationAPIState(data) {
+
+ override type NextState = IO2State
+
+ def nextState(data: UrlsWithThrowableList): IO2State = new IO2State(data)
+
+ def nextMonad: IO[Throwable, IO2State] = {
+
+ val set: Set[IO[Throwable, SourcePageValidation]] = data.nextUrls
+ .map(SourcePageIO2FromInternalUrl.apply)
+ val monad: IO[Throwable, SourcePageValidationSet] = IO2State.sequence(set)
+
+ monad.map(newState)
+ }
+}
+```
+
+Dla tej wersji monady `IO` także nie znalazłem prostej metody trawersowania,
+więc napisałem ją za pomocą metod `flatMap` i `map`.
+
+## `scalaz.ioeffect.Task` - Task po raz drugi
+W bibliotece `scalaz-ioeffect` monada `Task` jest tylko aliasem do monady `IO`:
+```scala
+ type Task[A] = IO[Throwable, A]
+```
+Ponieważ w większości przypadków chcemy obsługiwać wszystkie rodzaje błędów jest to bardzo użyteczny alias.
+
+Logika programu [linkcheckera] nie zmienia się za wiele po przepisaniu kodu z monady `IO` na monadę `Task`:
+```scala
+object Task2State {
+
+ def fromDomain(implicit d: Domain): Task2State = new Task2State(UrlsWithThrowableList.fromDomain)
+
+ def run(state: Task2State): ParallelStateTask2 =
+ if (state.isEmptyNextInternalUrls) Task.now(state) else state.nextMonad.flatMap(run)
+
+ private def sequence(set: Set[Task[SourcePageValidation]]): Task[SourcePageValidationSet] =
+ set.foldLeft(Task.point[SourcePageValidationSet](Set.empty)) { (b: Task[SourcePageValidationSet], a: Task[SourcePageValidation]) =>
+ b.flatMap(bb => a.map(aa => bb + aa))
+ }
+}
+
+class Task2State(data: UrlsWithThrowableList)(implicit d: Domain) extends ValidationAPIState(data) {
+
+ override type NextState = Task2State
+
+ def nextState(data: UrlsWithThrowableList): Task2State = new Task2State(data)
+
+ def nextMonad: Task[Task2State] = {
+
+ val set: Set[Task[SourcePageValidation]] = data.nextUrls
+ .map(SourcePageIO2FromInternalUrl.apply)
+ val monad: Task[SourcePageValidationSet] = Task2State.sequence(set)
+
+ monad.map(newState)
+ }
+}
+```
+
+## `zio.IO` - IO po raz trzeci
+
+Monada `IO` z biblioteki ` scalaz-ioeffect` także została zdeprecjonowana.
+
+Czemu powstała kolejna biblioteka?
+Dla wielu osób programowanie czysto funkcyjne z biblioteką `scalaz` było odpychające
+z powodu ogromnej ilości typów proponowanych przez tą bibliotekę
+(`Option`, `Maybe`, `Either`, `Disjunction`, `Validation`).
+Jest to spowodowane tym,
+że biblioteka `scalaz` jest próbą przeniesienia full typowania z języka **[Haskell]**.
+
+Dla kontrastu biblioteka `zio` skupia się na dwóch klasach.
+Monadzie `ZIO` oraz klasie `ZManaged`.
+I od początku jest ukierunkowana tylko na pisanie czystego kodu bez efektów ubocznych.
+Jednocześnie cały czas jest kompatybilna z biblioteką `scalaz`.
+
+Monada `IO` jest zdefiniowana jako alias dla monady `ZIO`:
+```scala
+type IO[+E, +A] = ZIO[Any, E, A]
+```
+
+Monada `zio.IO` w przeciwieństwie do swoich poprzedników wreszcie posiada metodę `traverse`,
+dzięki czemu logika programu [linkchecker] wymaga mniej kodu:
+```scala
+object IO3State {
+
+ def fromDomain(implicit d: Domain): IO3State = new IO3State(UrlsWithThrowableList.fromDomain)
+
+ @SuppressWarnings(Array("org.wartremover.warts.Any"))
+ def run(state: IO3State): ParallelStateIO3 =
+ if (state.isEmptyNextInternalUrls) IO.effect(state) else state.nextMonad.flatMap(run)
+
+ private def sequence(set: Set[IO[Throwable, SourcePageValidation]]): IO[Throwable, SourcePageValidationSet] =
+ IO.traverse(set)(identity)
+ .map(_.toSet)
+}
+
+class IO3State(data: UrlsWithThrowableList)(implicit d: Domain) extends ValidationAPIState(data) {
+
+ override type NextState = IO3State
+
+ def nextState(data: UrlsWithThrowableList): IO3State = new IO3State(data)
+
+ def nextMonad: IO[Throwable, IO3State] = {
+
+ val set: Set[IO[Throwable, SourcePageValidation]] = data.nextUrls
+ .map(SourcePageIO3FromInternalUrl.apply)
+ val monad: IO[Throwable, SourcePageValidationSet] = IO3State.sequence(set)
+
+ monad.map(newState)
+ }
+}
+```
+
+## `zio.Task` - Task po raz trzeci
+
+Kolejny raz monadzie `IO` towarzyszy monada `Task`:
+```scala
+ type Task[+A] = ZIO[Any, Throwable, A]
+```
+
+I kolejny raz logika [linkchekera] nie zmienia się za wiele po przepisaniu kodu z monady `IO` na monadę `Task`:
+```scala
+object Task3State {
+
+ def fromDomain(implicit d: Domain): Task3State = new Task3State(UrlsWithThrowableList.fromDomain)
+
+ @SuppressWarnings(Array("org.wartremover.warts.Any"))
+ def run(state: Task3State): ParallelStateTask3 =
+ if (state.isEmptyNextInternalUrls) IO.effect(state) else state.nextMonad.flatMap(run)
+
+ private def sequence(set: Set[Task[SourcePageValidation]]): Task[SourcePageValidationSet] =
+ Task
+ .traverse(set)(identity)
+ .map(_.toSet)
+}
+
+class Task3State(data: UrlsWithThrowableList)(implicit d: Domain) extends ValidationAPIState(data) {
+
+ override type NextState = Task3State
+
+ def nextState(data: UrlsWithThrowableList): Task3State = new Task3State(data)
+
+ def nextMonad: Task[Task3State] = {
+
+ val set: Set[Task[SourcePageValidation]] = data.nextUrls
+ .map(SourcePageTask3FromInternalUrl.apply)
+ val monad: Task[SourcePageValidationSet] = Task3State.sequence(set)
+
+ monad.map(newState)
+ }
+}
+```
+
+## `zio.UIO` i reszta
+
+Istnieje także więcej aliasów dla monady `ZIO`.
+Z czego chwilowo najbardziej użytecznym jest dla mnie `UIO`:
+```scala
+ type UIO[+A] = ZIO[Any, Nothing, A]
+```
+
+Wynika to z tego,
+że i tak w linkcheckerze wszystkie błędy obsługiwałem samodzielnie
+oraz niemożliwe było żeby linkchecker zwrócił odpowiedź błędną.
+
+## Podsumowanie
+
+Chociaż **[Scala]** nie była do tego zaprojektowana jako język programowania,
+czyste programowanie bez wyjątków jest możliwe za jej pomocą.
+Wymaga to jednak dużo samozaparcia i jest trudniejsze niż w językach od początku zaprojektowanych w tym celu jak **[Haskell]** czy **[Eta]**.
+
+Kod jest oczywiście dostępny na [Githubie](https://github.com/writeonly/linkchecker/tree/v4.0).
+
+[eta]: /langs/eta
+[haskell]: /langs/haskell
+[scala]: /langs/scala
+
+[scalaz]: /libs/scalaz
+[zio]: /libs/zio
+
+[linkchecker]: /projects/linkchecker
+[linkcheckera]: /projects/linkchecker
+
+[api]: /tags/api
+[aplikatywem]: /tags/applicative
+[aplikatywy]: /tags/applicative
+[io]: /tags/io
+[for comprehensions]: /tags/for-comprehensions
+[monad]: /tags/monad
+[monada]: /tags/monad
+[monad]: /tags/monad
+[monady]: /tags/monad
+[no-exceptions]: /tags/no-exceptions
diff --git a/_collections/_posts/2020-01-29-git-filter-branch.md b/_collections/_posts/2020-01-29-git-filter-branch.md
new file mode 100644
index 00000000..05b090e7
--- /dev/null
+++ b/_collections/_posts/2020-01-29-git-filter-branch.md
@@ -0,0 +1,116 @@
+---
+title: 'Git - zmiana informacji o autorze'
+author: TheKamilAdam
+category: cli
+tags: cli filter-branch script
+tools: bash git
+redirect_from:
+ - no-exceptions-io
+ - scala-jvm/no-exceptions-io
+---
+
+System kontroli wersji **[git]** przechowuje informacje o autorach zatwierdzeń (ang. *commit*)
+w każdym zatwierdzeniu osobno.
+Tzn. nie istnieje żadne globalne miejsce w którym moglibyśmy zmienić te informacje,
+jak np. nazwisko autora zatwierdzenia.
+Zamiast tego musimy modyfikować historię wszystkich zatwierdzeń.
+Na szczęście nie trzeba robić tego ręcznie dla każdego zatwierdzenia
+tylko można napisać jednolinijkowy [skrypt] używający podpolecenia (ang. *subcommend*) `filter-branch`.
+
+## Najprostszy przypadek
+
+Najprostszy przypadek występuje,
+gdy wszystkie zatwierdzenia w repozytorium chcemy przypisać sobie.
+Wtedy wystarczy jednolinijkowe polecenie, które dla wygody wolę przechowywać jako [skrypt]:
+
+```bash
+!/bin/sh -x
+
+git filter-branch --env-filter '
+ GIT_AUTHOR_NAME="Newname"
+ GIT_AUTHOR_EMAIL="new@email"
+ GIT_COMMITTER_NAME="Newname"
+ GIT_COMMITTER_EMAIL="new@email"
+' --tag-name-filter cat -- --branches --tags
+```
+Polecenie to dla każdego zatwierdzenia ustawia nowe
+`GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME` i `GIT_COMMITTER_EMAIL`.
+
+Tutaj warto dodać,
+że *committer* (nie mam pojęcia jak to będzie po polsku) jest to osoba,
+która włącza zatwierdzenia z gałęzi tymczasowej do głównej.
+Na końcu należy jeszcze wypchnąć zmiany do repozytorium za pomocą polecenia
+`git push --force --tags origin 'refs/heads/*'`.
+
+## Najpopularniejszy przypadek
+Często jednak nie chcemy zmieniać wszystkich zatwierdzeń,
+ale tylko te utworzone przez konkretnego autora.
+Prawdopodobnie najpopularniejszym przypadkiem jest zmiana adresu autora zatwierdzeń.
+Można to osiągnąć za pomocą poniższego skryptu zawierającego dwie instrukcje `if`
+```bash
+#!/bin/sh -x
+
+git filter-branch --env-filter '
+
+WRONG_EMAIL="your-wrong-email@example.com"
+CORRECT_NAME="Your Correct Name"
+CORRECT_EMAIL="your-correct-email@example.com"
+
+if [ "$GIT_COMMITTER_EMAIL" = "$WRONG_EMAIL" ]
+then
+ export GIT_COMMITTER_NAME="$CORRECT_NAME"
+ export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
+fi
+if [ "$GIT_AUTHOR_EMAIL" = "$WRONG_EMAIL" ]
+then
+ export GIT_AUTHOR_NAME="$CORRECT_NAME"
+ export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
+fi
+' --tag-name-filter cat -- --branches --tags
+```
+W tym wypadku zmieniamy tylko zatwierdzenia zawierające konkretny, błędny adres email.
+
+Także w tym wypadku musimy wypchnąć zmiany do repozytorium za pomocą polecenia
+`git push --force --tags origin 'refs/heads/*'`.
+
+## Mój przypadek
+
+W moim przypadku chciałem jednak zmienić nie adres email, a nazwę użytkownika.
+W rezultacie powyższy [skrypt] musiałem zmodyfikować do następującej postaci:
+```bash
+!/bin/sh -x
+
+git filter-branch -f --env-filter '
+
+WRONG_NAME="Kamil.Zabinski"
+CORRECT_NAME="Kamil Adam"
+CORRECT_EMAIL="kamil.adam.zabinski@gmail.com"
+if [ "$GIT_COMMITTER_NAME" = "$WRONG_NAME" ]
+then
+ export GIT_COMMITTER_NAME="$CORRECT_NAME"
+ export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
+fi
+if [ "$GIT_AUTHOR_NAME" = "$WRONG_NAME" ]
+then
+ export GIT_AUTHOR_NAME="$CORRECT_NAME"
+ export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
+fi
+' --tag-name-filter cat -- --branches --tags
+```
+
+## Podsumowanie
+
+Oryginalny klient systemu kontroli wersji **[git]** powstał jako polecenie do używania ze skryptów.
+I chociaż obecnie nie trzeba umieć pisać skryptów by wykonać podstawowe operacje,
+warto wiedzieć, że istnieje taka opcja.
+Zwłaszcza biorąc pod uwagę,
+że wiele zaawansowanych opcji systemu kontroli wersji **[git]** jest dostępnych tylko z [konsoli].
+
+[bash]: /tools/bash
+[git]: /tools/git
+
+[cli]: /tags/cli
+[filter-branch]: /tags/filter-branch
+[konsoli]: /tags/cli
+[script]: /tags/script
+[skrypt]: /tags/script
diff --git a/_collections/_posts/2020-02-26-preload-css.md b/_collections/_posts/2020-02-26-preload-css.md
new file mode 100644
index 00000000..f5c82d73
--- /dev/null
+++ b/_collections/_posts/2020-02-26-preload-css.md
@@ -0,0 +1,98 @@
+---
+title: 'Krótki wpis o tym jak Google niszczy konkurencję'
+author: TheKamilAdam
+category: jekyll
+tags: css html
+langs: javascript
+tools: jekyll
+redirect_from:
+ - preload-css
+ - jekyll/preload-css
+---
+
+Żyję sobie spokojnie jak gdyby nigdy nic i nagle [cerrato] z [4programmers.net](https://4programmers.net/) pisze do mnie,
+że moja strona mi się rozjechała i podsyła screena.
+Patrzę i faktycznie plik [CSS] się w ogóle nie wczytał.
+Sprawdzam w Chromium, Chromie, Operze i Edge i wszędzie działa.
+Pytam się [cerrato] co za niszową przeglądarkę używa.
+
+Firefox, a wszystkie przeglądarki w których testowałem są oparte na silniku z Chromium.
+Chyba już tylko Firefox ma niespokrewniony silnik.
+
+## Analiza
+
+Często analizuję swoją statyczną stronę generowaną przez Jekylla w [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/).
+Ostatnio Google stwierdził,
+że źle robię wczytując [blokująco swoje CSSy](https://web.dev/render-blocking-resources/?utm_source=lighthouse&utm_medium=unknown)
+i dał mi poradę z [preload](https://web.dev/defer-non-critical-css/).
+
+W rezultacie moje ładowanie pliku [CSS] przed uruchomieniem jekylla wygląda następująco:
+{% raw %}
+```html
+
+
+
+
+```
+{% endraw %}
+
+Co ostatecznie daje następujący kod [html]:
+```html
+
+
+
+
+```
+Czyli jeśli przeglądarka ma włączony [JavaScript] to plik [CSS] jest ładowany asynchronicznie.
+W przeciwnym wypadku jest wykonane klasyczne ładowanie synchroniczne.
+Niestety Google nie powiedział,
+że [preload nie jest wspierany przez Firefox](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content) :(
+
+Dlaczego Firefox nie wspiera `preload`?
+Bo `preload` nie jest w standardzie,
+ale jest w [drafcie standardu](https://w3c.github.io/preload/#x2.link-type-preload) i jest duża szansa, że będzie.
+Moim skromnym zdaniem Firefox nie nadąża lub ogranicza zasoby na programistów.
+
+## Rozwiązanie
+
+Rozwiązaniem na szybko jest oczywiście usunięcie `preload` z kodu [HTML].
+Nie jest to oczywiście rozwiązanie zadowalające.
+
+Na szczęście istnieje skrypt [loadCSS](https://github.com/filamentgroup/loadCSS),
+który rozwiązuje wszystkie moje problemy.
+W rezultacie moje ładowanie pliku [CSS] przed uruchomieniem jekylla wygląda następująco:
+{% raw %}
+```html
+
+
+
+
+
+```
+{% endraw %}
+
+A po uruchomieniu jekylla dostaję:
+```html
+
+
+
+
+
+```
+
+# Podsumowanie
+* Nie ufaj Googlowi, niszczą konkurencję
+* Warto testować strony na Firefoxie
+
+[JavaScript]: /langs/javascript
+
+[jekyll]: /tools/jekyll
+
+[CSS]: /tags/css
+[html]: /tags/html
+
+[cerrato]: https://4programmers.net/Profile/90224
diff --git a/_collections/_posts/2020-03-11-interface-collection.md b/_collections/_posts/2020-03-11-interface-collection.md
new file mode 100644
index 00000000..d5159870
--- /dev/null
+++ b/_collections/_posts/2020-03-11-interface-collection.md
@@ -0,0 +1,155 @@
+---
+title: 'java.util vs vavr - problem z typami generycznymi w metodzie Collection::remove'
+author: TheKamilAdam
+category: java
+tags: collection interface immutable fp
+langs: java kotlin scala
+libs: vavr vavr-kotlin
+redirect_from:
+ - java-util-vs-vavr
+ - java/java-util-vs-vavr
+---
+
+Niedawno na [4programers.net](https://4programmers.net/Forum/Java/337090-spring_dao) pojawiło się pytanie,
+gdzie ostatecznie problemem była niedoskonałość metody `Collection::remove(Object)` ze standardowej biblioteki Javy.
+
+Cały problem można sprowadzić do przykładu:
+
+```java
+import java.util.*;
+
+public class ImmutableLists {
+ public static void main(String[] args) {
+
+final var immutableList = List.of("java", "util", "sucks");
+
+ final var result0 = immutableList.remove(0);
+ System.out.println(result0);
+
+ final var result1 = immutableList.remove(Integer.valueOf(0));
+ System.out.println(result1);
+ }
+}
+```
+
+Ok, nie można.
+Jeśli spróbujecie uruchomić powyższy kod to walnie was w twarz wyjątek `UnsupportedOperationException`,
+ponieważ **[Java]** ma upośledzone kolekcje niemutowalne:
+
+```bash
+Exception in thread "main" java.lang.UnsupportedOperationException
+ at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:71)
+ at java.base/java.util.ImmutableCollections$AbstractImmutableList.remove(ImmutableCollections.java:107)
+ at WriteOnly.main(WriteOnly.java:9)
+```
+
+Dlatego trzeba ten przykład przepisać na kod:
+```java
+import java.util.*;
+
+public class MutableLists {
+ public static void main(String[] args) {
+
+final var immutableList = List.of("java", "util", "sucks");
+
+ final var mutableList0 = new ArrayList(immutableList);
+ final var result0 = mutableList0.remove(0);
+ System.out.println(result0);
+
+ final var mutableList1 = new ArrayList(immutableList);
+ final var result1 = mutableList1.remove(Integer.valueOf(0));
+ System.out.println(result1);
+ }
+}
+```
+
+## Analiza
+Dawno temu,
+w odległej przeszłości,
+w **[Java]** nie było typów parametrycznych zwanych w Javie typami generycznymi lub skrótowo generykami.
+Smród tego ciągnie się po dziś dzień.
+W rezultacie metoda `Object::equals(Object)` nie jest generyczna.
+Co jest totalnie bez sensu,
+bo to że `"1"` nie będzie równe `Integer.valueOf(1)` widać już na etapie kompilacji i nie ma sensu w tym celu włączać w ogóle JVMa.
+Pisałem już o tym w [no universal equality]
+
+Także w interface `Collection`, który jest rozszerzany np. przez interface `List`,
+istnieją niegeneryczne metody jak `Collection::remove(Object)` i `Collection::contains(Object)`.
+Ale już np. metoda `Collection::add(E)` jest generyczna.
+Wydaje się to pełną losówką,
+ale stał za tym sprytny marketing kompatybilności wstecznej próbujący przekonać jak najwięcej ludzi do nowej wtedy Javy 5.
+Z tych samych powodów marketingowych zwanych kompatybilnością wsteczną nie poprawiono tego do czasów współczesnych.
+Dodatkowo dochodzi do tego to,
+że metoda usuwająca element z listy po wartości elementu (`Collection::remove(Object)`)
+nazywa się dokładnie tak samo jak metoda usuwająca element z listy po indeksie (`Collection::remove(int)`)
+Razem prowadzi to do powyższych patologii,
+czyli że metoda działa w zupełnie inny sposób dla typu `Integer`, a w innny dla `int`.
+## Rozwiązanie
+
+Rozwiązaniem jest porzucenie bezsensownych kolekcji z standardowej biblioteki Javy i użycie biblioteki [vavr].
+
+Przy użyciu biblioteki [vavr] kod wygląda następująco:
+```java
+import java.io.vavr.collection.*;
+
+public class VavrLists {
+ public static void main(String[] args) {
+
+final var immutableList = List.of("Vavr", "is", "awesome");
+
+ final var result0 = immutableList.removeAt(0);
+ System.out.println(result0);
+
+ final var result1 = immutableList.remove(Integer.valueOf(0));
+ System.out.println(result1);
+ }
+}
+```
+Jego największą zaletą jest to,
+że się nawet nie skompiluje.
+A to wszystko dlatego,
+że kolekcje z biblioteki [vavr] używają typów generycznych wszędzie gdzie jest to potrzebne,
+a nie tylko tam gdzie pozwolili ludzie od marketingu.
+
+Teraz przepiszmy kod na następujący:
+
+```java
+import java.io.vavr.collection.*;
+
+public class VavrLists {
+ public static void main(String[] args) {
+
+final var immutableList = List.of("Vavr", "is", "awesome");
+
+ final var result0 = immutableList.removeAt(0);
+ System.out.println(result0);
+
+ final var result1 = immutableList.remove("is");
+ System.out.println(result1);
+ }
+}
+```
+I wszystko działa tak jak należy.
+
+## Podsumowanie
+
+Zalety bibliotek [vavr] jest mnóstwo i aż trudno je zliczyć.
+Są to między innymi:
+* metoda `List::remove(E)` służąca do usuwania elementu na podstawie wartości elementu jest generyczna
+* istnieje osobna metoda do usuwania elementu po indeksie o nazwie `List::removeAt(int)`
+* jest pełne wsparcie dla niemutowalności
+* kolekcje z [vavr] są wzorowane na bibliotece standardowej Scali, więc jeśli będziesz kiedyś chcieć nauczyć się Scali będzie Ci łatwiej
+* [vavr] wspiera Kotlina za pomocą biblioteki [vavr-kotlin]! (Kotlin nie posiada własnej biblioteki kolekcji co jest moim skromnym zdaniem największą porażką tego języka)
+
+[no universal equality]: /no-universal-equality
+
+[Java]: /langs/java
+[Kotlin]: /langs/kotlin
+[Scala]: /langs/scala
+
+[vavr]: /libs/vavr
+[vavr-kotlin]: /libs/vavr-kotlin
+
+[collection]: /tags/collection
+[immutable]: /tags/immutable
+[interface]: /tags/interface
diff --git a/_collections/_posts/2020-04-01-sojowe-latte.md b/_collections/_posts/2020-04-01-sojowe-latte.md
new file mode 100644
index 00000000..d7df0a5b
--- /dev/null
+++ b/_collections/_posts/2020-04-01-sojowe-latte.md
@@ -0,0 +1,81 @@
+---
+title: 'Sojowe latte - To nie ma sensu'
+author: TheKamilAdam
+category: thoughts
+redirect_from:
+ - sojowe-latte
+ - thoughts/sojowe-latte
+---
+
+Czy was też denerwuje argument `sojowe latte`?
+Jakakolwiek sensowna rozmowa może zakończyć się argumentem `sojowe latte`.
+I jest to uważane za argument ostateczny i niepodważalny.
+
+Jako że od 10 lat piję kawę,
+od pięciu lat nie piję mleka krowiego
+oraz od trzech miesięcy mam Maca to się wypowiem
+To nie ma sensu i to z wielu powodów.
+
+## To nie ma sensu, bo taki typ kawy nie istnieje
+
+Naprawdę. Jedźcie do Włoch (gdy już będzie można) i poproście o `latte`.
+A dostaniecie mleko.
+Prawdopodobnie podobnie będzie, gdy poprosicie o `soya latte`.
+Bo pełna nazwa tego rodzaju kawy to `latte macchiato` co znaczy `mleko splamione [kawą]`.
+Co ciekawe czasem polskie restauracje robią rozróżnienie `latte` a `latte macchiato`,
+gdzie `latte` oznacza `latte macchiato` które się nie udało.
+(Dobrze zrobione `latte macchiato` powinno mieć trzy warstwy kawę, mleko, pianę).
+
+Istnieje także odwrotność `latte macchiato` jest to `espresso macchiato`,
+czyli `espresso splamione [mlekiem]`.
+
+## To nie ma sensu, bo soja jest niezdrowa
+
+Są to dwa najmniejsze powody,
+i prawdopodobnie nieprawdziwe,
+czyli GMO i estrogen.
+
+Jeśli boisz się GMO (ja się nie boję) to powinieneś wiedzieć,
+że soja jest jedną z najbardziej zmodyfikowanych roślin.
+Jej przekleństwem jest to,
+że jest wysokobiałkowa,
+więc jest używana na pasze dla zwierząt hodowlanych.
+Nawet jeśli na soi jest napisane,
+że nie jest GMO to prawo Unii Europejskiej mówi,
+że modyfikacja do pół procenta to nie modyfikacja.
+Genialne prawda?
+
+Soja powoduje impotencję, bo zawiera substancje podobne do estrogenu.
+A przynajmniej takie krążą miejskie legendy.
+Zwykle,
+gdy człowiek zaczyna się pytać to ktoś coś kiedyś słyszał tylko o jakimś weganinie kulturyscie żywiącem się tylko soją
+(bo soja ma dużo białka).
+Legenda prawdziwa czy nie,
+rezultat jest taki,
+że wiele wegańskich produktów chwali się tym,
+że nie zawiera soi.
+Co ciekawe nie chwalą się tym produkty mięsne,
+które często zawierają soję w roli taniego wypełniacza.
+
+## To nie ma sensu, bo soja jest niesmaczna
+
+Kto jadł tofu (`ser` z soi) to wie, że jest to fu.
+Smakuje jak połączenie gąbki i tektury.
+Podobnie z napojem sojowym.
+Dlatego jest on dosładzany w ogromnych ilościach, żeby zabić ziemistość soi.
+Niesłodzony napój sojowy nadaje się tylko do marynowania mięsa.
+Podobnie jedyną dobrą rzeczą jaką można zrobić z tofu to zasypać go cukrem i zrobić tofurnik (`sernik` z tofu).
+
+Naprawdę jedyną dobrą rzeczą robioną z soi jest sos sojowy, ale tu wchodzi magia fermentacji.
+Ewentualnie prażona soja do chrupania, ale dalej jest bez smaku.
+
+## To nie ma sensu, bo soja jest tania
+
+Myślę, że jest to najważniejszy argument w całej dyskusji.
+Soja wcale nie pasuje do Maca i innych drogich rzeczy.
+Obecnie napój sojowy jest tylko dwa złote droższy od zwykłego krowiego mleka
+i tylko o złotówkę droższy od krowiego mleka bez laktozy.
+Od napoju sojowego jest trochę droższy napój ryżowy oraz owsiany.
+Dwa razy droższy jest napój migdałowy
+i jest to najdroższe `mleko roślinne` jakie można dostać w Polsce w kawiarniach i sklepach.
+Dalej w kolejności są napoje z orzechów laskowych i orzechów nerkowca.
diff --git a/_collections/_posts/2020-04-15-serialization.md b/_collections/_posts/2020-04-15-serialization.md
new file mode 100644
index 00000000..01ff1f32
--- /dev/null
+++ b/_collections/_posts/2020-04-15-serialization.md
@@ -0,0 +1,255 @@
+---
+title: 'Krótka historia informatyki na przykładzie serializacji danych'
+author: TheKamilAdam
+category: programming
+tags: ajax assembler di hocon json json-merge-patch json-patch json-pointer json-schema microservice rest rison rpc soap toml webservice xml yaml
+labels: jsf json-rpc jsp orm xml-rpc
+langs: coffeescript java javascript python rust scala
+libs: akka akka-http jsonpath jsonsurfer
+tools: bash jvm seed swagger
+redirect_from:
+ - serialization
+ - programming/serialization
+---
+
+Najpierw odpowiedzmy sobie na dodatkowe pytanie `kto to jest informatyk`?
+Odpowiedź jest oczywista `jest to człowiek znający się na informatyce`.
+I tu dochodzimy do głównego pytania `a co to jest informatyka`?
+Można pomyśleć,
+że informatyka to nauka o komputerach.
+Przecież codziennie informatycy używają komputerów.
+Ale
+
+> Informatyka ma tyle samo wspólnego z komputerami, co astronomia ma z teleskopami.
+
+Tak przynajmniej powiedział *Edsger Wybe Dijkstra*, jeden z pierwszych informatyków w Europie.
+
+Informatyka to nauka o informacji,
+a dokładniej informatyka jest to nauka o PPPP informacji,
+czyli:
+* **P**obieraniu informacji.
+* **P**rzetwarzaniu informacji.
+* **P**rzesyłaniu informacji.
+* **P**rzechowywaniu informacji.
+
+Jest to co prawda definicja bardzo nieścisła,
+ponieważ np. analiza danych jest to nauka o PPP informacji,
+czyli:
+* **P**obieraniu informacji.
+* **P**rzetwarzaniu informacji.
+* **P**rzesyłaniu informacji.
+
+A co ma z tym wspólnego serializacja?
+Serializacja danych jest to zamiana hierarchicznej struktury danych na liniową.
+Serializacja jest najbardziej związana z przesyłaniem informacji.
+Ale także z pozostałymi aspektami informatyki jak przetwarzanie i przechowywanie.
+Chyba najmniej z pobieraniem.
+Więc serializacja danych dość mocno przenika *naukę o informacji*.
+
+Ze względu na sposób serializacji danych można bardzo prosto podzielić historię informatyki i programowania na kilka etapów:
+* Komunikacja tekstowa bez struktury
+* Serializacja binarna powiązana z językiem
+* Serializacja do formatu **[XML]** (ang. *Extensible Markup Language*)
+* Serializacja do formatu **[JSON]** (ang. *JavaScript Object Notation*)
+* Serializacja binarna ortogonalna dla języka programowania
+
+## Komunikacja tekstowa bez struktury
+
+Była używana w starych i prostych systemach.
+Często pod postacią prostych poleceń tekstowych podobnych do języka asemblerowego lub rozkazów basha.
+W zasadzie to nie ma co za dużo o niej mówić.
+
+## Serializacja binarna
+
+Szybko pierwszą komunikację tekstową bez struktury zastąpiła serializacja binarna.
+Posiadała ona wiele zalet między innymi pozwalała przekazywać dane strukturalne.
+Ale posiadała ona także wiele wad.
+* Pierwszą wadą jaką dziś bym wymienił było to,
+że serializacja binarna jest nieczytelna dla człowieka i trudne jest debugowanie takiej komunikacji.
+Ten problem oczywiście można rozwiaząć za pomocą odpowiednich narzędzi do debugowania i przeglądania logów.
+* Drugą wadą było to,
+że różne języki programowania rozwinęły niezależnie swoje własne formaty serializacji binarnej.
+W rezultacie było niemożliwe zdalne wywoływanie procedur/metod (ang. *Remote Procedure Call*, **[RPC]**)
+napisanych w Javie za pomocą innego języka programowania niż Java.
+Ten problem oczywiście można rozwiązać za pomocą ustandaryzowanego formatu binarnego.
+Ten jednak nie powstał, a przyczyną była trzecia wada
+* Trzecim i największym problemem serializacji binarnej było to,
+że podejrzany ruch w tamtych czasach był blokowany na routerach.
+Przy czym podejrzanym ruchem była komunikacja binarna.
+Dopuszczalna była tylko komunikacja testowa.
+Dziś jest to już problem historyczny ponieważ i tak całą komunikacja jest kopresowana i szyfrowana,
+więc dziś nawet komunikacja tekstowa wygląda jak binarna.
+Rozwiązaniem tego problemu było zastąpienie binarnej serializacji na testową serializację ze strukturą,
+a binarnego **[RPC]** przez tekstowy **[RPC]**.
+Na format kodowania struktur wybrano **[XML]**.
+
+## XML - Extensible Markup Language
+
+Dzięki Roższeżalnemu Językowi Znaczników można było wymienić binarne **[RPC]** na XML-RPC.
+Szybko pojawił się kolejny problem.
+Każdy język programowania posiadał swoją własną,
+niekompatybilną wersję XML-RPC.
+Rozwiązaniem było to,
+że największe firmy tamtych czasów siadły razem do stołu i opracowały standard **[SOAP]** (ang. *Simple Object Access Protocol*).
+Stał on się zalecanym protokołem do komunikacji między Webserwisami w miejsce problematycznego **XML-RPC**.
+Później, i wcześniej,
+stworzono mnóstwo innych standardów jak XML Schema Definition (XSD), XPointer, XPath, XQuery i wiele innych.
+W rezultacie **[XML]** jest dziś najbardziej ustandaryzowanym formatem wymiany danych.
+Powstawały całe ksiażki o XMLu.
+Niektórzy widząc,
+że programy stają się tylko procesorami XMLa zaproponowali stworzenie XMLowych baz danych,
+które się jednak nie przyjęły.
+Nawet X w słowie **[AJAX]** pochodzi od XMLa.
+
+Panował zachwyt nad XMLem.
+I szybko zaczęto go wykorzystywać także do pisania konfiguracji.
+W tamtych czasach śmiano się z programistów Javy,
+że piszą więcej kodu **[XML]** niż Javy.
+XMLa używano do konfiguracji:
+* Frameworków Mapowania Obiektowo-Relacyjnego (ang. *Object-Relational Mapping*, **ORM**).
+* Frameworków Wstrzykiwania Zależności (ang. *Dependency Injection*, **[DI]**).
+* Frameworków generowania **[HTMLa]** za pomocą **JSP** i **JSF**.
+
+Ogólnie w tamtych strasznych czasach królowały frameworki, **[XML]**, Webserwisy i SOAP.
+
+Czas XMLa i X-menów jednak przeminą.
+Na format **[XML]** narzekano długo, za jego rozwlekłość i nadmiarowość.
+Oskarżano o nieczytelność.
+Ale prawdopodobnie gwoździem do trumny był sam **[AJAX]**.
+A dokładniej **[JavaScript]**.
+Wiele formatów walczyło o to by zastąpić **[XML]**,
+ale wygrał ten który jest najłatwiejszy do sparsowania w **[JavaScripcie]**,
+czyli **[JSON]**.
+
+## JSON - JavaScript Object Notation
+
+**[JSON]** posiada zwięźlejszy zapis niż **[XML]**.
+
+Dla formatu **[JSON]** powstało oczywiście mnóstwo standardów RFC jak np. **[JSON Pointer]**, **[JSON Patch]**, **[JSON Merge Patch]**
+Powstało też wiele standardów nie RFC jak np. **[JSON Schema]**, **[JsonPath]**/**[JsonSurfer]**, **[OpenApi]**/**[Swagger]**
+
+Szeroko przyjęły się dokumentowe bazy danych używające JSONa jak np. **Couchbase**, **CouchDB** i **MongoDB**,
+ale także klasyczne relacyjne bazy danych jak **[PostgreSQL]** i **[SQLite]** zyskały narzędzia do przetwarzania JSONa.
+Także silniki wyszukiwania (ang. *Search Engine*) **Elastic Search** lub **[Solr]** używają JSONa do wymiany danych.
+
+Jedynie tylko **Json-RPC** się nie przyjął j zamiast niego jest używany **[REST]**
+Co ciekawe **[REST]** nie musi używać JSONa, ale nie widziałem XRESTa,
+czyli RESTa używającego JSONa.
+
+Informatyka 2.0,
+czyli JSONika to nauka o JSONie,
+a dokładniej nauka o:
+* Pobieraniu JSONa
+* Przetwarzania JSONa
+* Przesyłaniu JSONa
+* Przechowywaniu JSONa
+
+**[JSON]** ma oczywiście kilka wad:
+* obsługuje tylko tablice i obiekty
+* jest formatem tekstowym przez co zajmuje więcej niż formaty binarne
+* jest często mało czytelny
+
+## Nowa serializacja binarna
+
+Mimo że **[JSON]** jest o wiele bardziej spakowany niż **[XML]** dalej zawiera wiele nadmiarowości.
+Jest to o tyle istotne,
+że dziś w czasach mikroserwisów i nanoserwisów
+
+Nowe formaty binarne można podzielić na kilka kategorii,
+ale to co je wyróżnia to to,
+że nie są tworzone dla jednego języka,
+ale dla wielu jednocześnie i dostarczane jaki biblioteki.
+
+* **[BSON]** i **[Smile]** - binarne formaty JSONa.
+* **[Ion]** - binarny nadzbiór JSONa.
+* **[CBOR]** i **[MessagePack]** - binarne formaty luźno oparte o JSONa.
+* **[Avro]**, **[Protocol Buffers]** i **[Thrift]** - binarne formaty nie oparte o JSONa, do zastosowań uniwersalnych.
+* **[FlatBuffers]** - binarny format nieoparty o JSONa dedykowany do gier.
+
+## Konfiguracja
+
+Sukces formatu **[JSON]** spowodował,
+że zaczął on by używany do innych celów niż tylko jako format serializacji danych.
+Jednym z takich innych celów jest wszelkiego rodzaju konfiguracja zapisywana w plikach tekstowych.
+Wybór JSONa do tego zadania nie powinien dziwić biorąc pod uwagę,
+że posiadamy bardzo dobre narzędzia do przetwarzania go.
+Są jednak formaty dedykowane do przechowywania konfiguracji,
+które warto rozważyć.
+Są to:
+* pliki **[INI]** - używane przez Windowsa i **[Python]**.
+* [TOML] - prosty format konfiguracji inspirowany formatem **[INI]** używany w języku **[Rust]** i narzędziu **[Seed]**.
+* pliki properties, nazywane formatem **[Java Properties]** używane w Javie.
+* **[HOCON]** - nadzbiór formatów JSON oraz Java Properties.
+Używany przez biblioteki **[akka]** i **[akka-http]**.
+Oryginalna biblioteka jest napisana w czystej Javie bez zależności i jest proponowana jako uniwersalny sposób konfigurowania aplikacji na **[JVM]**.
+Za to wersja **[SHOCON]** jest napisana w czystej **[Scali]**.
+* **[YAML]** - nadzbiór JSONa, nastawiony na maksymalną czytelność dla człowieka.
+Niestety z powodu używania wcięć zapisanie poprawnego YAMLa jest o wiele trudniejsze.
+
+## Inne
+Kilka ciekawych formatów nie można zaliczyć do żadnej z powyższych definicji:
+* **[Rison]** - Skrócony JSON, który można przesyłać w URLu.
+* **[CSON]** - JSON zgodny z składnią języka **[CoffeeScript]**.
+* **[Kryo]** - Serializacja binarna w starym stylu.
+Czyli związana z jednym konkretnym językiem.
+A dokładniej z językiem Java.
+Po co taka serializacja?
+Czasem mamy pewność że zserializowane obiekty będą czytane tylko przez jedną technologię,
+np. podczas zapisywania zserializowanych danych w Cache.
+Zaletą Kryo jest to, że jest 10 razy szybsza od standardowej serializacji z Javy.
+
+[CoffeeScript]: /langs/coffeescript
+[Java]: /langs/java
+[JavaScript]: /langs/javascript
+[Python]: /langs/python
+[Rust]: /langs/rust
+[Scala]: /langs/scala
+[Scali]: /langs/scala
+
+[akka]: /libs/akka
+[akka-http]: /libs/akka-http
+[Jolt]: /libs/jolt
+[JsonPath]: /libs/jsonpath
+[JsonSurfer]: /libs/jsonsurfer
+[SHOCON]: /libs/shocon
+[SQLite]: /libs/sqlite
+
+[Bash]: /tools/bash
+[JVM]: /tools/jvm
+[PostgreSQL]: /tools/postgresql
+[Seed]: /tools/seed
+[Solr]: /tools/solr
+[Swagger]: /tools/swagger
+
+[AJAX]: /tags/ajax
+[Assembler]: /tags/assembler
+[CSON]: /tags/cson
+[DI]: /tags/di
+[HOCON]: /tags/hocon
+[HTMLa]: /tags/html
+[INI]: /tags/ini
+[Java Properties]: /tags/java-properties
+[JSON]: /tags/json
+[JSON Merge Patch]: /tags/json-merge-patch
+[JSON Patch]: /tags/json-patch
+[JSON Pointer]: /tags/json-pointer
+[JSON Schema]: /tags/json-schema
+[OpenApi]: /tags/openapi
+[Rison]: /tags/rison
+[REST]: /tags/rest
+[RPC]: /tags/rpc
+[SOAP]: /tags/soap
+[TOML]: /tags/toml
+[YAML]: /tags/yaml
+[XML]: /tags/xml
+
+[Avro]: http://avro.apache.org
+[BSON]: http://bsonspec.org
+[CBOR]: https://www.rfc-editor.org/info/rfc7049
+[FlatBuffers]: https://google.github.io/flatbuffers/
+[Ion]: https://amzn.github.io/ion-docs/index.html
+[Kryo]: https://github.com/EsotericSoftware/kryo#projects-using-kryo
+[MessagePack]: https://msgpack.org
+[Protocol Buffers]: https://github.com/protocolbuffers/protobuf
+[Smile]: https://github.com/FasterXML/smile-format-specification
+[Thrift]: https://thrift.apache.org
diff --git a/_collections/_posts/2020-04-29-monads.md b/_collections/_posts/2020-04-29-monads.md
new file mode 100644
index 00000000..65f23943
--- /dev/null
+++ b/_collections/_posts/2020-04-29-monads.md
@@ -0,0 +1,363 @@
+---
+title: 'Haskell i monady - czy monady są jeszcze egzotyczne?'
+author: TheKamilAdam
+category: haskell-eta
+tags: currying do-notation flatmappable for-comprehensions fp library monad operator type-class
+langs: haskell java scala
+libs: scalaz vavr
+tools: bash
+redirect_from:
+ - monads
+ - haskell-eta/monads
+---
+
+Język programowania **[Haskell]** to ma straszną opinię.
+Że trzeba rozumieć co to teoria kategorii albo monady.
+Tylko że teoria kategorii odnosi się do wszystkich języków programowania.
+A monady są podobno możliwe nawet w **[Bashu]**.
+Gdy tak mówię lub piszę,
+ludzie mi nie wierzą.
+Ostatnio z tego powodu dostałem kod w **[Haskellu]**,
+który wyglądał mniej więcej tak:
+
+```haskell
+import qualified Data.Map as Map
+
+nestedMap = Map.fromList [("Scheme", Map.fromList [("OCaml", Map.fromList [("Haskell", "MonadsAreAwesome")])])]
+
+main = do
+ print $ Map.lookup "Scheme" nestedMap >>= Map.lookup "OCaml" >>= Map.lookup "Haskell"
+ print $ Map.lookup "Scheme" nestedMap >>= Map.lookup "Racket" >>= Map.lookup "Haskell"
+```
+
+Po uruchomieniu dający na wyjściu:
+```haskell
+Just "MonadsAreAwesome"
+Nothing
+```
+
+Do kodu dostałem pytanie, czy można to łatwo napisać w **[Scali]**.
+Otóż można i to nie tylko w **[Scali]**,
+ale także w **[Javie]**.
+
+## Analiza przykładu w Haskellu
+
+Ale najpierw przyjrzyjmy się kodowi w **[Haskellu]**.
+Za pomocą trzykrotnego wywołania funkcji `fromList` o sygnaturze:
+```haskell
+fromList :: Ord k => [(k, a)] -> Map k a
+```
+tworzymy trzykrotnie zagnieżdżoną mapę.
+Następnie za pomocą funkcji `lookup` o sygnaturze:
+```haskell
+lookup :: Ord k => k -> Map k a -> Maybe a
+```
+wyciągamy z mapy wartości.
+Jednak metoda ta nie zwraca gołych wartości,
+a wartości opakowane w `Maybe`,
+które jest odpowiednikiem `Option` ze **[Scali]** oraz `Optional` z **[Javy]**.
+Konstrukcja `Maybe`/`Option`/`Optional` jest prawdopodobnie najprostszą możliwą do implementacji monadą.
+
+A czym jest monada?
+Zacznijmy od tego,
+że monada w **[Haskellu]** jest po prostu klasą typów rozszerzająca klasę typów `Monad`:
+```haskell
+class Monad m where
+ (>>=) :: m a -> ( a -> m b) -> m b
+ (>>) :: m a -> m b -> m b
+ return :: a -> m a
+ fail :: String -> m a
+```
+Oraz spełniająca pewne *prawa monad*,
+które jednak tym razem pominę.
+
+Teraz wystarczy ustalić co to jest klasa typu.
+Cytując [Programowanie Funkcyjne dla Śmiertelników ze Scalaz](https://leanpub.com/fpmortals-pl/read#leanpub-auto-funkcjonalnoci),
+Klasa typu (ang. *[type class]*) jest to cecha (ang. *[trait]*),
+która:
+> * nie ma wewnętrznego stanu
+> * ma parametr typu [generyk]
+> * ma przynajmniej jedną metodą abstrakcyjną (kombinator prymitywny (primitive combinator))
+> * może mieć metody uogólnione (kombinatory pochodne (derived combinators))
+> * może rozszerzać inne typeklasy [klasy typów]
+
+W naszym przypadku parametrem typu jest `a`.
+Ponieważ nie ma wypisanych żadnych ograniczeń co do `a`,
+`a` reprezentuje dowolny typ.
+W szczególnym przypadku inną monadę,
+dzięki czemu możemy zagnieżdżać monady różnych typów.
+
+Spójrzmy jeszcze raz na deklarację monady w **[Haskellu]**:
+```haskell
+class Monad m where
+ (>>=) :: m a -> ( a -> m b) -> m b
+ (>>) :: m a -> m b -> m b
+ return :: a -> m a
+ fail :: String -> m a
+```
+
+Mamy tu zadeklarowane dwa operatory i dwie metody:
+* Operator `>>=` składa dwie monady w jedną.
+Nazywany jest `bind`.
+W innych językach programowania jego odpowiednikiem często jest metoda `flatMap`.
+Chyba że jak Groovy inspirują się SmallTakiem i wtedy jest `collectMany`.
+Ale wtedy to już nic nie pomoże.
+* Operator `>>` odrzuca pierwszy operand i zwraca drugi.
+Wydaje się to totalnie bezsensowne.
+Przynajmniej do czasu,
+gdy sobie nie uświadomimy,
+że w **[Haskellu]** nie ma klasycznego bloku kodu do wykonania i ten operator jest hakiem na to.
+* Metoda `return` zwana jest w innych językach programowania też `pure`, `unit` lub po prostu `create`.
+W **[Scali]** można także spotkać `apply` co wynika z lukru składniowego tego języka programowania.
+Służy ona do tworzenia monady.
+* Metoda `fail` służy do tworzenia monady zawierającej błąd (ang. *error*).
+
+## Kod z Scalaz
+**[Scalaz]** jest biblioteką,
+która dla języka **[Scala]** dodaje składnię z języka **[Haskell]**,
+czyli głównie wszelkiego rodzaju monady.
+
+Ten sam kod napisany w **[Scali]** przy pomocy biblioteki **[Scalaz]** i operatora `>>=`:
+```scala
+object ScalazMonad extends App {
+
+ import scala.collection.Map
+ import scalaz.Scalaz._
+
+ val nestedMap = Map("Scheme" -> Map("OCaml" -> Map("Haskell" -> "MonadsAreAwesome")))
+
+ println(nestedMap.get("Scheme") >>= (_.get("OCaml") >>= (_.get("Haskell"))))
+ println(nestedMap.get("Scheme") >>= (_.get("Racket") >>= (_.get("Haskell"))))
+}
+```
+
+Po jego uruchomieniu na wyjściu dostaniemy:
+```scala
+Some(MonadsAreAwesome)
+None
+```
+
+## Kod w gołej Scali
+Powyższy kod też można napisać w gołej **[Scali]** bez żadnych dodatkowych bibliotek:
+```scala
+object ScalaMonad extends App {
+
+ import scala.collection.Map
+
+ val nestedMap = Map("Scheme" -> Map("OCaml" -> Map("Haskell" -> "MonadsAreAwesome")))
+
+ println(nestedMap.get("Scheme") flatMap (_.get("OCaml") flatMap (_.get("Haskell"))))
+ println(nestedMap.get("Scheme") flatMap (_.get("Racket") flatMap (_.get("Haskell"))))
+}
+```
+
+Zwróć uwagę,
+że zamiast operatora `>>=` mamy tu metodę `flatMap`.
+
+Po uruchomieniu kodu na wyjściu dostaniemy:
+```scala
+Some(MonadsAreAwesome)
+None
+```
+
+Wniosek? Kolekcje w **[Scali]** są monadami,
+ponieważ mają metodę `flatMap`.
+Czyli jeśli używałeś kolekcji w **[Scali]**,
+to już używałeś **[monad]** w swoim życiu.
+
+## Kod z Vavr
+
+**[Vavr]** to biblioteka,
+która do języka **[Java]** dodaje składnię języka **[Scala]**.
+Głównie kolekcje i kilka monad do opakowywania wartości (`Option`, `Either`, `Try`)
+oraz interfejsy dla funkcji umożliwiające `currying`.
+
+Biblioteka **[Vavr]** dla **[Javy]** w wielu miejscach wygląda jak przepisana biblioteka kolekcji ze **[Scali]**.
+Tak więc nikogo nie powinno dziwić,
+że kod jest prawie identyczny,
+nie licząc oczywiście różnic wynikających z ograniczeń **[Javy]**:
+```java
+import io.vavr.collection.*;
+
+public class WriteOnly {
+
+ public static void main(String[] args){
+ final var nestedMap = HashMap.of("Scheme", HashMap.of("OCaml", HashMap.of("Haskell", "MonadsAreAwesome")));
+
+ System.out.println(nestedMap.get("Scheme")).flatMap(v1 -> v1.get("OCaml")).flatMap(v2 -> v2.get("Haskell"));
+ System.out.println(nestedMap.get("Scheme")).flatMap(v1 -> v1.get("Racket")).flatMap(v2 -> v2.get("Haskell"));
+ }
+}
+```
+
+Po uruchomieniu kodu na wyjściu dostaniemy:
+```java
+Some(MonadsAreAwesome)
+None
+```
+
+## Kod w gołej Javie
+
+I wreszcie monada w gołej Javie:
+```java
+import java.util.*;
+
+public class WriteOnly {
+
+ public static void main(String[] args){
+ final var nestedMap = Map.of("Scheme", Map.of("OCaml", Map.of("Haskell", "MonadsAreAwesome")));
+
+ System.out.println(Optional.ofNullable(nestedMap.get("Scheme")).flatMap(v1 -> Optional.ofNullable(v1.get("OCaml")).flatMap(v2 -> Optional.ofNullable(v2.get("Haskell")))));
+ System.out.println(Optional.ofNullable(nestedMap.get("Scheme")).flatMap(v1 -> Optional.ofNullable(v1.get("Racket")).flatMap(v2 -> Optional.ofNullable(v2.get("Haskell")))));
+ }
+}
+```
+
+Po uruchomieniu kodu na wyjściu dostaniemy:
+```java
+Optional[MonadsAreAwesome]
+Optional.empty
+```
+
+Tutaj kod jest najbardziej rozwlekły.
+Wynika to głównie z tego,
+że metoda `Map::get` w **[Javie]** zwraca gołą wartość,
+a nie wartość opakowaną w `Optional`.
+Na szczęście możemy sami opakować tę wartość,
+jednak wymaga to sporo kodu.
+Jeszcze dodatkowo jakiś geniusz wymyślił,
+że instancja klasy `Optional` jest tworzona za pomocą metody `Optional.ofNullable`.
+Bo metoda `Optional.of` przyjmuje tylko wartości różne od wartości `null`.
+Tak jakby był sens tworzyć instancje klasy `Optional` dla wartości,
+która na pewno nie jest równa `null`.
+
+Z drugiej strony,
+dzięki temu,
+że metoda `ofNullable` jest zadeklarowana tylko w klasie `Optional` możemy użyć statycznego importu i skrócić kod
+```java
+import java.util.*;
+import static java.util.Optional.ofNullable;
+
+public class WriteOnly {
+
+ public static void main(String[] args){
+ final var nestedMap = Map.of("Scheme", Map.of("OCaml", Map.of("Haskell", "someValue")));
+
+ System.out.println(ofNullable(nestedMap.get("Scheme")).flatMap(v1 -> ofNullable(v1.get("OCaml")).flatMap(v2 -> ofNullable(v2.get("Haskell")))));
+ System.out.println(ofNullable(nestedMap.get("Scheme")).flatMap(v1 -> ofNullable(v1.get("Racket)")).flatMap(v2 -> ofNullable(v2.get("Haskell")))));
+ }
+}
+```
+
+Po uruchomieniu kodu na wyjściu dostaniemy:
+```java
+Optional[MonadsAreAwesome]
+Optional.empty
+```
+
+## Haskell i notacja `do`
+
+Ktoś pomoże powiedzieć,
+że te długie linie źle się czyta.
+Szczęśliwie w **[Haskellu]** jest notacja `do` (ang. *[do notation]*),
+która pozwala zapisać ten kod w sposób bardziej czytelny:
+
+```haskell
+import Data.Map.Strict as Map
+
+nestedMap = Map.fromList [("Scheme", Map.fromList [("OCaml", Map.fromList [("Haskell", "MonadsAreAwesome")])])]
+
+main = do
+ print $ do
+ scheme <- nestedMap !? "Scheme"
+ ocaml <- scheme !? "OCaml"
+ haskell <- ocaml !? "Haskell"
+ return haskell
+ print $ do
+ scheme <- nestedMap !? "Scheme"
+ ocaml <- scheme !? "Racket"
+ haskell <- ocaml !? "Haskell"
+ return haskell
+```
+
+* Po prawej stronie operatora `<-` mamy wyrażenie,
+które zwraca monadę
+* Po lewej stronie operatora `<-` mamy wartość wypakowaną z monady,
+którą możemy użyć do konstrukcji kolejnej monady.
+Czyli operator `<-` jest tłumaczony na metodę `bind`.
+* słowo `return` nie jest słowem kluczowym **[Haskella]**,
+tylko metodą konstruującą monadę z wartości.
+Jest to metoda polimorficzna ze względu na typ zwracany.
+Rzecz nie do osiągnięcia w obiektowych językach programowania.
+
+## Scala i For comprehensions
+
+I znów notacja `do` nie jest niczym wyjątkowym,
+zarezerwowanym tylko dla **[Haskella]**.
+Jest dostępna np. w **[Scali]** jako *[for comprehensions]*:
+
+```scala
+object ForComprehensions extends App {
+ import scala.collection.Map
+
+ val nestedMap = Map("Scheme" -> Map("OCaml" -> Map("Haskell" -> "MonadsAreAwesome")))
+
+ println (
+ for {
+ scheme <- nestedMap get "Scheme"
+ ocaml <- scheme get "OCaml"
+ haskell <- ocaml get "Haskell"
+ } yield haskell
+ )
+
+ println (
+ for {
+ scheme <- nestedMap get "Scheme"
+ racket <- scheme get "Racket"
+ haskell <- racket get "Haskell"
+ } yield haskell
+ )
+}
+```
+
+Tutaj podobnie:
+* Po prawej stronie `<-` jest monada,
+chociaż w przypadku **[Scali]** wystarczy,
+że będzie to *[FlatMappable]*,
+czyli obiekt posiadający metodę `flatMap`.
+* Po lewej stronie `<-` jest wartość wypakowana z monady.
+* `yield` jest słowem kluczowym **[Scali]**.
+
+Ktoś może spytać skąd wyrażenie `For Comprehensions` wie którą monade zwrócić?
+Otóż jest tu stosowana pewna sztuczka,
+że ostatnie użycie `<-` jest zamieniane na metodą `map` a nie `flatMap`.
+Dlatego każda monada w **[Scali]** powinna także posiadać metodę `map`.
+## Podsumowanie
+
+Monady nie są niczym strasznym i możliwe,
+że używasz już ich na co dzień,
+nawet o tym nie wiedząc.
+
+[Java]: /langs/java
+[Javie]: /langs/java
+[Javy]: /langs/java
+[Haskell]: /langs/haskell
+[Haskella]: /langs/haskell
+[Haskellu]: /langs/haskell
+[Scala]: /langs/scala
+[Scali]: /langs/scala
+
+[Scalaz]: /libs/scalaz
+[Vavr]: /libs/vavr
+
+[Bash]: /tools/bash
+[Bashu]: /tools/bash
+
+[currying]: /tags/currying
+[do notation]: /tags/do-notation
+[flatmappable]: /tags/flatmappable
+[for comprehensions]: /tags/for-comprehensions
+[monad]: /tags/monad
+[operator]: /tags/operator
+[trait]: /tags/trait
+[type class]: /tags/type-class
diff --git a/_collections/_posts/2020-05-13-polymorphism.md b/_collections/_posts/2020-05-13-polymorphism.md
new file mode 100644
index 00000000..1032adde
--- /dev/null
+++ b/_collections/_posts/2020-05-13-polymorphism.md
@@ -0,0 +1,391 @@
+---
+title: 'Sześć rodzajów polimorfizmu'
+author: TheKamilAdam
+category: programming
+tags: dsl compiler fp interface interpreter monad protocol trait type-class
+langs: clojure common-lisp go haskell java javascript kotlin meta-language ocaml perl pony racket ruby rust scala scheme smalltalk typescript vala
+libs: arrow cats scalaz
+tools: bash
+redirect_from:
+ - polymorphism
+ - programming/polymorphism
+---
+
+Gdy dociera do mnie informacja o kolejnym wspaniałym języku programowania,
+którego warto się nauczyć,
+to pierwsze co robię to sprawdzam jak wygląda polimorfizm w tym języku programowania.
+
+* Jeśli język nie wspiera polimorfizmu to stwierdzam,
+że nie warto się go uczyć.
+Znam już C i nie mam zamiaru pisać małych programów, w których polimorfizm nie jest potrzebny.
+Znam też [Basha] do pisania prostych skryptów.
+Więc o ile nie jest to jakiś **[DSL]** to prawdopodobnie nie można się nauczyć nic ciekawego przy jego nauce.
+* Jeśli język wspiera polimorfizm z programowania obiektowego,
+czyli podtypowanie to nie widze sensu,
+żeby się go uczyć.
+Znam programowanie obiektowe z **[Javy]**, **[Kotlina]** i **[Scali]** czy **[Vali]**.
+Obiektowe języki programowania są bardzo podobne i różnią się tylko zwięzłością składni,
+szybkością działania i ilością dostępnych bibliotek.
+Nie ma w nich żadnych nowych idei.
+To ciągle te same koncepcje i te same problemy pod nową postacią.
+* Jeśli język wspiera inny rodzaj polimorfizmu to znaczy, że jest ciekawy i przy jego nauce można się czegoś nowego nauczyć.
+
+Ale zaraz, zaraz.
+Przecież polimorfizm to część programowania obiektowego i poza programowaniem obiektowym polimorfizm jest niemożliwy.
+Z takim przynajmniej przeświadczeniem można w Polsce wyjść po niektórych uczelniach.
+No nie do końca jest to prawda.
+
+Usłyszałem kiedyś od Jarka Pałki,
+że istnieje 6 rodzajów polimorfizmu.
+Niestety nie wymienił wszystkich rodzai.
+Od tego czasu postanowiłem zebrać je wszystkie razem.
+I są to:
+* Polimorfizm podtypowy
+* Polimorfizm strukturalny
+* Wielometody (Multimetody)
+* Polimorfizm parametryczny
+* Polimorfizm *ad hoc*
+* Inne rodzaje polimorfizmu :)
+
+Jednak nie mam pojęcia czy są to te rodzaje polimorfizmu,
+które Jarek Pałka miał na myśli.
+
+Polimorfizm można podzielić też na dwa rodzaje ze względu na czas wykonania:
+* Polimorfizm statyczny to polimorfizm czasu kompilacji rozwiązywany przez [kompilator].
+* Polimorfizm dynamiczny to polimorfizm czasu wykonania.
+
+Polimorfizm statyczny jest bezpieczniejszy i nie wprowadza opóźnień podczas działania aplikacji.
+Za to polimorfizm czasu wykonania jest potężniejszy.
+
+## Podtypowanie (ang. *[subtyping]*)
+
+> Subtyping (also called subtype polymorphism or inclusion polymorphism): when a name denotes instances of many different classes related by some common superclass.
+
+Za [wikipedią].
+
+Czyli w wolnym tłumaczeniu:
+> Podtypowanie (zwane również polimorfizmem podtypu lub polimorfizmem inkluzyjnym): gdy nazwa oznacza wystąpienie wielu różnych klas powiązanych przez jakąś wspólną nadklasę.
+
+Podtypowanie jest powiązane *nominalny system typów* (ang. *[nominal type system]* lub *name-based type system*)
+zwanym też *równoważnością przez nazwę*.
+W nominalnym systemie typów jeden typ można zastosować w miejsce drugiego,
+jeśli implementują ten sam protokół (ang. *[protocol]*), interfejs (ang. *[interface]*) lub cechę (ang. [trait]).
+
+Często jest nazywany także dziedziczeniem.
+Jednak określenie dziedziczenie może być nieprecyzyjne,
+ponieważ może odnosić się zarówno do dziedziczenia method,
+jak i dziedziczenia pól.
+
+Podtypowanie jest to główny rodzaj polimorfizmu używany w statycznych i obiektowych językach programowania takich jak **[Vala]**, **[Java]**, **[Kotlin]**, **[Scala]**, **[OCaml]** czy **[Pony]**.
+
+Główną zaletą podtypowania jest to,
+że jest prawdopodobnie najszybszym rodzajem polimorfizmu dynamicznego.
+Główną wadą jest to że jest to bardzo ograniczony rodzaj polimorfizmu.
+
+Polimorfizm ograniczeniowy
+
+## Polimorfizm strukturalny (ang. *[row polymorphism]*)
+
+Polimorfizm strukturalny nazywany także polimorfizmem opartym na sygnaturach (ang. *signature-based polymorphism*) można podzielić na dwa podrodzaje:
+* Polimorfizm strukturalny w językach dynamicznie typowanych.
+* Polimorfizm strukturalny w językach statycznie typowanych.
+
+Polimorfizm strukturalny w językach statycznie typowanych jest powiązany z *strukturalnym system typów* (ang. *[structural type system]* lub *property-based type system*)
+zwanym też *równoważnością strukturalną*.
+W systemie typów strukturalnych dwa typy są równe,
+jeśli posiadają taki sam zestaw metod.
+Czyli żeby użyć jednego typu w miejsce drugiego wystarczy,
+że posiada on taki sam zestaw metod.
+Polimorfizm strukturalny jest używany jako polimorfizm pomocniczy w niektórych statycznych i obiektowych językach programowania jak **[Scala]**, **[OCaml]** lub **[Pony]**.
+Jest także używany jako główny rodzaj polimorfizmu w statycznych językach programowania **[Go]** i **[TypeScript]**.
+
+Polimorfizm strukturalny w językach dynamicznie typowanych jest powiązany z *kaczym typowaniem* (ang. *[duck typing]*).
+W takich językach programowania nie ma sprawdzania,
+czy typy są równe.
+Po prostu są wywoływane metody.
+Polimorfizm strukturalny z kaczym typowanie jest głównym sposobem polimorfizmu w dynamicznych i obiektowych językach programowania takich jak **[Perl]**, **[Ruby]**, **[Python]**, **[JavaScript]**.
+
+Ponieważ polimorfizm strukturalny działa często przez refleksję i wybiera metody po nazwie,
+jest wolniejsze niż podtypowanie.
+W polimorfizmie strukturalnym także używa się dziedziczenia,
+ale bardziej do dziedziczenia pól lub jako wskazówkę dla programisty niż dlatego,
+że jest to wymagane przez kompilator lub interpreter.
+
+## [Wielometody] (ang. *multimethods*)
+
+Żeby wyjaśnić co to jest wielomatoda (Wielometoda),
+muszę najpierw zdefiniować,
+co to jest metoda.
+Poprzednie dwa rodzaje polimorfizmu można uznać za tradycyjny obiektowy polimorfizm z jednokrotną i dynamiczną wysyłką (ang. *[single and dynamic dispatch]*).
+Używają one metod do zapewnienia polimorfizmu w czasie uruchomienia (ang. *[runtime]*).
+W większości języków programowania metody zapisywane są jako:
+```
+obiekt.metoda(arg1, arg2, ..., argN)
+```
+
+Metodę można sobie jednak wyobrazić jako funkcję polimorficzną ze względu na swój pierwszy parametr:
+```
+metoda(obiekt, arg1, arg2, ..., argN)
+```
+Powyższy zapis jest możliwy w niektórych starszych językach obiektowych np. w **[Perlu]** podczas wywoływania metod oraz w **[Pythonie]** podczas deklarowania metod.
+
+Wielomatoda jest to funkcja,
+która może być polimorficzna ze względu na swoje wszystkie argumenty.
+Polimorfizm rozwiązywany ze względy na kilka obiektów jest nazywany wielokrotną wysyłką (ang. *[multiple dispatch]*).
+```
+wielomatoda(arg0, arg1, arg2, ..., argN)
+```
+
+Wielometody są zwykle używane w językach programowania z rodziny **[Lisp]** jak **[Common Lisp]**, **[Scheme]**, **[Racket]** i **[Clojure]**.
+Dlatego tam zapis wygląda następująco:
+```
+(wielomatoda arg0, arg1, arg2, ..., argN)
+```
+
+Wielometod są najpotężniejszym ze wszystkich typów polimorfizmu.
+I w oparciu o wielometody można zbudować tradycyjny obiektowy polimorfizm.
+
+Wadą wielometod ich jest to,
+że są najpowolniejsze ze wszystkich rodzajów polimorfizmy.
+Ponieważ trzeba sprawdzić większą ilość warunków,
+żeby wywołać konkretną implementację.
+
+## Polimorfizm parametryczny (ang. *[parametric polymorphism]*)
+
+> Parametric polymorphism: when one or more types are not specified by name but by abstract symbols that can represent any type.
+
+Za [wikipedią].
+
+Czyli w wolnym tłumaczeniu:
+> Polimorfizm parametryczny: gdy jeden lub więcej typów nie jest określonych przez nazwę, ale przez abstrakcyjne symbole, które mogą reprezentować dowolny typ.
+
+Polimorfizm parametryczny został wymyślony w 1975 roku dla języka programowania **[Meta Language]**,
+który według legendy miał być statycznie typowaną wersją języka **[LISP]**.
+Polimorfizm parametryczny pozwolił na [programowanie uogólnione] (ang. *[generic programming]*) w statycznie typowanych językach programowania.
+
+Polimorfizm parametryczny można podzielić na dwa rodzaje:
+* Polimorfizm parametryczny oparty na szablonach w C++ i D - kod jest generowany podczas kompilacji dla każdego typu osobno.
+* Polimorfizm parametryczny oparty na typach (funkcja, metodach, klasach itd.) uogólnionych (ang. generic types) - dla wszystkich typów jest używany ten sam kod.
+
+Co ciekawe *[Common Lisp Object System]*,
+czyli wielometody z **[Common Lisp]** są uważane za przykład funkcji uogólnionych (ang. *[generic function]*).
+
+## [Polimorfizm ad hoc] (ang. *[ad hoc polymorphism]*)
+
+> Ad hoc polymorphism: defines a common interface for an arbitrary set of individually specified types.
+
+Za [wikipedią].
+
+Czyli w wolnym tłumaczeniu:
+> Polimorfizm ad hoc: definiuje wspólny interfejs dla dowolnego zestawu indywidualnie określonych typów.
+
+Wymyślony w roku 1968 dla języka programowania **Algol 68**.
+Jest to niejako odwrotność polimorfizmu parametrycznego.
+Polimorfizm parametryczny służy do opisania ogólnego algorytmu,
+za to polimorfizm *ad hoc* służy do opisania szczególnych przypadków.
+
+Polimorfizm *ad hoc* można podzielić na *dwa* rodzaje ze względu na czas wiązania:
+* Wczesne wiązanie (ang. *[Early binding]*) - rozwiązywane w czasie kompilacji.
+* Późne wiązanie (ang. *[Late binding]*) - rozwiązywane w czasie wywoływania.
+* Nie wiadomo jakie wiązanie.
+* Wiadomo jakie wiązanie.
+
+### Wczesne wiązanie i statyczny polimorfizm *ad hoc*
+W językach statycznie typowanych jest rozwiązywany podczas kompilacji i dzieli się na:
+* [przeciążanie funkcji] (ang. *[function overloading]*)
+* [przeciążanie operatorów] (ang. *[operator overloading]*)
+
+Jest to w zasadzie lukier składniowy dzięki,
+któremu można deklarować takie same nazwy funkcji i metod dla różnych typów danych.
+
+Dzięki temu metoda statyczna `max` w Javie jest identyczna dla wszystkich typów prymitywnych:
+```java
+static dataType max(dataType a, dataType b)
+```
+
+Chociaż pod spodem są to cztery różne metody statyczne:
+```java
+static double max(double a, double b);
+static float max(float a, float b);
+static int max(int a, int b);
+static long max(long a, long b);
+```
+
+W języku,
+który nie posiada polimorfizmu *ad hoc*,
+trzeba utworzyć każdą funkcję z inną nazwą.
+```java
+double fmax (double a, double b);
+float fmaxf(float a, float b);
+long double fmaxl(long double a, long double b);
+```
+
+Za statyczny polimorfizm *ad hoc* są uważane także:
+* `extensions` w **[Kotlinie]**
+* specyfikacja szablonów w C++
+
+### Późne wiązanie i dynamiczny polimorfizm *ad hoc*
+
+Niektóre języki programowania jak np. **[SmallTalk]** posiadają podwójną wysyłkę (ang. *[double dispatch]*).
+Metody są tam polimorficzne nie tylko ze względu na obiekt, dla którego wywoływana jest funkcja,
+ale także ze względu na argument.
+W tradycyjnych językach obiektowych można to zasymulować za pomocą wzorca [odwiedzający], (ang. *[visitor pattern]*).
+
+Za dynamiczny polimorfizm *ad hoc* są uważane także:
+* `implicit conversion` w **[Scali]**
+* Wielometody w języki **[Clojure]**
+
+A teraz zagadka.
+Jeśli podwójna wysyłka i wielokrotna wysyłka są podrodzajami polimorfizmu *ad hoc*
+to czemu pojedyncza wysyłka (subtyping i polimorfizm strukturalny) nie jest podrodzajem polimorfizmu *ad hoc*?
+Może istnieją tylko dwa rodzaje polimorfizmu?
+Polimorfizm parametryczny i polimorfizm *ad hoc*?
+
+### Nie wiadomo jakie wiązanie
+
+Występuje dla przypadku [klasy typów] w **[Haskellu]**.
+W większości przypadków [klasy typów] są rozwiązywane podczas kompilacji.
+Jednak czasem jest to niemożliwe dla kompilatora.
+W takim przypadku kompilator przesuwa czas wiązania na czas wykonania.
+Co pozwala osiągnąć polimorfizm podobny do subtypingu i sprawia,
+że programowanie obiektowe jest możliwe w **[Haskellu]**.
+
+[Klasy typów] są możliwe do uzyskania także w innych językach programowania jak np.:
+* w **[Scali]** przy używaniu bibliotek **[Scalaz]**/**[Cats]**r
+* w **[Kotlina]** przy używaniu biblioteki **[ARROW]**
+
+### Wiadomo jakie wiązanie
+
+Cechy (ang. *[trait]*) w języku **[Rust]** są uproszczonymi wersjami [klas typów].
+Wiązania w nich są rozwiązywane w czasie kompilacji.
+Jednak dzięki wskaźnikom można przesunąć czas rozwiązywania wiązań na czas wykonania.
+Co pozwala osiągnąć polimorfizm podobny do subtypingu i sprawia,
+że programowanie obiektowe jest możliwe w **[Ruscie]**.
+
+## Inne rodzaje polimorfizmu
+
+* *Overriding with single dispatch* - nie widzę różnicy między polimorfizmem strukturalnym.
+* *Wielotypowanie* (ang. *[polytypism]*) jest to odmiana automatycznie generowanego polimorfizmu *ad hoc*.
+* Polimorfizm ograniczeniowy.
+W klasycznym świecie obiektowym jest to polimorfizm parametryczny + polimorfizm podtypowy.
+Ale w **[Haskellu]** ograniczenia dla polimorfizmu parametrycznego robi się za pomocą **[klas typów]** i polimorfizmu *ad hoc*.
+* Rekordy wariantowe.
+Nie uważam,
+żeby to był rodzaj polimorfizmu. A jeśli tak to należałoby uznać `Either` także za polimorfizm.
+
+## Podsumowanie
+
+Istnieje wiele rodzai polimorfizmu.
+Niektóre rodzaje polimorfizmu jak podtypowanie i polimorfizm strukturalny,
+są tradycyjnie łączone z programowaniem obiektowym.
+Jednak także wielometody i dynamiczny polimorfizm *ad hoc* pozwalają programować obiektowo.
+Dlatego warto czasem spojrzeć poza języki obiektowe,
+żeby nauczyć się czegoś nowego i poszerzyć swoje horyzonty.
+
+Jaka jest różnica?
+Tradycyjne języki obiektowe często gwałcą polimorfizmem.
+Tzn. wpychają go nam wtedy,
+gdy go nie potrzebujemy.
+Np. w **[Javie]** nie ma innego sposobu na napisanie kodu niż umieszczenie go wewnątrz klasy i metody.
+Dodatkowo metoda ta jest domyślnie wirtualna.
+Odwrotnie jest w językach funkcyjnych,
+gdzie dynamiczny polimorfizm jest ostatecznością.
+W moim idealnym statycznie typowanym języku programowania kod powinien być domyślnie monomorficzny a struktury danych niezmienne.
+Definicję tę jak na razie spełniają języki **[Haskell]**, **[OCaml]** i **[Rust]**.
+
+Trochę lepiej niż w **[Javie]** jest w **[Scali]**,
+gdzie nie trzeba tworzyć żadnej klasy,
+żeby napisać program,
+ale trzeba utworzyć obiekt singletonowy.
+Jeszcze lepiej jest w **[Kotlinie]**,
+gdzie nie trzeba tworzyć w ogóle obiektów.
+[Clojure]: /langs/clojure
+[Common Lisp]: /langs/common-lisp
+[Erlang]: /langs/erlang
+[Go]: /langs/go
+[Haskell]: /langs/haskell
+[Haskellu]: /langs/haskell
+[Java]: /langs/java
+[JavaScript]: /langs/javascript
+[Javie]: /langs/java
+[Javy]: /langs/java
+[Kotlin]: /langs/kotlin
+[Kotlina]: /langs/kotlin
+[Kotlinie]: /langs/kotlin
+[LISP]: /langs/lisp
+[Meta Language]: /langs/meta-language
+[OCaml]: /langs/ocaml
+[Perl]: /langs/perl
+[Perlu]: /langs/perl
+[Pony]: /langs/pony
+[Python]: /langs/python
+[Pythonie]: /langs/python
+[Racket]: /langs/racket
+[Ruby]: /langs/ruby
+[Ruscie]: /langs/rust
+[Rust]: /langs/rust
+[SmallTack]: /langs/smalltalk
+[Scala]: /langs/scala
+[Scali]: /langs/scala
+[Scheme]: /langs/scheme
+[TypeScript]: /langs/typescript
+[Vala]: /langs/vala
+[Vali]: /langs/vala
+
+[Bash]: /tools/bash
+[Basha]: /tools/bash
+
+[ARROW]: /libs/arrow
+[Cats]: /libs/cats
+[Scalaz]: /libs/scalaz
+
+[Dsl]: /tags/dsl
+[Kompilator]: /tags/compiler
+[klas typów]: /tags/type-class
+
+[Ad hoc polymorphism]: https://en.wikipedia.org/wiki/Ad_hoc_polymorphism
+[Anemic domain model]: https://en.wikipedia.org/wiki/Anemic_domain_model
+[Common Lisp Object System]: https://en.wikipedia.org/wiki/Common_Lisp_Object_System
+[Duck typing]: https://en.wikipedia.org/wiki/Duck_typing
+[Double dispatch]: https://en.wikipedia.org/wiki/Double_dispatch
+[Early binding]: https://en.wikipedia.org/wiki/Ad_hoc_polymorphism#Early_binding
+[Function overloading]: https://en.wikipedia.org/wiki/Function_overloading
+[Generic function]: https://en.wikipedia.org/wiki/Generic_function
+[Generic programming]: https://en.wikipedia.org/wiki/Generic_programming
+[Higher-kinded polymorphism]: https://en.wikipedia.org/wiki/Type_class#Higher-kinded_polymorphism
+[Interface]: https://en.wikipedia.org/wiki/Interface_(computing)
+[Late binding]: https://en.wikipedia.org/wiki/Ad_hoc_polymorphism#Late_binding
+[Memento pattern]: https://en.wikipedia.org/wiki/Memento_pattern
+[Multiple dispatch]: https://en.wikipedia.org/wiki/Multiple_dispatch
+[Mixin]: https://en.wikipedia.org/wiki/Mixin
+[Nominal type system]: https://en.wikipedia.org/wiki/Nominal_type_system
+[Operator overloading]: https://en.wikipedia.org/wiki/Operator_overloading
+[Parametric polymorphism]: https://en.wikipedia.org/wiki/Parametric_polymorphism
+[Polytypism]: https://en.wikipedia.org/wiki/Generic_programming#Functional_languages
+[Protocol]: https://en.wikipedia.org/wiki/Protocol_(object-oriented_programming)
+[Row polymorphism]: https://en.wikipedia.org/wiki/Row_polymorphism
+[Runtime]: https://en.wikipedia.org/wiki/Runtime_(program_lifecycle_phase)
+[Single and dynamic dispatch]: https://en.wikipedia.org/wiki/Dynamic_dispatch
+[Structural subtyping]: https://en.wikipedia.org/wiki/Structural_type_system
+[Structural type system]: https://en.wikipedia.org/wiki/Structural_type_system
+[Subtyping]: https://en.wikipedia.org/wiki/Subtyping
+[Trait]: https://en.wikipedia.org/wiki/Trait_(computer_programming)
+[Visitor pattern]: https://en.wikipedia.org/wiki/Visitor_pattern
+[wikipedią]: https://en.wikipedia.org/wiki/Polymorphism_(computer_science)
+
+[Abstrakcja]: https://pl.wikipedia.org/wiki/Abstrakcja_(programowanie)
+[Cecha]: https://pl.wikipedia.org/wiki/Cecha_(programowanie_obiektowe)
+[Domieszka]: https://pl.wikipedia.org/wiki/Domieszka_(programowanie_obiektowe)
+[Interfejs]: https://pl.wikipedia.org/wiki/Interfejs_(programowanie_obiektowe)
+[Kompozycja]: https://pl.wikipedia.org/wiki/Agregacja_(programowanie_obiektowe)#Kompozycja
+
+[Odwiedzający]: https://pl.wikipedia.org/wiki/Odwiedzaj%C4%85cy
+[Pamiątka]: https://pl.wikipedia.org/wiki/Pami%C4%85tka_(wzorzec_projektowy)
+[Polimorfizm ad hoc]: https://pl.wikipedia.org/wiki/Polimorfizm_(informatyka)#Polimorfizm_ad-hoc
+[Programowanie uogólnione]: https://pl.wikipedia.org/wiki/Programowanie_uogólnione
+[Przeciążanie funkcji]: https://pl.wikipedia.org/wiki/Przeci%C4%85%C5%BCanie_funkcji
+[Przeciążanie operatorów]: https://pl.wikipedia.org/wiki/Przeci%C4%85%C5%BCanie_operator%C3%B3w
+
+[Wielometody]: https://randomseed.pl/pub/poczytaj-mi-clojure/21-polimorfizm/#Wielometody
+
+[Polytypism]: http://zenzike.com/posts/2010-12-10-from-polymorphic-to-polytypic
diff --git a/_collections/_posts/2020-05-27-type-class.md b/_collections/_posts/2020-05-27-type-class.md
new file mode 100644
index 00000000..d32925c0
--- /dev/null
+++ b/_collections/_posts/2020-05-27-type-class.md
@@ -0,0 +1,372 @@
+---
+title: 'Haskell i klasy typów `Show` oraz `Read`'
+author: TheKamilAdam
+category: haskell-eta
+tags: adt compiler interpreter lexer type-class
+langs: haskell java kotlin scala
+libs: hunit
+tools: cabal etlas
+projects: helcam helvm
+eso: brainfuck
+redirect_from:
+ - type-class
+ - haskell-eta/type-class
+---
+
+Wiele osób zadaje takie pytanie:
+> Co napisać w nowym języku programowania, żeby się go nauczyć
+
+Kiedyś usłyszałem odpowiedź,
+że jako pierwszy projekt w nowym języku programowania najlepiej napisać [interpreter] [BrainFucka].
+[BrainFucka] nie trzeba chyba przedstawiać.
+Jest to najpopularniejszy ezoteryczny język programowania.
+Przy tym jest bardzo prosty,
+ale ma też ciekawe właściwości.
+Interpreter [BrainFucka] będzie częścią projektu [HelCam],
+a [HelCam] częścią większego projektu [HelVM] (wymawiaj Helium).
+
+Na razie nie będziemy pisać całego interpretera a ograniczymy się do [leksera].
+[Lekser] jest to program zamieniający kod źródłowy na tokeny.
+Tokeny są przetwarzane później przez kolejne części kompilatora,
+czyli np. [parser].
+[Lekser] zmienia kod źródłowy zapisany w **[BrainFucku]** na listę tokenów,
+a następnie tę listę tokenów znów możemy zamienić na kod źródłowy i porównać,
+że dostaliśmy to samo.
+A dokładniej zminimalizowany kod bez komentarzy.
+
+## Haskell i programowanie funkcyjne
+
+Można pomyśleć,
+że w programowaniu funkcyjnym tworzy się bez ładu i składu funkcje,
+które szybko zamieniają się w Latającego Potwora Spaghetti.
+
+My jednak nie będziemy pisać funkcji (z jednym małym wyjątkiem),
+tylko będziemy implementować klasy typu (ang. [type class]).
+
+## Typ danych `Token`
+
+Najpierw zdefiniujmy tym danych `Token`:
+```haskell
+data Token = MoveR
+ | MoveL
+ | Inc
+ | Dec
+ | Output
+ | Input
+ | JmpPast
+ | JmpBack
+ deriving (Eq, Ord, Enum)
+```
+Osiem tokenów odpowiadających ośmiu instrukcjom **[BrainFucka]**.
+
+Słowo kluczowe `data` służy do tworzenia typów danych.
+Zarówno iloczynów (ang. *product*), jak i sum (ang. *sum*, *coproduct*).
+Teraz tylko pytanie, co to jest iloczyn i suma :)
+
+Iloczyn jest to iloczyn kartezjański zmiennych,
+czyli krotka/tupla (ang. *tuple*) lub struktura/rekord.
+W **[Kotline]** służą do tego klasy danych (ang. *data class*),
+a w **[Scali]** - klasy przypadków (ang. *case class*)
+Tu trzeba uważać,
+ponieważ w **[Haskellu]** struktury nie mają nazwanych pól (wyglądają prawie jak krotki),
+za to rekordy, które mają nazwane pola, są niepolecane z powodu dziwnych zachowań.
+Najprostszym możliwym iloczynem, z którego można zbudować wszystkie pozostałe, jest para,
+czyli krotka dwuelementowa.
+
+Suma to alternatywa wyłączająca (albo-albo).
+Czyli coś jest albo typu A, albo typu B.
+Najprostsza możliwa suma, z której można zbudować wszystkie pozostałe sumy, to `Either`.
+
+Razem iloczyn i suma tworzą algebraiczne typy danych (ang. *algebraic data type*, **[ADT]**).
+
+Na razie jednak nie potrzebujemy pełnej mocy algebraicznych typów danych,
+a prostego enuma,
+takiego jak w **[Javie]**.
+
+`Eq, Ord, Enum` to klasy typów, które potrafi wywnioskować kompilator **[Haskella]**:
+* `Eq` to możliwość sprawdzania, czy zmienne są sobie równe (operatory `==` i `\=`).
+* `Ord` to możliwość ustalania kolejności między zmiennymi (operatory `<`, `<=`, `>` i `>=` )
+* `Enum` to możliwość enumeracji, czyli znalezienia następnika i poprzednika
+
+Tak naprawdę z tych trzech klas typów potrzebujemy tylko `Eq`,
+ale chciałem pokazać,
+że możemy dostać za darmo wiele instancji klas typów.
+
+Następnie tworzymy jeszcze alias `TokenList` dla listy tokenów.
+```haskell
+type TokenList = [Token]
+```
+
+## Klasy typów `Show` i `Read`
+
+Oprócz klasy typów `Eq`,` Ord` i `Enum` potrzebujemy jeszcze dwóch innych implementacji klas typów z biblioteki standardowej,
+są to `Show` i `Read`.
+
+`Show` także posiada domyślną implementację,
+jednak nie jest tu ona satysfakcjonująca.
+Dlatego,
+żeby móc używać klasy typu `Show` musimy napisać już trochę kodu.
+Musimy zaimplementować jedną metodę `show` i zrobimy to za pomocą dopasowywania wzorców (ang. **[pattern matching]**):
+```haskell
+instance Show Token where
+ show MoveR = ">"
+ show MoveL = "<"
+ show Inc = "+"
+ show Dec = "-"
+ show Output = "."
+ show Input = ","
+ show JmpPast = "["
+ show JmpBack = "]"
+```
+Dla każdej możliwej wartości tworzymy osobny przypadek,
+gdzie zwracamy `Stringa` reprezentującego token.
+
+Żeby utworzyć instancję klasy typu `Read` trzeba zaimplementować jedną metodę `readsPrec`.
+Teraz także zrobimy to za pomocą dopasowywania wzorców:
+```haskell
+instance Read Token where
+ readsPrec _ ">" = [( MoveR , "")]
+ readsPrec _ "<" = [( MoveL , "")]
+ readsPrec _ "+" = [( Inc , "")]
+ readsPrec _ "-" = [( Dec , "")]
+ readsPrec _ "." = [( Output , "")]
+ readsPrec _ "," = [( Input , "")]
+ readsPrec _ "[" = [( JmpPast, "")]
+ readsPrec _ "]" = [( JmpBack, "")]
+ readsPrec _ _ = []
+```
+
+Mamy tu kilka rzeczy:
+* dopasowywanie wzorców dla dwóch zmiennych
+* `_` to ignorowanie wartości zmiennej (metoda `readsPrec` przyjmuje dwa parametry, a nas interesuje tylko ten drugi).
+* `[,]` to składnia listy.
+* `(,)` to składnia krotki.
+
+Implementujemy jedną metodę `readsPrec`,
+ale w zamian za to dostajemy wiele innych metod do użycia:
+* `read` - niebezpieczna metoda,
+która zgłasza błąd,
+jeśli nie uda się parsowanie.
+* `readMaybe` - bezpieczna metoda,
+która zwraca `Maybe` będące odpowiednikiem `Option` ze **[Scali]** i `Optional` z **[Javy]**.
+* `readEither` - bezpieczna metoda,
+która zwraca `Either`.
+
+## Nowy typ `Tokens`
+
+Klasy typów niestety mają swoje ograniczenia.
+Nie jesteśmy w stanie utworzyć klas typów `Show` i `Read` dla listy tokenów.
+Rozwiązaniem na to jest utworzenie nowego typu danych zawierającego listę tokenów:
+```haskell
+import Data.Maybe
+import Text.Read
+
+newtype Tokens = Tokens TokenList
+```
+
+I znów tworzymy nowy typ danych.
+Jednak tym razem nie za pomocą `data` a `newtype`.
+Jaka jest różnica między tymi słowami?
+`newtype` nie tworzy dodatkowej alokacji.
+Działa jak `case class Tokens(tokens: TokenList) extends AnyVal` w **[Scali]**.
+
+Instancja dla `Show` jest prosta do zaimplementowania:
+```haskell
+instance Show Tokens where
+ show (Tokens tokens) = tokens >>= show
+```
+`>>=` to operator składania monad.
+Odpowiednik `flatMap` z innych języków programowania.
+W naszym przypadku monadami jest lista tokenów i lista znaków wyprodukowanych przez metodę `show` wywoływaną dla każdego tokenu.
+W rezultacie dostajemy listę znaków, czyli `String`.
+
+W drugą stronę jest niestety trudniej:
+```haskell
+charToString :: Char -> String
+charToString = (:[])
+
+instance Read Tokens where
+ readsPrec _ text = [( Tokens $ text >>= maybeToList . readMaybe . charToString, "")]
+```
+
+* `.` to operator składania funkcji.
+* `$` to sprytny operator zmieniania kolejności operacji.
+Dzięki niemu [wywołania cebulowe] `d(c(b(a)))` można zapisać jako `d $ c $ b $ a`.
+
+Dla każdego znaku w liście kolejno musimy:
+* zamienić `char` na `string` za pomocą `charToString`
+* sparsować każdy string w liście za pomocą metody `readMaybe`
+* każde `Maybe` zamienić na listę zero- lub jedno-elementową za pomocą funkcji `maybeToList`
+
+W rezultacie dostajemy listę tokenów,
+którą zamieniamy na typ `Tokens`.
+
+## Budowanie projektu - Cabal
+
+[Cabal] jest najprostszym programem do budowania projektów i zarządzania zależnościami dla **[Haskella]**.
+Pozostałe to Stack i Nix.
+Początkowy plik konfiguracyjny można wygenerować za pomocą polecenia `cabal init`.
+Plik konfiguracyjny nazywa się `.cabal`,
+czyli w naszym przypadku `helcam.cabal`.
+
+Do pliku projektu `helcam.cabal` musimy dodać informacje o modułach do kompilacji:
+```cabal
+library
+ exposed-modules:
+ HelVM.HelCam.BrainFuck.Token
+ HelVM.HelCam.BrainFuck.Tokens
+ other-modules:
+ hs-source-dirs:
+ src/main/eta
+ build-depends:
+ base >=4.7 && <5
+ default-language: Haskell2010
+ ghc-options: -Wall
+```
+
+i teraz możemy skompilować projekt za pomocą polecenia:
+```bash
+cabal clean && cabal build
+```
+
+## Pisanie testów i biblioteka HUnit
+
+Teraz trzeba by jakoś ten kod przetestować.
+Można manualnie,
+ale nie po to jesteśmy programistami,
+żeby rzeczy robić manualnie.
+Na szczęście dla **[Haskella]** istnieje prosta biblioteka,
+która umożliwia testy jednostkowe.
+
+do pliku `hs-esovm.cabal` dodajemy konfigurację:
+```cabal
+test-suite hs-esovm-test
+ type: exitcode-stdio-1.0
+ main-is: Test.hs
+ other-modules:
+ hs-source-dirs:
+ src/test/eta
+ ghc-options: -threaded -rtsopts -with-rtsopts=-N
+ build-depends:
+ base >=4.7 && <5
+ , hs-esovm
+ , HUnit
+ , test-framework
+ default-language: Haskell2010
+```
+
+i już możemy pisać testy
+
+```haskell
+helloWorldWithComments :: String
+helloWorldWithComments = " \
+++++++++ \
+[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-] \
+>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. \
+"
+
+helloWorld :: String
+helloWorld = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
+
+helloWorldAsList :: String
+helloWorldAsList = "[+,+,+,+,+,+,+,+,[,>,+,+,+,+,[,>,+,+,>,+,+,+,>,+,+,+,>,+,<,<,<,<,-,],>,+,>,+,>,-,>,>,+,[,<,],<,-,],>,>,.,>,-,-,-,.,+,+,+,+,+,+,+,.,.,+,+,+,.,>,>,.,<,-,.,<,.,+,+,+,.,-,-,-,-,-,-,.,-,-,-,-,-,-,-,-,.,>,>,+,.,>,+,+,.]"
+
+--------------------------------------------------------------------------------
+
+testHelloWorld :: Test
+testHelloWorld = TestCase (assertEqual "testHelloWorld" helloWorld (show $ readTokens helloWorld))
+
+testHelloWorldWithComments :: Test
+testHelloWorldWithComments = TestCase (assertEqual "testHelloWorldWithComments" helloWorld (show $ readTokens helloWorldWithComments))
+
+testTokenAsList :: Test
+testTokenAsList = TestCase (assertEqual "testTokenAsList" helloWorldAsList (show $ tokenList $ readTokens helloWorldWithComments))
+```
+
+Następnie wszystkie testy trzeba zebrać razem:
+```haskell
+testsOfTokens :: Test
+testsOfTokens = TestList [ TestLabel "testHelloWorld" testHelloWorld
+ , TestLabel "testHelloWorldWithComments" testHelloWorldWithComments
+ , TestLabel "testTokenAsList" testTokenAsList
+ ]
+```
+
+Oraz stworzyć moduł startowy dla testów:
+```haskell
+module Main(main) where
+
+import HelVM.HelCam.BrainFuck.TokensTest
+
+import Test.HUnit
+
+testExample :: Test
+testExample = TestCase (assertEqual "test" "test" "test")
+
+testList :: Test
+testList = TestList [ TestLabel "testExample" testExample
+ , TestLabel "testsOfTokens" testsOfTokens
+ ]
+
+main :: IO ()
+main = do
+ _ <- runTestTT testList
+ return ()
+```
+
+Teraz możemy wywołać testy za pomocą polecenia:
+```bash
+cabal test
+```
+
+## Wyprowadzenie i podsumowanie
+
+No ale po co programiście **[Javy]**, **[Kotlina]** czy **[Scali]** język **[Haskell]**?
+Oczywiście oprócz tego,
+że **[Haskell]** uczy programowania funkcyjnego,
+które jest coraz bardziej potrzebne.
+Przecież tego i tak nie można użyć w projekcie działającym na **[JVM]**.
+
+Otóż od niedawna można.
+Można skompilować **[Haskella]** i uruchomić go na [JVMie].
+Kompilator, który to robi nazywa się **[Eta]** a odpowiednikiem [Cabala] jest [Etlas].
+
+Mając zainstalowany kompilator [Eta] i narzędzie do budowania [Etlas] można skompilować projekt za pomocą polecenia:
+```bash
+etlas clean && etlas build && etlas test
+etlas run helcam
+```
+
+Kod jest dostępny na [Githubie](https://github.com/helvm/helcam/releases/tag/v0.2.0.0).
+
+[Eta]: /langs/eta
+[Haskell]: /langs/haskell
+[Haskella]: /langs/haskell
+[Haskellu]: /langs/haskell
+[Java]: /langs/java
+[Javie]: /langs/java
+[Javy]: /langs/java
+[Kotlin]: /langs/kotlin
+[Kotlina]: /langs/kotlin
+[Scala]: /langs/scala
+[Scali]: /langs/scala
+
+[Cabal]: /tools/cabal
+[Cabala]: /tools/cabal
+[Etlas]: /tools/etlas
+[JVM]: /tools/jvm
+[JVMie]: /tools/jvm
+
+[helcam]: /projects/helcam
+[helvm]: /projects/helvm
+
+[BrainFucka]: /eso/brainfuck
+
+[interpreter]: /tags/interpreter
+[lekser]: /tags/lexer
+[leksera]: /tags/lexer
+[pattern matching]: /tags/pattern-matching
+[parser]: /tags/parser
+[type class]: /tags/type-class
+
+[wywołania cebulowe]: /scalapipe
diff --git a/_collections/_posts/2020-06-17-state-monad.md b/_collections/_posts/2020-06-17-state-monad.md
new file mode 100644
index 00000000..5cef0e6b
--- /dev/null
+++ b/_collections/_posts/2020-06-17-state-monad.md
@@ -0,0 +1,253 @@
+---
+title: 'Testy jednostkowe i mockowanie wyścia-wejścia w Haskellu'
+author: TheKamilAdam
+category: haskell-eta
+tags: io monad state testing type-class unit-testing
+langs: eta haskell
+libs: hunit
+tools: cabal etlas
+projects: helcam helvm
+redirect_from:
+ - state-monad
+ - haskell-eta/state-monad
+---
+
+Testy pisać trzeba, to oczywiste.
+Pozostaje pytanie `jednostkowe czy integracyjne?`
+Ja na razie zdecydowałem się na jednostkowe,
+co postawiło mnie przed kolejnym pytaniem `jak przetestować kod używający wyjścia-wejścia w Haskellu?`
+To znowu sprowadza się do pytania `jak zamockować monadę IO w Haskellu?`
+
+Poglądowo spójrzmy na kod zawierający odczyt i zapis ze standardowych strumieni napisany w języku **[Haskell]**:
+
+```haskell
+pipe :: IO ()
+pipe = do
+ char <- getChar
+ putChar char
+ pipe
+```
+Ten program to proste echo.
+Odczytuje jeden znak ze standardowego wejścia i wypisuje go na standardowe wyjście,
+po czym ponawia w nieskończoność za pomocą rekurencji.
+Za odczyt odpowiedzialna jest funkcja `getChar` a za wypisanie - `putChar`.
+Co ciekawe na [EsoLangs] nazywają taki program [Cat].
+
+Ponieważ nie ma tu za wiele do testowania,
+spójrzmy na bardziej skomplikowaną wersję.
+
+```haskell
+filterIf0 :: IO ()
+filterIf0 = do
+ char <- getChar
+ if char == '0'
+ then putChar '\n'
+ else do
+ putChar char
+ filterIf0
+```
+Tutaj odczyt jest przerywany,
+jeśli zostanie wczytany znak '0'.
+Dodatkowo jest na końcu dodawany znak nowej linii dla lepszego działania w konsoli.
+
+Niestety powyższy kod jest nietestowalny w sposób jednostkowy.
+Dla testów jednostkowych najlepiej by było,
+gdyby kod wyglądał następująco:
+```haskell
+listFilterIf0 :: [Char] -> [Char]
+listFilterIf0 [] = []
+listFilterIf0 (char:rest) =
+ if char == '0'
+ then ['\n']
+ else char : listFilterIf0 rest
+```
+
+Niestety takiego kodu nie można używać w sposób interaktywny.
+
+## Funkcje wyższego rzędu (ang. *Higher-order functions*)
+
+Rozwiązaniem jest przekazywanie funkcji odczytujących i zapisujących jako parametry.
+Dzięki czemu dla testów będziemy mogli przekazać zamockowaną implementację.
+
+Najpierw sprawdźmy jaki typ mają funkcje które nas interesują:
+```haskell
+getChar :: IO Char
+putChar :: Char -> IO ()
+```
+
+Następnie utwórzmi aliasy dla tych typów:
+```haskell
+type IOGetChar = IO Char
+type IOPutChar = Char -> IO ()
+```
+
+Nasz produkcyjny kod będzie wyglądać następująco:
+```haskell
+ioFilterIf0 :: IO ()
+ioFilterIf0 = ioFilterIf0' getChar putChar
+```
+
+A funkcja,
+którą będziemy testować jednostkowy,
+będzie miała postać:
+```haskell
+ioFilterIf0' :: IOGetChar -> IOPutChar -> IO ()
+ioFilterIf0' ioGetChar ioPutChar = do
+ char <- ioGetChar
+ if char == '0'
+ then ioPutChar '\n'
+ else do
+ ioPutChar char
+ ioFilterIf0' ioGetChar ioPutChar
+```
+
+Niestety powyższy kod dalej jest nietestowalny jednostkowo.
+Ponieważ nie jesteśmy w stanie napisać zamockowanych implementacji `getChar` i `putChar`.
+
+## Kod zależny od interfejsu, a nie od implementacji
+
+Na początek musimy rozluźnić trochę typy,
+żeby zależały od *interfejsu* a nie od *implementacji*.
+```haskell
+type MGetChar m = m Char
+type MPutChar m = Char -> m ()
+```
+W naszym przypadku *interfejsem* jest klasa typów `Monad` czyli [monada],
+a *implementacją* - monada [IO].
+
+Teraz nasza funkcja,
+którą będziemy,
+testować wygląda następująco:
+```haskell
+mFilterIf0 :: Monad m => MGetChar m -> MPutChar m -> m ()
+mFilterIf0 mGetChar mPutChar = do
+ char <- mGetChar
+ if char == '0'
+ then mPutChar '\n'
+ else do
+ mPutChar char
+ mFilterIf0 mGetChar mPutChar
+```
+Kod produkcyjny dużo się nie zmienił:
+```haskell
+ioMFilterIf0 :: IO ()
+ioMFilterIf0 = mFilterIf0 getChar putChar
+```
+
+## Testy jednostkowe i monada State
+Na potrzeby testów potrzebujemy strukturę,
+która będzie zastępować wejście-wyjście:
+```haskell
+data MockIO = MockIO { input :: String, output :: String }
+ deriving (Eq, Show)
+
+createMockIO :: String -> MockIO
+createMockIO input = MockIO (input) []
+
+getOutput :: MockIO -> String
+getOutput (MockIO input output) = reverse output
+```
+
+Następnie możemy stworzyć nasze zamockowane funkcje:
+```haskell
+mockGetChar :: MockIO Char
+mockGetChar = do
+ state <- get
+ let char = head $ input state
+ put $ state { input = tail $ input state }
+ return char
+
+mockPutChar :: Char -> MockIO ()
+mockPutChar char = do
+ state <- get
+ put $ state { output = char : output state }
+```
+
+Przyda się też funkcja konwertująca naszą monadę `State` na funkcję `String -> String`:
+```haskell
+execMockIO :: MockIO () -> String -> String
+execMockIO mockIO input = getOutput $ execState mockIO $ createMockIO input
+```
+
+Ostatecznie nasz test wygląda następująco:
+```haskell
+testsOfFilterIf0 :: Test
+testsOfFilterIf0 = test
+ [ "testFilter0" ~: "test FilterIf0" ~: "qwerty\n" ~=? execMockIO (mFilterIf0 mockGetChar mockPutChar) "qwerty0uiop"
+ ]
+```
+
+## Klasy typów
+
+W tym przykładzie mieliśmy do zamokowania tylko dwie funkcje.
+Jeśli jednak byłoby ich więcej, np. sześć jak poniżej, mogłoby to zacząć być problematyczne.
+Na szczęście w **[Haskellu]** można grupować funkcje za pomocą interfejsów a dokładniej za pomocą [klas typów].
+
+```haskell
+class Monad m => WrapperIO m where
+ wGetChar :: m Char
+ wPutChar :: Char -> m ()
+ wGetLine :: m String
+ wPutStr :: String -> m ()
+ wPutStrLn :: String -> m ()
+ wFlush :: m ()
+ wPutStrLn s = wPutStr $ s ++ "\n"
+ wFlush = return ()
+```
+
+Implementacja produkcyjna:
+```haskell
+instance WrapperIO IO where
+ wGetChar = getChar
+ wPutChar = putChar
+ wGetLine = getLine
+ wPutStr = putStr
+ wPutStrLn = putStrLn
+ wFlush = hFlush stdout
+```
+
+Implementacja zamockowana (na potrzeby testów):
+```haskell
+instance WrapperIO MockIO where
+ wGetChar = mockGetChar
+ wPutChar = mockPutChar
+ wGetLine = mockGetLine
+ wPutStr = mockPutStr
+```
+
+Kod produkcyjny:
+```haskell
+main :: IO ()
+main = do
+ putStrLn "Hello, Eta!"
+ ioWFilterIf0
+```
+
+Nowe testy nie różnią się wiele od poprzednich.
+Jednak tym razem nie musimy przekazywać funkcji jako parametrów:
+```haskell
+testsOfFilterIf0 :: Test
+testsOfFilterIf0 = test
+ [ "testWFilter0" ~: "test WFilterIf0" ~: "qwerty\n" ~=? execMockIO wFilterIf0 "qwerty0uiop"
+ ]
+```
+
+## Podsumowanie
+
+Nie chciałem poznawać monady [State] tak wcześnie podczas mojej nauki **[Haskella]**,
+ale zostałem do tego zmuszony przez chęć napisania testów jednostkowych do mojego interpretera.
+Monada [State] umożliwia modyfikowanie zmiennych w języku który raczej słynie z niemodyfikowalnych zmiennych.
+Myślę,
+że tej monady nie należy nadużywać.
+
+Kod jest dostępny na [GitHubie](https://github.com/helvm/helcam/releases/tag/v0.4.0.0).
+
+[Haskell]: /langs/haskell
+[Haskella]: /langs/haskell
+[Haskellu]: /langs/haskell
+
+[IO]: /tags/io
+[State]: /tags/state
+
+[EsoLangs]: https://esolangs.org/
+[Cat]: https://esolangs.org/wiki/Cat_program
diff --git a/_collections/_posts/2020-07-01-optparse-applicative.md b/_collections/_posts/2020-07-01-optparse-applicative.md
new file mode 100644
index 00000000..d21616d9
--- /dev/null
+++ b/_collections/_posts/2020-07-01-optparse-applicative.md
@@ -0,0 +1,221 @@
+---
+title: 'Parsowanie parametrów wiersza poleceń w Haskellu'
+author: TheKamilAdam
+category: haskell-eta
+tags: assembler cli interpreter
+langs: eta haskell
+libs: optparse-applicative
+tools: cabal etlas
+projects: helcam helpa helvm
+eso: brainfuck eta subleq whitespace
+redirect_from:
+ - optparse-applicative
+ - haskell-eta/optparse-applicative
+---
+
+Prawie każdy program,
+który można wywoływać z wiersza poleceń (ang. *Command Line Interface*, **[CLI]**),
+a [interpreter] jak [HelCam] w szczególności,
+musi posiadać obsługę parametrów (ang. *Options*) przekazywanych z wiersza poleceń.
+Obsługę taką można napisać samodzielnie albo z pomocą dedykowanej bibliotek.
+Ja zdecydowałem się na bibliotekę [optparse-applicative].
+Biblioteka ta posiada szereg zalet.
+Między innymi można jej używać w **[eta-lang]**.
+
+## Biblioteka `optparse-applicative` w praktyce
+
+Biblioteka [optparse-applicative] jest jedną z tych bibliotek,
+do których najlepiej nie czytać dokumentacji tylko od razu spojrzeć na przykład kodu.
+Zwłaszcza jeśli mało umie się jeszcze **[Haskella]**.
+
+Najpierw tworzymy moduł,
+który będzie zawierać parser parametrów przekazywanych przez wiersz poleceń:
+```haskell
+{-# Language DataKinds #-}
+{-# Language ExplicitNamespaces #-}
+
+module AppOptions where
+
+import Options.Applicative
+
+import Text.Read
+```
+
+### Parser parametrów
+Następnie tworzymy sam parser parametrów:
+```haskell
+optionParser :: Parser AppOptions
+optionParser = AppOptions
+ <$> strOption ( long "lang"
+ <> short 'l'
+ <> metavar "[LANG]"
+ <> help ("Language to interpret " ++ show langs)
+ <> value (show Cat)
+ <> showDefault
+ )
+ <*> switch ( long "emit-tl"
+ <> short 'T'
+ <> help "Emit the lexed tokens"
+ <> showDefault
+ )
+ <*> switch ( long "emit-il"
+ <> short 'I'
+ <> help "Emit the parsed instructions"
+ <> showDefault
+ )
+ <*> switch ( long "ascii-labels"
+ <> short 'A'
+ <> help "Use ascii labels"
+ <> showDefault
+ )
+ <*> switch ( long "eta"
+ <> short 'E'
+ <> help "Eta compliance mode"
+ <> showDefault
+ )
+ <*> strOption ( long "impl"
+ <> short 'i'
+ <> metavar "[IMPL]"
+ <> help ("Implementation of interpreter " ++ show impls)
+ <> value (show Monadic)
+ <> showDefault
+ )
+ <*> argument str ( metavar "FILE")
+```
+
+Biblioteka [optparse-applicative] obsługuje kilka typów parametrów.
+Są to między innymi:
+* `strOption` - opcjonalny parametr typu `String`
+* `switch` - parametr typu `boolean` nieprzyjmujący wartości
+* `argument` - wymagany parametr typu `String`
+
+### Record
+Kolejnym krokiem jest zdefiniowanie rekordu,
+do którego będą zapisywane parametry:
+```haskell
+data AppOptions = AppOptions
+ { lang :: String -- Lang
+ , emitTL :: EmitTL
+ , emitIL :: EmitIL
+ , asciiLabels :: AsciiLabels
+ , etaMode :: EtaMode
+ , impl :: String -- Impl
+ , file :: String
+ }
+```
+
+### Typy niestandardowe
+Niestandardowe typy danych to tylko aliasy na typy standardowe:
+```haskell
+type EmitIL = Bool
+type EmitTL = Bool
+type AsciiLabels = Bool
+type EtaMode = Bool
+```
+
+Żeby używać niestandardowych typów danych, musimy je ręcznie sparsować.
+W przypadku nieudanego parsowania możemy zgłosić błąd:
+```haskell
+data Lang = Cat | BF | WS
+ deriving (Eq, Read, Show)
+
+langs :: [Lang]
+langs = [Cat, BF, WS]
+
+computeLang :: String -> Lang
+computeLang raw = valid $ readMaybe raw where
+ valid (Just a) = a
+ valid Nothing = error ("Lang '" ++ raw ++ "' is not valid lang. Valid langs are : " ++ show langs)
+
+----
+
+data Impl = Monadic | Interact deriving (Eq, Read, Show)
+
+impls :: [Impl]
+impls = [Monadic, Interact]
+
+computeImpl :: String -> Impl
+computeImpl raw = valid $ readMaybe raw where
+ valid (Just a) = a
+ valid Nothing = error ("Impl '" ++ raw ++ "' is not valid impl. Valid impls are : " ++ show impls)
+```
+
+## Main i złożenie wszystkiego razem
+
+W funkcji `main` znajduje się wywołanie parsera parametrów i przekazanie sterowania do funkcji `run`:
+```haskell
+main :: IO ()
+main = execParser opts >>= run where
+ opts = info (optionParser <**> helper)
+ ( fullDesc
+ <> header "HelCam: The Interpreter of BrainFuck and WhiteSpace"
+ <> progDesc "Runs esoteric programs - complete with pretty bad error messages" )
+```
+
+### Run
+W funkcji `run` znajdują się globalne ustawienia oraz przekazanie sterowania do funkcji `eval`:
+```haskell
+run :: AppOptions -> IO ()
+run AppOptions{file, lang, emitTL, emitIL, asciiLabels, etaMode, impl} = do
+ hSetBuffering stdout NoBuffering
+ source <- readFile file
+ eval (computeLang lang) emitTL emitIL asciiLabels etaMode (computeImpl impl) source
+```
+
+### Eval
+Główna logika wyboru interpretera znajduje się w funkcji `eval`.
+Zamienia ona kombinację sparsowanych parametrów linii poleceń na konkretne akcje,
+głównie wywołania interpreterów konkretnych języków ezoterycznych:
+```haskell
+eval :: Lang -> EmitTL -> EmitIL -> AsciiLabels -> EtaMode -> Impl -> Source -> IO ()
+eval BF _ _ _ True Interact = BFIE.interactEvalBF
+eval BF _ _ _ True _ = BFME.monadicEvalBF
+eval BF _ _ _ _ Interact = interactEvalBF
+eval BF _ _ _ _ _ = monadicEvalBF
+eval WS True _ _ _ _ = print . tokenizeWS
+eval WS _ True a _ _ = pPrintNoColor . parseWS a
+eval WS _ _ a True Interact = WSIE.interactEvalWS a
+eval WS _ _ a True _ = WSME.monadicEvalWS a
+eval WS _ _ a _ Interact = interactEvalWS a
+eval WS _ _ a _ _ = monadicEvalWS a
+eval _ _ _ _ _ _ = putStrLn
+```
+
+## Podsumowanie
+
+Można uznać,
+że zakończyłem pisanie interpretera języka [BrainFuck],
+dodatkowo pisząc także interpreter języka [WhiteSpace].
+Nie czuję jednak,
+żebym umiał język programowania **[Haskell]**.
+
+Projekt można kontynuować na różne sposoby:
+* Praca w głąb, czyli optymalizacja interpreterów.
+W tej chwili jednak nie wiem co optymalizować,
+ponieważ mam za mało danych.
+* Praca wzwyż, czyli nadbudowanie abstrakcji,
+czyli np. dodanie wspólnego pseudo asemblerem dla języków [BrainFuck] i [WhiteSpace].
+To jednak nadaje się bardziej na kolejny projekt jak [Helpa].
+* Praca wszerz, czyli dodawanie kolejnych ezoterycznych języków programowania jak [SubLeq] i [ETA].
+
+Kod jest dostępny na [GitHubie](https://github.com/helvm/helcam/releases/tag/v0.5.0.0).
+
+[eta-lang]: /langs/eta
+[Haskell]: /langs/haskell
+[Haskella]: /langs/haskell
+[Haskellu]: /langs/haskell
+
+[optparse-applicative]: /libs/optparse-applicative
+
+[HelCam]: /projects/helcam
+[HelPA]: /projects/helpa
+[HelVM]: /projects/helvm
+
+[BrainFuck]: /eso/brainfuck
+[ETA]: /eso/eta
+[SubLeq]: /eso/subleq
+[WhiteSpace]: /eso/whitespace
+
+[assembler]: /tags/assembler
+[cli]: /tags/cli
+[interpreter]: /tags/interpreter
diff --git a/_collections/_posts/2020-08-05-attoparsec.md b/_collections/_posts/2020-08-05-attoparsec.md
new file mode 100644
index 00000000..1f5901aa
--- /dev/null
+++ b/_collections/_posts/2020-08-05-attoparsec.md
@@ -0,0 +1,401 @@
+---
+title: 'Wyrażenia regularne kontra parsery'
+author: TheKamilAdam
+category: haskell-eta
+tags: assembler cisc dsl lexer misc parser regexp risc rpn
+langs: dc forth haskell joy mouse perl postscript rpl webassembly
+libs: attoparsec earley fastparser happy-alex megaparsec parsec readp trifecta
+tools:
+projects: helcam helpa helvm
+eso: beatnik brainfuck eas eta false funge piet whitespace
+redirect_from:
+ - attoparsec
+ - haskell-eta/attoparsec
+---
+
+Wyrażenia regularne słyną z tego,
+że są trudne i mało czytelne.
+Czy są dla nich jakieś alternatywy?
+Tak, są to parsery.
+
+## Rodzaje parserów
+
+Z grubsza najczęściej występujące parsery można podzielić na zstępujące (ang. *top-down parsers*) i wstępujące (ang. *bottom-up parsers*).
+Dla języków programowania głównymi przedstawicielami parserów zstępujących są parsery LL,
+a parserów wstępujących - parsery LR (które dalej dzielą się na kanoniczne parsery LR, parsery SLR, i parsery LALR).
+Parsery LL czytają tekst od lewej i analizują także od lewej.
+Parsery LR czytają tekst od lewej i analizują od prawej.
+
+Historycznie pierwsze były parsery LL.
+Jednak parsery LR są wydajniejsze niż parsery LL.
+Dlatego parsery LR wyparły prawie całkowicie parsery LL z zastosowań profesjonalnych,
+czyli przy tworzeniu języków programowania ogólnego przeznaczenia.
+Wadą parserów LR jest jednak to,
+że bardzo trudno jest pisać ręcznie
+w przeciwieństwie do parserów LL,
+które wręcz idealnie pisze się ręcznie.
+Dlatego do implementowania prostych języków **[DSL]** lepsze są parsery LL.
+
+Dla Haskella istnieją cztery popularne biblioteki do pisania parserów (plus co najmniej drugie tyle mniej popularnych):
+* **[Happy & Alex]**
+* **[Parsec]**
+* **[MegaParsec]**
+* **[AttoParsec]**
+
+Z mniej popularnych można wymienić:
+* **[ReadP]**
+* **[Trifecta]**
+* **[FastParser]**
+* **[Earley]**
+
+### Happy & Alex
+
+Happy & Alex haskellowe wersje klasycznej pary Yacc i Lex (lub ich darmowych odpowiedników Bison i Flex).
+Jedyne w tym zestawieniu pozwalają na używanie gramatyk LR.
+Wadą pary Happy & Alex jest to,
+że trzeba napisać gramatykę,
+czyli nauczyć się nowego języka niewiele ładniejszego niż wyrażenia regularne.
+
+### Parsec i MegaParsec
+
+Parsec jest to klasyczna haskellowa biblioteka do pisania parserów
+oraz klasyczny przedstawiciel biblioteki kombinatorów parserów (ang. *[Parser combinator](https://en.wikipedia.org/wiki/Parser_combinator)*).
+Biblioteki kombinatory parserów są dedykowane do ręcznego pisania parserów.
+Tak utworzone parsery są bardzo podobne do parserów LL i posiadają ich zalety,
+jednocześnie eliminując wady parserów LL,
+czyli problem lewostronnej rekurencji.
+Parsec niestety nie jest już rozwijany.
+Zamiast tego jest rozwijana jego ulepszona wersja,
+czyli MegaParsec.
+
+### AttoParsec
+AttoParsec to biblioteka oryginalnie pomyślana do parsowania logów na bieżąco.
+Jest szybsza niż MegaParsec czy Parsec oraz jako jedyna umożliwia parsowanie przyrastającego pliku linia po linii.
+Niestety jest też o wiele uboższa w składni,
+przez co jest uważana za dobrą do parsowania plików o prostszej strukturze.
+Ubogość składni przekłada się także na prostszą strukturę samej biblioteki.
+Dzięki czemu o wiele prościej się jej nauczyć.
+
+## Tekst o prostej strukturze
+
+Ponieważ moim marzeniem jest skompilowanie C do BrainFucka.
+Jako przykład nie będziemy parsować logów,
+tylko plik z językiem asemblera.
+Wcześniej jednak zobaczmy rodzaje języków asemblera.
+
+### Rodzaje języków assemblera
+
+Składnia języka asemblera jest mocno powiązana z [modelem programowym procesora](https://pl.wikipedia.org/wiki/Model_programowy_procesora)
+(ang. *[Instruction set architecture](https://en.wikipedia.org/wiki/Instruction_set_architecture)*, **[ISA]**).
+
+Trzy najczęściej spotykane typy modeli programowych procesora to:
+* CISC (ang. Complex Instruction Set Computing)
+* RISC (ang. Reduced Instruction Set Computing)
+* MISC (ang. Minimal Instruction Set Computing)
+
+**[CISC]** historycznie był pierwszym modelem.
+Charakteryzował się skomplikowanymi rozkazami ze skomplikowanymi sposobami adresowania.
+Miało to ułatwić pisanie kompilatorów.
+Nie ułatwiło.
+Żyjącym przedstawicielem tego modelu jest x86.
+Także mikroprocesor 8051 bywa uważany za przedstawiciela modelu **[CISC]**.
+
+**[RISC]** został stworzony jako reakcja na to,
+że model CISC okazał się jednak ślepą uliczką.
+Skomplikowane rozkazy i sposoby adresowania nie pomagały w pisaniu kompilatorów.
+W związku z tym postanowiono pójść w drugą skrajność maksymalnie upraszczając listę rozkazów oraz sposoby adresowania.
+Wynikiem tego była prostsza jednostka arytmetyczno-logiczna.
+Zaoszczędzone tranzystory przeznaczano na większą ilość rejestrów ogólnego przeznaczenia.
+Prawdopodobnie najpopularniejszym przedstawicielem tego modelu jest ARM.
+Także mikroprocesory AVR bywają uważane za przedstawicieli modelu **[RISC]**.
+
+**[MISC]** był rozwijany niezależnie.
+Charakteryzuje się bardzo małą ilością rozkazów.
+Niektóre języki assemblera **[MISC]** wyglądają wręcz jak języki ezoteryczne.
+
+Nie jest to w zasadzie wymagane,
+ale zwykle maszyny MISC to [maszyny stosowe](https://pl.wikipedia.org/wiki/Maszyna_stosowa) nie posiadające rejestrów,
+tylko wszystkie operacje wykonujące na stosie.
+Rozwiązuje to także problem adresowania,
+bo większość operacji wykonywanych na stosie to rozkazy 0-adresowe,
+ewentualnie 1-adresowe.
+
+Co ciekawe rzeczywiste procesory są rzadko budowane jako maszyny stosowe.
+Prawdopodobnie najbardziej znanym procesorem stosowym był [Transputer](https://en.wikipedia.org/wiki/Transputer).
+Także koprocesor matematyczny był maszyną stosową.
+
+O wiele częściej maszynami stosowymi są maszyny wirtualne jak **[JVM]**, [Wirtualna Maszyna Perla](https://pl.wikipedia.org/wiki/Kod_bajtowy_Perla) czy **[WebAssembly]**.
+Wiele języków ezoterycznych jak **[ETA]**, **[False]**, **[Funge]**, **[Piet]**, **[WhiteSpace]** to języki stosowe.
+Istnieją też nieezoteryczne wysokopoziomowe języki stosowe (ang. stack-based) jak **[dc]**, **[Joy]**, **[Forth]**, **[Mouse]**, **[PostScript]** i **[RPL]**.
+
+Najprostszy możliwi zestaw instrukcji dla maszyny stosowej został opisany jako [A Minimal CISC](http://homepage.divms.uiowa.edu/~jones/arch/cisc/)).
+Zawiera on tylko 8 instrukcji.
+Ja jednak zdecydowałem się na inny zestaw instrukcji będący językiem ezoterycznym **[ETA]**.
+
+### ETA i EAS
+
+Język **[ETA]** posiada także prosty assembler, i język asemblerowy o tej samej nazwie, **[EAS]**.
+Jest on co prawda zaimplementowany Perlu,
+ale przy pomocy wyrażeń regularnych.
+Oryginalny jest dostępny [tutaj](http://www.miketaylor.org.uk/tech/eta/src/eas),
+a mirror [tutaj](https://github.com/helvm/eta/blob/master/src/eas).
+
+## Struktura asemblera, czyli programu asemblującego (montującego)
+
+Cztery główne moduły asemblera to:
+* Parser asemblera EAS
+* Konsolidator (ang. Linker)
+* Reduktor (ang. Reducer) instrukcji
+* Generator kodu wynikowego, czyli kodu ETA
+
+```haskell
+assemblyIO :: String -> String -> IO (Either String String)
+assemblyIO dirName fileName = runExceptT $ assembly dirName fileName
+
+assembly :: String -> String -> ExceptT String IO String
+assembly dirName fileName = generateCode . reduce <$> link dirName fileName
+```
+
+Najpierw naprzemiennie następuje faza parsowania i konsolidacji.
+Następnie następuje redukcja instrukcji i generacja kodu docelowego.
+
+### Parser języka asemblera
+
+Pierwszym modułem programu jest parser:
+```haskell
+parseAssembler :: T.Text -> Either String InstructionList
+parseAssembler = parseOnly instructionListParser
+
+instructionListParser :: Parser InstructionList
+instructionListParser = skipManyComment *> skipHorizontalSpace *> many (instructionParser <* skipHorizontalSpace)
+```
+Parser pobiera zmienną typu `Text` i w przypadku powodzenia zwraca listę sparsowanych instrukcji.
+W przypadku niepowodzenia zwraca mało intuicyjny komunikat o błędzie generowany przez bibliotekę **[AttoParsec]**.
+
+Parsowanie pojedynczej instrukcji dzieli się na kilka przypadków:
+```haskell
+instructionParser :: Parser Instruction
+instructionParser =
+ try zeroOperandInstructionParser
+ <|> naturalNumberParser
+ <|> unescapedStringParser
+ <|> labelDefinitionParser
+ <|> includeFileParser
+ <|> lineBreakParser
+ <|> commentParser
+```
+Czyli:
+* parsowanie instrukcji bezargumentowej
+* parsowanie liczby naturalnej
+* parsowanie literału stringa
+* parsowanie deklaracji etykiety
+* parsowanie dołączenia pliku
+* parsowanie końca linii
+* parsowanie komentarza
+
+**[EAS]** jak to język assemblera dla maszyny stosowej zawiera wiele rozkazów bezargumentowych:
+```haskell
+zeroOperandInstructionParser :: Parser Instruction
+zeroOperandInstructionParser =
+ zeroOperandInstruction E ["E", "dividE"]
+ <|> zeroOperandInstruction T ["T", "Transfer"]
+ <|> zeroOperandInstruction A ["A", "Address"]
+ <|> zeroOperandInstruction O ["O", "Output"]
+ <|> zeroOperandInstruction I ["I", "Input"]
+ <|> zeroOperandInstruction S ["S", "Subtract"]
+ <|> zeroOperandInstruction H ["H", "Halibut"]
+ where zeroOperandInstruction i ts = i <$ (asciiCIChoices ts *> endWordParser)
+```
+
+Oryginalnie EAS posiada tylko jeden rozkaz jednoargumentowy.
+Jest tu umieszczenie liczby naturalnej na stosie.
+Przy czym liczbą może być wartość podana wprost,
+wartość literału znakowego lub adres etykiety.
+Ja rozszerzyłem to jeszcze o możliwość umieszczenie nieescepowanego literału znakowego na stosie.
+Dodatkowo posiada także możliwość dołączenia (ang. *incluDe*) pliku oraz zdefiniowania etykiety (ang. *Label*):
+```haskell
+naturalNumberParser :: Parser Instruction
+naturalNumberParser = N <$> (
+ naturalValueParser
+ <|> (asciiCI "N" *> skipHorizontalSpace *> naturalValueParser)
+ <|> (asciiCI "Number" *> endWordParser *> skipHorizontalSpace *> naturalValueParser)
+ )
+
+unescapedStringParser :: Parser Instruction
+unescapedStringParser = U <$> stringParser
+
+labelDefinitionParser :: Parser Instruction
+labelDefinitionParser = L <$> (char '>' *> identifierParser <* char ':')
+
+includeFileParser :: Parser Instruction
+includeFileParser = D <$> (char '*' *> fileNameParser <* char '\n')
+```
+
+Ponieważ w **[EAS]** znaki końca linii są znaczące to trzeba je parsować w sposób świadomy:
+```haskell
+lineBreakParser :: Parser Instruction
+lineBreakParser = R <$ (skipMany1EndLine *> skipManyComment)
+
+commentParser :: Parser Instruction
+commentParser = skipComment *> lineBreakParser
+
+skipManyComment :: Parser [()]
+skipManyComment = many (skipComment <* skipMany1EndLine)
+
+skipComment :: Parser ()
+skipComment = char commentChar *> skipAllToEndOfLine
+
+skipMany1EndLine :: Parser String
+skipMany1EndLine = many1 (char '\n')
+```
+
+Problem końca wyrazu (identyfikatora) to coś,
+co zajęło mi jeden wieczór.
+W wyrażeniach regularnych byłoby to proste `\b`.
+Tutaj jednak trzeba było napisać ręcznie funkcję wykrywania końca wyrazu oraz funkcję pobierającą wszystko przed końcem wyrazu.
+Ostatecznie stwierdziłem,
+że koniec wyrazu to albo biały znak,
+albo początek komentarza:
+```haskell
+endWordParser :: Parser T.Text
+endWordParser = takeTill isEndWord
+
+isEndWord :: Char -> Bool
+isEndWord c = isSpace c || (c == commentChar)
+
+commentChar :: Char
+commentChar = '#'
+```
+
+### Konsolidator
+
+Konsolidator (ang. linker) to program łączący pliki.
+Dołącza on plik biblioteczny w miejsce wystąpienia `*nazwa_biblioteki.wsa`:
+```haskell
+link :: String -> String -> ExceptT String IO InstructionList
+link dirName fileName = includeFiles $ ExceptT $ parseAssembler <$> T.readFile (dirName ++ "/" ++ fileName) where
+
+ includeFiles :: ExceptT String IO InstructionList -> ExceptT String IO InstructionList
+ includeFiles expect = loadFiles =<< expect
+
+ loadFiles :: InstructionList -> ExceptT String IO InstructionList
+ loadFiles il = concat <$> mapM loadFile il
+
+ loadFile :: Instruction -> ExceptT String IO InstructionList
+ loadFile (D libName) = link dirName libName
+ loadFile i = pure [i]
+```
+Ponieważ dołączana biblioteka może zawierać inne biblioteki to funkcja link jest funkcją rekurencyjną.
+
+### Reduktor instrukcji
+
+Redukcja siły operatorów (ang. [Strength reduction](https://en.wikipedia.org/wiki/Strength_reduction))
+jest częścią optymalizacji.
+W naszym przypadku mamy redukcję skomplikowanych instrukcji na instrukcje proste.
+Reduktor instrukcji jest to w zasadzie uproszczony selektor instrukcji,
+który normalnie jest częścią generatora kodu docelowego.
+
+Redukcja etykiet,
+czyli wyliczanie adresów skoków:
+```haskell
+replaceLabels :: LabelAddresses -> InstructionList -> InstructionList
+replaceLabels addresses il = replaceLabel addresses <$> il
+
+replaceLabel :: LabelAddresses -> Instruction -> Instruction
+replaceLabel addresses (N (Variable l)) = N $ Literal $ findOrError l addresses
+replaceLabel _ i = i
+```
+
+Redukcja literałów stringów,
+czyli zamiana na literały znaków:
+```haskell
+replaceStrings :: InstructionList -> InstructionList
+replaceStrings il = replaceString =<< il
+
+replaceString :: Instruction -> InstructionList
+replaceString (U s) = charToInstruction <$> reverse s
+replaceString i = [i]
+
+charToInstruction :: Char -> Instruction
+charToInstruction c = N $ Literal $ fromIntegral $ ord c
+```
+
+### Właściwy generator kodu docelowego
+
+Ponieważ wszystkie potrzebne operacje zostały już wykonane,
+to właściwy generator kodu docelowego zamienia naszą zredukowaną listę instrukcji na język **ETA**:
+```haskell
+generateCode :: InstructionList -> String
+generateCode il = show . WhiteInstruction =<< il
+
+newtype WhiteInstruction = WhiteInstruction Instruction
+
+instance Show WhiteInstruction where
+ show (WhiteInstruction (N (Literal n))) = "N" ++ showValue n ++ "e"
+ show (WhiteInstruction (N (Variable i))) = error $ show i
+ show (WhiteInstruction (D i)) = error $ show i
+ show (WhiteInstruction (U i)) = error $ show i
+ show (WhiteInstruction (L _)) = ""
+ show (WhiteInstruction R) = "\n"
+ show (WhiteInstruction i) = show i
+
+showValue :: Natural -> String
+showValue value = naturalToChar <$> naturalToDigits7 value
+
+naturalToChar :: Natural -> Char
+naturalToChar index = ['h', 't', 'a', 'o', 'i', 'n', 's'] `genericIndex` index
+```
+
+## Podsumowanie
+
+AttoParsec jest prostą biblioteką.
+Czy tak samo prostą jak wyrażenia regularne?
+Tego nie wiem,
+ale na pewno jest dużo czytelniejszy.
+Jednocześnie AttoParsec posiada o wiele większe możliwości.
+Szkoda,
+że nie jest przeportowany do innych języków programowania niż **[Haskell]**.
+
+Kod assemblera **[EAS]** jest dostępny na [GitHubie](https://github.com/helvm/helpa/releases/tag/v0.2.1.0).
+Kod interpretera **[ETA]** też jest dostępny na [GitHubie](https://github.com/helvm/helcam/releases/tag/v0.6.0.0).
+
+[dc]: /langs/dc
+[Forth]: /langs/forth
+[Haskell]: /langs/haskell
+[Joy]: /langs/joy
+[Perl]: /langs/perl
+[Mouse]: /langs/mouse
+[PostScript]: /langs/postscript
+[RPL]: /langs/rpl
+[WebAssembly]: /langs/webassembly
+
+[AttoParsec]: /libs/attoparsec
+[Earley]: /libs/earley
+[Happy & Alex]: /libs/happy-alex
+[MegaParsec]: /libs/megaparsec
+[Parsec]: /libs/parsec
+[ReadP]: /libs/readp
+[Trifecta]: /libs/trifecta
+
+[HelCam]: /projects/helcam
+[HelPA]: /projects/helpa
+[HelVM]: /projects/helvm
+
+[Beatnik]: /eso/beatnik
+[BrainFucka]: /eso/brainfuck
+[EAS]: /eso/eas
+[ETA]: /eso/eta
+[False]: /eso/false
+[Funge]: /eso/funge
+[Piet]: /eso/piet
+[WhiteScape]: /eso/whitespace
+
+[asembler]: /tags/assembler
+[CISC]: /tags/cisc
+[DSL]: /tags/dsl
+[lekser]: /tags/lexer
+[MISC]: /tags/misc
+[parser]: /tags/parser
+[regexp]: /tags/regexp
+[RISC]: /tags/risc
+[RPN]: /tags/rpn
diff --git a/_collections/_posts/2020-09-02-pipe-operators.md b/_collections/_posts/2020-09-02-pipe-operators.md
new file mode 100644
index 00000000..8a631920
--- /dev/null
+++ b/_collections/_posts/2020-09-02-pipe-operators.md
@@ -0,0 +1,204 @@
+---
+title: 'Problem wywołań cebulowych w Haskellu'
+author: TheKamilAdam
+category: haskell-eta
+tags: operator onion
+langs: haskell ocaml rust scala
+libs: scalaz zio
+redirect_from:
+ - pipe-operators
+ - haskell-eta/pipe-operators
+---
+
+Przez `Problem wywołań cebulowych` rozumiem sytuację zagnieżdżonego wywoływania różnego rodzaju funkcji jak:
+```haskell
+someFunction someData = thirdFunction (secondFunction (firstFunction someData))
+```
+
+Duża ilość wywołań powoduje dużą ilość nawiasów na końcu:
+```haskell
+f x = f9 (f8 (f7 (f6 (f5 (f4 (f3 (f2 (f1 (f0 x)))))))))
+```
+co jest mało czytelne.
+
+W **[Haskellu]** można zapisać to trochę czytelniej za pomocą klauzuli `where`:
+```haskell
+someFunction someData = thirdFunction secondDate where
+ secondData = secondFunction firstData
+ firstData = firstFunction someData
+```
+
+Niestety klauzula `where` może powodować dużą rozwlekłość kodu:
+```haskell
+f x = f9 x8 where
+ x8 = f8 x7
+ x7 = f7 x6
+ x6 = f6 x5
+ x5 = f5 x4
+ x4 = f4 x3
+ x3 = f3 x2
+ x2 = f2 x1
+ x1 = f1 x
+```
+Dodatkowo tworzymy dużą ilość pośrednich zmiennych,
+które tylko zaciemniają kod.
+
+W językach obiektowych (lub wspierających notację obiektową jak **[Rust]**) mamy szansę na lepszy zapis,
+jeśli `firstFunction` jest metodą obiektu `firstData`,
+`secondFunction` jest metodą obiektu `secondData`,
+a `thirdFunction` jest metodą obiektu `thirdData`:
+```scala
+def someFunction(someDate: SomeDate): SomeResult = someData
+ .firstFunction()
+ .secondFunction()
+ .thirdFunction()
+```
+
+Niestety nie zawsze mamy takie szczęście i wtedy kod wygląda mniej więcej tak:
+```scala
+def someFunction(someData: SomeDate): SomeResult = {
+ val firstData = firstFunction(someData)
+ val secondDate = secondFunction(firstData)
+ third_function(secondDate)
+}
+```
+
+Lub w krótszej formie bez zmiennych pośrednich tak:
+```scala
+def someFunction(someData: SomeDate): SomeResult = third_function(secondFunction(firstData(someData)))
+```
+
+W **[Scali]** można jeszcze próbować dodać metodę do obiektu za pomocą konwersji `implicit`,
+jednak może wymagać to dużej ilości kodu,
+a zysk jest raczej mały.
+Chociaż czasem jest to używane w bibliotekach jak [Scalaz] czy [Zio].
+
+Na szczęście można rozwiązać to za pomocą operatora potoku,
+zwanego też w **[Scali]** operatorem drozda:
+```scala
+def someFunction(someData: SomeDate): someData |> firstFunction |> secondFunction |> thirdFunction
+```
+Pisałem o tym w artykule [Problem wywołań cebulowych w Scali](/scalapipe).
+
+## Operatory aplikacji (i kombinacji)
+
+**[Haskell]** także posiada swoje operatory potoku.
+Jednak dla *utrudnienia* nazywają się one operatorami aplikacji.
+Znajdują się one w module [Data.Function](https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Function.html).
+
+Podobnie jak w przypadku języków **[Scala]** czy **[OCaml]**,
+w **[Haskell]** operatory te nie są częścią składni języka,
+tylko zdefiniowane są tak jak funkcje.
+Dzięki temu,
+że te języki programowania mają elastyczną składnię można definiować własne operatory.
+
+W dalszej części artykułu będę poszukiwać czytelniejszej formy dla funkcji:
+```haskell
+f x = f3 (f2 (f1 x))
+```
+
+### Operator dolara (ang. *Dollar operator*)
+Pierwszym operatorem aplikacji jest operator dolara `($)`.
+Operator ten robi "apply forward" zwane też "pipe into".
+Definicja:
+```haskell
+($) :: (a -> b) -> (a -> b)
+```
+
+Użycie operatora dolara wygląda następująco:
+```haskell
+f d = f3 $ f2 $ f1 d
+```
+
+Jest to odpowiednik z innych języków programowania:
+```haskell
+f d = f3 <| f2 <| f1 <| d
+```
+
+Powyższy zapis jest czytelniejszy niż zapis nawiasowy,
+jednak dalej wymaga czytania od prawej do lewej,
+co jest nienaturalne.
+
+### Operator et (ang. *Ampersand operator*)
+Drugim operatorem aplikacji jest operator et `(&)`.
+Operator ten robi "apply backward" zwane też "pipe from".
+Definicja:
+```haskell
+a -> (a -> b) -> b
+```
+
+Użycie operatora et wygląda następująco:
+```haskell
+f d = d & f1 & f2 & f3
+```
+
+Jest to odpowiednik z innych języków programowania:
+```haskell
+f d = d |> f1 |> f2 |> f3
+```
+
+Jest to czytelniejsza postać dla użytkowników języków obiektowych oraz języka **[Rust]**,
+jednak w Haskellu rzadko używana.
+
+### Operator kropki (ang. *Dot operator*)
+Operator kropki `(.)` służy do składania funkcji (ang. *[Function composition](https://wiki.haskell.org/Function_composition)*).
+Jest to operator kompozycji.
+Definicja:
+```haskell
+(.) :: (b -> c) -> (a -> b) -> a -> c
+```
+I użycie w **[Haskellu]** jakiego moglibyśmy się spodziewać:
+```haskell
+f d = (f3 . f2 . f1) d
+```
+
+Jednak nie jest to to,
+czego można by spodziewać się po programistach **[Haskella]**.
+Haskell pozwala na *[PointFree](https://wiki.haskell.org/Pointfree) Style*,
+czyli możliwość niezapisywania argumentów:
+```haskell
+f = f3 . f2 . f1
+```
+
+Styl PointFree bywa też nazywany stylem Pointless,
+ponieważ jest oskarżany o zaciemnianie kodu.
+
+## Pakiet Flow
+Pakiet [Flow](https://hackage.haskell.org/package/flow-1.0.21/docs/Flow.html) pozwala używać operatorów znanych z innych języków programowania,
+takich jak **[Scala]** czy **[OCaml]**.
+Definiuje on dwa operatory aplikacji oraz dwa operatory kompozycji,
+które w uproszczeniu można wyjaśnić jako:
+```haskell
+(<|) = ($) -- "apply forward" or "pipe into"
+(|>) = (&) -- "apply backward" or "pipe from"
+(<.) = (.) -- "compose backward" or "but first"
+(.>) = flip (.) -- "compose forward" or "and then"
+```
+
+Dzięki tym operatorom możemy zdefiniować złożenie funkcji na cztery różne czytelne sposoby:
+```haskell
+f x = f3 (f2 (f1 x)) -- normalny zapis
+f x = f3 <| f2 <| f1 <| x -- apply forward
+f x = x |> f1 |> f2 |> f3 -- apply backward
+f = f3 <. f2 <. f1 -- compose backward
+f = f1 .> f2 .> f3 -- compose forward
+```
+
+## Podsumowanie
+
+**[Haskell]** posiada wiele operatorów pozwalających na redukcję nawiasów podczas wywoływania funkcji.
+Samodzielnie (lub w zespole) należy ustalić,
+który ze styli jest najbardziej czytelny dla nas.
+
+[Haskell]: /langs/haskell
+[Haskella]: /langs/haskell
+[Haskellu]: /langs/haskell
+[OCaml]: /langs/ocaml
+[Scala]: /langs/scala
+[Scali]: /langs/scala
+[Rust]: /langs/rust
+
+[scalaz]: /libs/scalaz
+[zio]: /libs/zio
+
+[operator]: /tags/operator
diff --git a/_collections/_posts/2020-10-07-functor-monad-applicative.md b/_collections/_posts/2020-10-07-functor-monad-applicative.md
new file mode 100644
index 00000000..fb233d7e
--- /dev/null
+++ b/_collections/_posts/2020-10-07-functor-monad-applicative.md
@@ -0,0 +1,236 @@
+---
+title: 'Funktor, Monada i Aplikatyw'
+author: TheKamilAdam
+category: haskell-eta
+tags: applicative functor library operator monad type-class
+langs: haskell
+libs: semigroupoids
+projects: helpa
+eso: eta
+redirect_from:
+ - functor-monad-applicative
+ - haskell-eta/functor-monad-applicative
+---
+
+Trzy **[klasy typów]** **[Funktor]**, **[Monada]** i **[Aplikatyw]** są to prawdopodobnie trzy najpopularniejsze klasy typów do przetwarzania danych.
+
+### Funktor (ang. Funktor)
+
+[Funktor w Haskellu](https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Functor.html#t:Functor)
+jest prawdopodobnie najprostszą **[klasą typu]** do przetwarzania danych.
+
+Podstawą **Funktora** jest metoda `fmap`:
+```haskell
+fmap :: (a -> b) -> (f a -> f b)
+```
+
+`fmap` może wydawać się bezsensowny,
+ponieważ pobiera funkcję i zwraca funkcję.
+Jeśli jednak zapiszemy tę sygnaturę inaczej,
+to nabierze to większego sensu:
+```haskell
+fmap :: (a -> b) -> f a -> f b
+(<$>) :: (a -> b) -> f a -> f b
+(<&>) :: f a -> (a -> b) -> f b
+```
+
+Teraz:
+* Funkcja `fmap` pobiera dwa argumenty, funkcję mapującą i funktor do przemapowania.
+* Operator `(<$>)` podobnie jak operator `($)` pozwala pomijać nawiasy.
+* Operator `(<&>)` podobnie jak operator `(&)` pozwala pisać kod w stylu bardziej obiektowym.
+
+Przykłady użycia:
+```haskell
+fmap (function1 data1)
+fmap $ function1 data1
+function1 <$> data1
+data1 <&> function1
+```
+
+W moim parserze języka **[ETA]** preferuje operator `(<$>)`:
+```haskell
+unescapedStringParser :: Parser Instruction
+unescapedStringParser = U <$> stringParser
+
+labelDefinitionParser :: Parser Instruction
+labelDefinitionParser = L <$> (char '>' *> identifierParser <* char ':')
+
+includeFileParser :: Parser Instruction
+includeFileParser = D <$> (char '*' *> fileNameParser <* char '\n')
+```
+
+Są jeszcze dwa pomocnicze operatory różniące się kolejnością argumentów:
+```haskell
+($>) :: f a -> b -> f b
+(<$) :: a -> f b -> f a
+```
+
+Przykład użycia:
+```haskell
+>>> Nothing $> "Haskell"
+Nothing
+>>> Just "Scala" $> "Haskell"
+Just "haskell"
+>>> "Haskell" <$ Nothing
+Nothing
+>>> "Haskell" <$ Just "Scala"
+Just "Haskell"
+```
+
+W moim parserze języka **[ETA]** preferuje operator `(<$)`:
+```haskell
+zeroOperandInstructionParser :: Parser Instruction
+zeroOperandInstructionParser =
+ zeroOperandInstruction E ["E", "dividE"]
+ <|> zeroOperandInstruction T ["T", "Transfer"]
+ <|> zeroOperandInstruction A ["A", "Address"]
+ <|> zeroOperandInstruction O ["O", "Output"]
+ <|> zeroOperandInstruction I ["I", "Input"]
+ <|> zeroOperandInstruction S ["S", "Subtract"]
+ <|> zeroOperandInstruction H ["H", "Halibut"]
+ where zeroOperandInstruction i ts = i <$ (asciiCIChoices ts *> endWordParser)
+```
+
+### Monada (ang. Monad)
+
+[Monada w Haskellu](https://hackage.haskell.org/package/base-4.14.0.0/docs/Control-Monad.html#t:Monad)
+jest bazą dla całej rodziny klas typów.
+To właśnie nią straszy się niegrzeczne dzieci.
+W praktyce **[Monada]** jest bardzo prosta i sprowadza się do zdefiniowania jednego operatora,
+który występuje w dwóch wersjach:
+```haskell
+(>>=) :: m a -> (a -> m b) -> m b
+(=<<) :: (a -> m b) -> m a -> m b
+```
+Pozwalają one na łączenie dwóch monad w jedną monadę.
+
+Tu można się zdziwić,
+bo dokumentacja **Haskella** preferuje operator `(>>=)`.
+Mnie jednak bardziej pasuje operator `(=<<)`,
+ponieważ pozwala czytać kodo prawej do lewej,
+podobnie jak operatory `($)` i `(<$>)`.
+
+Przykład z asemblera języka **[ETA]** wygląda następująco:
+```haskell
+replaceStrings :: InstructionList -> InstructionList
+replaceStrings il = replaceString =<< il
+
+replaceString :: Instruction -> InstructionList
+```
+
+### Aplikatyw (ang. Applicative)
+
+[Aplikatyw w Haskellu](https://hackage.haskell.org/package/base-4.14.0.0/docs/Control-Applicative.html#t:Applicative) jest klasą pośrednią między Funktorem a Monadą.
+
+**[Aplikatyw]** dziedziczy z **Funktora**,
+a **[Monada]** dziedziczy z **Aplikatywu**.
+W zasadzie jest to **[Monada]** bez operatorów `(>>=)` i `(=<<)`,
+czyli bez możliwości składania.
+
+**[Aplikatyw]** posiada następujące operacje:
+```haskell
+pure :: a -> f a
+(<*>) :: f (a -> b) -> f a -> f b
+(<**>) :: f a -> f (a -> b) -> f b
+```
+
+Gdzie:
+* Funkcja `pure` pozwala utworzyć **[Aplikatyw]**.
+* Operator `(<*>)` jest bardzo podobny do `(<$>)`, ale tutaj także funkcja jest opakowana w kontekst.
+* Operator `(<**>)` podobnie jak operator `(<&)` pozwala na zapis w stylu bardziej obiektowym.
+
+
+Są jeszcze dwa operatory pomocnicze:
+```haskell
+(*>) :: f a -> f b -> f b
+(<*) :: f a -> f b -> f a
+```
+
+Gdzie:
+* Operator `(*>)` pozwala odrzucić pierwszy argument.
+* Operator `(<*)` pozwala odrzucić drugi argument.
+
+Tu kolejność jest ważna.
+Pierwszy ignoruje pierwszą wartość.
+Drugi operator ignoruje drugą wartość.
+
+W przeciwieństwie do poprzednich par operatorów,
+oba te operatory są potrzebne.
+
+Przykład z asemblera języka **[ETA]** wygląda następująco:
+```haskell
+labelDefinitionParser :: Parser Instruction
+labelDefinitionParser = L <$> (char '>' *> identifierParser <* char ':')
+
+includeFileParser :: Parser Instruction
+includeFileParser = D <$> (char '*' *> fileNameParser <* char '\n')
+```
+### Problemy z Aplikatywem
+
+Nie zawsze było tak,
+że **[Aplikatyw]** był klasą bazową dla **[Monady]**.
+Aplikatyw został dodany później w związku z pracami nad parserami w **[Haskell]**.
+
+Z tego powodu niektóre operacje z **Aplikatywu** są zdupkiowane w **Monadzie**.
+Są to:
+```haskell
+pure = return
+(<*>) = ap
+(>>) = (*>)
+```
+
+Zawsze należy dbać o to,
+żeby operacje te posiadały te same implementacje.
+
+### Szczegóły implementacyjne w standardowej bibliotece Haskella
+
+Nie wszystkie podane przeze mnie powyżej metody są zdefiniowane w **[klasach typów]**.
+* **[Funktor]** posiada tylko metody `fmap` i `(<$)`,
+przy czym do minimalnej definicji wystarczy tylko implementacja `fmap`.
+`(<$>)` i `($>)` są funkcjami przyjmującymi **[Funktor]**.
+* **[Aplikatyw]** posiada tylko metody `pure`, `(<*>)`, `lift`, `(*>)` oraz `(*>)`.
+przy czym do minimalnej definicji wystarczy tylko implementacja `pure` oraz `(<*>)` lub `liftA2`.
+`(<**>)` jest dostarczana jako funkcja przyjmująca **[Aplikatyw]**.
+* **[Monad]** posiada tylko metody `(>>=)`, `(>>)`, `return` i `fail` ,
+przy czym do minimalnej definicji wystarczy tylko implementacja `(>>=)`.
+`(=<<)`, `ap` i wiele innych są dostarczane jako funkcje przyjmujące **[Monadę]**
+
+### Inne problemy i inne implementacje
+
+Nie tylko hierarcha dziedziczenia między **[Aplikatywem]** a **[Monadą]** jest zepsuta w **[Haskellu]**.
+Ogólnie cała hierarcha dziedziczenia jest popsuta (nie zawiera odpowiednio dużo kroków pośrednich).
+Na szczęście jest biblioteka [semigroupoids](https://hackage.haskell.org/package/semigroupoids),
+która rozwiązuje ten problem.
+Implementuje ona wszystkie teoretycznie istniejące kroki pośrednie:
+```
+Foldable ----> Traversable <--- Functor ------> Alt ---------> Plus Semigroupoid
+ | | | | |
+ v v v v v
+Foldable1 ---> Traversable1 Apply --------> Applicative -> Alternative Category
+ | | | |
+ v v v v
+ Bind ---------> Monad -------> MonadPlus Arrow
+```
+
+Jest tylko jeden problem.
+Posiada ona własną definicję [Funktora](https://hackage.haskell.org/package/semigroupoids/docs/Data-Functor-Apply.html#t:Functor).
+
+## Podsumowanie
+
+**[Haskell]** jest wspaniałym językiem programowania,
+ale niestety nie wszystko w nim jest idealne.
+Zmiany są jednak wprowadzane stopniowo,
+nawet jeśli wiąże się to ze złamaniem kompatybilności.
+
+[Haskell]: /langs/haskell
+
+[semigroupoids]: /libs/semigroupoids
+
+[ETA]: /eso/eta
+
+[Aplikatyw]: /tags/applicative
+[Funktor]: /tags/functor
+[klasą typu]: /tags/type-class
+[klasy typów]: /tags/type-class
+[klasach typów]: /tags/type-class
+[Monada]: /tags/monad
diff --git a/_collections/_posts/2020-12-01-declaration-vs-expression-style.md b/_collections/_posts/2020-12-01-declaration-vs-expression-style.md
new file mode 100644
index 00000000..a56b52f0
--- /dev/null
+++ b/_collections/_posts/2020-12-01-declaration-vs-expression-style.md
@@ -0,0 +1,248 @@
+---
+title: 'Styl wyrażenia a styl deklaracji'
+author: TheKamilAdam
+category: haskell-eta
+langs: haskell ocaml perl python racket scheme
+redirect_from:
+ - declaration-vs-expression-style
+ - haskell-eta/declaration-vs-expression-style
+---
+
+Wiele styli - jak perl
+Jeden styl - jak python
+Dwa style
+
+Istnieją dwa główne style pisania programów funkcjonalnych, które są obsługiwane przez Haskella głównie dlatego, że kilku projektantów języków preferowało te różne style.
+
+W stylu deklaracji formułujesz algorytm za pomocą kilku równań, które powinny być spełnione.
+W stylu wyrażeń tworzysz duże wyrażenia z małych wyrażeń.
+
+## Styl wyrażeń
+
+Zacznę od stylu wyrażeń,
+bo jest to coś co częściej jest spotykane w językach funkcyjnych.
+
+Scheme Racket
+
+Styl wyrażeń
+
+### Abstrakcja lambda i wiązanie
+
+Trudno powiedzieć czym jest programowanie funkcyjne.
+Wielu pisze że jest programowanie oparte na zwracaniu wartości.
+Trudno jednak wyokrazić sobie programowanie funkcyjne bez możliwości deklarowania lambd.
+
+(Functions (Procedures): lambda)[https://docs.racket-lang.org/guide/lambda.html]
+
+```
+(lambda (arg-id ...)
+ body ...+)
+```
+
+Przykładowe utworzenie lambdy to
+```racket
+(lambda (a b) (+ a b))
+```
+
+Z taką utworznoną lambdą niewiele można zrobić.
+W zasadzie można ją tylko wywołać (zaaplikować)
+```racket
+((lambda (a b) (+ a b)) 2 3)
+```
+
+(Definitions: define)[https://docs.racket-lang.org/guide/define.html]
+```
+(define id expr)
+```
+
+Czyli w maszym przypadku
+```racket
+(define add (lambda (a b) (+ a b)))
+```
+
+
+Konstrukcja
+```racket
+(define id (lambda (arg ...) body ...+))
+```
+jest na tyle popularna, że istnieje dla niej skrót
+```
+(define (id arg ...) body ...+)
+```
+
+Czyli maszą lambdę można przypisać do zmiennej za pomocą kodu:
+```racket
+(define (add a b) (+ a b))
+```
+
+https://www2.lib.uchicago.edu/keith/ocaml-class/data.html#function
+```ocaml
+let inc = fun n -> n + 1;;
+```
+
+W Haskellu w trybie interaktywnym
+```haskell
+let f :: Num -> Num -> Num
+let f = \a b -> a+b
+```
+
+Poza intrybem interaktywnym
+```haskell
+f :: Num -> Num -> Num
+f = \a b -> a+b
+```
+
+[Lambda abstraction](https://wiki.haskell.org/Lambda_abstraction)
+[Anonymous function](https://wiki.haskell.org/Anonymous_function)
+
+### wyrażenie `let in` czyli wiązanie lokalny
+
+[Local Binding](https://docs.racket-lang.org/guide/let.html)
+
+[Local Binding: let, let*, letrec, ...](https://docs.racket-lang.org/reference/let.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._let%29%29)
+
+```racket
+(let ([id val-expr] ...) body ...+)
+```
+
+```racket
+((lambda (id ...) body ...+) val-expr ...)
+```
+
+```racket
+((lambda (a b) (+ a b)) 2 3)
+```
+
+(let )
+
+https://www2.lib.uchicago.edu/keith/ocaml-class/definitions.html
+
+#### Ocaml
+
+```ocaml
+let n = 2 in n * n;;
+```
+
+#### Haskell
+
+W Haskellu jest wyrażenie `let-in`
+
+```
+aaa x y = let r = 3
+ s = 6
+ in r*x + s*y
+```
+
+### wyrażenie if
+
+[Conditionals](https://docs.racket-lang.org/guide/conditionals.html)
+
+[Conditionals: if, cond, and, and or](https://docs.racket-lang.org/reference/if.html)
+
+[https://wiki.haskell.org/If-then-else](If-then-else)
+
+### wyrażenie case
+
+[Simple Dispatch: case](https://docs.racket-lang.org/guide/case.html)
+
+[Pattern Matching](https://docs.racket-lang.org/guide/match.html)
+
+[Case](https://wiki.haskell.org/Case)
+
+[Type declarations and pattern matching](https://caml.inria.fr/pub/docs/oreilly-book/html/book-ora016.html)
+
+```ocaml
+let imply v = match v with
+ (true,true) -> true
+ | (true,false) -> false
+ | (false,true) -> true
+ | (false,false) -> true;;
+val imply : bool * bool -> bool =
+```
+
+[Data Types and Matching](https://ocaml.org/learn/tutorials/data_types_and_matching.html)
+
+```ocaml
+# let rec to_string e =
+ match e with
+ | Plus (left, right) ->
+ "(" ^ to_string left ^ " + " ^ to_string right ^ ")"
+ | Minus (left, right) ->
+ "(" ^ to_string left ^ " - " ^ to_string right ^ ")"
+ | Times (left, right) ->
+ "(" ^ to_string left ^ " * " ^ to_string right ^ ")"
+ | Divide (left, right) ->
+ "(" ^ to_string left ^ " / " ^ to_string right ^ ")"
+ | Value v -> v;;
+val to_string : expr -> string =
+# let print_expr e =
+ print_endline (to_string e);;
+val print_expr : expr -> unit =
+```
+
+[Pattern Matching](https://www2.lib.uchicago.edu/keith/ocaml-class/pattern-matching.html)
+```ocaml
+ # let f x =
+ if x = "foo"
+ then "it is foo"
+ else if x = "bar"
+ then "bar is the one"
+ else if x = "zap"
+ then "totally different"
+ else "our default: " ^ x
+ ;;
+ val f : string -> string =
+ # f "hello";;
+ - : string = "our default: hello"
+ # f "bar";;
+ - : string = "bar is the one"
+```
+
+https://ocaml.org/learn/tutorials/data_types_and_matching.html#Pattern-matching-on-datatypes
+
+## Styl deklaracja
+
+### Deklaracja funkcji i wiązanie
+
+W Scheme ani Racket nie ma innej możliwości deklaracji funkcji niż za pomocą lambdy.
+Dlatego przejrziemy odrazu do języka Haskell
+
+W Haskellu deklaracja funkcji wygląda następująco
+```haskell
+f :: Num -> Num -> Num
+f x = x*x
+```
+
+Co warto zauważyć?
+Otóż typ funkcji oraz typ lambdy przypisanej do zmiennej są identyczne.
+Dlatego w każdym miejscu,
+gdzie jest wymagana lambda,
+możemy też użyć funkcji.
+
+Jeśli jednak postanowimy napisać lambdę jak w poniższym przykładzie:
+```haskell
+map (\x -> abs x) [1, -1, 2 -2]
+```
+
+Kompilator haskella skorzysta z [Eta conversion](https://wiki.haskell.org/Eta_conversion)
+i zamieni to na postać:
+```haskell
+map abs [1, -1, 2 -2]
+```
+
+
+### Klauzura `where` czyli wiązanie lokalny
+
+[Let vs. Where](https://wiki.haskell.org/Let_vs._Where)
+
+### Strażnicy (ang. `Guards`)
+
+### Dopasowanie do wzorców (ang `Pattern matching`)
+
+
+## Podsumowanie
+Który ze styli jest lepszy?
+Moim skromnym zdaniem
+
+[Declaration vs. expression style](https://wiki.haskell.org/Declaration_vs._expression_style)
+
diff --git a/_collections/_posts/2022-09-01-juice-pixels.md b/_collections/_posts/2022-09-01-juice-pixels.md
new file mode 100644
index 00000000..1e1a2441
--- /dev/null
+++ b/_collections/_posts/2022-09-01-juice-pixels.md
@@ -0,0 +1,8 @@
+Juice.pixels
+
+Piet
+
+Ładowanie obrazków.
+
+
+
diff --git a/_collections/_posts/2022-10-01-5-jezykow-programowania.md b/_collections/_posts/2022-10-01-5-jezykow-programowania.md
new file mode 100644
index 00000000..a9b0484e
--- /dev/null
+++ b/_collections/_posts/2022-10-01-5-jezykow-programowania.md
@@ -0,0 +1,127 @@
+
+Ostatnio oglądałem wypowiedź twórcy języka C++,
+gdzie Bjarne Stroustrup powiedział, że zna ponad 20 języków programowania w przynajmniej podstawowym stopniu,
+dodał, że dobry programista powinien znać bardzo dobrze przynajmniej 5 języków,
+aby potrafił spojrzeć na problem z różnych perspektyw.
+Jaką piątkę wy byście wybrali, w jakiej kolejności i dlaczego?
+
+
+U mnie to wygląda tak:
+
+## Haskell
+
+I to wcale nie dlatego że czysto funkcyjny
+
+bo fulltyped
+bo lazy
+
+## Scheme
+
+Lisp
+
+### Common Lisp
+
+### Scheme
+
+Prosty język z małym rdzeniem
+
+Write Scheme in 48 h
+
+To że rdzeń jest mały nie znaczy że biblioteka jest mała.
+Istnieje przenośna biblioteka standardowa niezależna od implementacji
+
+Higieniczne makra
+
+
+### Racket
+
+Ludzie nie są zgodni czy Racket jest kolejną implementacją Scheme czy już osobnym językiem programowania z powodu dużej ilości rozszeżeńļ
+
+Racket posiada też Duża ilość bibliotek
+Oraz możliwość pisania frontów do kompilatora racket.
+Dzięki temu udało się tstworzyć osobny język [Typed Racket]
+
+### Clojure
+
+Prawdopodobnie najpopularniejszy dialekt Lispa w Polsce, a może nawet w Europie.
+Jego ogromną zaletą jest to że działą na JVM i dobrze integruje się z klasami Javowymi.
+Przez co jest prawdopodobnie najbardziej klasycznie obiektowym dialektem języka Lisp.
+Inne dialekty Lispa także posiadają polimorfizm i mo.żliwość programowania obiektowego, ale zwykle w niestandardowy sposób
+
+## Rust
+
+Niskopoziomowy, uproszczony Haskell
+
+Rustowe Traity to uproszczone KlasyTypów
+
+Dowód na to że jest możliwe
+
+
+Dla mnie ten język to fenomen.
+Nie stoi za nim żadna wielka korporacja a momentalnie wbił się do 20 najpopularniejszych języków programowania według indeksu Tiobe
+Higieniczne makra
+
+## Idris
+
+Poprawiony Haskell z typami zależnymi.
+Jeszcze nie wiem co to typy zależne i czemu to potrzebuje, ale wiem rze to przyszłość.
+Typy zależne są potrzebne do dowodzenia poprawności programu
+
+W przeciwieństwie do innych języków z typami zależnymi jak Adga i Coq,
+Idris jest zaprojektowany jako język ogólnego przeznaczenia, a nie tylko do dowodzenia twierdzeń.
+
+Ogólnego przeznaczenia
+
+Jego największą wadą jest to że to nisza niszy
+
+## Inny
+
+Zostało jedno wolne miejsce, które można by przeznaczyć na
+
+### PureScript
+PureScript gorliwie ewaluaowany/oceniany Haskell dedykowany do pisania frontu
+
+Odrzuciłem z listy ponieważ to tylko minimalnie poprawiony Haskell.
+(Zreszta wiekszość tych poprawek Haskell 8 także już zawiera)
+Oraz dlatego że wszystkie powyższe języki są też kompilowane do weba.
+Większość jest kompilowana do JSa a Rucket do WebAssembly.
+
+### OCaml
+Obiektowy potomek [MetaLanguage] i [Standard ML].
+[Standard ML] jest uważany za ostatniego wspólnego przodka Haskella i OCalma
+
+
+
+F# i [ReasonML]
+
+Odrzuciłem z listy, ponieważ nie uczy niczego nowego w stosunku do wymienionych.
+Ma gorszy system typów niż [Haskell],
+jest mniej niskopoziomowy niż [Rust]
+oraz ma trudniejszą składnię niż [Typed Racket]
+
+Jednak ten klasyczny polimorfizm obiektowy odrzuca
+
+### Scala
+
+Czyli skrzyżowanie Javy i OCamla które
+
+### Język, w którym można zarabiać.
+
+Powyższe języki mają dużo wad z czego największą jest mała ilość pracy w nich.
+Dlatego piąte miejsce zostawiam dla języka z klasycznym obiektowym polimorfizmem w którym można pracować i zarabiać
+A w czasie wolnym uczyć się powyższych czterech
+
+Ja widzę tu jednak Scalę :D
+
+## Podsumowanie
+
+Mój plan nauki języków to:
+
+1. Haskell i dokończyć eso-assembler WebAssembly do języków ezoterycznych'a.
+2. Scheme i napisać kompilator eso-C do języków ezoterycznych.
+3. Rust i przepisać interpretery języków ezoterycznych.
+4. Idris jeszcze nie wiem do czego mi to potrzebne, ale jak się dowiem to powiem o tym wszystkim.
+5. Scala i dostać w niej pracę.
+
+
+
diff --git a/_collections/_posts/2022-10-01-czego-nauczylem-sie-w-haskellu.md b/_collections/_posts/2022-10-01-czego-nauczylem-sie-w-haskellu.md
new file mode 100644
index 00000000..fe3af692
--- /dev/null
+++ b/_collections/_posts/2022-10-01-czego-nauczylem-sie-w-haskellu.md
@@ -0,0 +1,50 @@
+
+
+
+
+Kolejność parametrów w funkcji
+
+
+Kolejność imperatywna
+
+```java
+ A functionName (B b, C c, D d);
+```
+
+
+```scala
+ functionName(D d, C c, B b): A
+```
+
+```haskell
+ functionName D -> C -> B -> A
+```
+
+```haskell
+ functionName d -> c -> b -> a
+```
+
+```haskell
+ functionName d -> (c -> (b -> a))
+```
+
+
+```haskell
+ functionName b -> a -> a
+```
+
+```haskell
+ functionName b -> a -> Bool
+```
+
+
+
+
+
+monady należy ograniczać
+
+monady to najbardziej skomplikowane narzędzie jakie mamy inależy je ograniczać
+
+Można programować bez null
+
+Programowanie reaktywne jest proste - o ile rozumiesz monady
\ No newline at end of file
diff --git a/_collections/_projects/helcam.html b/_collections/_projects/helcam.html
new file mode 100644
index 00000000..6985a1f5
--- /dev/null
+++ b/_collections/_projects/helcam.html
@@ -0,0 +1,5 @@
+---
+project: helcam
+title: HelCam
+---
+HelCam
diff --git a/_collections/_projects/hell.html b/_collections/_projects/hell.html
new file mode 100644
index 00000000..5e6e454d
--- /dev/null
+++ b/_collections/_projects/hell.html
@@ -0,0 +1,5 @@
+---
+project: hell
+title: HelL
+---
+HelL
diff --git a/_collections/_projects/helms.html b/_collections/_projects/helms.html
new file mode 100644
index 00000000..0cc5a967
--- /dev/null
+++ b/_collections/_projects/helms.html
@@ -0,0 +1,5 @@
+---
+project: helms
+title: HelMS
+---
+HelMS
diff --git a/_collections/_projects/helpa.html b/_collections/_projects/helpa.html
new file mode 100644
index 00000000..8e38568b
--- /dev/null
+++ b/_collections/_projects/helpa.html
@@ -0,0 +1,5 @@
+---
+project: helpa
+title: HelPA
+---
+HelPA
diff --git a/_collections/_projects/helvm.html b/_collections/_projects/helvm.html
new file mode 100644
index 00000000..cd7f331a
--- /dev/null
+++ b/_collections/_projects/helvm.html
@@ -0,0 +1,5 @@
+---
+project: helvm
+title: HelVM
+---
+HelVM
diff --git a/_collections/_projects/linkchecker.html b/_collections/_projects/linkchecker.html
new file mode 100644
index 00000000..ff116e6e
--- /dev/null
+++ b/_collections/_projects/linkchecker.html
@@ -0,0 +1,4 @@
+---
+project: linkchecker
+title: LinkChecker
+---
\ No newline at end of file
diff --git a/_collections/_projects/resentiment.html b/_collections/_projects/resentiment.html
new file mode 100644
index 00000000..b791d78f
--- /dev/null
+++ b/_collections/_projects/resentiment.html
@@ -0,0 +1,4 @@
+---
+project: resentiment
+title: Resentiment
+---
diff --git a/_collections/_tags/adt.html b/_collections/_tags/adt.html
new file mode 100644
index 00000000..bb1cc125
--- /dev/null
+++ b/_collections/_tags/adt.html
@@ -0,0 +1,6 @@
+---
+tag: adt
+title: ADT
+---
+Abstrakcyjny typ danych
+(ang. Abstract data type , ADT )
\ No newline at end of file
diff --git a/_collections/_tags/ajax.html b/_collections/_tags/ajax.html
new file mode 100644
index 00000000..911684d9
--- /dev/null
+++ b/_collections/_tags/ajax.html
@@ -0,0 +1,4 @@
+---
+tag: ajax
+title: AJAX
+---
diff --git a/_collections/_tags/alias.html b/_collections/_tags/alias.html
new file mode 100644
index 00000000..934c081a
--- /dev/null
+++ b/_collections/_tags/alias.html
@@ -0,0 +1,4 @@
+---
+tag: alias
+title: Alias
+---
\ No newline at end of file
diff --git a/_collections/_tags/api.html b/_collections/_tags/api.html
new file mode 100644
index 00000000..568e6be4
--- /dev/null
+++ b/_collections/_tags/api.html
@@ -0,0 +1,6 @@
+---
+tag: api
+title: API
+---
+Interfejs programowania aplikacji
+(ang. Application programming interface , API )
\ No newline at end of file
diff --git a/_collections/_tags/applicative.html b/_collections/_tags/applicative.html
new file mode 100644
index 00000000..df12dc48
--- /dev/null
+++ b/_collections/_tags/applicative.html
@@ -0,0 +1,4 @@
+---
+tag: applicative
+title: Applicative
+---
\ No newline at end of file
diff --git a/_collections/_tags/assembler.html b/_collections/_tags/assembler.html
new file mode 100644
index 00000000..a02f76f7
--- /dev/null
+++ b/_collections/_tags/assembler.html
@@ -0,0 +1,4 @@
+---
+tag: assembler
+title: Assembler
+---
\ No newline at end of file
diff --git a/_collections/_tags/ast.html b/_collections/_tags/ast.html
new file mode 100644
index 00000000..ec01651e
--- /dev/null
+++ b/_collections/_tags/ast.html
@@ -0,0 +1,8 @@
+---
+tag: ast
+title: AST
+---
+Drzewo składniowe
+(ang. syntax tree ),
+czyli drzewo składni abstrakcyjnej
+(ang. abstract syntax tree , AST ).
diff --git a/_collections/_tags/bdd.html b/_collections/_tags/bdd.html
new file mode 100644
index 00000000..f18ff2c9
--- /dev/null
+++ b/_collections/_tags/bdd.html
@@ -0,0 +1,6 @@
+---
+tag: bdd
+title: BDD
+---
+Rozwój oparty na zachowaniu
+(ang. Behavior-driven development , BDD )
\ No newline at end of file
diff --git a/_collections/_tags/blog.html b/_collections/_tags/blog.html
new file mode 100644
index 00000000..aa1ac48d
--- /dev/null
+++ b/_collections/_tags/blog.html
@@ -0,0 +1,4 @@
+---
+tag: blog
+title: Blog
+---
\ No newline at end of file
diff --git a/_collections/_tags/bytecode.html b/_collections/_tags/bytecode.html
new file mode 100644
index 00000000..29e9c8c1
--- /dev/null
+++ b/_collections/_tags/bytecode.html
@@ -0,0 +1,5 @@
+---
+tag: bytecode
+title: Bytecode
+---
+Kod bajtowy (ang. Bytecode ).
\ No newline at end of file
diff --git a/_collections/_tags/cfg.html b/_collections/_tags/cfg.html
new file mode 100644
index 00000000..45ce799e
--- /dev/null
+++ b/_collections/_tags/cfg.html
@@ -0,0 +1,6 @@
+---
+tag: cfg
+title: CFG
+---
+Graf przepływu sterowania
+(ang. Control-flow graph , CFG ).
diff --git a/_collections/_tags/cisc.html b/_collections/_tags/cisc.html
new file mode 100644
index 00000000..586bbadf
--- /dev/null
+++ b/_collections/_tags/cisc.html
@@ -0,0 +1,5 @@
+---
+tag: cisc
+title: CISC
+tags: isc
+---
diff --git a/_collections/_tags/cli.html b/_collections/_tags/cli.html
new file mode 100644
index 00000000..8d8e182d
--- /dev/null
+++ b/_collections/_tags/cli.html
@@ -0,0 +1,6 @@
+---
+tag: cli
+title: CLI
+---
+Wiersz poleceń
+(ang. Command-line interface , CLI )
\ No newline at end of file
diff --git a/_collections/_tags/code-analysis.html b/_collections/_tags/code-analysis.html
new file mode 100644
index 00000000..088592be
--- /dev/null
+++ b/_collections/_tags/code-analysis.html
@@ -0,0 +1,4 @@
+---
+tag: code-analysis
+title: Code analysis
+---
\ No newline at end of file
diff --git a/_collections/_tags/collection.html b/_collections/_tags/collection.html
new file mode 100644
index 00000000..ea251f62
--- /dev/null
+++ b/_collections/_tags/collection.html
@@ -0,0 +1,4 @@
+---
+tag: collection
+title: Collection
+---
diff --git a/_collections/_tags/compiler.html b/_collections/_tags/compiler.html
new file mode 100644
index 00000000..59f99add
--- /dev/null
+++ b/_collections/_tags/compiler.html
@@ -0,0 +1,8 @@
+---
+tag: compiler
+title: Compiler
+---
+Ksiązki
+
+ Kompilatory. Reguły, metody i narzędzia. KLASYKA INFORMATYKI. Autorzy: Jeffrey D. Ullman , Alfred V. Aho , Ravi Sethi
+
diff --git a/_collections/_tags/cps.html b/_collections/_tags/cps.html
new file mode 100644
index 00000000..3f2ac70d
--- /dev/null
+++ b/_collections/_tags/cps.html
@@ -0,0 +1,6 @@
+---
+tag: cps
+title: cps
+---
+Programowania w stylu kontynuacyjnym
+(ang. Continuation-passing style , CPS ).
diff --git a/_collections/_tags/cson.html b/_collections/_tags/cson.html
new file mode 100644
index 00000000..2e060b83
--- /dev/null
+++ b/_collections/_tags/cson.html
@@ -0,0 +1,5 @@
+---
+tag: cson
+title: CSON
+langs: coffeescript
+---
diff --git a/_collections/_tags/css.html b/_collections/_tags/css.html
new file mode 100644
index 00000000..b1c4315e
--- /dev/null
+++ b/_collections/_tags/css.html
@@ -0,0 +1,4 @@
+---
+tag: css
+title: CSS
+---
\ No newline at end of file
diff --git a/_collections/_tags/cst.html b/_collections/_tags/cst.html
new file mode 100644
index 00000000..14ea34e3
--- /dev/null
+++ b/_collections/_tags/cst.html
@@ -0,0 +1,8 @@
+---
+tag: cst
+title: CST
+---
+Drzewo wyprowadzenia
+(ang. parse tree ),
+czyli drzewo składni konkretnej
+(ang. concrete syntax tree , CST ).
\ No newline at end of file
diff --git a/_collections/_tags/currying.html b/_collections/_tags/currying.html
new file mode 100644
index 00000000..d478b048
--- /dev/null
+++ b/_collections/_tags/currying.html
@@ -0,0 +1,4 @@
+---
+tag: currying
+title: Currying
+---
diff --git a/_collections/_tags/dag.html b/_collections/_tags/dag.html
new file mode 100644
index 00000000..a30bd739
--- /dev/null
+++ b/_collections/_tags/dag.html
@@ -0,0 +1,6 @@
+---
+tag: dag
+title: DAG
+---
+Skierowany graf acykliczny
+(ang. directed acyclic graph , DAG ).
diff --git a/_collections/_tags/di.html b/_collections/_tags/di.html
new file mode 100644
index 00000000..5c6b8633
--- /dev/null
+++ b/_collections/_tags/di.html
@@ -0,0 +1,4 @@
+---
+tag: di
+title: DI
+---
diff --git a/_collections/_tags/do-notation.html b/_collections/_tags/do-notation.html
new file mode 100644
index 00000000..64642517
--- /dev/null
+++ b/_collections/_tags/do-notation.html
@@ -0,0 +1,5 @@
+---
+tag: do-notation
+title: bo notation
+---
+Notacja do
(ang. do
notation )
diff --git a/_collections/_tags/dsl.html b/_collections/_tags/dsl.html
new file mode 100644
index 00000000..168c0ae0
--- /dev/null
+++ b/_collections/_tags/dsl.html
@@ -0,0 +1,6 @@
+---
+tag: dsl
+title: DSL
+---
+Język dziedzinowy
+(ang. Domain-specific language , DSL )
\ No newline at end of file
diff --git a/_collections/_tags/dynamic-code-analysis.html b/_collections/_tags/dynamic-code-analysis.html
new file mode 100644
index 00000000..bde0c404
--- /dev/null
+++ b/_collections/_tags/dynamic-code-analysis.html
@@ -0,0 +1,6 @@
+---
+tag: dynamic-code-analysis
+title: Dynamic code analysis
+---
+Dynamiczna analiza kodu
+(ang. Dynamic code analysis )
diff --git a/_collections/_tags/factory.html b/_collections/_tags/factory.html
new file mode 100644
index 00000000..89cd0f2e
--- /dev/null
+++ b/_collections/_tags/factory.html
@@ -0,0 +1,4 @@
+---
+tag: factory
+title: Factory
+---
\ No newline at end of file
diff --git a/_collections/_tags/filter-branch.html b/_collections/_tags/filter-branch.html
new file mode 100644
index 00000000..79fe1506
--- /dev/null
+++ b/_collections/_tags/filter-branch.html
@@ -0,0 +1,5 @@
+---
+tag: filter-branch
+title: Filter Branch
+tools: git
+---
\ No newline at end of file
diff --git a/_collections/_tags/flatmappable.html b/_collections/_tags/flatmappable.html
new file mode 100644
index 00000000..c9800681
--- /dev/null
+++ b/_collections/_tags/flatmappable.html
@@ -0,0 +1,4 @@
+---
+tag: flatmappable
+title: FlatMappable
+---
diff --git a/_collections/_tags/for-comprehensions.html b/_collections/_tags/for-comprehensions.html
new file mode 100644
index 00000000..44604906
--- /dev/null
+++ b/_collections/_tags/for-comprehensions.html
@@ -0,0 +1,5 @@
+---
+tag: for-comprehensions
+title: For Comprehensions
+langs: eta haskell scala
+---
\ No newline at end of file
diff --git a/_collections/_tags/fp.html b/_collections/_tags/fp.html
new file mode 100644
index 00000000..d8eefdf9
--- /dev/null
+++ b/_collections/_tags/fp.html
@@ -0,0 +1,4 @@
+---
+tag: fp
+title: Functional Programing
+---
\ No newline at end of file
diff --git a/_collections/_tags/github-pages.html b/_collections/_tags/github-pages.html
new file mode 100644
index 00000000..fc05f2af
--- /dev/null
+++ b/_collections/_tags/github-pages.html
@@ -0,0 +1,5 @@
+---
+tag: github-pages
+title: GitHub Pages
+---
+GitHub Pages
diff --git a/_collections/_tags/gui.html b/_collections/_tags/gui.html
new file mode 100644
index 00000000..28ed933b
--- /dev/null
+++ b/_collections/_tags/gui.html
@@ -0,0 +1,7 @@
+---
+tag: gui
+title: GUI
+tags: ui
+---
+Graficzny interfejs użytkownika
+(ang. CGraphical user interface , GUI )
diff --git a/_collections/_tags/hocon.html b/_collections/_tags/hocon.html
new file mode 100644
index 00000000..da3f6ecb
--- /dev/null
+++ b/_collections/_tags/hocon.html
@@ -0,0 +1,6 @@
+---
+tag: hocon
+title: HOCON
+langs: java scala
+---
+HOCON
diff --git a/_collections/_tags/html.html b/_collections/_tags/html.html
new file mode 100644
index 00000000..64c111cc
--- /dev/null
+++ b/_collections/_tags/html.html
@@ -0,0 +1,4 @@
+---
+tag: html
+title: HTML
+---
\ No newline at end of file
diff --git a/_collections/_tags/http.html b/_collections/_tags/http.html
new file mode 100644
index 00000000..64a24ff7
--- /dev/null
+++ b/_collections/_tags/http.html
@@ -0,0 +1,4 @@
+---
+tag: http
+title: HTTP
+---
\ No newline at end of file
diff --git a/_collections/_tags/immutable.html b/_collections/_tags/immutable.html
new file mode 100644
index 00000000..15cdab06
--- /dev/null
+++ b/_collections/_tags/immutable.html
@@ -0,0 +1,4 @@
+---
+tag: immutable
+title: Immutable
+---
diff --git a/_collections/_tags/ini.html b/_collections/_tags/ini.html
new file mode 100644
index 00000000..c903e88f
--- /dev/null
+++ b/_collections/_tags/ini.html
@@ -0,0 +1,5 @@
+---
+tag: ini
+title: INI
+langs: Python
+---
diff --git a/_collections/_tags/interface.html b/_collections/_tags/interface.html
new file mode 100644
index 00000000..5b93db37
--- /dev/null
+++ b/_collections/_tags/interface.html
@@ -0,0 +1,4 @@
+---
+tag: interface
+title: Interface
+---
\ No newline at end of file
diff --git a/_collections/_tags/interpreter.html b/_collections/_tags/interpreter.html
new file mode 100644
index 00000000..9ff81a18
--- /dev/null
+++ b/_collections/_tags/interpreter.html
@@ -0,0 +1,4 @@
+---
+tag: interpreter
+title: Interpreter
+---
\ No newline at end of file
diff --git a/_collections/_tags/io.html b/_collections/_tags/io.html
new file mode 100644
index 00000000..3589317d
--- /dev/null
+++ b/_collections/_tags/io.html
@@ -0,0 +1,7 @@
+---
+tag: io
+title: IO
+---
+IO - skrót oznaczający operacje wejścia-wyjścia (Input-Output),
+a także monadę z języku programowania Haskell (oraz inspirującym się na nim)
+do przeprowadzania operacji wejścia i wyjścia.
\ No newline at end of file
diff --git a/_collections/_tags/java-properties.html b/_collections/_tags/java-properties.html
new file mode 100644
index 00000000..c48e56e1
--- /dev/null
+++ b/_collections/_tags/java-properties.html
@@ -0,0 +1,4 @@
+---
+tag: java-properties
+title: Java Properties
+---
diff --git a/_collections/_tags/jekyllcodex.html b/_collections/_tags/jekyllcodex.html
new file mode 100644
index 00000000..14c0e660
--- /dev/null
+++ b/_collections/_tags/jekyllcodex.html
@@ -0,0 +1,4 @@
+---
+tag: jekyllcodex
+title: jekyllcodex
+---
\ No newline at end of file
diff --git a/_collections/_tags/json-merge-patch.html b/_collections/_tags/json-merge-patch.html
new file mode 100644
index 00000000..bbd70fa3
--- /dev/null
+++ b/_collections/_tags/json-merge-patch.html
@@ -0,0 +1,10 @@
+---
+tag: json-merge-patch
+title: JSON Merge Patch
+tags: json
+---
+RFC 7386 (JSON Merge Patch)
+
+
diff --git a/_collections/_tags/json-patch.html b/_collections/_tags/json-patch.html
new file mode 100644
index 00000000..823e4d63
--- /dev/null
+++ b/_collections/_tags/json-patch.html
@@ -0,0 +1,10 @@
+---
+tag: json-patch
+title: JSON Patch
+tags: json
+---
+RFC 6902 (JSON Patch)
+
+
diff --git a/_collections/_tags/json-pointer.html b/_collections/_tags/json-pointer.html
new file mode 100644
index 00000000..2f78ad21
--- /dev/null
+++ b/_collections/_tags/json-pointer.html
@@ -0,0 +1,6 @@
+---
+tag: json-pointer
+title: JSON pointer
+tags: json
+---
+RFC 6901 (JSON Pointer)
diff --git a/_collections/_tags/json-schema.html b/_collections/_tags/json-schema.html
new file mode 100644
index 00000000..2dc89340
--- /dev/null
+++ b/_collections/_tags/json-schema.html
@@ -0,0 +1,7 @@
+---
+tag: json-schema
+title: JSON Schema
+tags: json
+---
+JSON Schema
+
diff --git a/_collections/_tags/json.html b/_collections/_tags/json.html
new file mode 100644
index 00000000..a60aa314
--- /dev/null
+++ b/_collections/_tags/json.html
@@ -0,0 +1,5 @@
+---
+tag: json
+title: JSON
+---
+JavaScript Object Notation
\ No newline at end of file
diff --git a/_collections/_tags/lambda-calculus.html b/_collections/_tags/lambda-calculus.html
new file mode 100644
index 00000000..9200ebf4
--- /dev/null
+++ b/_collections/_tags/lambda-calculus.html
@@ -0,0 +1,6 @@
+---
+tag: lambda-calculus
+title: lambda calculus
+---
+Rachunek lambda
+(ang. Lambda calculus ).
\ No newline at end of file
diff --git a/_collections/_tags/lexer.html b/_collections/_tags/lexer.html
new file mode 100644
index 00000000..5c2302ad
--- /dev/null
+++ b/_collections/_tags/lexer.html
@@ -0,0 +1,4 @@
+---
+tag: lexer
+title: Lexer
+---
\ No newline at end of file
diff --git a/_collections/_tags/library.html b/_collections/_tags/library.html
new file mode 100644
index 00000000..6ff54326
--- /dev/null
+++ b/_collections/_tags/library.html
@@ -0,0 +1,4 @@
+---
+tag: library
+title: Library
+---
\ No newline at end of file
diff --git a/_collections/_tags/logging.html b/_collections/_tags/logging.html
new file mode 100644
index 00000000..876b6b13
--- /dev/null
+++ b/_collections/_tags/logging.html
@@ -0,0 +1,4 @@
+---
+tag: logging
+title: Logging
+---
\ No newline at end of file
diff --git a/_collections/_tags/mappable.html b/_collections/_tags/mappable.html
new file mode 100644
index 00000000..45b01385
--- /dev/null
+++ b/_collections/_tags/mappable.html
@@ -0,0 +1,4 @@
+---
+tag: mappable
+title: Mappable
+---
diff --git a/_collections/_tags/microservice.html b/_collections/_tags/microservice.html
new file mode 100644
index 00000000..7c3a90f6
--- /dev/null
+++ b/_collections/_tags/microservice.html
@@ -0,0 +1,4 @@
+---
+tag: microservice
+title: MicroService
+---
diff --git a/_collections/_tags/misc.html b/_collections/_tags/misc.html
new file mode 100644
index 00000000..da8f3f2b
--- /dev/null
+++ b/_collections/_tags/misc.html
@@ -0,0 +1,5 @@
+---
+tag: misc
+title: MISC
+tags: isc
+---
diff --git a/_collections/_tags/monad.html b/_collections/_tags/monad.html
new file mode 100644
index 00000000..9b80af87
--- /dev/null
+++ b/_collections/_tags/monad.html
@@ -0,0 +1,12 @@
+---
+tag: monad
+title: Monad
+---
+Monada to monoid w kategorii endofunktorów
+
+Youtube
+
\ No newline at end of file
diff --git a/_collections/_tags/monoid.html b/_collections/_tags/monoid.html
new file mode 100644
index 00000000..8055d27d
--- /dev/null
+++ b/_collections/_tags/monoid.html
@@ -0,0 +1,4 @@
+---
+tag: monoid
+title: Monoid
+---
diff --git a/_collections/_tags/native.html b/_collections/_tags/native.html
new file mode 100644
index 00000000..715a7a4c
--- /dev/null
+++ b/_collections/_tags/native.html
@@ -0,0 +1,4 @@
+---
+tag: native
+title: Native
+---
\ No newline at end of file
diff --git a/_collections/_tags/no-exceptions.html b/_collections/_tags/no-exceptions.html
new file mode 100644
index 00000000..58b758c1
--- /dev/null
+++ b/_collections/_tags/no-exceptions.html
@@ -0,0 +1,5 @@
+---
+tag: no-exceptions
+title: No exceptions
+---
+No exceptions
\ No newline at end of file
diff --git a/_collections/_tags/nojvm.html b/_collections/_tags/nojvm.html
new file mode 100644
index 00000000..726981b3
--- /dev/null
+++ b/_collections/_tags/nojvm.html
@@ -0,0 +1,5 @@
+---
+tag: nojvm
+title: NoJVM
+---
+Not Only Java Virtual Machine
\ No newline at end of file
diff --git a/_collections/_tags/oisc.html b/_collections/_tags/oisc.html
new file mode 100644
index 00000000..aa68c7b6
--- /dev/null
+++ b/_collections/_tags/oisc.html
@@ -0,0 +1,5 @@
+---
+tag: oisc
+title: OICS
+tags: isc
+---
diff --git a/_collections/_tags/openapi.html b/_collections/_tags/openapi.html
new file mode 100644
index 00000000..32f91683
--- /dev/null
+++ b/_collections/_tags/openapi.html
@@ -0,0 +1,4 @@
+---
+tag: openapi
+title: OpenAPI
+---
\ No newline at end of file
diff --git a/_collections/_tags/operator.html b/_collections/_tags/operator.html
new file mode 100644
index 00000000..a216a01b
--- /dev/null
+++ b/_collections/_tags/operator.html
@@ -0,0 +1,4 @@
+---
+tag: operator
+title: Operator
+---
\ No newline at end of file
diff --git a/_collections/_tags/parser.html b/_collections/_tags/parser.html
new file mode 100644
index 00000000..a3fd600f
--- /dev/null
+++ b/_collections/_tags/parser.html
@@ -0,0 +1,7 @@
+---
+tag: parser
+title: Parser
+---
+Parser to program dokonujący procesu analizy składniowej na ciągu leksemów (tokenach z typami),
+czyli sprawdzeniu ich zgodności z określoną gramatyką formalną.
+Wynikiem pracy parsera jest drzewo składniowe na którym są przeprowadzane dalsze operacje.
diff --git a/_collections/_tags/pattern-matching.html b/_collections/_tags/pattern-matching.html
new file mode 100644
index 00000000..dd259bbe
--- /dev/null
+++ b/_collections/_tags/pattern-matching.html
@@ -0,0 +1,4 @@
+---
+tag: pattern-matching
+title: Pattern Matching
+---
diff --git a/_collections/_tags/properties.html b/_collections/_tags/properties.html
new file mode 100644
index 00000000..d3c46d8f
--- /dev/null
+++ b/_collections/_tags/properties.html
@@ -0,0 +1,4 @@
+---
+tag: properties
+title: Properties
+---
\ No newline at end of file
diff --git a/_collections/_tags/protocol.html b/_collections/_tags/protocol.html
new file mode 100644
index 00000000..864326fb
--- /dev/null
+++ b/_collections/_tags/protocol.html
@@ -0,0 +1,4 @@
+---
+tag: protocol
+title: Protocol
+---
\ No newline at end of file
diff --git a/_collections/_tags/regexp.html b/_collections/_tags/regexp.html
new file mode 100644
index 00000000..a3e98044
--- /dev/null
+++ b/_collections/_tags/regexp.html
@@ -0,0 +1,4 @@
+---
+tag: regexp
+title: RegExp
+---
diff --git a/_collections/_tags/rest.html b/_collections/_tags/rest.html
new file mode 100644
index 00000000..3173bd6d
--- /dev/null
+++ b/_collections/_tags/rest.html
@@ -0,0 +1,4 @@
+---
+tag: rest
+title: REST
+---
diff --git a/_collections/_tags/risc.html b/_collections/_tags/risc.html
new file mode 100644
index 00000000..e7e5afb2
--- /dev/null
+++ b/_collections/_tags/risc.html
@@ -0,0 +1,5 @@
+---
+tag: risc
+title: RISC
+tags: isc
+---
diff --git a/_collections/_tags/rison.html b/_collections/_tags/rison.html
new file mode 100644
index 00000000..9f5a9fb8
--- /dev/null
+++ b/_collections/_tags/rison.html
@@ -0,0 +1,4 @@
+---
+tag: rison
+title: Rison
+---
diff --git a/_collections/_tags/rpc.html b/_collections/_tags/rpc.html
new file mode 100644
index 00000000..19b0c829
--- /dev/null
+++ b/_collections/_tags/rpc.html
@@ -0,0 +1,4 @@
+---
+tag: rpc
+title: RPC
+---
diff --git a/_collections/_tags/rpn.html b/_collections/_tags/rpn.html
new file mode 100644
index 00000000..a028b1c0
--- /dev/null
+++ b/_collections/_tags/rpn.html
@@ -0,0 +1,4 @@
+---
+tag: rpn
+title: RPN
+---
\ No newline at end of file
diff --git a/_collections/_tags/script.html b/_collections/_tags/script.html
new file mode 100644
index 00000000..b16f3f37
--- /dev/null
+++ b/_collections/_tags/script.html
@@ -0,0 +1,4 @@
+---
+tag: script
+title: Script
+---
diff --git a/_collections/_tags/seo.html b/_collections/_tags/seo.html
new file mode 100644
index 00000000..d2169cbe
--- /dev/null
+++ b/_collections/_tags/seo.html
@@ -0,0 +1,6 @@
+---
+tag: seo
+title: SEO
+---
+Optymalizacja dla wyszukiwarek internetowych
+(ang. Search engine optimization , SEO ).
diff --git a/_collections/_tags/soap.html b/_collections/_tags/soap.html
new file mode 100644
index 00000000..46363252
--- /dev/null
+++ b/_collections/_tags/soap.html
@@ -0,0 +1,4 @@
+---
+tag: soap
+title: SOAP
+---
diff --git a/_collections/_tags/ssa.html b/_collections/_tags/ssa.html
new file mode 100644
index 00000000..27c5cf1c
--- /dev/null
+++ b/_collections/_tags/ssa.html
@@ -0,0 +1,5 @@
+---
+tag: ssa
+title: SSA
+---
+Single Static Assignment SSA .
diff --git a/_collections/_tags/state.html b/_collections/_tags/state.html
new file mode 100644
index 00000000..35b1b706
--- /dev/null
+++ b/_collections/_tags/state.html
@@ -0,0 +1,7 @@
+---
+tag: state-monad
+title: State monad
+tags: monad
+---
+Monada State - monada z języku programowania Haskell
+do przechowywania stanu.
\ No newline at end of file
diff --git a/_collections/_tags/static-code-analysis.html b/_collections/_tags/static-code-analysis.html
new file mode 100644
index 00000000..079aa6d5
--- /dev/null
+++ b/_collections/_tags/static-code-analysis.html
@@ -0,0 +1,6 @@
+---
+tag: static-code-analysis
+title: Static code analysis
+---
+Statyczna analiza kodu
+(ang. Static code analysis )
\ No newline at end of file
diff --git a/_collections/_tags/task.html b/_collections/_tags/task.html
new file mode 100644
index 00000000..2bbc7255
--- /dev/null
+++ b/_collections/_tags/task.html
@@ -0,0 +1,4 @@
+---
+tag: task
+title: Task
+---
diff --git a/_collections/_tags/tco.html b/_collections/_tags/tco.html
new file mode 100644
index 00000000..0b332031
--- /dev/null
+++ b/_collections/_tags/tco.html
@@ -0,0 +1,5 @@
+---
+tag: tco
+title: TCO
+---
+Optymalizacja rekuncji ogonowej (ang. *Tail Call Optimization*, **TCO**)
\ No newline at end of file
diff --git a/_collections/_tags/testing.html b/_collections/_tags/testing.html
new file mode 100644
index 00000000..dd0e3705
--- /dev/null
+++ b/_collections/_tags/testing.html
@@ -0,0 +1,4 @@
+---
+tag: testing
+title: Testing
+---
diff --git a/_collections/_tags/toml.html b/_collections/_tags/toml.html
new file mode 100644
index 00000000..3deda2d0
--- /dev/null
+++ b/_collections/_tags/toml.html
@@ -0,0 +1,7 @@
+---
+tag: toml
+title: TOML
+langs: rust
+tools: seed
+---
+TOML
diff --git a/_collections/_tags/trait.html b/_collections/_tags/trait.html
new file mode 100644
index 00000000..dd03d5ba
--- /dev/null
+++ b/_collections/_tags/trait.html
@@ -0,0 +1,4 @@
+---
+tag: trait
+title: trait
+---
\ No newline at end of file
diff --git a/_collections/_tags/transpiler.html b/_collections/_tags/transpiler.html
new file mode 100644
index 00000000..225d346f
--- /dev/null
+++ b/_collections/_tags/transpiler.html
@@ -0,0 +1,6 @@
+---
+tag: transpiler
+title: Transpiler
+---
+Transpilator (ang. transpiler ) jest to
+kompilator ze źródła do źródła (ang. source-to-source compiler ).
\ No newline at end of file
diff --git a/_collections/_tags/tui.html b/_collections/_tags/tui.html
new file mode 100644
index 00000000..d6b36dbe
--- /dev/null
+++ b/_collections/_tags/tui.html
@@ -0,0 +1,5 @@
+---
+tag: tui
+title: TUI
+tags: ui
+---
\ No newline at end of file
diff --git a/_collections/_tags/type-class.html b/_collections/_tags/type-class.html
new file mode 100644
index 00000000..65ca3dfa
--- /dev/null
+++ b/_collections/_tags/type-class.html
@@ -0,0 +1,14 @@
+---
+tag: type-class
+title: Type Class
+---
+Klasa Typów (ang. Type Class ) jest to cecha (ang. trait która:
+
+ nie ma wewnętrznego stanu
+ ma parametr typu
+ ma przynajmniej jedną metodą abstrakcyjną (kombinator prymitywny (primitive combinator))
+ może mieć metody uogólnione (kombinatory pochodne (derived combinators))
+ może rozszerzać inne typeklasy
+
+
+Definicja za Programowanie Funkcyjne dla Śmiertelników ze Scalaz
\ No newline at end of file
diff --git a/_collections/_tags/ui.html b/_collections/_tags/ui.html
new file mode 100644
index 00000000..42c11b1b
--- /dev/null
+++ b/_collections/_tags/ui.html
@@ -0,0 +1,4 @@
+---
+tag: ui
+title: UI
+---
\ No newline at end of file
diff --git a/_collections/_tags/unit-testing.html b/_collections/_tags/unit-testing.html
new file mode 100644
index 00000000..4d4f4a06
--- /dev/null
+++ b/_collections/_tags/unit-testing.html
@@ -0,0 +1,5 @@
+---
+tag: unit-testing
+title: Unit Testing
+tags: testing
+---
diff --git a/_collections/_tags/webservice.html b/_collections/_tags/webservice.html
new file mode 100644
index 00000000..5183f96d
--- /dev/null
+++ b/_collections/_tags/webservice.html
@@ -0,0 +1,4 @@
+---
+tag: webservice
+title: WebService
+---
diff --git a/_collections/_tags/xml.html b/_collections/_tags/xml.html
new file mode 100644
index 00000000..1d2fc8ba
--- /dev/null
+++ b/_collections/_tags/xml.html
@@ -0,0 +1,5 @@
+---
+tag: xml
+title: XML
+---
+XML (ang. Extensible Markup Language , w wolnym tłumaczeniu Rozszerzalny Język Znaczników ).
diff --git a/_collections/_tags/yaml.html b/_collections/_tags/yaml.html
new file mode 100644
index 00000000..88227da1
--- /dev/null
+++ b/_collections/_tags/yaml.html
@@ -0,0 +1,4 @@
+---
+tag: yaml
+title: YAML
+---
diff --git a/_collections/_tools/bash.html b/_collections/_tools/bash.html
new file mode 100644
index 00000000..57f87458
--- /dev/null
+++ b/_collections/_tools/bash.html
@@ -0,0 +1,4 @@
+---
+tool: bash
+title: Bash
+---
\ No newline at end of file
diff --git a/_collections/_tools/bucklescript.html b/_collections/_tools/bucklescript.html
new file mode 100644
index 00000000..29d4bcd4
--- /dev/null
+++ b/_collections/_tools/bucklescript.html
@@ -0,0 +1,14 @@
+---
+tool: bucklescript
+title: BuckleScript
+langs: ocaml meta-language
+---
+BuckleScript - transpilator obiektowo-funkcyjnego języka programowania OCaml do języka JavaScript .
+
diff --git a/_collections/_tools/cabal.html b/_collections/_tools/cabal.html
new file mode 100644
index 00000000..53b4c0eb
--- /dev/null
+++ b/_collections/_tools/cabal.html
@@ -0,0 +1,6 @@
+---
+tool: cabal
+title: Cabal
+langs: haskell
+---
+Cabal
\ No newline at end of file
diff --git a/_collections/_tools/clang.html b/_collections/_tools/clang.html
new file mode 100644
index 00000000..67c39705
--- /dev/null
+++ b/_collections/_tools/clang.html
@@ -0,0 +1,5 @@
+---
+tool: clang
+title: Clang
+---
+Clang
\ No newline at end of file
diff --git a/_collections/_tools/clojurescript.html b/_collections/_tools/clojurescript.html
new file mode 100644
index 00000000..b36f1d18
--- /dev/null
+++ b/_collections/_tools/clojurescript.html
@@ -0,0 +1,11 @@
+---
+tool: clojurescript
+title: ClojureScript
+langs: clojure
+---
+ClojureScript - transpilator obiektowo-funkcyjnego języka programowania Clojure do języka JavaScript .
+
diff --git a/_collections/_tools/docker.html b/_collections/_tools/docker.html
new file mode 100644
index 00000000..218b61b2
--- /dev/null
+++ b/_collections/_tools/docker.html
@@ -0,0 +1,4 @@
+---
+tool: docker
+title: Docker
+---
\ No newline at end of file
diff --git a/_collections/_tools/etlas.html b/_collections/_tools/etlas.html
new file mode 100644
index 00000000..9a8bd4ef
--- /dev/null
+++ b/_collections/_tools/etlas.html
@@ -0,0 +1,6 @@
+---
+tool: etlas
+title: Etlas
+langs: eta haskell
+---
+Etlas
\ No newline at end of file
diff --git a/_collections/_tools/git.html b/_collections/_tools/git.html
new file mode 100644
index 00000000..ef0af9dc
--- /dev/null
+++ b/_collections/_tools/git.html
@@ -0,0 +1,4 @@
+---
+tool: git
+title: Git
+---
\ No newline at end of file
diff --git a/_collections/_tools/github.html b/_collections/_tools/github.html
new file mode 100644
index 00000000..9ba59013
--- /dev/null
+++ b/_collections/_tools/github.html
@@ -0,0 +1,4 @@
+---
+tool: github
+title: Github
+---
diff --git a/_collections/_tools/graalvm.html b/_collections/_tools/graalvm.html
new file mode 100644
index 00000000..2c554023
--- /dev/null
+++ b/_collections/_tools/graalvm.html
@@ -0,0 +1,5 @@
+---
+tool: graalvm
+title: GraalVM
+langs: java
+---
diff --git a/_collections/_tools/jekyll.html b/_collections/_tools/jekyll.html
new file mode 100644
index 00000000..4b657837
--- /dev/null
+++ b/_collections/_tools/jekyll.html
@@ -0,0 +1,4 @@
+---
+tool: jekyll
+title: Jekyll
+---
\ No newline at end of file
diff --git a/_collections/_tools/jvm.html b/_collections/_tools/jvm.html
new file mode 100644
index 00000000..2395d230
--- /dev/null
+++ b/_collections/_tools/jvm.html
@@ -0,0 +1,7 @@
+---
+tool: jvm
+title: JVM
+langs: java
+---
+https://pl.wikipedia.org/wiki/Wirtualna_maszyna_Javy
+(ang. Java virtual machine , JVM )
\ No newline at end of file
diff --git a/_collections/_tools/kotlin-js.html b/_collections/_tools/kotlin-js.html
new file mode 100644
index 00000000..9e32eaa5
--- /dev/null
+++ b/_collections/_tools/kotlin-js.html
@@ -0,0 +1,6 @@
+---
+tool: kotlin-js
+title: kotlin.js
+langs: kotlin
+---
+Transpilator Kotlin JS
\ No newline at end of file
diff --git a/_collections/_tools/kotlin-native.html b/_collections/_tools/kotlin-native.html
new file mode 100644
index 00000000..e74786fd
--- /dev/null
+++ b/_collections/_tools/kotlin-native.html
@@ -0,0 +1,6 @@
+---
+tool: kotlin-native
+title: Kotlin/Native
+langs: kotlin
+---
+Kompilator Kotlin Native
\ No newline at end of file
diff --git a/_collections/_tools/llvm.html b/_collections/_tools/llvm.html
new file mode 100644
index 00000000..55145a96
--- /dev/null
+++ b/_collections/_tools/llvm.html
@@ -0,0 +1,16 @@
+---
+tool: llvm
+title: LLVM
+---
+
+LLVM Haskell Examples
+llvm-hs
+llvm-hs-pure
+llvm-hs-typed
+
+llvm-general
+llvm-general-pure
+llvm-general-quote
+
+llvm-data-interop
+
diff --git a/_collections/_tools/lunr.html b/_collections/_tools/lunr.html
new file mode 100644
index 00000000..f7452a70
--- /dev/null
+++ b/_collections/_tools/lunr.html
@@ -0,0 +1,5 @@
+---
+tool: lunr
+title: Lunr
+tags: search
+---
\ No newline at end of file
diff --git a/_collections/_tools/node-js.html b/_collections/_tools/node-js.html
new file mode 100644
index 00000000..0c72deba
--- /dev/null
+++ b/_collections/_tools/node-js.html
@@ -0,0 +1,5 @@
+---
+tool: node-js
+title: Node.js
+langs: javascript
+---
\ No newline at end of file
diff --git a/_collections/_tools/postgresql.html b/_collections/_tools/postgresql.html
new file mode 100644
index 00000000..a53ac3f2
--- /dev/null
+++ b/_collections/_tools/postgresql.html
@@ -0,0 +1,5 @@
+---
+tool: postgresql
+title: PostgreSQL
+tags: database
+---
\ No newline at end of file
diff --git a/_collections/_tools/sass.html b/_collections/_tools/sass.html
new file mode 100644
index 00000000..46839c35
--- /dev/null
+++ b/_collections/_tools/sass.html
@@ -0,0 +1,4 @@
+---
+tool: sass
+title: Sass
+---
\ No newline at end of file
diff --git a/_collections/_tools/sbt.html b/_collections/_tools/sbt.html
new file mode 100644
index 00000000..62ebc27e
--- /dev/null
+++ b/_collections/_tools/sbt.html
@@ -0,0 +1,6 @@
+---
+tool: sbt
+title: sbt
+langs: scala
+---
+Scala Build Tool
\ No newline at end of file
diff --git a/_collections/_tools/scala-js.html b/_collections/_tools/scala-js.html
new file mode 100644
index 00000000..95102a15
--- /dev/null
+++ b/_collections/_tools/scala-js.html
@@ -0,0 +1,6 @@
+---
+tool: scala-js
+title: Scala.js
+langs: scala
+---
+Transpilator Scala.js
\ No newline at end of file
diff --git a/_collections/_tools/scala-jvm.html b/_collections/_tools/scala-jvm.html
new file mode 100644
index 00000000..b933b33a
--- /dev/null
+++ b/_collections/_tools/scala-jvm.html
@@ -0,0 +1,5 @@
+---
+tool: scala-jvm
+title: Scala JVM
+langs: scala
+---
\ No newline at end of file
diff --git a/_collections/_tools/scala-native.html b/_collections/_tools/scala-native.html
new file mode 100644
index 00000000..c53b341c
--- /dev/null
+++ b/_collections/_tools/scala-native.html
@@ -0,0 +1,9 @@
+---
+tool: scala-native
+title: Scala Native
+langs: scala
+---
+Kompilator Scala Native .
+@scala_native
+
+Zobacz Awesome Scala Native
diff --git a/_collections/_tools/scalafix.html b/_collections/_tools/scalafix.html
new file mode 100644
index 00000000..1aabf803
--- /dev/null
+++ b/_collections/_tools/scalafix.html
@@ -0,0 +1,6 @@
+---
+tool: scalafix
+title: Scalafix
+langs: scala
+---
+Scalafix
\ No newline at end of file
diff --git a/_collections/_tools/sed.html b/_collections/_tools/sed.html
new file mode 100644
index 00000000..3d7c647a
--- /dev/null
+++ b/_collections/_tools/sed.html
@@ -0,0 +1,4 @@
+---
+tool: sed
+title: Sed
+---
diff --git a/_collections/_tools/seed.html b/_collections/_tools/seed.html
new file mode 100644
index 00000000..4e0cae6c
--- /dev/null
+++ b/_collections/_tools/seed.html
@@ -0,0 +1,7 @@
+---
+tool: seed
+title: Seed
+langs: scala
+tags: toml
+---
+Seed
diff --git a/_collections/_tools/solr.html b/_collections/_tools/solr.html
new file mode 100644
index 00000000..b3cf346d
--- /dev/null
+++ b/_collections/_tools/solr.html
@@ -0,0 +1,5 @@
+---
+tool: solr
+title: Solr
+tags: search
+---
\ No newline at end of file
diff --git a/_collections/_tools/swagger.html b/_collections/_tools/swagger.html
new file mode 100644
index 00000000..c9e45455
--- /dev/null
+++ b/_collections/_tools/swagger.html
@@ -0,0 +1,4 @@
+---
+tool: swagger
+title: Swagger
+---
diff --git a/_collections/_tools/teavm.html b/_collections/_tools/teavm.html
new file mode 100644
index 00000000..9ac8451c
--- /dev/null
+++ b/_collections/_tools/teavm.html
@@ -0,0 +1,5 @@
+---
+tool: teavm
+title: TeaVM
+langs: java
+---
diff --git a/_collections/_tools/ubuntu.html b/_collections/_tools/ubuntu.html
new file mode 100644
index 00000000..960b30ef
--- /dev/null
+++ b/_collections/_tools/ubuntu.html
@@ -0,0 +1,4 @@
+---
+tool: ubuntu
+title: Ubuntu
+---
\ No newline at end of file
diff --git a/_config.yml b/_config.yml
index 3da6a50c..a3d6eac8 100644
--- a/_config.yml
+++ b/_config.yml
@@ -1,115 +1,312 @@
-# Welcome to Jekyll!
-#
-# This config file is meant for settings that affect your whole blog, values
-# which you are expected to set up once and rarely edit after that. If you find
-# yourself editing this file very often, consider using Jekyll's data files
-# feature for the data you need to update frequently.
-#
-# For technical reasons, this file is *NOT* reloaded automatically when you use
-# 'bundle exec jekyll serve'. If you change this file, please restart the server process.
-
-# Site settings
-# These are used to personalize your new site. If you look in the HTML files,
-# you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
-# You can create any custom variable you would like, and they will be accessible
-# in the templates via {{ site.myvariable }}.
-title: MM
-email:
-description: >- # this means to ignore newlines until "baseurl:"
- Write an awesome description for your new site here. You can edit this
- line in _config.yml. It will appear in your document head meta (for
- Google search results) and in your feed.xml site description.
-twitter_username: username
-github_username: username
-minimal_mistakes_skin: default
-search: true
-
-# Build settings
-markdown: kramdown
-remote_theme: mmistakes/minimal-mistakes
-# Outputting
-permalink: /:categories/:title/
-paginate: 5 # amount of posts to show
-paginate_path: /page:num/
-timezone: # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+# Jekyll: https://jekyllrb.com/docs/configuration/
+## Default Configuration: https://jekyllrb.com/docs/configuration/default/
+
+future : true
+
+### Conversion
+markdown : kramdown
+highlighter : rouge
+
+### Outputting
+permalink : /:categories/:title/
+paginate_path : /:num
+timezone : "Europe/Warsaw" # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+
+### Where things are
include:
+ - _collections
- _pages
-# Exclude from processing.
-# The following items will not be processed, by default. Create a custom list
-# to override the default setting.
-# exclude:
-# - Gemfile
-# - Gemfile.lock
-# - node_modules
-# - vendor/bundle/
-# - vendor/cache/
-# - vendor/gems/
-# - vendor/ruby/
-
-# Plugins (previously gems:)
-plugins:
- - jekyll-paginate
- - jekyll-sitemap
- - jekyll-gist
- - jekyll-feed
- - jemoji
- - jekyll-include-cache
+sass:
+ # sass_dir: ui/_scss
+ style: compressed
-author:
- name : "First Lastname"
- avatar : "/assets/images/bio-photo.jpg"
- bio : "My awesome biography constrained to a sentence or two goes here."
- links:
- - label: "Website"
- icon: "fas fa-fw fa-link"
- url: "https://"
- - label: "Twitter"
- icon: "fab fa-fw fa-twitter-square"
- url: "https://twitter.com/"
- - label: "GitHub"
- icon: "fab fa-fw fa-github"
- url: "https://github.com/"
- - label: "Instagram"
- icon: "fab fa-fw fa-instagram"
- url: "https://instagram.com/"
+## Collections: https://jekyllrb.com/docs/collections/
+collections_dir : _collections
+collections:
+ categories:
+ output : true
+ permalink : /:collection/:path/
+ tags:
+ output : true
+ permalink : /:collection/:path/
+ langs:
+ output : true
+ permalink : /:collection/:path/
+ tools:
+ output : true
+ permalink : /:collection/:path/
+ libs:
+ output : true
+ permalink : /:collection/:path/
+ projects:
+ output : true
+ permalink : /:collection/:path/
+ eso:
+ output : true
+ permalink : /:collection/:path/
+ books:
+ output : true
+ permalink : /:collection/:path/
-footer:
- links:
- - label: "Twitter"
- icon: "fab fa-fw fa-twitter-square"
- url: "https://twitter.com/"
- - label: "GitHub"
- icon: "fab fa-fw fa-github"
- url: "https://github.com/"
- - label: "Instagram"
- icon: "fab fa-fw fa-instagram"
- url: "https://instagram.com/"
+## Front Matter Defaults: https://jekyllrb.com/docs/configuration/front-matter-defaults/
defaults:
# _posts
- scope:
- path: ""
- type: posts
+ path : ""
+ type : posts
values:
- layout: single
- author_profile: true
- read_time: true
- comments: true
- share: true
- related: true
+ layout : post
+ read_time : true
+ comments : true
+ share : true
+ related : true
+ pagination : true
+ toc: true
+ toc_sticky : true
+ sidebar:
+ nav : sidebar-main
# _pages
- scope:
- path: "_pages"
- type: pages
+ path : "_pages"
+ type : pages
+ values:
+ layout : page
+ classes : wide
+ sidebar :
+ main : true
+ nav : sidebar-main
+ # _categories
+ - scope:
+ path : ""
+ type : categories
+ values:
+ layout : page-category
+ share : true
+ classes : wide
+ sidebar:
+ main : true
+ nav : sidebar-main
+ # _tags
+ - scope:
+ path : ""
+ type : tags
+ values:
+ layout : page-tag
+ share : true
+ classes : wide
+ sidebar:
+ main : true
+ nav : sidebar-main
+ # _langs
+ - scope:
+ path : ""
+ type : langs
+ values :
+ layout : page-lang
+ share : true
+ classes : wide
+ sidebar:
+ main : true
+ nav : sidebar-main
+ # _tools
+ - scope:
+ path : ""
+ type : tools
+ values:
+ layout : page-tool
+ share : true
+ classes : wide
+ sidebar:
+ main : true
+ nav : sidebar-main
+ # _libs
+ - scope:
+ path : ""
+ type : libs
+ values:
+ layout : page-lib
+ share : true
+ classes : wide
+ sidebar:
+ main : true
+ nav : sidebar-main
+ # _projects
+ - scope:
+ path : ""
+ type : projects
+ values:
+ layout : page-project
+ share : true
+ classes : wide
+ sidebar:
+ main : true
+ nav : sidebar-main
+ # _eso
+ - scope:
+ path : ""
+ type : eso
+ values:
+ layout : page-eso
+ share : true
+ classes : wide
+ sidebar:
+ main : true
+ nav : sidebar-main
+ # _books
+ - scope:
+ path : ""
+ type : books
values:
- layout: single
- author_profile: true
+ layout : page-book
+ share : true
+ classes : wide
+ sidebar:
+ main : true
+ nav : sidebar-main
+
+# Plugins
+plugins:
+ - jemoji
+ - jekyll-avatar
+ - jekyll-coffeescript
+ - jekyll-commonmark-ghpages
+ - jekyll-default-layout
+ - jekyll-feed
+ - jekyll-gist
+ - jekyll-github-metadata
+ - jekyll-include-cache
+ - jekyll-mentions
+ - jekyll-optional-front-matter
+ - jekyll-paginate
+ - jekyll-readme-index
+ - jekyll-redirect-from
+ - jekyll-relative-links
+ - jekyll-remote-theme
+ - jekyll-sass-converter
+ - jekyll-seo-tag
+ - jekyll-sitemap
+ - jekyll-titles-from-headings
+
+## jekyll-commonmark-ghpages
+commonmark:
+ options : ["SMART", "FOOTNOTES"]
+ extensions : ["strikethrough", "autolink", "table", "tagfilter"]
+
+## jekyll-mentions
+jekyll-mentions:
+ base_url : "https://twitter.com"
+
+## jekyll-paginate
+paginate : 1
+
+## jekyll-remote-theme
+remote_theme : twocolumn/minimal-mistakes@gh-pages
+
+## jekyll-seo-tag
+title : "WriteOnly.pl"
+tagline : "WriteOnly Haskell, Scala, Jekyll, Git & Bash Blog"
+description: >-
+ Blog o programowaniu w językach Haskell, Eta, Scala Native i Scala.js
+ oraz generatorze stron Jekyll, systemie kontroli wersji Git i użyciu wiersza poleceń CLI
+url :
+author:
+ twitter : "TheKamilAdam"
+ name : "Kamil Adam"
+ avatar : "/assets/images/kamil.adam.jpg"
+ bio : "My awesome biography constrained to a sentence or two goes here."
+twitter:
+ username : "TheKamilAdam"
+facebook:
+logo : "/assets/favicon.ico"
+social:
+ name : "Kamil Adam"
+ links:
+ - https://github.com/writeonly
+ - https://www.linkedin.com/company/writeonly-pl
+ - https://www.facebook.com/WriteOnlyPL
+ - https://www.instagram.com/degustujacaistota/
+ - https://twitter.com/TheKamilAdam
+
+# External systems
+
+## Compress HTML
+compress_html:
+ clippings : all
+ comments : all
+ endings : all
+ profile : false
+ startings : [head, body]
+
+## Analytics
+analytics:
+ provider : "google-gtag"
+ google:
+ tracking_id : "UA-136426906-1"
+ anonymize_ip : false
+
+## Comments
+comments:
+ provider : "disqus"
+ disqus:
+ shortname : "writeonly-pl"
+
+## Search
+search : true
+search_full_content : true
+search_provider : "lunr"
+
+## Social Sharing
+og_image : "/favocon.ico"
+footer:
+ links:
+ - label : "GitHub"
+ icon : "fab fa-fw fa-github"
+ url : "https://github.com/writeonly"
+ - label : "Linkedin"
+ icon : "fab fa-fw fa-linkedin"
+ url : "https://www.linkedin.com/company/writeonly-pl/"
+ - label : "Facebook"
+ icon : "fab fa-fw fa-facebook"
+ url : "https://www.facebook.com/WriteOnlyPL"
+ - label : "Instagram"
+ icon : "fab fa-fw fa-instagram"
+ url : "https://instagram.com/degustujacaistota"
+ - label : "Twitter"
+ icon : "fab fa-fw fa-twitter"
+ url : "https://twitter.com/TheKamilAdam"
+ - label : "Dev.to"
+ icon : "fab fa-fw fa-dev"
+ url : "https://dev.to/kamiladam"
+
+# Theme settings
+locale : "pl-PL"
+
+masthead_title : "Blog o programowaniu w językach Haskell, Eta, Scala Native i Scala.js"
+subtitle : "oraz generatorze stron Jekyll, systemie kontroli wersji Git i użyciu wiersza poleceń CLI"
+email : "kamil.adam.zabinski@gmail.com"
+
+repository : "writeonly/writeonly.github.io"
+twitter_username : "TheKamilAdam"
+github_username : "kamil-adam"
+
+minimal_mistakes_skin : "gold"
+breadcrumbs : true
+words_per_minute : 100
+
+## Scripts
+scripts:
+# - https://code.jquery.com/jquery-3.4.1.min.js
+ - https://kit.fontawesome.com/4eee35f757.js
+ - /assets/js/main.min.js
+ - /assets/js/app.js
+## Archives
category_archive:
- type: liquid
- path: /categories/
+ type : collection
+ path : /categories/
tag_archive:
- type: liquid
- path: /tags/
+ type : collection
+ path : /tags/
diff --git a/_data/navigation.yml b/_data/navigation.yml
index e3af8aec..2b38ccdd 100644
--- a/_data/navigation.yml
+++ b/_data/navigation.yml
@@ -1,9 +1,36 @@
main:
- - title: "Posts"
+
+sidebar-main:
+ - title: "Artykuły"
url: /posts/
- - title: "Categories"
- url: /categories/
- - title: "Tags"
- url: /tags/
- - title: "About"
- url: /about/
\ No newline at end of file
+ children:
+ - title: "Po kategoriach"
+ url: /categories/
+ - title: "Po językach"
+ url: /langs/
+ - title: "Po narzędziach"
+ url: /tools/
+ - title: "Po bibliotekach"
+ url: /libs/
+ - title: "Po tagach"
+ url: /tags/
+ - title: "Po projektach"
+ url: /projects/
+ - title: "Eso"
+ url: /eso/
+ - title: "Strony"
+ children:
+ - title: "Przeczytane ksiązki"
+ url: /books/
+ - title: "O autorze"
+ url: /about/
+ - title: "Polityka prywatności"
+ url: /privacy/
+ - title: "Degustujaca Istota"
+ url: https://www.degustujacaistota.pl/
+ - title: "Wyszukiwarki"
+ children:
+ - title: "Wyszukiwarka Jekyll"
+ url: /search-jekyll/
+ - title: "Wyszukiwarka Jekyll Prosta"
+ url: /search-jekyll-simple/
diff --git a/_data/ui-text.yml b/_data/ui-text.yml
new file mode 100644
index 00000000..e92f18f2
--- /dev/null
+++ b/_data/ui-text.yml
@@ -0,0 +1,1618 @@
+# User interface text and labels
+
+# English (default)
+# -----------------
+en: &DEFAULT_EN
+ skip_links : "Skip links"
+ skip_primary_nav : "Skip to primary navigation"
+ skip_content : "Skip to content"
+ skip_footer : "Skip to footer"
+ page : "Page"
+ pagination_previous : "Previous"
+ pagination_next : "Next"
+ breadcrumb_home_label : "Home"
+ breadcrumb_separator : "/"
+ menu_label : "Toggle menu"
+ search_label : "Toggle search"
+ toc_label : "On this page"
+ ext_link_label : "Direct link"
+ less_than : "less than"
+ minute_read : "minute read"
+ share_on_label : "Share on"
+ meta_label :
+ tags_label : "Tags:"
+ categories_label : "Categories:"
+ date_label : "Updated:"
+ comments_label : "Leave a comment"
+ comments_title : "Comments"
+ more_label : "Learn more"
+ related_label : "You may also enjoy"
+ follow_label : "Follow:"
+ feed_label : "Feed"
+ powered_by : "Powered by"
+ website_label : "Website"
+ email_label : "Email"
+ recent_posts : "Recent posts"
+ undefined_wpm : "Undefined parameter words_per_minute at _config.yml"
+ comment_form_info : "Your email address will not be published. Required fields are marked"
+ comment_form_comment_label : "Comment"
+ comment_form_md_info : "Markdown is supported."
+ comment_form_name_label : "Name"
+ comment_form_email_label : "Email address"
+ comment_form_website_label : "Website (optional)"
+ comment_btn_submit : "Submit comment"
+ comment_btn_submitted : "Submitted"
+ comment_success_msg : "Thanks for your comment! It will show on the site once it has been approved."
+ comment_error_msg : "Sorry, there was an error with your submission. Please make sure all required fields have been completed and try again."
+ loading_label : "Loading..."
+ search_label_text : "Enter your search term..."
+ search_placeholder_text : "Enter your search term..."
+ results_found : "Result(s) found"
+ back_to_top : "Back to top"
+en-US:
+ <<: *DEFAULT_EN
+en-CA:
+ <<: *DEFAULT_EN
+en-GB:
+ <<: *DEFAULT_EN
+en-AU:
+ <<: *DEFAULT_EN
+
+# Spanish
+# -------
+es: &DEFAULT_ES
+ skip_links : "Saltar enlaces"
+ skip_primary_nav : "Saltar a navegación principal"
+ skip_content : "Saltar a contenido"
+ skip_footer : "Saltar a pie"
+ page : "Página"
+ pagination_previous : "Anterior"
+ pagination_next : "Siguiente"
+ breadcrumb_home_label : "Inicio"
+ breadcrumb_separator : "/"
+ menu_label : "Alternar menú"
+ search_label : "Alternar búsqueda"
+ toc_label : "En esta página"
+ ext_link_label : "Enlace directo"
+ less_than : "menos de"
+ minute_read : "minuto(s) de lectura"
+ share_on_label : "Compartir en"
+ meta_label :
+ tags_label : "Etiquetas:"
+ categories_label : "Categorías:"
+ date_label : "Actualizado:"
+ comments_label : "Deja un comentario"
+ comments_title : "Comentarios"
+ more_label : "Ver más"
+ related_label : "Puede que también te interese"
+ follow_label : "Seguir:"
+ feed_label : "Feed"
+ powered_by : "Funciona con"
+ website_label : "Sitio web"
+ email_label : "Correo electrónico"
+ recent_posts : "Entradas recientes"
+ undefined_wpm : "El parámetro words_per_minute (palabras por minuto) no está definido en _config.yml"
+ comment_form_info : "Tu dirección de correo electrónico no se publicará. Los campos obligatorios están marcados"
+ comment_form_comment_label : "Comentario"
+ comment_form_md_info : "Puedes utilizar Markdown"
+ comment_form_name_label : "Nombre"
+ comment_form_email_label : "Dirección de correo electrónico"
+ comment_form_website_label : "Sitio web (opcional)"
+ comment_btn_submit : "Enviar comentario"
+ comment_btn_submitted : "Enviado"
+ comment_success_msg : "¡Gracias por tu comentario! Se publicará una vez sea aprobado."
+ comment_error_msg : "Ha ocurrido un error al enviar el comentario. Asegúrate de completar todos los campos obligatorios e inténtalo de nuevo."
+ loading_label : "Cargando..."
+ search_label_text : "Términos de búsqueda..."
+ search_placeholder_text : "Términos de búsqueda..."
+ results_found : "resultado(s) encontrado(s)"
+ back_to_top : "Volver arriba"
+es-ES:
+ <<: *DEFAULT_ES
+es-CO:
+ <<: *DEFAULT_ES
+
+# French
+# ------
+fr: &DEFAULT_FR
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Page"
+ pagination_previous : "Précédent"
+ pagination_next : "Suivant"
+ breadcrumb_home_label : "Accueil"
+ breadcrumb_separator : "/"
+ menu_label : "Menu"
+ search_label :
+ toc_label : "Sur cette page"
+ ext_link_label : "Lien direct"
+ less_than : "moins de"
+ minute_read : "minute(s) de lecture"
+ share_on_label : "Partager sur"
+ meta_label :
+ tags_label : "Tags :"
+ categories_label : "Catégories :"
+ date_label : "Mis à jour :"
+ comments_label : "Laisser un commentaire"
+ comments_title : "Commentaires"
+ more_label : "Lire plus"
+ related_label : "Vous pourriez aimer aussi"
+ follow_label : "Contact"
+ feed_label : "Flux"
+ powered_by : "Propulsé par"
+ website_label : "Site"
+ email_label : "Email"
+ recent_posts : "Posts récents"
+ undefined_wpm : "Le paramètre words_per_minute n'est pas défini dans _config.yml"
+ comment_form_info : "Votre adresse email ne sera pas visible. Les champs obligatoires sont marqués"
+ comment_form_comment_label : "Commentaire"
+ comment_form_md_info : "Markdown est supporté."
+ comment_form_name_label : "Nom"
+ comment_form_email_label : "Adresse mail"
+ comment_form_website_label : "Site web (optionnel)"
+ comment_btn_submit : "Envoyer"
+ comment_btn_submitted : "Envoyé"
+ comment_success_msg : "Merci pour votre commentaire, il sera visible sur le site une fois approuvé."
+ comment_error_msg : "Désolé, une erreur est survenue lors de la soumission. Vérifiez que les champs obligatoires ont été remplis et réessayez."
+ loading_label : "Chargement..."
+ search_label_text :
+ search_placeholder_text : "Entrez votre recherche..."
+ results_found : "Résultat(s) trouvé(s)"
+ back_to_top : "Retour en haut"
+fr-FR:
+ <<: *DEFAULT_FR
+fr-BE:
+ <<: *DEFAULT_FR
+fr-CH:
+ <<: *DEFAULT_FR
+
+# Turkish
+# -------
+tr: &DEFAULT_TR
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Sayfa"
+ pagination_previous : "Önceki"
+ pagination_next : "Sonraki"
+ breadcrumb_home_label : "Ana Sayfa"
+ breadcrumb_separator : "/"
+ menu_label :
+ search_label :
+ toc_label : "İçindekiler"
+ ext_link_label : "Doğrudan Bağlantı"
+ less_than : "Şu süreden az: "
+ minute_read : "dakika tahmini okuma süresi"
+ share_on_label : "Paylaş"
+ meta_label :
+ tags_label : "Etiketler:"
+ categories_label : "Kategoriler:"
+ date_label : "Güncelleme tarihi:"
+ comments_label : "Yorum yapın"
+ comments_title : "Yorumlar"
+ more_label : "Daha fazlasını öğrenin"
+ related_label : "Bunlar ilginizi çekebilir:"
+ follow_label : "Takip et:"
+ feed_label : "RSS"
+ powered_by : "Emeği geçenler: "
+ website_label : "Web sayfası"
+ email_label : "E-posta"
+ recent_posts : "Son yazılar"
+ undefined_wpm : "_config.yml dosyasında tanımlanmamış words_per_minute parametresi"
+ comment_form_info : "Email adresiniz gösterilmeyecektir. Zorunlu alanlar işaretlenmiştir"
+ comment_form_comment_label : "Yorumunuz"
+ comment_form_md_info : "Markdown desteklenmektedir."
+ comment_form_name_label : "Adınız"
+ comment_form_email_label : "Email adresiniz"
+ comment_form_website_label : "Websiteniz (opsiyonel)"
+ comment_btn_submit : "Yorum Yap"
+ comment_btn_submitted : "Gönderildi"
+ comment_success_msg : "Yorumunuz için teşekkürler! Yorumunuz onaylandıktan sonra sitede gösterilecektir."
+ comment_error_msg : "Maalesef bir hata oluştu. Lütfen zorunlu olan tüm alanları doldurduğunuzdan emin olun ve sonrasında tekrar deneyin."
+ loading_label : "Yükleniyor..."
+ search_label_text :
+tr-TR:
+ <<: *DEFAULT_TR
+
+# Portuguese
+# ----------
+pt: &DEFAULT_PT
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Página"
+ pagination_previous : "Anterior"
+ pagination_next : "Seguinte"
+ breadcrumb_home_label : "Início"
+ breadcrumb_separator : "/"
+ menu_label :
+ search_label :
+ toc_label : "Nesta Página"
+ ext_link_label : "Link Direto"
+ less_than : "menos de"
+ minute_read : "minutos de leitura"
+ share_on_label : "Partilhar no"
+ meta_label :
+ tags_label : "Etiquetas:"
+ categories_label : "Categorias:"
+ date_label : "Atualizado:"
+ comments_label : "Deixe um Comentário"
+ comments_title : "Comentários"
+ more_label : "Saber mais"
+ related_label : "Também pode gostar de"
+ follow_label : "Siga:"
+ feed_label : "Feed"
+ powered_by : "Feito com"
+ website_label : "Site"
+ email_label : "Email"
+ recent_posts : "Artigos Recentes"
+ undefined_wpm : "Parâmetro words_per_minute não definido em _config.yml"
+ comment_form_info : "O seu endereço email não será publicado. Os campos obrigatórios estão assinalados"
+ comment_form_comment_label : "Comentário"
+ comment_form_md_info : "Markdown é suportado."
+ comment_form_name_label : "Nome"
+ comment_form_email_label : "Endereço Email"
+ comment_form_website_label : "Site (opcional)"
+ comment_btn_submit : "Sumbeter Comentário"
+ comment_btn_submitted : "Submetido"
+ comment_success_msg : "Obrigado pelo seu comentário! Será visível no site logo que aprovado."
+ comment_error_msg : "Lamento, ocorreu um erro na sua submissão. Por favor verifique se todos os campos obrigatórios estão corretamente preenchidos e tente novamente."
+ loading_label : "A carregar..."
+ search_label_text :
+pt-PT:
+ <<: *DEFAULT_PT
+# Brazilian Portuguese
+pt-BR:
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Página"
+ pagination_previous : "Anterior"
+ pagination_next : "Próxima"
+ breadcrumb_home_label : "Home"
+ breadcrumb_separator : "/"
+ menu_label :
+ search_label : "Buscar"
+ toc_label : "Nesta página"
+ ext_link_label : "Link direto"
+ less_than : "menos que"
+ minute_read : "minuto(s) de leitura"
+ share_on_label : "Compartilhe"
+ meta_label :
+ tags_label : "Tags:"
+ categories_label : "Categorias:"
+ date_label : "Atualizado em:"
+ comments_label : "Deixe um comentário"
+ comments_title : "Comentários"
+ more_label : "Saiba mais"
+ related_label : "Talvez você também goste"
+ follow_label : "Acompanhe no"
+ feed_label : "Feed"
+ powered_by : "Desenvolvido com"
+ website_label : "Site"
+ email_label : "E-mail"
+ recent_posts : "Publicações recentes"
+ undefined_wpm : "Parâmetro words_per_minute indefinido no _config.yml"
+ comment_form_info : "Seu e-mail não será publicado. Os campos obrigatórios estão marcados"
+ comment_form_comment_label : "Comentário"
+ comment_form_md_info : "Você pode usar Markdown."
+ comment_form_name_label : "Nome"
+ comment_form_email_label : "E-mail"
+ comment_form_website_label : "Site (opcional)"
+ comment_btn_submit : "Enviar comentário"
+ comment_btn_submitted : "Enviado"
+ comment_success_msg : "Obrigado pelo seu comentário! Ele aparecerá no site assim que for aprovado."
+ comment_error_msg : "Desculpe, ocorreu um erro no envio. Verifique se todos os campos obrigatórios foram preenchidos e tente novamente."
+ loading_label : "Carregando..."
+ search_label_text :
+ search_placeholder_text : "Pesquisar..."
+ results_found : "Resultado(s) encontrado(s)"
+ back_to_top : "Voltar para o topo"
+
+# Italian
+# -------
+it: &DEFAULT_IT
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Pagina"
+ pagination_previous : "Precedente"
+ pagination_next : "Prossima"
+ breadcrumb_home_label : "Home"
+ breadcrumb_separator : "/"
+ menu_label :
+ search_label :
+ toc_label : "Indice della pagina"
+ ext_link_label : "Link"
+ less_than : "meno di"
+ minute_read : "minuto/i di lettura"
+ share_on_label : "Condividi"
+ meta_label :
+ tags_label : "Tags:"
+ categories_label : "Categorie:"
+ date_label : "Aggiornato:"
+ comments_label : "Scrivi un commento"
+ comments_title :
+ more_label : "Scopri di più"
+ related_label : "Potrebbe Piacerti Anche"
+ follow_label : "Segui:"
+ feed_label : "Feed"
+ powered_by : "Powered by"
+ website_label : "Website"
+ email_label : "Email"
+ recent_posts : "Articoli Recenti"
+ undefined_wpm : "Parametro words_per_minute non definito in _config.yml"
+ comment_form_info : "Il tuo indirizzo email non sarà pubblicato. Sono segnati i campi obbligatori"
+ comment_form_comment_label : "Commenta"
+ comment_form_md_info : "Il linguaggio Markdown è supportato"
+ comment_form_name_label : "Nome"
+ comment_form_email_label : "Indirizzo email"
+ comment_form_website_label : "Sito Web (opzionale)"
+ comment_btn_submit : "Invia commento"
+ comment_btn_submitted : "Inviato"
+ comment_success_msg : "Grazie per il tuo commento! Verrà visualizzato nel sito una volta che sarà approvato."
+ comment_error_msg : "C'è stato un errore con il tuo invio. Assicurati che tutti i campi richiesti siano stati completati e riprova."
+ loading_label : "Caricamento..."
+ search_label_text :
+ search_placeholder_text : "Inserisci termini di ricerca..."
+ results_found : "Risultati"
+ back_to_top : "Vai su"
+it-IT:
+ <<: *DEFAULT_IT
+
+# Chinese (zh-CN Chinese - China)
+# --------------------------------
+zh: &DEFAULT_ZH_HANS
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "页面"
+ pagination_previous : "向前"
+ pagination_next : "向后"
+ breadcrumb_home_label : "首页"
+ breadcrumb_separator : "/"
+ menu_label : "切换菜单"
+ search_label :
+ toc_label : "在本页上"
+ ext_link_label : "直接链接"
+ less_than : "少于"
+ minute_read : "分钟阅读"
+ share_on_label : "分享"
+ meta_label :
+ tags_label : "标签:"
+ categories_label : "分类:"
+ date_label : "更新时间:"
+ comments_label : "留下评论"
+ comments_title : "评论"
+ more_label : "了解更多"
+ related_label : "猜您还喜欢"
+ follow_label : "关注:"
+ feed_label : "Feed"
+ powered_by : "技术来自于"
+ website_label : "网站"
+ email_label : "电子邮箱"
+ recent_posts : "最新文章"
+ undefined_wpm : "_config.yml 配置中 words_per_minute 字段未定义"
+ comment_form_info : "您的电子邮箱地址并不会被展示。请填写标记为必须的字段。"
+ comment_form_comment_label : "评论"
+ comment_form_md_info : "支持 Markdown 语法。"
+ comment_form_name_label : "姓名"
+ comment_form_email_label : "电子邮箱"
+ comment_form_website_label : "网站(可选)"
+ comment_btn_submit : "提交评论"
+ comment_btn_submitted : "已提交"
+ comment_success_msg : "感谢您的评论!被批准后它会立即在此站点展示。"
+ comment_error_msg : "很抱歉,您的提交存在错误。请确保所有必填字段都已填写正确,然后再试一次。"
+ loading_label : "正在加载..."
+ search_label_text :
+ search_placeholder_text : "输入您要搜索的关键词..."
+ results_found : "条记录匹配"
+ back_to_top : "返回顶部"
+zh-CN:
+ <<: *DEFAULT_ZH_HANS
+zh-SG:
+ <<: *DEFAULT_ZH_HANS
+# Taiwan (Traditional Chinese)
+zh-TW: &DEFAULT_ZH_HANT
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "頁面"
+ pagination_previous : "較舊"
+ pagination_next : "較新"
+ breadcrumb_home_label : "首頁"
+ breadcrumb_separator : "/"
+ menu_label : "切換選單"
+ search_label :
+ toc_label : "本頁"
+ ext_link_label : "外部連結"
+ less_than : "少於"
+ minute_read : "分鐘閱讀"
+ share_on_label : "分享到"
+ meta_label :
+ tags_label : "標籤:"
+ categories_label : "分類:"
+ date_label : "更新時間:"
+ comments_label : "留言"
+ comments_title : "留言內容"
+ more_label : "了解更多"
+ related_label : "猜您有與趣"
+ follow_label : "追蹤:"
+ feed_label : "RSS Feed"
+ powered_by : "Powered by"
+ website_label : "網站"
+ email_label : "電子信箱"
+ recent_posts : "最新文章"
+ undefined_wpm : "_config.yml 中未定義 words_per_minute"
+ comment_form_info : "您的電子信箱不會被公開. 必填部份已標記"
+ comment_form_comment_label : "留言內容"
+ comment_form_md_info : "支援Markdown語法。"
+ comment_form_name_label : "名字"
+ comment_form_email_label : "電子信箱帳號"
+ comment_form_website_label : "網頁 (可選填)"
+ comment_btn_submit : "送出留言"
+ comment_btn_submitted : "已送出"
+ comment_success_msg : "感謝您的留言! 審核後將會顯示在站上。"
+ comment_error_msg : "抱歉,部份資料輸入有問題。請確認資料填寫正確後再試一次。"
+ loading_label : "載入中..."
+ search_label_text :
+zh-HK:
+ <<: *DEFAULT_ZH_HANT
+
+# German / Deutsch
+# ----------------
+de: &DEFAULT_DE
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Seite"
+ pagination_previous : "Vorherige"
+ pagination_next : "Nächste"
+ breadcrumb_home_label : "Start"
+ breadcrumb_separator : "/"
+ menu_label : "Menü ein-/ausschalten"
+ search_label :
+ toc_label : "Auf dieser Seite"
+ ext_link_label : "Direkter Link"
+ less_than : "weniger als"
+ minute_read : "Minuten zum lesen"
+ share_on_label : "Teilen auf"
+ meta_label :
+ tags_label : "Tags:"
+ categories_label : "Kategorien:"
+ date_label : "Aktualisiert:"
+ comments_label : "Hinterlassen Sie einen Kommentar"
+ comments_title : "Kommentare"
+ more_label : "Mehr anzeigen"
+ related_label : "Ihnen gefällt vielleicht auch"
+ follow_label : "Folgen:"
+ feed_label : "Feed"
+ powered_by : "Möglich durch"
+ website_label : "Webseite"
+ email_label : "E-Mail"
+ recent_posts : "Aktuelle Beiträge"
+ undefined_wpm : "Undefinierter Parameter words_per_minute in _config.yml"
+ comment_form_info : "Ihre E-Mail Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert"
+ comment_form_comment_label : "Kommentar"
+ comment_form_md_info : "Markdown wird unterstützt."
+ comment_form_name_label : "Name"
+ comment_form_email_label : "E-Mail-Addresse"
+ comment_form_website_label : "Webseite (optional)"
+ comment_btn_submit : "Kommentar absenden"
+ comment_btn_submitted : "Versendet"
+ comment_success_msg : "Danke für Ihren Kommentar! Er wird auf der Seite angezeigt, nachdem er geprüft wurde."
+ comment_error_msg : "Entschuldigung, es gab einen Fehler. Bitte füllen Sie alle benötigten Felder aus und versuchen Sie es erneut."
+ loading_label : "Lade..."
+ search_label_text :
+ search_placeholder_text : "Suchbegriff eingeben..."
+ results_found : "Ergebnis(se) gefunden"
+de-DE:
+ <<: *DEFAULT_DE
+de-AT:
+ <<: *DEFAULT_DE
+de-CH:
+ <<: *DEFAULT_DE
+de-BE:
+ <<: *DEFAULT_DE
+de-LI:
+ <<: *DEFAULT_DE
+de-LU:
+ <<: *DEFAULT_DE
+
+# Nepali (Nepal)
+# --------------
+ne: &DEFAULT_NE
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "पृष्ठ"
+ pagination_previous : "अघिल्लो"
+ pagination_next : "अर्को"
+ breadcrumb_home_label : "गृह"
+ breadcrumb_separator : "/"
+ menu_label : "टगल मेनु"
+ search_label :
+ toc_label : "यो पृष्ठमा"
+ ext_link_label : "सिधा सम्पर्क"
+ less_than : "कम्तिमा"
+ minute_read : "मिनेट पढ्नुहोस्"
+ share_on_label : "शेयर गर्नुहोस्"
+ meta_label :
+ tags_label : "ट्यागहरू:"
+ categories_label : "वर्गहरु:"
+ date_label : "अद्यावधिक:"
+ comments_label : "टिप्पणी दिनुहोस्"
+ comments_title : "टिप्पणीहरू"
+ more_label : "अझै सिक्नुहोस्"
+ related_label : "तपाईं रुचाउन सक्नुहुन्छ "
+ follow_label : "पछ्याउनुहोस्:"
+ feed_label : "फिड"
+ powered_by : "Powered by"
+ website_label : "वेबसाइट"
+ email_label : "इमेल"
+ recent_posts : "ताजा लेखहरु"
+ undefined_wpm : "अपरिभाषित प्यारामिटर शब्दहरू_प्रति_मिनेट at _config.yml"
+ comment_form_info : "तपाइँको इमेल ठेगाना प्रकाशित गरिने छैन।आवश्यक जानकारीहरुमा चिन्ह लगाइको छ"
+ comment_form_comment_label : "टिप्पणी"
+ comment_form_md_info : "मार्कडाउन समर्थित छ।"
+ comment_form_name_label : "नाम"
+ comment_form_email_label : "इमेल ठेगाना"
+ comment_form_website_label : "वेबसाइट (वैकल्पिक)"
+ comment_btn_submit : "टिप्पणी दिनुहोस् "
+ comment_btn_submitted : "टिप्पणी भयो"
+ comment_success_msg : "तपाईंको टिप्पणीको लागि धन्यवाद! एक पटक यो अनुमोदन गरेपछी यो साइटमा देखाउनेछ।"
+ comment_error_msg : "माफ गर्नुहोस्, तपाईंको टिप्पणी त्रुटि थियो।सबै आवश्यक जानकारीहरु पूरा गरिएको छ भने निश्चित गर्नुहोस् र फेरि प्रयास गर्नुहोस्।"
+ loading_label : "लोड हुँदैछ ..."
+ search_label_text :
+ne-NP:
+ <<: *DEFAULT_NE
+
+# Korean
+# ------
+ko: &DEFAULT_KO
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "페이지"
+ pagination_previous : "이전"
+ pagination_next : "다음"
+ breadcrumb_home_label : "Home"
+ breadcrumb_separator : "/"
+ menu_label : "토글 메뉴"
+ search_label :
+ toc_label : "On This Page"
+ ext_link_label : "직접 링크"
+ less_than : "최대"
+ minute_read : "분 소요"
+ share_on_label : "공유하기"
+ meta_label :
+ tags_label : "태그:"
+ categories_label : "카테고리:"
+ date_label : "업데이트:"
+ comments_label : "댓글남기기"
+ comments_title : "댓글"
+ more_label : "더 보기"
+ related_label : "참고"
+ follow_label : "팔로우:"
+ feed_label : "피드"
+ powered_by : "Powered by"
+ website_label : "웹사이트"
+ email_label : "이메일"
+ recent_posts : "최근 포스트"
+ undefined_wpm : "Undefined parameter words_per_minute at _config.yml"
+ comment_form_info : "이메일은 공개되지 않습니다. 작성 필요 필드:"
+ comment_form_comment_label : "댓글"
+ comment_form_md_info : "마크다운을 지원합니다."
+ comment_form_name_label : "이름"
+ comment_form_email_label : "이메일"
+ comment_form_website_label : "웹사이트(선택사항)"
+ comment_btn_submit : "댓글 등록"
+ comment_btn_submitted : "등록됨"
+ comment_success_msg : "감사합니다! 댓글이 머지된 후 확인하실 수 있습니다."
+ comment_error_msg : "댓글 등록에 문제가 있습니다. 필요 필드를 작성했는지 확인하고 다시 시도하세요."
+ loading_label : "로딩중..."
+ search_label_text :
+ search_placeholder_text : "검색어를 입력하세요..."
+ results_found : "개 결과 발견"
+ back_to_top : "맨 위로 이동"
+ko-KR:
+ <<: *DEFAULT_KO
+
+# Russian / Русский
+# -----------------
+ru: &DEFAULT_RU
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Страница"
+ pagination_previous : "Предыдущая"
+ pagination_next : "Следующая"
+ breadcrumb_home_label : "Главная"
+ breadcrumb_separator : "/"
+ menu_label : "Выпадающее меню"
+ search_label :
+ toc_label : "Содержание"
+ ext_link_label : "Прямая ссылка"
+ less_than : "менее"
+ minute_read : "мин на чтение"
+ share_on_label : "Поделиться"
+ meta_label :
+ tags_label : "Метки:"
+ categories_label : "Разделы:"
+ date_label : "Дата изменения:"
+ comments_label : "Оставить комментарий"
+ comments_title : "Комментарии"
+ more_label : "Читать далее"
+ related_label : "Вам также может понравиться"
+ follow_label : "Связаться со мной:"
+ feed_label : "RSS-лента"
+ powered_by : "Сайт работает на"
+ website_label : "Сайт"
+ email_label : "Электронная почта"
+ recent_posts : "Свежие записи"
+ undefined_wpm : "Не определён параметр words_per_minute в _config.yml"
+ comment_form_info : "Ваш адрес электронной почты не будет опубликован. Обязательные поля помечены"
+ comment_form_comment_label : "Комментарий"
+ comment_form_md_info : "Поддерживается синтаксис Markdown."
+ comment_form_name_label : "Имя"
+ comment_form_email_label : "Электронная почта"
+ comment_form_website_label : "Ссылка на сайт (необязательно)"
+ comment_btn_submit : "Оставить комментарий"
+ comment_btn_submitted : "Отправлено"
+ comment_success_msg : "Спасибо за Ваш комментарий! Он будет опубликован на сайте после проверки."
+ comment_error_msg : "К сожалению, произошла ошибка с отправкой комментария. Пожалуйста, убедитесь, что все обязательные поля заполнены и попытайтесь снова."
+ loading_label : "Отправка..."
+ search_label_text :
+ search_placeholder_text : "Введите поисковый запрос..."
+ results_found : "Найдено"
+ru-RU:
+ <<: *DEFAULT_RU
+
+# Lithuanian / Lietuviškai
+# ------------------------
+lt: &DEFAULT_LT
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Puslapis"
+ pagination_previous : "Ankstesnis"
+ pagination_next : "Sekantis"
+ breadcrumb_home_label : "Pagrindinis"
+ breadcrumb_separator : "/"
+ menu_label : "Meniu rodymas"
+ search_label :
+ toc_label : "Turinys"
+ ext_link_label : "Tiesioginė nuoroda"
+ less_than : "mažiau nei"
+ minute_read : "min. skaitymo"
+ share_on_label : "Pasidalinti"
+ meta_label :
+ tags_label : "Žymės:"
+ categories_label : "Kategorijos:"
+ date_label : "Atnaujinta:"
+ comments_label : "Palikti komentarą"
+ comments_title : "Komentaras"
+ more_label : "Skaityti daugiau"
+ related_label : "Taip pat turėtų patikti"
+ follow_label : "Sekti:"
+ feed_label : "Šaltinis"
+ powered_by : "Sukurta su"
+ website_label : "Tinklapis"
+ email_label : "El. paštas"
+ recent_posts : "Naujausi įrašai"
+ undefined_wpm : "Nedeklaruotas parametras words_per_minute faile _config.yml"
+ comment_form_info : "El. pašto adresas nebus viešinamas. Būtini laukai pažymėti"
+ comment_form_comment_label : "Komentaras"
+ comment_form_md_info : "Markdown palaikomas."
+ comment_form_name_label : "Vardas"
+ comment_form_email_label : "El. paštas"
+ comment_form_website_label : "Tinklapis (nebūtina)"
+ comment_btn_submit : "Komentuoti"
+ comment_btn_submitted : "Įrašytas"
+ comment_success_msg : "Ačiū už komentarą! Jis bus parodytas kai bus patvirtintas."
+ comment_error_msg : "Atleiskite, įvyko netikėta klaida įrašant komentarą. Pasitikrinkite ar užpildėte visus būtinus laukus ir pamėginkite dar kartą."
+ loading_label : "Kraunama..."
+ search_label_text :
+lt-LT:
+ <<: *DEFAULT_LT
+
+# Greek
+# -----
+gr: &DEFAULT_GR
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Σελίδα"
+ pagination_previous : "Προηγούμενo"
+ pagination_next : "Επόμενo"
+ breadcrumb_home_label : "Αρχική"
+ breadcrumb_separator : "/"
+ menu_label : "Μενού"
+ search_label :
+ toc_label : "Περιεχόμενα"
+ ext_link_label : "Εξωτερικός Σύνδεσμος"
+ less_than : "Λιγότερο από"
+ minute_read : "λεπτά ανάγνωσης"
+ share_on_label : "Μοιραστείτε το"
+ meta_label :
+ tags_label : "Ετικέτες:"
+ categories_label : "Κατηγορίες:"
+ date_label : "Ενημερώθηκε:"
+ comments_label : "Αφήστε ένα σχόλιο"
+ comments_title : "Σχόλια"
+ more_label : "Διάβαστε περισσότερα"
+ related_label : "Σχετικές αναρτήσεις"
+ follow_label : "Ακολουθήστε:"
+ feed_label : "RSS Feed"
+ powered_by : "Δημιουργήθηκε με"
+ website_label : "Ιστοσελίδα"
+ email_label : "Email"
+ recent_posts : "Τελευταίες αναρτήσεις"
+ undefined_wpm : "Δεν έχει οριστεί η παράμετρος words_per_minute στο αρχείο _config.yml"
+ comment_form_info : "Η διεύθυνση email σας δεν θα δημοσιευθεί. Τα απαιτούμενα πεδία εμφανίζονται με αστερίσκο"
+ comment_form_comment_label : "Σχόλιο"
+ comment_form_md_info : "Το πεδίο υποστηρίζει Markdown."
+ comment_form_name_label : "Όνομα"
+ comment_form_email_label : "Διεύθυνση email"
+ comment_form_website_label : "Ιστοσελίδα (προαιρετικό)"
+ comment_btn_submit : "Υπόβαλε ένα σχόλιο"
+ comment_btn_submitted : "Έχει υποβληθεί"
+ comment_success_msg : "Ευχαριστούμε για το σχόλιό σας! Θα εμφανιστεί στην ιστοσελίδα αφού εγκριθεί."
+ comment_error_msg : "Λυπούμαστε, παρουσιάστηκε σφάλμα με την υποβολή σας. Παρακαλούμε βεβαιωθείτε ότι έχετε όλα τα απαιτούμενα πεδία συμπληρωμένα και δοκιμάστε ξανά."
+ loading_label : "Φόρτωση..."
+ search_label_text :
+ search_placeholder_text : "Εισάγετε όρο αναζήτησης..."
+ results_found : "Αποτελέσματα"
+gr-GR:
+ <<: *DEFAULT_GR
+
+# Swedish
+# -------
+sv: &DEFAULT_SV
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Sidan"
+ pagination_previous : "Föregående"
+ pagination_next : "Nästa"
+ breadcrumb_home_label : "Hem"
+ breadcrumb_separator : "/"
+ menu_label : "Växla menyläge"
+ search_label : "Växla sökläge"
+ toc_label : "På denna sida"
+ ext_link_label : "Direkt länk"
+ less_than : "mindre än"
+ minute_read : "minut läsning"
+ share_on_label : "Dela på"
+ meta_label :
+ tags_label : "Taggar:"
+ categories_label : "Kategorier:"
+ date_label : "Uppdaterades:"
+ comments_label : "Lämna en kommentar"
+ comments_title : "Kommentarer"
+ more_label : "Lär dig mer"
+ related_label : "Du kanske vill även läsa:"
+ follow_label : "Följ:"
+ feed_label : "Flöde"
+ powered_by : "Framställd med"
+ website_label : "Webbsida"
+ email_label : "E-post"
+ recent_posts : "Senaste inlägg"
+ undefined_wpm : "Odefinerade parametrar words_per_minute i _config.yml"
+ comment_form_info : "Din e-post adress kommer inte att publiceras. Obligatoriska fält är markerade"
+ comment_form_comment_label : "Kommentar"
+ comment_form_md_info : "Stöd för Markdown finns."
+ comment_form_name_label : "Namn"
+ comment_form_email_label : "E-post adress"
+ comment_form_website_label : "Webdsida (valfritt)"
+ comment_btn_submit : "Skicka en kommentar"
+ comment_btn_submitted : "Kommentaren har tagits emot"
+ comment_success_msg : "Tack för din kommentar! Den kommer att visas på sidan så fort den har godkännts."
+ comment_error_msg : "Tyvärr det har blivit något fel i ett av fälten, se till att du fyllt i alla obligatoriska fält och försök igen."
+ loading_label : "Laddar..."
+ search_label_text :
+ search_placeholder_text : "Fyll i sökterm..."
+ results_found : "Resultat funna"
+ back_to_top : "Tillbaka till toppen"
+sv-SE:
+ <<: *DEFAULT_SV
+sv-FI:
+ <<: *DEFAULT_SV
+
+# Dutch
+# -----
+nl: &DEFAULT_NL
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Pagina"
+ pagination_previous : "Vorige"
+ pagination_next : "Volgende"
+ breadcrumb_home_label : "Home"
+ breadcrumb_separator : "/"
+ menu_label : "Wissel Menu"
+ search_label :
+ toc_label : "Op deze pagina"
+ ext_link_label : "Directe Link"
+ less_than : "minder dan"
+ minute_read : "minuut gelezen"
+ share_on_label : "Deel op"
+ meta_label :
+ tags_label : "Labels:"
+ categories_label : "Categorieën:"
+ date_label : "Bijgewerkt:"
+ comments_label : "Laat een reactie achter"
+ comments_title : "Commentaren"
+ more_label : "Meer informatie"
+ related_label : "Bekijk ook eens"
+ follow_label : "Volg:"
+ feed_label : "Feed"
+ powered_by : "Aangedreven door"
+ website_label : "Website"
+ email_label : "Email"
+ recent_posts : "Recente berichten"
+ undefined_wpm : "Niet gedefinieerde parameter words_per_minute bij _config.yml"
+ comment_form_info : "Uw e-mailadres wordt niet gepubliceerd. Verplichte velden zijn gemarkeerd"
+ comment_form_comment_label : "Commentaar"
+ comment_form_md_info : "Markdown wordt ondersteund."
+ comment_form_name_label : "Naam"
+ comment_form_email_label : "E-mailadres"
+ comment_form_website_label : "Website (optioneel)"
+ comment_btn_submit : "Commentaar toevoegen"
+ comment_btn_submitted : "Toegevoegd"
+ comment_success_msg : "Bedankt voor uw reactie! Het zal op de site worden weergegeven zodra het is goedgekeurd."
+ comment_error_msg : "Sorry, er is een fout opgetreden bij uw inzending. Zorg ervoor dat alle vereiste velden zijn voltooid en probeer het opnieuw."
+ loading_label : "Laden..."
+ search_label_text : "Geef uw zoekterm in..."
+ search_placeholder_text : "Geef uw zoekterm in..."
+ results_found : "Resultaat gevonden"
+ back_to_top : "Terug naar boven"
+nl-BE:
+ <<: *DEFAULT_NL
+nl-NL:
+ <<: *DEFAULT_NL
+
+# Indonesian
+# ----------
+id: &DEFAULT_ID
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Halaman"
+ pagination_previous : "Kembali"
+ pagination_next : "Maju"
+ breadcrumb_home_label : "Home"
+ breadcrumb_separator : "/"
+ menu_label : "Menu Toggle"
+ search_label :
+ toc_label : "Pada Halaman Ini"
+ ext_link_label : "Link langsung"
+ less_than : "Kurang dari"
+ minute_read : "Waktu baca"
+ share_on_label : "Berbagi di"
+ meta_label :
+ tags_label : "Golongan:"
+ categories_label : "Kategori:"
+ date_label : "Diupdate:"
+ comments_label : "Tinggalkan komentar"
+ comments_title : "Komentar"
+ more_label : "Pelajari lagi"
+ related_label : "Anda juga akan suka"
+ follow_label : "Ikuti:"
+ feed_label : "Feed"
+ powered_by : "Didukung oleh"
+ website_label : "Website"
+ email_label : "Email"
+ recent_posts : "Posting terbaru"
+ undefined_wpm : "Parameter terdeskripsi words_per_minute di _config.yml"
+ comment_form_info : "Email Anda tidak akan dipublish. Kolom yang diperlukan ditandai"
+ comment_form_comment_label : "Komentar"
+ comment_form_md_info : "Markdown disupport."
+ comment_form_name_label : "Nama"
+ comment_form_email_label : "Alamat email"
+ comment_form_website_label : "Website (opsional)"
+ comment_btn_submit : "Submit Komentar"
+ comment_btn_submitted : "Telah disubmit"
+ comment_success_msg : "Terimakasih atas komentar Anda! Komentar ini akan tampil setelah disetujui."
+ comment_error_msg : "Maaf, ada kesalahan pada submisi Anda. Pastikan seluruh kolom sudah dilengkapi dan coba kembali."
+ loading_label : "Sedang meload..."
+ search_label_text :
+id-ID:
+ <<: *DEFAULT_ID
+
+# Vietnamese
+# ----------
+vi: &DEFAULT_VI
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Trang"
+ pagination_previous : "Trước"
+ pagination_next : "Sau"
+ breadcrumb_home_label : "Trang chủ"
+ breadcrumb_separator : "/"
+ menu_label : "Menu"
+ search_label :
+ toc_label : "Tại trang này"
+ ext_link_label : "Đường dẫn trực tiếp"
+ less_than : "nhỏ hơn"
+ minute_read : "phút đọc"
+ share_on_label : "Chia sẻ tại"
+ meta_label :
+ tags_label : "Nhãn:"
+ categories_label : "Chủ đề:"
+ date_label : "Cập nhật:"
+ comments_label : "Để lại bình luận"
+ comments_title : "Bình luận"
+ more_label : "Mở rộng"
+ related_label : "Có thể bạn cũng thích"
+ follow_label : "Theo dõi:"
+ feed_label : "Feed"
+ powered_by : "Được hỗ trợ bởi"
+ website_label : "Website"
+ email_label : "Email"
+ recent_posts : "Bài viết mới"
+ undefined_wpm : "Chưa định nghĩa thông số words_per_minute tại _config.yml"
+ comment_form_info : "Email của bạn sẽ được giữ bí mật. Các phần bắt buộc được đánh dấu"
+ comment_form_comment_label : "Bình luận"
+ comment_form_md_info : "Hỗ trợ Markdown."
+ comment_form_name_label : "Tên"
+ comment_form_email_label : "Địa chỉ email"
+ comment_form_website_label : "Website (không bắt buộc)"
+ comment_btn_submit : "Gửi bình luận"
+ comment_btn_submitted : "Đã được gửi"
+ comment_success_msg : "Cảm ơn bạn đã bình luận! Bình luận sẽ xuất hiện sau khi được duyệt."
+ comment_error_msg : "Rất tiếc, có lỗi trong việc gửi bình luận. Hãy đảm bảo toàn bộ các phần bắt buộc đã được điền đầy đủ và thử lại."
+ loading_label : "Đang tải..."
+ search_label_text :
+ search_placeholder_text : "Nhập từ khóa cần tìm..."
+ results_found : "Kết quả tìm được"
+ back_to_top : "Lên đầu trang"
+vi-VN:
+ <<: *DEFAULT_VI
+
+# Danish
+# ------
+da: &DEFAULT_DA
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Side"
+ pagination_previous : "Forrige"
+ pagination_next : "Næste"
+ breadcrumb_home_label : "Home"
+ breadcrumb_separator : "/"
+ menu_label : "Vis/skjul menu"
+ search_label :
+ toc_label : "På denne side"
+ ext_link_label : "Direkte link"
+ less_than : "mindre end"
+ minute_read : "minutters læsning"
+ share_on_label : "Del på"
+ meta_label :
+ tags_label : "Nøgleord:"
+ categories_label : "Kategorier:"
+ date_label : "Opdateret:"
+ comments_label : "Skriv en kommentar"
+ comments_title : "Kommentarer"
+ more_label : "Lær mere"
+ related_label : "Måske kan du også lide"
+ follow_label : "Følg:"
+ feed_label : "Feed"
+ powered_by : "Drives af"
+ website_label : "Website"
+ email_label : "E-mail"
+ recent_posts : "Seneste indlæg"
+ undefined_wpm : "Parameteren words_per_minute er ikke defineret i _config.yml"
+ comment_form_info : "Din e-mail bliver ikke offentliggjort. Obligatoriske felter er markeret"
+ comment_form_comment_label : "Kommentar"
+ comment_form_md_info : "Markdown er understøttet."
+ comment_form_name_label : "Navn"
+ comment_form_email_label : "E-mail"
+ comment_form_website_label : "Website (frivillig)"
+ comment_btn_submit : "Send kommentar"
+ comment_btn_submitted : "Sendt"
+ comment_success_msg : "Tak for din kommentar! Den bliver vist på siden, så snart den er godkendt."
+ comment_error_msg : "Desværre skete der en fejl. Prøv igen, mens du sørger for at alle obligatoriske felter er udfyldt."
+ loading_label : "Indlæser..."
+ search_label_text :
+ search_placeholder_text : "Hvad leder du efter..."
+ results_found : "Resultat(er) fundet"
+ back_to_top : "Tilbage til toppen"
+da-DK:
+ <<: *DEFAULT_DA
+
+# Polish
+# ------
+pl: &DEFAULT_PL
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Strona"
+ pagination_previous : "Poprzednia"
+ pagination_next : "Następna"
+ breadcrumb_home_label : "Strona główna"
+ breadcrumb_separator : "/"
+ menu_label : "Przełącz menu"
+ search_label :
+ toc_label : "Spis treści"
+ ext_link_label : "Link bezpośredni"
+ less_than : "mniej niż"
+ minute_read : "minut(y)"
+ share_on_label : "Udostępnij"
+ meta_label :
+ tags_label : "Tagi:"
+ categories_label : "Kategorie:"
+ date_label : "Ostatnia aktualizacja:"
+ comments_label : "Zostaw komentarz"
+ comments_title : "Komentarze"
+ more_label : "Dowiedz się więcej"
+ related_label : "Także może Ci się spodobać"
+ follow_label : "Śledź:"
+ feed_label : "Feed"
+ powered_by : "Powstało dzięki"
+ website_label : "Strona"
+ email_label : "Email"
+ recent_posts : "Najnowsze wpisy"
+ undefined_wpm : "Parametr words_per_minute nie został zdefiniowany w _config.yml."
+ comment_form_info : "Twój adres email nie będzie udostępiony. Wymagane pola są oznaczone"
+ comment_form_comment_label : "Skomentuj"
+ comment_form_md_info : "Markdown jest wspierany"
+ comment_form_name_label : "Imię"
+ comment_form_email_label : "Adres email"
+ comment_form_website_label : "Strona www (opcjonalna)"
+ comment_btn_submit : "Skomentuj"
+ comment_btn_submitted : "Komentarz dodany"
+ comment_success_msg : "Dziękuję za Twój komentarz! Zostanie dodany po akceptacji."
+ comment_error_msg : "Niestety wystąpił błąd. Proszę upewnij się, że wszystkie wymagane pola zostały wypełnione i spróbuj ponownie."
+ loading_label : "Trwa ładowanie strony..."
+ search_label_text :
+ posts_older : "Starsze artykuły"
+ posts_newer : "Nowsze artykuły"
+ back_to_top : "Wróc do góry"
+ go_to_comments : "Idź do komentarzy"
+ go_to_post : "Idź do artykułu"
+pl-PL:
+ <<: *DEFAULT_PL
+
+# Japanese
+# --------
+ja: &DEFAULT_JA
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "ページ"
+ pagination_previous : "前へ"
+ pagination_next : "次へ"
+ breadcrumb_home_label : "ホーム"
+ breadcrumb_separator : "/"
+ menu_label : "メニュー"
+ search_label :
+ toc_label : "目次"
+ ext_link_label : "リンク"
+ less_than :
+ minute_read :
+ share_on_label : "共有"
+ meta_label :
+ tags_label : "タグ:"
+ categories_label : "カテゴリー:"
+ date_label : "更新日時:"
+ comments_label : "コメントする"
+ comments_title : "コメント"
+ more_label : "さらに詳しく"
+ related_label : "関連記事"
+ follow_label : "フォロー"
+ feed_label :
+ powered_by :
+ website_label :
+ email_label :
+ recent_posts : "最近の投稿"
+ undefined_wpm : "パラメータ words_per_minute が _config.yml で定義されていません"
+ comment_form_info : "メールアドレスが公開されることはありません。次の印のある項目は必ず入力してください:"
+ comment_form_comment_label : "コメント"
+ comment_form_md_info : "Markdown を使用できます"
+ comment_form_name_label : "名前"
+ comment_form_email_label : "メールアドレス"
+ comment_form_website_label : "URL (任意)"
+ comment_btn_submit : "コメントを送信する"
+ comment_btn_submitted : "送信しました"
+ comment_success_msg : "コメントありがとうございます! コメントは承認されるとページに表示されます。"
+ comment_error_msg : "送信エラーです。必須項目がすべて入力されていることを確認して再送信してください。"
+ loading_label : "読み込み中..."
+ search_label_text :
+ search_placeholder_text : "検索キーワードを入力してください..."
+ results_found : "件"
+ja-JP:
+ <<: *DEFAULT_JA
+
+# Slovak
+# -----------------
+sk: &DEFAULT_SK
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Stránka"
+ pagination_previous : "Predošlá"
+ pagination_next : "Ďalšia"
+ breadcrumb_home_label : "Domov"
+ breadcrumb_separator : "/"
+ menu_label : "Menu"
+ search_label :
+ toc_label : "Obsah"
+ ext_link_label : "Priamy odkaz"
+ less_than : "menej ako"
+ minute_read : "minút"
+ share_on_label : "Zdieľaj na"
+ meta_label :
+ tags_label : "Tagy:"
+ categories_label : "Kategórie:"
+ date_label : "Aktualizované:"
+ comments_label : "Zanechaj odkaz"
+ comments_title : "Komentáre"
+ more_label : "Dozvedieť sa viac"
+ related_label : "Podobné články"
+ follow_label : "Sleduj:"
+ feed_label : "Zoznam"
+ powered_by : "Stránka vytvorená pomocou"
+ website_label : "Web stránka"
+ email_label : "Email"
+ recent_posts : "Najnovšie príspevky"
+ undefined_wpm : "Nedefinovaný parameter words_per_minute v _config.yml"
+ comment_form_info : "Tvoja emailová adresa nebude publikovaná. Požadované polia sú označené"
+ comment_form_comment_label : "Komentár"
+ comment_form_md_info : "Markdown je podporovaný."
+ comment_form_name_label : "Meno"
+ comment_form_email_label : "Emailová adresa"
+ comment_form_website_label : "Webstránka (voliteľné)"
+ comment_btn_submit : "Vlož komentár"
+ comment_btn_submitted : "Vložený"
+ comment_success_msg : "Ďakujem za tvoj komentár! Po schválení bude zobrazený na stránke."
+ comment_error_msg : "Prepáč, pri ukladaní nastala chyba. Ubezpeč sa prosím, že si vyplnil všetky požadované polia a skús znova."
+ loading_label : "Načítava sa..."
+ search_label_text :
+ search_placeholder_text : "Zadaj hľadaný výraz..."
+ results_found : "Nájdených výsledkov"
+ back_to_top : "Na začiatok stránky"
+sk-SK:
+ <<: *DEFAULT_SK
+
+# Hungarian
+# -----------------
+hu: &DEFAULT_HU
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Oldal"
+ pagination_previous : "Előző"
+ pagination_next : "Következő"
+ breadcrumb_home_label : "Kezdőlap"
+ breadcrumb_separator : "/"
+ menu_label : "Menü nyit/zár"
+ search_label :
+ toc_label : "Ezen az oldalon"
+ ext_link_label : "Közvetlen Link"
+ less_than : "kevesebb mint"
+ minute_read : "eltöltött percek"
+ share_on_label : "Megosztás"
+ meta_label :
+ tags_label : "Tagek:"
+ categories_label : "Kategóriák:"
+ date_label : "Frissítve:"
+ comments_label : "Szólj hozzá!"
+ comments_title : "Hozzászólások"
+ more_label : "Tovább"
+ related_label : "Ajánlások"
+ follow_label : "Követés:"
+ feed_label : "Folyam"
+ powered_by : "Powered by"
+ website_label : "Honlap"
+ email_label : "Email"
+ recent_posts : "Friss cikkek"
+ undefined_wpm : "Ismeretlen paraméter words_per_minute : _config.yml"
+ comment_form_info : "Az e-mail címed nem lesz publikus. A csillagozott mezők kitöltése kötelező"
+ comment_form_comment_label : "Hozzászólás"
+ comment_form_md_info : "Támogatott formázási mód: Markdown"
+ comment_form_name_label : "Név"
+ comment_form_email_label : "Email cím"
+ comment_form_website_label : "Honlap (nem kötelező):"
+ comment_btn_submit : "Hozzászólás elküldése"
+ comment_btn_submitted : "Hozzászólás elküldve"
+ comment_success_msg : "Köszönjük a Hozzászólást! A Hozzászólások csak előzetes moderáció után lesznek publikusak."
+ comment_error_msg : "Hoppá, hiba történt a beküldés közben. Kérlek ellenőrizd hogy minden kötelező mező ki van-e töltve."
+ loading_label : "Betöltés..."
+ search_label_text :
+ search_placeholder_text : "Keresendő szöveg..."
+ results_found : "Találatok:"
+ back_to_top : "Oldal tetejére"
+hu-HU:
+ <<: *DEFAULT_HU
+
+# Romanian
+# -----------------
+ro: &DEFAULT_RO
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "Pagina"
+ pagination_previous : "Anterior"
+ pagination_next : "Următor"
+ breadcrumb_home_label : "Acasă"
+ breadcrumb_separator : "/"
+ menu_label : "Comută meniul"
+ search_label :
+ toc_label : "Pe această pagină"
+ ext_link_label : "Link direct"
+ less_than : "mai puțin de"
+ minute_read : "minute de citit"
+ share_on_label : "Distribuie pe"
+ meta_label :
+ tags_label : "Etichete:"
+ categories_label : "Categorii:"
+ date_label : "Actualizat:"
+ comments_label : "Lasă un comentariu"
+ comments_title : "Comentarii"
+ more_label : "Citește mai departe"
+ related_label : "S-ar putea să-ți placă"
+ follow_label : "Urmărește:"
+ feed_label : "Feed RSS"
+ powered_by : "Cu sprijinul"
+ website_label : "Site"
+ email_label : "Email"
+ recent_posts : "Articole recente"
+ undefined_wpm : "Parametru words_per_minute nedefinit în _config.yml"
+ comment_form_info : "Adresa ta de email nu va fi făcută publică. Câmpurile marcate sunt obligatorii"
+ comment_form_comment_label : "Comentariu"
+ comment_form_md_info : "Markdown este suportat."
+ comment_form_name_label : "Nume"
+ comment_form_email_label : "Adresă de email"
+ comment_form_website_label : "Site (opțional)"
+ comment_btn_submit : "Trimite comentariul"
+ comment_btn_submitted : "Trimis"
+ comment_success_msg : "Mulțumesc pentru comentariu! Va apărea pe site în momentul în care va fi aprobat."
+ comment_error_msg : "Scuze, este o problemă cu comentariul tău. Asigură-te că toate câmpurile obligatorii au fost completate și încearcă din nou."
+ loading_label : "Se încarcă..."
+ search_label_text :
+ search_placeholder_text : "Caută ceva..."
+ results_found : "Rezultate găsite"
+ back_to_top : "Înapoi în susul paginii"
+ro-RO:
+ <<: *DEFAULT_RO
+
+# Punjabi
+# -----------------
+pa: &DEFAULT_PA
+ skip_links : "ਲਿੰਕ ਛੱਡੋ"
+ skip_primary_nav : "ਮੂਲ ਮਾਰਗ ਛੱਡੋ"
+ skip_content : "ਸਮੱਗਰੀ ਛੱਡੋ"
+ skip_footer : "ਅੰਤ ਵਿਚ ਲਿਖਿਆ ਛੱਡੋ"
+ page : "ਸਫ਼ਾ"
+ pagination_previous : "ਪਿਛਲਾ"
+ pagination_next : "ਅਗਲਾ "
+ breadcrumb_home_label : "ਘਰ"
+ breadcrumb_separator : "/"
+ menu_label : "ਟੌਗਲ ਮੀਨੂ"
+ search_label : "ਖੋਜ"
+ toc_label : "ਇਸ ਸਫ਼ੇ 'ਤੇ"
+ ext_link_label : "ਸਿੱਧਾ ਸੰਪਰਕ"
+ less_than : "ਤੋਂ ਘੱਟ"
+ minute_read : "ਮਿੰਟ ਵਿੱਚ ਪੜਿਆ ਜਾ ਸਕਦਾ ਹੈ"
+ share_on_label : "ਸਾਂਝਾ ਕਰੋ"
+ meta_label : "ਸਵੈ-ਸੰਦਰਭ ਜਾਣਕਾਰੀ"
+ tags_label : "ਟੈਗ"
+ categories_label : "ਵਰਗ"
+ date_label : "ਅਪਡੇਟ ਕੀਤਾ:"
+ comments_label : "ਇੱਕ ਟਿੱਪਣੀ ਛੱਡੋ"
+ comments_title : "ਟਿੱਪਣੀਆਂ"
+ more_label : "ਹੋਰ ਜਾਣੋ"
+ related_label : "ਤੁਸੀਂ ਇਸਦਾ ਆਨੰਦ ਵੀ ਲੈ ਸਕਦੇ ਹੋ"
+ follow_label : "ਫਾਲੋ ਅੱਪ ਕਰੋ:"
+ feed_label : "ਫੀਡ"
+ powered_by : "ਦੁਆਰਾ ਸੰਚਾਲਿਤ"
+ website_label : "ਵੈੱਬਸਾਇਟ"
+ email_label : "ਈਮੇਲ"
+ recent_posts : "ਹਾਲ ਹੀ ਦੇ ਪੋਸਟ"
+ undefined_wpm : "_config.yml ਤੇ ਅਣ-ਪ੍ਰਭਾਸ਼ਿਤ ਪੈਰਾਮੀਟਰ words_per_minute"
+ comment_form_info : "ਤੁਹਾਡਾ ਈਮੇਲ ਪਤਾ ਪ੍ਰਕਾਸ਼ਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ। ਅਨੁਮਾਨਿਤ ਸਥਾਨਾਂ ਨੂੰ ਅੰਡਰਲਾਈਨ ਕੀਤਾ ਗਿਆ ਹੈ"
+ comment_form_comment_label : "ਟਿੱਪਣੀ"
+ comment_form_md_info : "ਮਾਰਕਡਾਊਨ ਵਰਤ ਸਕਦੇ ਹੋ।"
+ comment_form_name_label : "ਨਾਮ"
+ comment_form_email_label : "ਈਮੇਲ ਪਤਾ"
+ comment_form_website_label : "ਵੈਬਸਾਈਟ (ਵਿਕਲਪਿਕ)"
+ comment_btn_submit : "ਕੋਈ ਟਿੱਪਣੀ ਭੇਜੋ"
+ comment_btn_submitted : "ਪੇਸ਼ ਕੀਤਾ"
+ comment_success_msg : "ਤੁਹਾਡੀਆਂ ਟਿੱਪਣੀਆਂ ਲਈ ਧੰਨਵਾਦ! ਇਹ ਮਨਜ਼ੂਰੀ ਮਿਲਣ ਦੇ ਬਾਅਦ ਸਾਈਟ 'ਤੇ ਦਿਖਾਇਆ ਜਾਵੇਗਾ।"
+ comment_error_msg : "ਮੁਆਫ ਕਰਨਾ, ਤੁਹਾਡੀ ਅਧੀਨਗੀ ਵਿੱਚ ਕੋਈ ਗਲਤੀ ਹੋਈ ਸੀ ਕਿਰਪਾ ਕਰਕੇ ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਸਾਰੇ ਲੋੜੀਂਦੇ ਖੇਤਰ ਪੂਰੇ ਹੋ ਗਏ ਹਨ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"
+ loading_label : "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ..."
+ search_label_text : "ਖੋਜ"
+ search_placeholder_text : "ਆਪਣੀ ਖੋਜ ਦੇ ਸ਼ਬਦ ਨੂੰ ਦਰਜ ਕਰੋ..."
+ results_found : "ਨਤੀਜਾ ਮਿਲਿਆ/ਮਿਲੇ"
+ back_to_top : "ਵਾਪਸ ਚੋਟੀ 'ਤੇ ਜਾਓ"
+pa-IN:
+ <<: *DEFAULT_PA
+
+# Persian (Farsi)
+# --------------
+fa: &DEFAULT_FA
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "صفحه"
+ pagination_previous : "قبلی"
+ pagination_next : "بعدی"
+ breadcrumb_home_label : "صفحه اصلی"
+ breadcrumb_separator : "/"
+ menu_label : "فهرست"
+ toc_label : "در این صفحه"
+ ext_link_label : "لینک مستقیم"
+ less_than : " "
+ minute_read : "(طول مطالعه (دقیقه"
+ share_on_label : "اشتراک گذاری در"
+ meta_label :
+ tags_label : "تگ ها: "
+ categories_label : "دسته بندی ها: "
+ date_label : "به روز شده در: "
+ comments_label : "ارسال نظر"
+ comments_title : "نظرات"
+ more_label : "ادامه مطلب"
+ related_label : "ممکن است از این مطالب نیز لذت ببرید"
+ follow_label : "دنبال کنید: "
+ feed_label : "خوراک"
+ powered_by : "طراحی شده توسط"
+ website_label : "سایت اینترنتی"
+ email_label : "پست الکترونیک"
+ recent_posts : "آخرین مطالب"
+ undefined_wpm : ".(words_per_minute) _config.yml متغیر اشتباه در"
+ comment_form_info : ".آدرس ایمیل شما منتشر نخواهد شد. فیلدهای اجباری مشخص شده اند"
+ comment_form_comment_label : "دیدگاه"
+ comment_form_md_info : ".پشتیبانی می شود Markdown"
+ comment_form_name_label : "نام"
+ comment_form_email_label : "پست الکترونیک"
+ comment_form_website_label : "سایت اینترنتی (اختیاری)"
+ comment_btn_submit : "ارسال نظر"
+ comment_btn_submitted : "ارسال شد"
+ comment_success_msg : ".باتشکر از ارسال دیدگاه! پس از تأیید، این دیدگاه در سایت نشان داده خواهد شد"
+ comment_error_msg : ".متاسفانه در ارسال شما خطایی بود. لطفا مطمئن شوید تمام فیلدهای مورد نیاز تکمیل شده و دوباره امتحان کنید"
+ loading_label : "...بارگذاری"
+ search_label_text :
+ search_placeholder_text : "...عبارت جستجوی خود را وارد کنید"
+ results_found : "نتایج"
+ back_to_top : "بازگشت به بالا"
+fa-IR:
+ <<: *DEFAULT_FA
+
+
+# Malayalam
+# -----------------
+ml: &DEFAULT_ML
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "പേജ്"
+ pagination_previous : "തിരികെ"
+ pagination_next : "മുന്നോട്ട്"
+ breadcrumb_home_label : "ഹോം"
+ breadcrumb_separator : "/"
+ menu_label : "ടോഗിൾ മെനു"
+ search_label : "ടോഗിൾ സെർച്ച്"
+ toc_label : "ഈ പേജിൽ"
+ ext_link_label : "ലിങ്കിലേക് പോകാൻ"
+ less_than : "ഏതാണ്ട്"
+ minute_read : "മിനിറ്റ് ദൈർഖ്യം"
+ share_on_label : "ഷെയർ ചെയ്യുവാൻ "
+ meta_label :
+ tags_label : "ടാഗുകൾ:"
+ categories_label : "വിഭാഗങ്ങൾ:"
+ date_label : "അവസാന മാറ്റം:"
+ comments_label : "അഭിപ്രായം രേഖപ്പെടുത്തുക"
+ comments_title : "അഭിപ്രായങ്ങൾ"
+ more_label : "കൂടുതൽ അറിയുവാൻ"
+ related_label : "നിങ്ങൾക് ഇതും ഇഷ്ടപ്പെട്ടേക്കാം"
+ follow_label : "പിന്തുടരുക:"
+ feed_label : "ഫീഡ്"
+ powered_by : "പവേർഡ് ബൈ"
+ website_label : "വെബ്സൈറ്റ്"
+ email_label : "ഇ-മെയിൽ"
+ recent_posts : "സമീപകാല പോസ്റ്റുകൾ"
+ undefined_wpm : "Config.yml ലെ words_per_minute പരാമീറ്റർ നിർവചിച്ചിട്ടില്ല."
+ comment_form_info : "നിങ്ങളുടെ ഇമെയിൽ വിലാസം പ്രസിദ്ധീകരിക്കില്ല. ആവശ്യമായ ഫീൽഡുകൾ അടയാളപ്പെടുത്തി."
+ comment_form_comment_label : "കമന്റ്"
+ comment_form_md_info : "Markdown സപ്പോർട്ട് ചെയ്യുന്നതാണ്."
+ comment_form_name_label : "പേര്"
+ comment_form_email_label : "ഇ-മെയിൽ"
+ comment_form_website_label : "വെബ്സൈറ് (ഓപ്ഷണൽ)"
+ comment_btn_submit : "അഭിപ്രായം രേഖപ്പെടുത്തുക"
+ comment_btn_submitted : "രേഖപ്പെടുത്തി"
+ comment_success_msg : "നിങ്ങളുടെ അഭിപ്രായത്തിന് നന്ദി! ഇത് അംഗീകരിച്ചുകഴിഞ്ഞാൽ ഇത് സൈറ്റിൽ പ്രദർശിപ്പിക്കും."
+ comment_error_msg : "ക്ഷമിക്കണം, നിങ്ങളുടെ സമർപ്പണവുമായി ബന്ധപ്പെട്ട് ഒരു പിശകുണ്ടായിരുന്നു. ആവശ്യമായ എല്ലാ ഫീൽഡുകളും പൂർത്തിയായിട്ടുണ്ടെന്ന് ഉറപ്പുവരുത്തുക, വീണ്ടും ശ്രമിക്കുക."
+ loading_label : "ലോഡിംഗ്..."
+ search_label_text :
+ search_placeholder_text : "നിങ്ങളുടെ തിരയൽ പദം നൽകുക..."
+ results_found : "ഫലം (കൾ) കണ്ടെത്തി"
+ back_to_top : "മുകളിലേയ്ക്ക്"
+ml-IN:
+ <<: *DEFAULT_ML
+
+# Thailand
+# --------------
+th: &DEFAULT_TH
+ skip_links :
+ skip_primary_nav :
+ skip_content :
+ skip_footer :
+ page : "หน้า"
+ pagination_previous : "ก่อนหน้า"
+ pagination_next : "ถัดไป"
+ breadcrumb_home_label : "หน้าแรก"
+ breadcrumb_separator : "/"
+ menu_label : "พับเมนู"
+ search_label : "พับการค้นหา"
+ toc_label : "บนหน้านี้"
+ ext_link_label : "ลิงก์โดยตรง"
+ less_than : "น้อยกว่า"
+ minute_read : "นาที ในการอ่าน"
+ share_on_label : "แชร์ไปที่"
+ meta_label :
+ tags_label : "แท็ก:"
+ categories_label : "หมวดหมู่:"
+ date_label : "อัพเดตล่าสุด:"
+ comments_label : "แสดงความคิดเห็น"
+ comments_title : "ความคิดเห็น"
+ more_label : "อ่านต่อ"
+ related_label : "คุณอาจจะชอบสิ่งนี้"
+ follow_label : "ติดตาม:"
+ feed_label : "ฟืดข่าว"
+ powered_by : "ขับเคลื่อนโดย"
+ website_label : "เว็บไซต์"
+ email_label : "อีเมล"
+ recent_posts : "โพสล่าสุด"
+ undefined_wpm : "ไม่สามารถระบุพารามิเตอร์ words_per_minute ได้ใน _config.yml"
+ comment_form_info : "อีเมลของคุณไม่สามารถโพสสาธารณะได้ กรุณากรอกช่องที่ระบุด้วยเครื่องหมายดอกจันไว้"
+ comment_form_comment_label : "แสดงความคิดเห็น"
+ comment_form_md_info : "มาร์กดาวน์ได้รับการสนับสนุน"
+ comment_form_name_label : "ชื่อ"
+ comment_form_email_label : "ที่อยู่อีเมล"
+ comment_form_website_label : "เว็บไซต์ (ตัวเลือก)"
+ comment_btn_submit : "ส่งความคิดเห็น"
+ comment_btn_submitted : "ส่งเรียบร้อยแล้ว"
+ comment_success_msg : "ขอบคุณสำหรับการแสดงความคิดเห็น! ความคิดเห็นจะได้รับการแสดงหลังจากได้รับการยืนยัน"
+ comment_error_msg : "ขออภัย, มีบางอย่างผิดพลาดจากการส่งแบบฟอร์ม กรุณาตรวจทานทุกช่อง และลองส่งใหม่อีกครั้ง"
+ loading_label : "กำลังโหลด..."
+ search_label_text :
+ search_placeholder_text : "ใส่คำค้นหาของคุณ..."
+ results_found : "ผลการค้นหา พบ"
+ back_to_top : "กลับด้านบน"
+th-TH:
+ <<: *DEFAULT_TH
+
+# Hindi
+# -----------------
+hi: &DEFAULT_HI
+ skip_links : "लिंक छोड़ें"
+ skip_primary_nav : "प्राथमिक पथ-प्रदर्शन छोड़ें"
+ skip_content : "सामग्री छोड़ें"
+ skip_footer : "अंत-में लिखा छोड़ें"
+ page : "पृष्ठ"
+ pagination_previous : "पिछला"
+ pagination_next : "अगला"
+ breadcrumb_home_label : "घर"
+ breadcrumb_separator : "/"
+ menu_label : "टॉगल मेनू"
+ toc_label : "इस पृष्ठ पर"
+ ext_link_label : "सीधा संपर्क"
+ less_than : "से कम"
+ minute_read : "मिनट में पढ़ सकते हैं"
+ share_on_label : "साझा करें"
+ meta_label : "स्व-संदर्भात्मक जानकारी"
+ tags_label : "अंकितक:"
+ categories_label : "श्रेणियाँ:"
+ date_label : "अपडेट किया गया:"
+ comments_label : "एक टिप्पणी छोड़ें"
+ comments_title : "टिप्पणियाँ"
+ more_label : "और अधिक जानें"
+ related_label : "आप इसका भी आनंद ले सकते हैं"
+ follow_label : "अनुसरण करे:"
+ feed_label : "फ़ीड"
+ powered_by : "द्वारा संचालित"
+ website_label : "वेबसाइट"
+ email_label : "ईमेल"
+ recent_posts : "हाल के पोस्ट"
+ undefined_wpm : "_config.yml पर अपरिभाषित पैरामीटर words_per_minute"
+ comment_form_info : "आपका ईमेल पता प्रकाशित नहीं किया जाएगा। अपेक्षित स्थानों को रेखांकित कर दिया गया है"
+ comment_form_comment_label : "टिप्पणी"
+ comment_form_md_info : "मार्कडाउन की अनुमति है।"
+ comment_form_name_label : "नाम"
+ comment_form_email_label : "ईमेल पता"
+ comment_form_website_label : "वेबसाइट (ऐच्छिक)"
+ comment_btn_submit : "टिप्पणी भेजें"
+ comment_btn_submitted : "प्रस्तुत"
+ comment_success_msg : "आपके कमेंट के लिए धन्यवाद! इसे स्वीकृति मिलने के बाद साइट पर दिखाया जाएगा।"
+ comment_error_msg : "क्षमा करें, आपके सबमिशन के साथ एक त्रुटि हुई थी। कृपया सुनिश्चित करें कि सभी आवश्यक फ़ील्ड पूरा हो गए हैं और पुनः प्रयास करें।"
+ loading_label : "लोड हो रहा है..."
+ search_label_text : "खोज"
+ search_placeholder_text : "अपना खोज शब्द दर्ज करें..."
+ results_found : "परिणाम मिला/मिले"
+ back_to_top : "शीर्ष पर वापस"
+hi-IN:
+ <<: *DEFAULT_HI
+
+# Catalan
+# --------------
+ca: &DEFAULT_CA
+ skip_links : "Salta els enllaços"
+ skip_primary_nav : "Salta a la navegació primària"
+ skip_content : "Salta al contingut"
+ skip_footer : "Salta al peu"
+ page : "Pàgina"
+ pagination_previous : "Anterior"
+ pagination_next : "Següent"
+ breadcrumb_home_label : "Inici"
+ breadcrumb_separator : "/"
+ menu_label : "Mostra/amaga el menú"
+ search_label : "Mostra/amaga la cerca"
+ toc_label : "En aquesta pàgina"
+ ext_link_label : "Enllaç directe"
+ less_than : "es llegeix en menys de"
+ minute_read : "minut(s)"
+ share_on_label : "Comparteix a"
+ meta_label :
+ tags_label : "Etiquetes:"
+ categories_label : "Categories:"
+ date_label : "Actualitzat:"
+ comments_label : "Deixa un comentari"
+ comments_title : "Comentaris"
+ more_label : "Llegeix més"
+ related_label : "També et pot agradar"
+ follow_label : "Segueix-me:"
+ feed_label : "Feed"
+ powered_by : "Funciona amb"
+ website_label : "Pàgina web"
+ email_label : "Correu electrònic"
+ recent_posts : "Entrades recents"
+ undefined_wpm : "El paràmetre words_per_minute no està definit a _config.yml"
+ comment_form_info : "No es mostrarà el teu correu electrònic. Els camps obligatoris estan marcats"
+ comment_form_comment_label : "Comentari"
+ comment_form_md_info : "Admet Markdown."
+ comment_form_name_label : "Nom"
+ comment_form_email_label : "Correu electrònic"
+ comment_form_website_label : "Pàgina web (opcional)"
+ comment_btn_submit : "Envia"
+ comment_btn_submitted : "Enviat"
+ comment_success_msg : "Gràcies pel teu comentari! Apareixerà un cop sigui aprovat."
+ comment_error_msg : "Hi ha hagut un error enviat el comentari. Comprova que els camps obligatirs estiguin omplerts i torna-ho a provar."
+ loading_label : "Carregant..."
+ search_label_text : "Introdueix termes per cercar..."
+ search_placeholder_text : "Introdueix termes per cercar..."
+ results_found : "resultat(s)"
+ back_to_top : "Torna a dalt"
+ca-ES:
+ <<: *DEFAULT_CA
+
+# Another locale
+# --------------
+#
diff --git a/_pages/about.html b/_pages/about.html
new file mode 100644
index 00000000..ff4d0da1
--- /dev/null
+++ b/_pages/about.html
@@ -0,0 +1,26 @@
+---
+layout: page
+title: O autorze
+permalink: /about/
+description: O autorze
+---
+
+
+ Backend Developer.
+ Jestem szczęśliwym Backend Developer ponieważ istnieją Frontendowcy, którzy piszą za mnie front.
+ Programuję komercyjnie od 2012 roku, głownie w Javie i Scali.
+ Epizodycznie w językach Kotlin , Perl , PL/Perl, PL/pgSQL, Lua i Bash
+ oraz hobbistyczne w językach Haskell , Scala
+ i Scheme /Racket ,
+ a kiedyś w - Perl i TCL .
+ O językach Rust i Clojure na razie tylko czytam, bo doba jest za krótka.
+
+
+
+ Pracuję głównie przy aplikacjach webowych we frameworkach takich jak zbyt magiczny Spring (Spring MVC, Spring Boot), DropWizard oraz Akka-Http,
+ a chciałbym jeszcze poznać ZIO-WEB i http4s.
+
+
+
+ Moim hobby jest programowanie czysto funkcyjne i pisanie parserów.
+
diff --git a/_pages/about.md b/_pages/about.md
deleted file mode 100644
index 9ba0655c..00000000
--- a/_pages/about.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-permalink: /about/
-title: "About"
----
-
-Tempor velit sint sunt ipsum tempor enim ad qui ullamco. Est dolore anim ad velit duis dolore minim sunt aliquip amet commodo labore. Ut eu pariatur aute ea aute excepteur laborum. Esse ea esse excepteur minim mollit qui cillum excepteur ex dolore magna. Labore deserunt fugiat incididunt incididunt sint ea. Consequat dolore aute laboris quis proident quis non et est consectetur ex eiusmod sit culpa.
-
-Cupidatat ea do et in excepteur in. Ad nostrud ut est esse eu duis ea sunt eiusmod. Aliquip tempor veniam sint elit fugiat. Velit incididunt laboris amet incididunt labore dolore irure velit excepteur commodo deserunt laborum. Consectetur eu fugiat veniam veniam Lorem labore magna eiusmod. Ea occaecat reprehenderit pariatur consectetur minim labore ut aliquip.
\ No newline at end of file
diff --git a/_pages/archive-categories.html b/_pages/archive-categories.html
new file mode 100644
index 00000000..645e9516
--- /dev/null
+++ b/_pages/archive-categories.html
@@ -0,0 +1,6 @@
+---
+title: "Artykuły po kategoriach"
+layout: archive-categories
+permalink: /categories/
+collections: categories
+---
diff --git a/_pages/archive-eso.html b/_pages/archive-eso.html
new file mode 100644
index 00000000..4ba33e70
--- /dev/null
+++ b/_pages/archive-eso.html
@@ -0,0 +1,6 @@
+---
+title: "Artykuły po eso"
+layout: archive-eso
+permalink: /eso/
+collections: eso
+---
diff --git a/_pages/archive-langs.html b/_pages/archive-langs.html
new file mode 100644
index 00000000..b08a0314
--- /dev/null
+++ b/_pages/archive-langs.html
@@ -0,0 +1,6 @@
+---
+title: "Artykuły po językach programowania"
+layout: archive-langs
+permalink: /langs/
+collection: langs
+---
diff --git a/_pages/archive-libs.html b/_pages/archive-libs.html
new file mode 100644
index 00000000..e762c2d6
--- /dev/null
+++ b/_pages/archive-libs.html
@@ -0,0 +1,6 @@
+---
+title: "Artykuły po bibliotekach programistycznych"
+layout: archive-libs
+permalink: /libs/
+collection: libs
+---
diff --git a/_pages/archive-projects.html b/_pages/archive-projects.html
new file mode 100644
index 00000000..e6829e5f
--- /dev/null
+++ b/_pages/archive-projects.html
@@ -0,0 +1,6 @@
+---
+title: "Artykuły po projektach"
+layout: archive-projects
+permalink: /projects/
+collection: projects
+---
diff --git a/_pages/archive-tags.html b/_pages/archive-tags.html
new file mode 100644
index 00000000..51ad1e0e
--- /dev/null
+++ b/_pages/archive-tags.html
@@ -0,0 +1,6 @@
+---
+title: "Artykuły po tagach"
+layout: archive-tags
+permalink: /tags/
+collections: tags
+---
diff --git a/_pages/archive-tools.html b/_pages/archive-tools.html
new file mode 100644
index 00000000..77a6fd64
--- /dev/null
+++ b/_pages/archive-tools.html
@@ -0,0 +1,6 @@
+---
+title: "Artykuły po narzędziach programistycznych"
+layout: archive-tools
+permalink: /tools/
+collection: tools
+---
diff --git a/_pages/archive-years.html b/_pages/archive-years.html
new file mode 100644
index 00000000..2114ef69
--- /dev/null
+++ b/_pages/archive-years.html
@@ -0,0 +1,5 @@
+---
+title: "Artykuły po roku"
+layout: posts
+permalink: /posts/
+---
diff --git a/_pages/category-archive.md b/_pages/category-archive.md
deleted file mode 100644
index 4cb3860e..00000000
--- a/_pages/category-archive.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: "Posts by Category"
-layout: categories
-permalink: /categories/
-author_profile: true
----
diff --git a/_pages/privacy.html b/_pages/privacy.html
new file mode 100644
index 00000000..56883d31
--- /dev/null
+++ b/_pages/privacy.html
@@ -0,0 +1,21 @@
+---
+layout : page
+title : Polityka prywatności
+description: Polityka prywatności plików cookies
+permalink : /privacy/
+---
+
+
+ Blog, o języku programowania Scala, WriteOnly.pl przechowuje pliki cookies (tzw. ciasteczka) są używane przez:
+
+ Google Analytics
+ do poprawego analizowania ruchu strony
+ Disqus
+ do obsługi komentarzy
+ WriteOnly.pl
+ po to żeby za każdym razem nie wyświetlać informacji o plikach cookies.
+
+
+
+
Pokaż ostrzeżenie
+
diff --git a/_pages/read-books.html b/_pages/read-books.html
new file mode 100644
index 00000000..059318fd
--- /dev/null
+++ b/_pages/read-books.html
@@ -0,0 +1,25 @@
+---
+layout: page
+title: Przeczytane książki
+permalink: /books/
+description: Przeczytane książki programistyczne
+---
+
+
+ {% assign books = site.books | reverse | sort: "year-of-publishment"| reverse %}
+ {% for book in books %}
+
+
+ {{ book.title }}
+
+
+
+
+ Autorzy: {{ book.authors | join: ", "}}
+ Tytuł oryginalny: {{ book.title-of-original }}
+ Rok pierwszego wydania: {{ book.year-of-publishment }}
+
+
+ {% endfor %}
+
+
diff --git a/_pages/search-jekyll-simple.html b/_pages/search-jekyll-simple.html
new file mode 100644
index 00000000..3ae791f2
--- /dev/null
+++ b/_pages/search-jekyll-simple.html
@@ -0,0 +1,10 @@
+---
+layout: search
+title: Wyszukiwarka Jekyll prosta
+permalink: /search-jekyll-simple/
+description: Wyszukiwarka artykułów
+power_supply_url: "https://github.com/christian-fei/Simple-Jekyll-Search"
+power_supply_label: "Simple-Jekyll-Search"
+---
+
+
diff --git a/_pages/search-jekyll.html b/_pages/search-jekyll.html
new file mode 100644
index 00000000..65bcb44e
--- /dev/null
+++ b/_pages/search-jekyll.html
@@ -0,0 +1,11 @@
+---
+layout: search
+title: Wyszukiwarka Jekyll
+permalink: /search-jekyll/
+description: Wyszukiwarka artykułów
+power_supply_url: "https://github.com/daviddarnes/jekyll-search-js"
+power_supply_label: "jekyll-search-js"
+---
+
+
+
diff --git a/_pages/tag-archive.md b/_pages/tag-archive.md
deleted file mode 100644
index 3f4e3f0d..00000000
--- a/_pages/tag-archive.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: "Posts by Tag"
-permalink: /tags/
-layout: tags
-author_profile: true
----
diff --git a/_pages/textarea.html b/_pages/textarea.html
new file mode 100644
index 00000000..e195d2f1
--- /dev/null
+++ b/_pages/textarea.html
@@ -0,0 +1,20 @@
+---
+layout: page
+title: The TextArea
+permalink: /textarea/
+description: The Text Area
+---
+
+
+
+
+
diff --git a/_pages/year-archive.md b/_pages/year-archive.md
deleted file mode 100644
index ce3413fc..00000000
--- a/_pages/year-archive.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: "Posts by Year"
-permalink: /posts/
-layout: posts
-author_profile: true
----
diff --git a/assets/android-chrome-192x192.png b/assets/android-chrome-192x192.png
new file mode 100644
index 00000000..b7145895
Binary files /dev/null and b/assets/android-chrome-192x192.png differ
diff --git a/assets/android-chrome-512x512.png b/assets/android-chrome-512x512.png
new file mode 100644
index 00000000..6df5b7fc
Binary files /dev/null and b/assets/android-chrome-512x512.png differ
diff --git a/assets/apple-touch-icon.png b/assets/apple-touch-icon.png
new file mode 100644
index 00000000..6dbed03e
Binary files /dev/null and b/assets/apple-touch-icon.png differ
diff --git a/assets/favicon-16x16.png b/assets/favicon-16x16.png
new file mode 100644
index 00000000..eb04e686
Binary files /dev/null and b/assets/favicon-16x16.png differ
diff --git a/assets/favicon-32x32.png b/assets/favicon-32x32.png
new file mode 100644
index 00000000..c86a5790
Binary files /dev/null and b/assets/favicon-32x32.png differ
diff --git a/assets/favicon.ico b/assets/favicon.ico
new file mode 100644
index 00000000..c57b5709
Binary files /dev/null and b/assets/favicon.ico differ
diff --git a/assets/images/bio-photo.jpg b/assets/images/bio-photo.jpg
deleted file mode 100644
index 00084517..00000000
Binary files a/assets/images/bio-photo.jpg and /dev/null differ
diff --git a/assets/images/kamil.adam.jpg b/assets/images/kamil.adam.jpg
new file mode 100644
index 00000000..db8a5ea1
Binary files /dev/null and b/assets/images/kamil.adam.jpg differ
diff --git a/assets/site.webmanifest b/assets/site.webmanifest
new file mode 100644
index 00000000..45dc8a20
--- /dev/null
+++ b/assets/site.webmanifest
@@ -0,0 +1 @@
+{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of file
diff --git a/atom.xml b/atom.xml
new file mode 100644
index 00000000..96c9681c
--- /dev/null
+++ b/atom.xml
@@ -0,0 +1,28 @@
+---
+layout: null
+---
+
+
+
+
+ {{ site.title }}
+
+
+ {{ site.time | date_to_xmlschema }}
+ {{ site.url }}
+
+ {{ site.author.name }}
+ {{ site.author.email }}
+
+
+ {% for post in site.posts %}
+
+ {{ post.title }}
+
+ {{ post.date | date_to_xmlschema }}
+ {{ site.url }}{{ post.id }}
+ {{ post.content | xml_escape }}
+
+ {% endfor %}
+
+
diff --git a/favicon.ico b/favicon.ico
new file mode 100644
index 00000000..8aba9aa9
Binary files /dev/null and b/favicon.ico differ
diff --git a/fix.sh b/fix.sh
new file mode 100755
index 00000000..fcc57806
--- /dev/null
+++ b/fix.sh
@@ -0,0 +1,22 @@
+#!/bin/sh -x
+
+git filter-branch -f --env-filter '
+
+NAME="Kamil.Zabinski"
+CORRECT_NAME="Kamil Adam"
+CORRECT_EMAIL="kamil.adam.zabinski@gmail.com"
+if [ "$GIT_COMMITTER_NAME" = "$NAME" ]
+then
+ export GIT_COMMITTER_NAME="$CORRECT_NAME"
+ export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
+ export GIT_AUTHOR_NAME="$CORRECT_NAME"
+ export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
+fi
+if [ "$GIT_AUTHOR_NAME" = "$NAME" ]
+then
+ export GIT_COMMITTER_NAME="$CORRECT_NAME"
+ export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
+ export GIT_AUTHOR_NAME="$CORRECT_NAME"
+ export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
+fi
+' --tag-name-filter cat -- --branches --tags
diff --git a/index.html b/index.html
index c5944a59..343940ed 100644
--- a/index.html
+++ b/index.html
@@ -3,5 +3,7 @@
# Edit theme's home layout instead if you wanna make some changes
# See: https://jekyllrb.com/docs/themes/#overriding-theme-defaults
layout: home
-author_profile: true
+sitemap: false
+sidebar:
+ nav: sidebar-main
---