]> git.xn--bdkaa.com Git - xn--bdkaa.com.git/commitdiff
new design
authorEvgenii Akentev <i@ak3n.com>
Mon, 2 Sep 2024 06:53:22 +0000 (10:53 +0400)
committerEvgenii Akentev <i@ak3n.com>
Mon, 2 Sep 2024 06:53:22 +0000 (10:53 +0400)
29 files changed:
config.toml
content/pages/projects.md [deleted file]
content/posts/implementations-of-the-handle-pattern.html [moved from content/posts/implementations-of-the-handle-pattern.md with 62% similarity]
content/posts/on-short-lived-software.html [new file with mode: 0644]
content/posts/on-short-lived-software.md [deleted file]
content/posts/row-types-and-modules.html [moved from content/posts/row-types-and-modules.md with 62% similarity]
content/posts/thoughts-on-backpack-modules-and-records.html [new file with mode: 0644]
content/posts/thoughts-on-backpack-modules-and-records.md [deleted file]
content/posts/why-i-am-not-a-scientist.html [new file with mode: 0644]
content/posts/why-i-am-not-a-scientist.md [deleted file]
content/posts/wisdom-and-software-engineering.html [new file with mode: 0644]
content/posts/wisdom-and-software-engineering.md [deleted file]
content/static/images/cubicaltt.png [deleted file]
content/static/images/rendertable.png [deleted file]
content/static/images/whereareyougame.png [deleted file]
themes/theme/layouts/_default/list.html
themes/theme/layouts/_default/single.html
themes/theme/layouts/index.html
themes/theme/layouts/pages/single.html [deleted file]
themes/theme/layouts/partials/header.html
themes/theme/layouts/partials/headline.html [deleted file]
themes/theme/layouts/partials/subheader.html [deleted file]
themes/theme/layouts/partials/tags.html [deleted file]
themes/theme/layouts/partials/toc.html [deleted file]
themes/theme/static/css/grids-responsive-min.css [deleted file]
themes/theme/static/css/pure-min.css [deleted file]
themes/theme/static/css/stylesheet.css [deleted file]
themes/theme/static/css/syntax.css [deleted file]
themes/theme/static/img/me_myself_and_i_tbilisi_2023.webp [deleted file]

index 9dee85457cdcdce2b0969c0fa27e78e67186e9f5..53ddb8f47fe45e6a2fba25d9a9a676cbe4aa9142 100644 (file)
@@ -1,42 +1,14 @@
 baseURL = "/"
 languageCode = "en-us"
-title = "Evgenii Akentev"
+title = "evgenii akentev"
 theme = "theme"
 port = 1313
 titleCaseStyle = 'none'
 uglyurls = true
 
 rssLimit = 10
-copyright = 'This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.'
-[author]
-  name = 'Evgenii Akentev'
-
-[taxonomies]
-  tag = 'tags'
 
 [params]
   sitename = "ak3n.com"
-
-[markup]
-  [markup.highlight]
-    anchorLineNos = true
-    codeFences = true
-    guessSyntax = false
-    hl_Lines = ""
-    lineAnchors = ""
-    lineNoStart = 1
-    lineNos = true
-    lineNumbersInTable = true
-    noClasses = false
-    style = "vs"
-    tabWidth = 4
-
-  [markup.goldmark]
-    [markup.goldmark.renderer]
-      unsafe = true
-
-  [markup.tableOfContents]
-    endLevel = 5
-    ordered = false
-    startLevel = 2
-
+  [author]
+    name = 'Evgenii Akentev'
diff --git a/content/pages/projects.md b/content/pages/projects.md
deleted file mode 100644 (file)
index 3a9ac93..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: Projects
----
-
-### Hackage packages
-
-<details open="">
-  <summary>
-    <strong><a href="https://hackage.haskell.org/package/debug-trace-file">debug-trace-file</a></strong> [<a href="https://git.ak3n.com/?p=debug-trace-file.git">source</a>]
-  </summary>
-  <p>
-    Debug.Trace like functions to trace to files.
-  </p>
-</details>
-
-<details open="">
-  <summary>
-    <strong><a href="https://hackage.haskell.org/package/line-indexed-cursor">line-indexed-cursor</a></strong> [<a href="https://git.ak3n.com/?p=line-indexed-cursor.git">source</a>]
-  </summary>
-  <p>
-    Lazily builds the index with the line numbers while reading the file making it possible to rewind to them quickly later.
-  </p>
-</details>
-
-### lean4 packages
-
-<details open="">
-  <summary>
-    <strong>temple.lean</strong> [<a href="https://git.ak3n.com/?p=temple.lean.git">source</a>]
-  </summary>
-  <p>
-    A rudimentary template engine written in Lean4 without fancy dependent types and useful operators yet. It can parse, build a tree, and substitute using de Bruijn Indices.
-  </p>
-</details>
-
-### Educational
-
-<details open="">
-  <summary>
-    <strong><a href="https://ulearn.me/Course/fpintroduction/">Introduction to Functional Programming</a></strong> <em>(in Russian) (2019 - 2021) (Haskell)</em>
-  </summary>
-  <p>
-    I helped to create and teach an online course that uses Haskell to introduce bachelor students to functional programming at Ural Federal University.
-  </p>
-</details>
-
-<details>
-  <summary>
-    <strong><a href="https://cubicaltt.ak3n.com">cubicaltt</a></strong> <em>(Haskell, Reflex, GHCJS, Monaco)</em> [<a href="https://git.ak3n.com/?p=cubicaltt.git">source</a>]
-  </summary>
-  <p>
-
-  A web version of [cubicalltt](https://github.com/mortberg/cubicaltt), built to reduce the entrance barrier (no need to install Emacs/build from sources). 
-
-  <a href=""><img src="/static/images/cubicaltt.png" /></a>
-  </p>
-</details>
similarity index 62%
rename from content/posts/implementations-of-the-handle-pattern.md
rename to content/posts/implementations-of-the-handle-pattern.html
index 496e0f4e1781455422956bcf0cabf6818b3426a0..71804ba27e85e78115b435001673791aaa8be3c3 100644 (file)
@@ -2,17 +2,22 @@
 title: Implementations of the Handle pattern
 date: 2021-01-31
 draft: false
-tags: [haskell, backpack]
-toc: true
 ---
+In <a href="https://blog.ocharles.org.uk/posts/2020-12-23-monad-transformers-and-effects-with-backpack.html">https://blog.ocharles.org.uk/posts/2020-12-23-monad-transformers-and-effects
+-with-backpack.html</a> @acid2 presented how to apply Backpack to monad
+transformers. There is a less-popular approach to deal with effects — so
+called Handle or Service pattern.
 
-In ["Monad Transformers and Effects with Backpack"](https://blog.ocharles.org.uk/posts/2020-12-23-monad-transformers-and-effects-with-backpack.html) [@acid2](https://twitter.com/acid2) presented how to apply Backpack to monad transformers. There is a less-popular approach to deal with effects — [Handle](https://jaspervdj.be/posts/2018-03-08-handle-pattern.html) ([Service](https://www.schoolofhaskell.com/user/meiersi/the-service-pattern)) pattern. I recommend reading both posts at first since they answer many questions regarding the design decisions behind the Handle pattern (why `IO`, why not type classes, etc). In this post, I want to show different implementations of the Handle pattern and compare them. All examples described below are available [in this repository](https://git.ak3n.com/?p=handle-examples.git).
+In this post, I want to show different implementations of the Handle pattern
+and compare them. All examples described below are available in this repository
+<a href="https://git.ak3n.com/?p=handle-examples.git">https://git.ak3n.com/?p=handle-examples.git</a>.
 
-### When you might need the Handle pattern [[simple](https://git.ak3n.com/?p=handle-examples.git;a=tree;f=simple)]
+When you might need the Handle pattern
+--------------------------------------
 
 Suppose we have a domain logic with a side effect:
 
-```haskell
+```
 module WeatherReporter where
 
 import qualified WeatherProvider
@@ -31,7 +36,7 @@ getCurrentWeatherReportInLondon = do
   return $ createWeatherReport weatherData
 ```
 
-```haskell
+```
 module WeatherProvider where
 
 type Temperature = Int
@@ -46,21 +51,27 @@ getWeatherData :: Location -> Day -> IO WeatherData
 getWeatherData _ _ = return $ WeatherData 30
 ```
 
-At some point in time, there appeared a need for tests to ensure that the domain logic is correct. There are different ways to do that:
+At some point in time, there appeared a need for tests to ensure that the
+domain logic is correct. There are different ways to do that:
 
 - integration tests
 - stub implementation of the service
-- minimize the logic with side effects moving as much as possible to pure functions for proper unit testing
+- minimize the logic with side effects moving as much as possible to pure
+  functions for proper unit testing
 - maybe something else
 
-All solutions have their pros and cons and the final choice depends on many factors — especially on the number of side effects and how they interact with each other. We are interested in how to achieve the second one with the Handle pattern.
+All solutions have their pros and cons and the final choice depends on many
+factors — especially on the number of side effects and how they interact with
+each other. We are interested in how to achieve the second one with the Handle
+pattern.
 
-### Simple Handle [[simple-handle](https://git.ak3n.com/?p=handle-examples.git;a=tree;f=simple-handle)]
+Simple Handle
+-------------
 
 Let's start with a simple Handle that doesn't support multiple implementations.
 Here is the updated domain logic:
 
-```haskell
+```
 module WeatherReporter where
 
 import qualified WeatherProvider
@@ -89,7 +100,7 @@ getCurrentWeatherReportInLondon (Handle wph) = do
 
 And the implementation of the `WeatherProvider`:
 
-```haskell
+```
 module WeatherProvider where
 
 type Temperature = Int
@@ -111,13 +122,19 @@ getWeatherData :: Handle -> Location -> Day -> IO WeatherData
 getWeatherData _ _ _ = return $ WeatherData 30
 ```
 
-We have wrapped our service with the Handle interface. It's not possible to have multiple implementations yet, but we got an interface of the service and can hide all the dependencies of the service into Handle.
+We have wrapped our service with the Handle interface. It's not possible to
+have multiple implementations yet, but we got an interface of the service and
+can hide all the dependencies of the service into Handle.
 
-### Handle with records [[records-handle](https://git.ak3n.com/?p=handle-examples.git;a=tree;f=records-handle)]
+Handle with records
+-------------------
 
-The approach with records is described in the aforementioned posts. Records are used as a dictionary with functions just like dictionary passing with type classes but explicitly. `WeatherReporter` module stays the same — it continues to use `WeatherProvider.Handle` while the `WeatherProvider` becomes an interface:
+The approach with records is described in the aforementioned posts. Records are
+used as a dictionary with functions just like dictionary passing with type
+classes but explicitly. `WeatherReporter` module stays the same — it continues
+to use `WeatherProvider.Handle` while the `WeatherProvider` becomes an interface:
 
-```haskell
+```
 module WeatherProvider where
 
 type Temperature = Int
@@ -130,9 +147,12 @@ type Day = String
 data Handle = Handle { getWeatherData :: Location -> Day -> IO WeatherData }
 ```
 
-The good thing is that we do not need to change our domain logic at all since `getWeatherData :: Handle -> Location -> Day -> IO WeatherData` has the same type. The interface allows us to create a concrete implementation for the application:
+The good thing is that we do not need to change our domain logic at all since
+`getWeatherData :: Handle -> Location -> Day -> IO WeatherData` has the same
+type. The interface allows us to create a concrete implementation for the
+application:
 
-```haskell
+```
 module SuperWeatherProvider where
 
 import WeatherProvider
@@ -147,7 +167,7 @@ getSuperWeatherData _ _ = return $ WeatherData 30
 
 And the stub for testing that we can control:
 
-```haskell
+```
 module TestWeatherProvider where
 
 import WeatherProvider
@@ -156,16 +176,22 @@ import WeatherProvider
 data Config = Config { initTemperature :: Temperature }
 
 new :: Config -> Handle
-new config = Handle { getWeatherData = getTestWeatherData $ initTemperature config }
+new config = Handle
+  { getWeatherData = getTestWeatherData $ initTemperature config }
 
 -- | This is an implementation `WeatherProvider` interface for tests
 getTestWeatherData :: Int -> Location -> Day -> IO WeatherData
 getTestWeatherData temp _ _ = return $ WeatherData temp
 ```
 
-The downside of this approach is the cost of an unknown function call mentioned in ["The Service Pattern"](https://www.schoolofhaskell.com/user/meiersi/the-service-pattern) post:
+The downside of this approach is the cost of an unknown function call mentioned
+in <a href="https://www.schoolofhaskell.com/user/meiersi/the-service-pattern">https://www.schoolofhaskell.com/user/meiersi/the-service-pattern</a> post:
 
-> In terms of call overhead, we pay the cost of an unknown function call, which is probably a bit slower than a virtual method invocation in an OOP langauge like Java. If this becomes a performance bottleneck, we will have to avoid the abstraction and specialize at compile time. Backpack will allow us to do this in a principled fashion without losing modularity.
+> In terms of call overhead, we pay the cost of an unknown function call, which
+is probably a bit slower than a virtual method invocation in an OOP langauge
+like Java. If this becomes a performance bottleneck, we will have to avoid the
+abstraction and specialize at compile time. Backpack will allow us to do this
+in a principled fashion without losing modularity.
 
 Here is the STG of `WeatherReporter`:
 
@@ -231,13 +257,23 @@ getCurrentWeatherReportInLondon =
 Handle = \r [eta_B1] Handle [eta_B1];
 ```
 
-`getCurrentWeatherReportInLondon` takes two arguments — the first one is `WeatherReporter`'s Handle dictionary which we pass to `getCurrentWeatherReportInLondon1`. We match on this dictionary to get `wph_s1Ck` — this is our `WeatherProvider`'s Handle. Matching on it we get `ds1_s1Cm` — `getWeatherData` function which is called with arguments: `getCurrentWeatherReportInLondon4 = "London"` and `getCurrentWeatherReportInLondon2 = "now"`.
+`getCurrentWeatherReportInLondon` takes two arguments — the first one is
+`WeatherReporter`'s Handle dictionary which we pass to
+`getCurrentWeatherReportInLondon1`. We match on this dictionary to get
+`wph_s1Ck` — this is our `WeatherProvider`'s Handle. Matching on it we get
+`ds1_s1Cm` — `getWeatherData` function which is called with arguments:
+`getCurrentWeatherReportInLondon4 = "London"` and
+`getCurrentWeatherReportInLondon2 = "now"`.
 
-The result of `getWeatherData "London" "now" = ipv1_s1Cp` is then passed to `createWeatherReport` where we show the result in `$wcreateWeatherReport` and append it to `createWeatherReport1 = "The current temperature in London is "`.
+The result of `getWeatherData "London" "now" = ipv1_s1Cp` is then passed to
+`createWeatherReport` where we show the result in `$wcreateWeatherReport` and
+append it to `createWeatherReport1 = "The current temperature in London is "`.
 
-The STG looks as expected. There are two allocations: one in `getCurrentWeatherReportInLondon1` and the other one in `$wcreateWeatherReport`.
+The STG looks as expected. There are two allocations: one in
+`getCurrentWeatherReportInLondon1` and the other one in `$wcreateWeatherReport`.
 
-### Handle with Backpack [[backpack-handle](https://git.ak3n.com/?p=handle-examples.git;a=tree;f=backpack-handle)]
+Handle with Backpack
+--------------------
 
 `WeatherProvider` becomes a signature in the cabal file:
 
@@ -250,9 +286,11 @@ library domain
   build-depends:    base
 ```
 
-and we rename `WeatherProvider.hs` to `WeatherProvider.hsig` with a little change — instead of using a concrete type for `Temperature` we make it abstract and will instantiate in implementations.
+and we rename `WeatherProvider.hs` to `WeatherProvider.hsig` with a little
+change — instead of using a concrete type for `Temperature` we make it
+abstract and will instantiate in implementations.
 
-```haskell
+```
 signature WeatherProvider where
 
 data Temperature
@@ -269,9 +307,12 @@ data Handle
 getWeatherData :: Handle -> Location -> Day -> IO WeatherData
 ```
 
-Our implementation module is almost the same as in the simple Handle case, but we have to follow the signature and export the same types. It's possible to move all common types to a different cabal library and import in the signature and the implementations.
+Our implementation module is almost the same as in the simple Handle case, but
+we have to follow the signature and export the same types. It's possible to
+move all common types to a different cabal library and import in the signature
+and the implementations.
 
-```haskell
+```
 module SuperWeatherProvider where
 
 type Temperature = Int
@@ -317,7 +358,9 @@ getWeatherData :: Handle -> Location -> Day -> IO WeatherData
 getWeatherData (Handle conf) _ _ = return $ WeatherData $ initTemperature conf
 ```
 
-Now we need to tell which module to use instead of `WeatherProvider` hole. There are two ways: by using mixins or by reexporting modules as `WeatherProvider` in the definition libraries:
+Now we need to tell which module to use instead of `WeatherProvider` hole.
+There are two ways: by using mixins or by reexporting modules as
+`WeatherProvider` in the definition libraries:
 
 ```
 library impl
@@ -347,7 +390,8 @@ test-suite spec
   build-depends: base, QuickCheck, hspec, domain, test-impl
 ```
 
-That's all. We do not need to change our domain logic or tests. Here is the STG of `WeatherReporter`:
+That's all. We do not need to change our domain logic or tests. Here is the STG
+of `WeatherReporter`:
 
 ```
 weatherProvider =
@@ -399,13 +443,17 @@ getCurrentWeatherReportInLondon =
 Handle = \r [eta_B1] Handle [eta_B1];
 ```
 
-We can see that GHC inlined our constant implementation in the `getCurrentWeatherReportInLondon3` — we show `30` immediately.
+We can see that GHC inlined our constant implementation in the
+`getCurrentWeatherReportInLondon3` — we show `30` immediately.
 
-### Handles with Backpack [[backpack-handles](https://git.ak3n.com/?p=handle-examples.git;a=tree;f=backpack-handles)]
+Handles with Backpack
+---------------------
 
-I decided to go further and make `WeatherReporter` a signature as well. Turned out this step required more actions with libraries. Here is `WeatherReporter.hsig`:
+I decided to go further and make `WeatherReporter` a signature as well. Turned
+out this step required more actions with libraries. Here is
+`WeatherReporter.hsig`:
 
-```haskell
+```
 signature WeatherReporter where
 
 import qualified WeatherProvider
@@ -418,7 +466,10 @@ data Handle = Handle { weatherProvider :: WeatherProvider.Handle }
 getCurrentWeatherReportInLondon :: Handle -> IO WeatherReport
 ```
 
-Then we need to split the `domain` library into two because `WeatherReport` depends on `WeatherProvider`. I tried to implement them both with one implementation library but seems it's impossible. The structure of libraries becomes the following:
+Then we need to split the `domain` library into two because `WeatherReport`
+depends on `WeatherProvider`. I tried to implement them both with one
+implementation library but seems it's impossible. The structure of libraries
+becomes the following:
 
 ```
 library domain-provider
@@ -448,23 +499,39 @@ library impl-reporter
   build-depends:    base, domain-provider
 ```
 
-Instead of `domain` we have `domain-provider` and `domain-reporter`. It allows to depend on them individually and instantiate with different implementations. In [the example](https://git.ak3n.com/?p=handle-examples.git;a=blob;f=backpack-handles/backpack-handles.cabal;h=6cfe4f87359e2bf02fff72cfea75d2669818b7e1;hb=HEAD#l36), I have instantiated the provider with implementation from `test-impl` using the reporter from `impl-reporter`. This is useful if you want to gradually write tests for different parts of the logic.
+Instead of `domain` we have `domain-provider` and `domain-reporter`. It allows
+to depend on them individually and instantiate with different implementations.
+In the example I have instantiated the provider with implementation from
+`test-impl` using the reporter from `impl-reporter`. This is useful if you want
+to gradually write tests for different parts of the logic.
 
-### Handle with Vinyl [[vinyl-handle](https://git.ak3n.com/?p=handle-examples.git;a=tree;f=vinyl-handle)]
+Handle with Vinyl
+-----------------
 
-Suppose that we want to extend our `WeatherData` and return not only temperature but wind's speed too. We need to add a field to `WeatherData`:
+Suppose that we want to extend our `WeatherData` and return not only temperature
+but wind's speed too. We need to add a field to `WeatherData`:
 
 ```
-data WeatherData = WeatherData { temperature :: T.Temperature, wind :: W.WindSpeed }
+data WeatherData =
+  WeatherData { temperature :: T.Temperature, wind :: W.WindSpeed }
 ```
 
-But also we want to provide separate Handles for these values: `TemperatureProvider` and `WindProvider`. We can create these two providers and then duplicate their methods in `WeatherProvider`. That might work if there are no so many methods, but what if their number will grow?
+But also we want to provide separate Handles for these values:
+`TemperatureProvider` and `WindProvider`. We can create these two providers and
+then duplicate their methods in `WeatherProvider`. That might work if there are
+no so many methods, but what if their number will grow?
 
-We know that records are nominally typed and can't be composed. There is a library called [vinyl](https://hackage.haskell.org/package/vinyl) that provides structural records supporting merge operation. I recommend Jon Sterling's [talk on Vinyl](https://vimeo.com/102785458) where you can learn why records are sheaves and other details on Vinyl.
+We know that records are nominally typed and can't be composed. There is a
+library called <a href="https://hackage.haskell.org/package/vinyl">https://hackage.haskell.org/package/vinyl</a> that provides
+structural records supporting merge operation. I recommend Jon Sterling's talk
+on Vinyl <a href="https://vimeo.com/102785458">https://vimeo.com/102785458</a> where you can learn why records are
+sheaves and other details on Vinyl.
 
-Let's explore what the Handle pattern will look like if we replace records with Vinyl records. We create our data providers `TemperatureProvider` and `WindProvider`:
+Let's explore what the Handle pattern will look like if we replace records
+with Vinyl records. We create our data providers `TemperatureProvider` and
+`WindProvider`:
 
-```haskell
+```
 module TemperatureProvider where
 
 import HandleRec
@@ -478,10 +545,9 @@ type Handle = HandleRec Methods
 
 getTemperatureData :: Handle -> Location -> Day -> IO Temperature
 getTemperatureData = getMethod @"getTemperatureData"
-
 ```
 
-```haskell
+```
 module WindProvider where
 
 import HandleRec
@@ -497,11 +563,12 @@ getWindData :: Handle -> Location -> Day -> IO WindSpeed
 getWindData = getMethod @"getWindData"
 ```
 
-Note that we provide `getTemperatureData` and `getWindData` functions which satisfy our Handle interface.
+Note that we provide `getTemperatureData` and `getWindData` functions which
+satisfy our Handle interface.
 
 We can compose them together and extend them to create `WeatherProvider`:
 
-```haskell
+```
 module WeatherProvider where
 
 import Data.Vinyl.TypeLevel
@@ -510,7 +577,8 @@ import qualified WindProvider as W
 import qualified TemperatureProvider as T
 import QueryTypes
 
-data WeatherData = WeatherData { temperature :: T.Temperature, wind :: W.WindSpeed }
+data WeatherData =
+  WeatherData { temperature :: T.Temperature, wind :: W.WindSpeed }
 
 -- We union the methods of providers and extend it with a common method.
 type Methods = '[ '("getWeatherData", (Location -> Day -> IO WeatherData))
@@ -524,7 +592,7 @@ getWeatherData = getMethod @"getWeatherData"
 
 Here is how our providers are implemented:
 
-```haskell
+```
 module SuperTemperatureProvider where
 
 import Data.Vinyl
@@ -552,7 +620,7 @@ getSuperWindData :: Location -> Day -> IO WindSpeed
 getSuperWindData _ _ = return 5
 ```
 
-```haskell
+```
 module SuperWeatherProvider where
 
 import Data.Vinyl
@@ -569,7 +637,8 @@ getSuperWeatherData :: Location -> Day -> IO WeatherData
 getSuperWeatherData _ _ = return $ WeatherData 30 10
 ```
 
-The domain logic and tests stay the same thanks to the Handle interface. The STG of `WeatherReporter`:
+The domain logic and tests stay the same thanks to the Handle interface. The
+STG of `WeatherReporter`:
 
 ```
 createWeatherReport2 = "The current temperature in London is "#;
@@ -577,32 +646,32 @@ createWeatherReport2 = "The current temperature in London is "#;
 createWeatherReport1 = " and wind speed is "#;
 
 $wcreateWeatherReport =
-    \r [ww_s2fz ww1_s2fA]
-        let {
-          sat_s2fN =
-              \u []
-                  case ww_s2fz of {
-                    I# ww3_s2fC ->
-                        case $wshowSignedInt 0# ww3_s2fC [] of {
-                          (#,#) ww5_s2fE ww6_s2fF ->
-                              let {
-                                sat_s2fM =
-                                    \s []
-                                        let {
-                                          sat_s2fL =
-                                              \u []
-                                                  case ww1_s2fA of {
-                                                    I# ww9_s2fH ->
-                                                        case $wshowSignedInt 0# ww9_s2fH [] of {
-                                                          (#,#) ww11_s2fJ ww12_s2fK ->
-                                                              : [ww11_s2fJ ww12_s2fK];
-                                                        };
-                                                  };
-                                        } in  unpackAppendCString# createWeatherReport1 sat_s2fL;
-                              } in  ++_$s++ sat_s2fM ww5_s2fE ww6_s2fF;
-                        };
-                  };
-        } in  unpackAppendCString# createWeatherReport2 sat_s2fN;
+  \r [ww_s2fz ww1_s2fA]
+    let {
+      sat_s2fN =
+        \u []
+          case ww_s2fz of {
+            I# ww3_s2fC ->
+              case $wshowSignedInt 0# ww3_s2fC [] of {
+                (#,#) ww5_s2fE ww6_s2fF ->
+                  let {
+                    sat_s2fM =
+                      \s []
+                        let {
+                          sat_s2fL =
+                            \u []
+                              case ww1_s2fA of {
+                                I# ww9_s2fH ->
+                                  case $wshowSignedInt 0# ww9_s2fH [] of {
+                                    (#,#) ww11_s2fJ ww12_s2fK ->
+                                        : [ww11_s2fJ ww12_s2fK];
+                                  };
+                              };
+                        } in  unpackAppendCString# createWeatherReport1 sat_s2fL;
+                  } in  ++_$s++ sat_s2fM ww5_s2fE ww6_s2fF;
+              };
+          };
+    } in  unpackAppendCString# createWeatherReport2 sat_s2fN;
 
 createWeatherReport =
     \r [w_s2fO]
@@ -625,22 +694,22 @@ getCurrentWeatherReportInLondon1 =
     \r [ds_s2fS void_0E]
         case ds_s2fS of {
           Handle wph_s2fV ->
-              case wph_s2fV of {
-                :& x1_s2fX _ ->
-                    case x1_s2fX of {
-                      Field _ x2_s2g1 ->
-                          case
-                              x2_s2g1
-                                  getCurrentWeatherReportInLondon4
-                                  getCurrentWeatherReportInLondon2
-                                  void#
-                          of
-                          { Unit# ipv1_s2g4 ->
-                                let { sat_s2g5 = \u [] createWeatherReport ipv1_s2g4;
-                                } in  Unit# [sat_s2g5];
-                          };
+            case wph_s2fV of {
+              :& x1_s2fX _ ->
+                case x1_s2fX of {
+                  Field _ x2_s2g1 ->
+                    case
+                        x2_s2g1
+                            getCurrentWeatherReportInLondon4
+                            getCurrentWeatherReportInLondon2
+                            void#
+                    of
+                    { Unit# ipv1_s2g4 ->
+                          let { sat_s2g5 = \u [] createWeatherReport ipv1_s2g4;
+                          } in  Unit# [sat_s2g5];
                     };
-              };
+                };
+            };
         };
 
 getCurrentWeatherReportInLondon =
@@ -649,12 +718,24 @@ getCurrentWeatherReportInLondon =
 Handle = \r [eta_B1] Handle [eta_B1];
 ```
 
-As we can see there is not much vinyl-specific runtime overhead in this case — we pattern match on `wph_s2fV` and `x1_s2fX` to get the function `x2_s2g1`. But keep in mind that accessing an element is linear since Vinyl is based on HList and compilation time will grow because of type-level machinery. Vinyl can be replaced for an alternative with logarithmic complexity.
+As we can see there is not much vinyl-specific runtime overhead in this case —
+we pattern match on `wph_s2fV` and `x1_s2fX` to get the function `x2_s2g1`. But
+keep in mind that accessing an element is linear since Vinyl is based on HList
+and compilation time will grow because of type-level machinery. Vinyl can be
+replaced for an alternative with logarithmic complexity.
 
-### Conclusions
+Conclusions
+-----------
 
-No surprises here. Backpack works as expected specifying things at compile time. Vinyl allows to compose records and can be replaced with any [alternative](https://github.com/danidiaz/red-black-record#alternatives). The Handle pattern works since it's just a type signature  `... :: Handle -> ...`.
+No surprises here. Backpack works as expected specifying things at compile time.
+Vinyl allows to compose records and can be replaced with any alternative. The
+Handle pattern works since it's just a type signature  `... :: Handle -> ...`.
 
-The Handle allows us to hide dependencies and to create interfaces, allowing us to easily replace the implementation without changes on the client-side — statically using Backpack for better performance or dynamically using records or alternatives in runtime (in first-class modules manner). Backpack might be too tedious for Handles that depend on each other but in simple cases, it introduces not much additional cost compared to records. And it's possible to mix them.
+The Handle allows us to hide dependencies and to create interfaces, allowing us
+to easily replace the implementation without changes on the client-side —
+statically using Backpack for better performance or dynamically using records
+or alternatives in runtime (in first-class modules manner). Backpack might be
+too tedious for Handles that depend on each other but in simple cases, it
+introduces not much additional cost compared to records. And it's possible to
+mix them.
 
-This post inspired me to write a follow-up post on [Backpack, modules, and records](/posts/thoughts-on-backpack-modules-and-records).
diff --git a/content/posts/on-short-lived-software.html b/content/posts/on-short-lived-software.html
new file mode 100644 (file)
index 0000000..9a5fe4d
--- /dev/null
@@ -0,0 +1,47 @@
+---
+title: On short-lived software
+date: 2024-01-05
+draft: false
+---
+Over time, being a software engineer might be frustrating a bit (or a lot,
+depends on the burnout rate). The written code changes quite often. Maybe
+next year, or in a month, or even tomorrow, because someone in your team
+finished working on their PR, introduced so many changes that there is no need
+in your code anymore.
+
+Sometimes it's okay, because engineers solve business problems, some solutions
+are temporary and matter only in a fixed time range. Still, it might frustrate.
+Emotionally it might be hard to accept that the amount of time that was spent
+on some detail will be replaced in a short time. It's important to acquire the
+business aspect of the solution. I guess that's where casual programmers grow
+into engineers. They understand the price of their solutions and how important
+it's to be agile in sense of trade-offs, keeping in mind the business
+requirements, available resources, and the complexity of the problem.
+
+I have never been a proper Ruby programmer but I still remember why_'s quote:
+
+> programming is rather thankless. u see your works become replaced by superior
+ones in a year. unable to run at all in a few more.
+
+and it affected me in a strong way for sure — not only as an engineer but as a
+person as well.
+
+Especially later, when I got into Haskell, where the sitatution with cabal was
+a huge problem known as cabal hell. Comparing to Standard ML where code written
+20-30 years ago still compiles and works fine. There is some beauty in
+standardised languages with strict formal specification where different
+compilers are possible.
+
+This viewpoint is somewhat rational — it helps to solve problems in an efficient
+way without extra perfectionism — but at the same time looks like an indication
+of an ongoing existential crisis (could be neverending). We are all just a
+cosmic dust, look at James Webb's pics.
+
+It's all about the _process_. The result is important, but it's the process that
+brings joy. The process creates a flow state — where we concentrate in a
+challenging activity and forget about our existential nature and problems. Maybe
+that's why sometimes people argue that the programming is art — it allows to
+express themselves and improve the mental health.
+
+This essay is written for myself, to remind me about why I started doing
+programming at all and keep doing it.
diff --git a/content/posts/on-short-lived-software.md b/content/posts/on-short-lived-software.md
deleted file mode 100644 (file)
index c66dbab..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: On short-lived software
-date: 2024-01-05
-draft: false
-tags: [programming, software]
----
-
-Over time, being a software engineer might be frustrating a bit (or a lot, depends on the burnout rate). The written code changes quite often. Maybe next year, or in a month, or even tomorrow, because someone in your team finished working on their PR, introduced so many changes that there is no need in your code anymore.
-
-Sometimes it's okay, because engineers solve business problems, some solutions are temporary and matter only in a fixed time range. Still, it might frustrate. Emotionally it might be hard to accept that the amount of time that was spent on some detail will be replaced in a short time. It's important to acquire the business aspect of the solution. I guess that's where casual coders / programmers grow into engineers. They understand the price of their solutions and how important it's to be agile in sense of trade-offs, keeping in mind the business requirements, available resources, and the complexity of the problem.
-
-I have never been a proper Ruby programmer but I still remember [why_](https://en.wikipedia.org/wiki/Why_the_lucky_stiff)'s quote:
-
-> programming is rather thankless. u see your works become replaced by superior ones in a year. unable to run at all in a few more.
-
-and it affected me in a strong way for sure — not only as an engineer but as a person as well.
-
-Especially later, when I got into Haskell, where the sitatution with cabal was a huge problem known as cabal hell.
-Comparing to Standard ML where code written 20-30 years ago still compiles and works fine. There is some beauty in standardised languages with strict formal specification where different compilers are possible.
-
-This viewpoint is somewhat rational — it helps to solve problems in an efficient way without extra perfectionism — but at the same time looks like an indication of an ongoing existential crisis (could be neverending). We are all just a cosmic dust, look at James Webb's pics.
-
-It's all about the _process_. The result is important, but it's the process that brings joy. The process creates [a flow state](https://en.wikipedia.org/wiki/Flow_(psychology)) — where we concentrate in a challenging activity and forget about our existential nature and problems. Maybe that's why sometimes people argue that the programming is art — it allows to express themselves and improve the mental health.
-
-This essay is written for myself, to remind me about why I started doing programming at all and keep doing it.
similarity index 62%
rename from content/posts/row-types-and-modules.md
rename to content/posts/row-types-and-modules.html
index 636f4c627dc5d367fd02cfbdb2cc8a2347e6e250..95ccad314369e52233babbdf4ae5936feeb6ac98 100644 (file)
@@ -2,29 +2,32 @@
 title: Row types and modules
 date: 2023-04-01
 draft: false
-tags: [haskell, modules, records, row types]
 ---
-
-I was thinking about modules a few years ago. One of the directions was the intersection of modules with row types. I decided to write something down to keep the idea.
+I was thinking about modules a few years ago. One of the directions was the
+intersection of modules with row types. I decided to write something down to
+keep the idea.
 
 OCaml consists of two languages:
 
 - term language — to construct programs with terms and types;
-
 - module language — to create signatures, modules, and functors.
 
-1ML merges these levels — modules become values. I noticed that modules behave in a similar way/correspond to records. Since the Service/Handle pattern in Haskell is about using a record to represent an interface and to have different implementations by filling the record's fields, what if we use row types on module level? If row types might be seen as an alternative to records, then it might be possible to represent row types values on module level as an alternative to modules.
-
+1ML merges these levels — modules become values. I noticed that modules behave
+in a similar way/correspond to records. Since the Service/Handle pattern in
+Haskell is about using a record to represent an interface and to have different
+implementations by filling the record's fields, what if we use row types on
+module level? If row types might be seen as an alternative to records, then it
+might be possible to represent row types values on module level as an
+alternative to modules.
 
 | Term language |  | Module language    |
 |---------------|--|--------------------|
 | Records       |~>| Modules            |
-| Row types     |~>|?                   |
-
+| Row types     |~>| ?                  |
 
-I don't want to imagine an artificial language for this purpose and will use Haskell with the Handle pattern, [extending the previous post](/posts/implementations-of-the-handle-pattern/).
+I don't want to imagine an artificial language for this purpose and will use
+Haskell with the Handle pattern, extending the previous post.
 
-```haskell
 import Data.Row
 
 import qualified WindProvider
@@ -68,8 +71,13 @@ type JoinedMethods = Methods .\/ Methods
 
 test4 :: Rec JoinedMethods -> Rec Methods
 test4 = id
-```
 
-That's similar to my previous approach with vinyl library — `Methods` is just a union of other methods with its own `getWeatherData` extension. The difference is that vinyl record supports only appending new elements while with rows it's also possible to remove items, take a difference, do a minimum join, override rows, etc.
+That's similar to my previous approach with vinyl library — `Methods` is just
+a union of other methods with its own `getWeatherData` extension. The
+difference is that vinyl record supports only appending new elements while with
+rows it's also possible to remove items, take a difference, do a minimum join,
+override rows, etc.
 
-By using row types as signatures we get more flexible interfaces, more ways to express and combine them. But I don't remember if I ever had a motivation for this in a real world.
\ No newline at end of file
+By using row types as signatures we get more flexible interfaces, more ways to
+express and combine them. But I don't remember if I ever had a motivation for
+this in a real world.
diff --git a/content/posts/thoughts-on-backpack-modules-and-records.html b/content/posts/thoughts-on-backpack-modules-and-records.html
new file mode 100644 (file)
index 0000000..a15834e
--- /dev/null
@@ -0,0 +1,434 @@
+---
+title: Thoughts on Backpack, modules, and records
+date: 2021-01-31
+draft: false
+---
+In the previous post I have explored how Backpack might be used for the Handle
+pattern. It helped me to take a better look at Backpack and reflect a bit on
+modules and records in Haskell.
+
+What's wrong with Backpack?
+---------------------------
+
+Backpack works as expected but there are downsides of the current implementation:
+
+  1. It's `cabal`-only. It means it's hard to integrate it in any big project
+     because developers tend to choose different build tools.
+  2. It's not user-friendly — it may throw some mysterious errors without
+     explaining what's going on. Or parse errors in mixins block
+     <a href="https://github.com/haskell/cabal/issues/5150">https://github.com/haskell/cabal/issues/5150</a>.
+  3. It's not maintained. `git blame` tells that there was not much activity in
+     Backpack modules in `cabal` repository for three years.
+  4. It does not support mutual recursive modules, sealing, higher-order units,
+     hierarchical modules, and other things. The functionality can be improved.
+  5. It lacks documentation.
+  6. It's not supported by Nix <a href="https://github.com/NixOS/nixpkgs/issues/40128">https://github.com/NixOS/nixpkgs/issues/40128</a>.
+     I don't think it's Backpack's problem but since Nix has become a very
+     popular choice for Haskell's build infrastructure it's a strong blocker
+     for Backpack's integration.
+  7. It's not used. Even if we close the eyes on problems with cabal or nix,
+     the developers don't use Backpack because it's too heavy-weight to use
+     and it's unidiomatic.
+
+These issues seem to be related: no users => bad support and bad support =>
+no users. Backpack was an attempt to bring a subset of ML modules system to
+Haskell, the language with anti-modular features and a big amount of legacy
+code written in that style. In my opinion, that attempt failed. The ML modules
+system is about explicit manipulation of modules in the program by design — the
+style that most Haskell programmers seem to dislike.
+
+What's the point of having an unused feature which is unmaintained and
+unfinished then? I write this not to criticize Backpack, but to understand its
+future. It's a great project that explored the important design space. The
+aforementioned downsides can be fixed and improved. The real question is
+"Should the community invest resources in that?"
+
+What's in the proposals
+-----------------------
+
+I looked at <a href="https://github.com/ghc-proposals/ghc-proposals/">https://github.com/ghc-proposals/ghc-proposals/</a> to see if there are
+any improvements of modularity in the future and, in my opinion, most proposals
+are focused on concrete problems instead of reflecting on the whole language.
+It may work well but also it may create inconsistency in the language.
+
+- QualifiedDo
+
+`QualifiedDo` brings syntax sugar for overloading `do` notation:
+
+```
+{-# LANGUAGE LinearTypes #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+module Control.Monad.Linear (Monad(..)) where
+
+class Monad m where
+  return :: a #-> m a
+  (>>=) :: m a #-> (a #-> m b) #-> mb
+
+-----------------
+
+module M where
+
+import qualified Control.Monad.Linear as Linear
+
+f :: Linear.Monad m => a #-> m b
+f a = Linear.do
+  b <- someLinearFunction a Linear.>>= someOtherLinearFunction
+  c <- anotherLinearFunction b
+  Linear.return c
+
+g :: Monad m => a -> m b
+g a = do
+  b <- someNonLinearFunction a >>= someOtherNonLinearFunction
+  c <- anotherNonLinearFunction b
+  return c
+```
+
+`Linear.do` overloads `return` and `(>>=)` with functions from
+`Control.Monad.Linear`. Hey, isn't this is why Backpack was created? To replace
+the implementation? Also, it can be achieved with records. And the authors used
+that solution in linear-base <a href="https://github.com/tweag/linear-base/blob/0d6165fbd8ad84dd1574a36071f00a6137351637/src/System/IO/Resource.hs#L119-L120">https://github.com/tweag/linear-base/blob/0d6165fb
+d8ad84dd1574a36071f00a6137351637/src/System/IO/Resource.hs#L119-L120</a>:
+
+```
+(<*>) :: forall a b. RIO (a ->. b) ->. RIO a ->. RIO b
+f <*> x = do
+    f' <- f
+    x' <- x
+    Linear.pure $ f' x'
+  where
+    Linear.Builder { .. } = Linear.monadBuilder
+```
+
+The quote from the proposal:
+
+>There is a way to emulate ``-XQualifiedDo`` in current GHC using
+``-XRecordWildcards``: have no ``(>>=)`` and such in scope, and import a
+builder with ``Builder {..} = builder``. It is used in `linear-base`. This is
+not a very good solution: it is rather a impenetrable idiom, and, if a single
+function uses several builders, it yields syntactic contortion (which is why
+shadowing warnings are deactivated here
+
+I don't mind about using records. It might be uncomfortable, but not worth to
+patch the language. Maybe I'm missing something important.
+
+At first glance, this syntactic extension may even look okay, but a more
+fundamental solution would be local modules support where you can open a module
+locally and bring its content into the scope:
+
+```
+(<*>) :: forall a b. RIO (a ->. b) ->. RIO a ->. RIO b
+f <*> x = let open Linear in do
+  f' <- f
+  x' <- x
+  Linear.pure $ f' x'
+```
+
+```
+(<*>) :: forall a b. RIO (a ->. b) ->. RIO a ->. RIO b
+f <*> x = do
+    f' <- f
+    x' <- x
+    Linear.pure $ f' x'
+  where
+    { .. } = open Linear
+```
+
+It's just like opening the records! It might be tedious to write these imports
+instead of `Linear.do`, but we wouldn't need to bring new functionality to the
+language if we had local imports. Maybe it means that "do notation" is really
+important to the Haskell community but to me, it feels like a temporary hack at
+the moment, not a fundamental part of the language.
+
+- Local modules
+
+`LocalModules` sounds like a good step in the right direction. It will be
+possible to create modules in modules and to open them locally! Just like in
+the example above with `Linear` module. Another good thing is that each `data`
+declaration implicitly creates a new local module, like in Agda. I'm not sure
+if it's possible to open them, I haven't found it in the proposal, but that
+would unify the opening of records and modules. Unfortunately, the proposal
+doesn't explore the interaction with Backpack:
+
+>This proposal does not appear to interact with Backpack. It does not address
+signatures, the key feature in Backpack. Perhaps the ideas here could be
+extended to work with signatures.
+
+Does it mean that there will be `LocalSignatures` in the future? Why not design
+the whole mechanism at once? Is there a risk of missing something important
+that would be hard to fix later?
+
+- First class modules
+
+This proposal is about making a module a first-class entity in the language.
+Its status is *dormant* because it's too much to change while the benefits seem
+to be the same as in `LocalModules`. While `LocalModules` is a technical
+proposal that goes into details, `First class modules` is more about language
+design proposal. `LocalModules` does not replace `First class modules`, but
+*a part of it*. This is exactly what I was looking for, the proposal that tries
+to build a vision for the language, what it might look in the future. The
+proposal mentions Backpack only once:
+
+> Interface files must be able to handle the possibility that an exported name
+refers to a module. This may have some interaction with Backpack.
+
+Unfortunately, the work on this proposal was stopped because most interesting
+things were described in `LocalModules` — a proposal that is about
+*local namespaces*, not *modules*. There is nothing about abstraction there.
+
+- Summing up
+
+It's important to remember that Haskell modules are just namespaces without any
+additional features. It's possible to import the contents of a module,
+everything or only specific things, and control what to export
+(except instances). While `LocalModules` will significantly improve developers'
+lives providing a flexible way to deal with scopes, it's unclear what the whole
+picture with modules will look like. And why Backpack is ignored by the
+proposals? What's wrong with it?
+
+The Backpack is ignored because it's not a proper part of the Haskell language.
+It's a mechanism that consists of *mixin linking* which is indifferent to
+Haskell source code, and *typechecking against interfaces*, which is purely the
+concern of the compiler. That's why it depends so much on Cabal — a frontend
+client for mixins description which can be replaced the compiler supports
+typechecking of interfaces. More details are available in Edward Z. Yang's
+thesis.
+
+Modules and records, and type classes
+-------------------------------------
+
+We understood that Backpack is a tool that uses the compiler and the package
+manager to express the features that are not supported in the language
+internally. Is it possible for Haskell to go further and improve the modularity
+in the language internally? To fit together anti-modular type classes and some
+subset of modules with abstract types? I want to explore what's in the ML
+languages at first.
+
+- What's in the ML land
+
+Let's take a look at what happens in languages with the ML modules system. The
+users of these languages accept the cost of the explicitness. Although, they
+would be glad to reduce the boilerplate when it's necessary.
+
+The theoretical works demonstrate that type classes and modules are not that
+different. <a href="http://www.stefanwehr.de/publications/Wehr_ML_modules_and_Haskell_type_classes.pdf">http://www.stefanwehr.de/publications/Wehr_ML_modules_and_Haskell_
+type_classes.pdf</a> showed that a subset of Haskell with type classes can be
+expressed with ML modules and vice versa with some limitations.
+<a href="https://www.cs.cmu.edu/~rwh/papers/mtc/full.pdf">https://www.cs.cmu.edu/~rwh/papers/mtc/full.pdf</a> went further in expressing type
+classes with modules. It starts with modules as the fundamental concept and
+then recovers type classes as a particular mode of use of modularity.
+
+The example of bringing type classes to the language with modules can be found
+in <a href="https://arxiv.org/abs/1512.01895">https://arxiv.org/abs/1512.01895</a> — an extension to the OCaml language for
+ad-hoc polymorphism inspired by Scala implicits and modular type classes. It's
+not supported by mainstream OCaml yet because the proper implementation
+requires a big change in the language. But here is a small example of how it
+might look for the `Show` type class:
+
+```
+(*
+  We express `Show` as a module type. It's a module signature that
+  can be instantiated with different implementations. It has an
+  abstract type `t` and a function `show` that takes `t` and returns `string`.
+
+  class Show t where
+    show :: t -> String
+*)
+module type Show = sig
+  type t
+  val show : t -> string
+end
+
+(*
+  This is a global function `show` with an implicit argument `S : Show`.
+  It means that it takes a module that implements the module type `Show`,
+  an argument `x`, and calls `S.show x` using the `show` from `S`.
+
+  show' :: Show a => a -> String
+  show' = show
+*)
+let show {S : Show} x = S.show x
+
+(*
+  An implementation of `Show` for `int`.
+
+  instance Show Int where
+    show = string_of_int
+*)
+implicit module Show_int = struct
+  type t = int
+  let show x = string_of_int x
+end
+
+(*
+  An implementation of `Show` for `float`.
+
+  instance Show Float where
+    show = string_of_float
+*)
+implicit module Show_float = struct
+  type t = float
+  let show x = string_of_float x
+end
+
+(*
+  An implementation of `Show` for `list`.
+  Since `list` contains elements of some type `t` we require
+  a module `S` to show them.
+
+  instance Show a => Show [a] where
+    show = string_of_list show
+*)
+implicit module Show_list {S : Show} = struct
+  type t = S.t list
+  let show x = string_of_list S.show x
+end
+
+let () =
+  print_endline ("Show an int: " ^ show 5);
+  print_endline ("Show a float: " ^ show 1.5);
+  print_endline ("Show a list of ints: " ^ show [1; 2; 3]);
+```
+
+As we can see the languages with ML modules system can get ad-hoc programming
+support to some degree.
+
+- Why modularity?
+
+Haskell's culture relies heavily on type classes. It's a foundation for monads,
+do-notation, and libraries. All instances of type classes should be unique and
+it's a cultural belief because the *global uniqueness of instances* is just an
+expectation that isn't forced by GHC <a href="http://blog.ezyang.com/2014/07/type-classes-confluence-coherence-global-uniqueness/">http://blog.ezyang.com/2014/07/type-classes
+-confluence-coherence-global-uniqueness/</a>. What's the point of living in an
+anti-modular myth that forbids the integration of possible modularity features?
+
+>It is easy to dismiss this example as an implementation wart in GHC, and
+continue pretending that global uniqueness of instances holds. However, the
+problem with global uniqueness of instances is that they are inherently
+nonmodular: you might find yourself unable to compose two components because
+they accidentally defined the same type class instance, even though these
+instances are plumbed deep in the implementation details of the components.
+This is a big problem for Backpack, or really any module system, whose mantra
+of separate modular development seeks to guarantee that linking will succeed
+if the library writer and the application writer develop to a common signature.
+
+The example with `QualifiedDo` shows that even one of the key features of
+Haskell needs modularity — monads and do-notation. That required additional
+patching of the language because do-notation is based on type classes instead
+of modules.
+
+`LocalModules` may help to deal with scopes (it's really annoying sometimes),
+but they won't provide the abstraction mechanism — the key feature of a module
+system. Modules with abstract types allow replacing the implementations because
+of Reynolds’s abstraction theorem.
+
+Type classes allow to create interfaces and implement them for different types,
+but they are usually global and ad-hoc. They make the project, the libraries,
+and the whole Hackage into one global world. Not always in practice for now,
+but it can be very annoying to track the import statement that brings an
+instance into the scope especially in a big codebase. Type classes become too
+expensive at some point as an abstraction tool.
+
+- Local signatures
+
+I wrote `LocalSignatures` as a joke when was writing about `LocalModules`, but
+then later I understood that it might work since GHC already supports type
+checking against interfaces it can be used to implement signatures on the
+language level. It might require lots of syntax changes though. Something like
+that:
+
+```
+module type EQ where
+  data T
+  eq :: T -> T -> Bool
+
+module type MAP where
+  data Key
+  data Map a
+  empty :: Map a
+  lookup :: Key -> Map a -> Maybe a
+  add :: Key -> a -> Map a -> Map a
+
+module Map (Key :: EQ) as MAP with (type Key as Key.T) where
+  type Key = Key.T
+  type Map a = Key -> Maybe a
+  empty x = Nothing
+  lookup x m = m x
+  add x y m = \z -> if Key.eq z x then Just y else m z
+```
+
+We have created two signatures (module types) `EQ` and `MAP`. And a module
+`Map` that implements `MAP`. Writing `as MAP`, we seal the module `Map` and
+hide the implementation details behind the signature `MAP`, specifying that
+`Key.T` is the same as `Key`.
+
+This is just an example to demonstrate how it might look like. It introduces a
+module system to the language but on a different level. We can't pass a module
+to a function — modules and core terms are separated.
+
+- Modules and records
+
+The Handle pattern demonstrates that Haskell's modules and records are alike in
+some way — they implement the Handle interface provided to the user, both
+containing functions. Records are dynamic and can be replaced in the runtime
+while signatures are static and can be specialized during the compilation. What
+if we could merge them into one entity?
+
+<a href="https://people.mpi-sws.org/~rossberg/1ml/">https://people.mpi-sws.org/~rossberg/1ml/</a> does that — it merges two languages
+in one: *core* with types and expressions, and *modules*, with signatures,
+structures and functors. And requires only System Fω. The example for local
+signatures mentioned above is the code I adapted from 1ML. Here is the
+original version:
+
+```
+type EQ =
+{
+  type t;
+  eq : t -> t -> bool;
+};
+
+type MAP =
+{
+  type key;
+  type map a;
+  empty 'a : map a;
+  lookup 'a : key -> map a -> opt a;
+  add 'a : key -> a -> map a -> map a;
+};
+
+Map (Key : EQ) :> MAP with (type key = Key.t) =
+{
+  type key = Key.t;
+  type map a = key -> opt a;
+  empty = fun x => none;
+  lookup x m = m x;
+  add x y m = fun z => if Key.eq z x then some y else m z;
+};
+
+datasize = 117;
+OrderedMap = Map {include Int; eq = curry (==)} :> MAP;
+HashMap = Map {include Int; eq = curry (==)} :> MAP;
+
+Map = if datasize <= 100 then OrderedMap else HashMap : MAP;
+```
+
+Looks similar, but now we can choose what module to use by analyzing the
+runtime value similar to what can be done in Haskell with records, vinyl, or
+something else. But they lack the abstract types support.
+
+Conclusions
+-----------
+
+I haven't thought about how local signatures or first-class modules may
+interact with type classes to achieve the same experience as with implicits in
+Agda, Scala, or OCaml. According to the recent paper on new implicits calculus
+<a href="https://lirias.kuleuven.be/2343745">https://lirias.kuleuven.be/2343745</a>, implicits don't have global uniqueness of
+instances, just GHC's type classes in practice, but have coherence and
+stability of type substitutions. It makes me wonder why not try to drop the
+global uniqueness property and improve the module system instead.
+
+The recently created Haskell Foundation states that it's going to address the
+need for *driving adoption*. It means more developers will write Haskell, more
+libraries, more projects, more type classes, and more instances that are
+*global* for the entire Hackage. I think it's important to decide what to do
+with Backpack, consider the improvement of the module system, and design the
+lianguage more carefully taking in mind the whole picture.
diff --git a/content/posts/thoughts-on-backpack-modules-and-records.md b/content/posts/thoughts-on-backpack-modules-and-records.md
deleted file mode 100644 (file)
index 7a4f8a6..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
----
-title: Thoughts on Backpack, modules, and records
-date: 2021-01-31
-draft: false
-tags: [haskell, backpack, modules, records]
-toc: true
----
-
-In ["Implementations of the Handle pattern"](/posts/implementations-of-the-handle-pattern) I have explored how Backpack might be used for the Handle pattern. It helped me to take a better look at Backpack and reflect a bit on modules and records in Haskell.
-
-### What's wrong with Backpack?
-
-Backpack works as expected but there are downsides of the current implementation:
-  1. It's `cabal`-only. It means it's hard to integrate it in any big project because developers tend to choose different build tools.
-  2. It's not user-friendly — it may throw [some mysterious errors](https://twitter.com/ak3n/status/1345358277803180034) without explaining what's going on. Or [parse errors in mixins block](https://github.com/haskell/cabal/issues/5150).
-  3. It's not maintained. `git blame` tells that there was not much activity in Backpack modules in `cabal` repository for three years.
-  4. It does not support mutual recursive modules, sealing, higher-order units, hierarchical modules, and other things. The functionality can be improved.
-  5. It lacks documentation.
-  6. It's [not supported by Nix](https://github.com/NixOS/nixpkgs/issues/40128). I don't think it's Backpack's problem but since Nix has become a very popular choice for Haskell's build infrastructure it's a strong blocker for Backpack's integration.
-  7. It's not used. Even if we close the eyes on problems with cabal or nix, the developers don't use Backpack because it's too [heavy-weight to use](https://www.reddit.com/r/haskell/comments/7ea0qg/backpack_why_does_this_cabal_file_fail_to_build/dq46myo/) and it's unidiomatic.
-
-These issues seem to be related: no users => bad support and bad support => no users. Backpack was an attempt to bring a subset of ML modules system to Haskell, the language with anti-modular features and a big amount of legacy code written in that style. In my opinion, that attempt failed. The ML modules system is about explicit manipulation of modules in the program by design — the style that most Haskell programmers seem to dislike.
-
-What's the point of having an unused feature which is unmaintained and unfinished then? I write this not to criticize Backpack, but to understand its future. It's a great project that explored the important design space. The aforementioned downsides can be fixed and improved. The real question is "Should the community invest resources in that?"
-
-### What's in the proposals
-
-I looked at [the GHC proposals](https://github.com/ghc-proposals/ghc-proposals/) to see if there are any improvements of modularity in the future and, in my opinion, most proposals are focused on concrete problems instead of reflecting on the whole language. It may work well but also it may create inconsistency in the language.
-
-#### QualifiedDo
-
-[`QualifiedDo`](https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0216-qualified-do.rst) brings syntax sugar for overloading `do` notation:
-
-```haskell
-{-# LANGUAGE LinearTypes #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-module Control.Monad.Linear (Monad(..)) where
-
-class Monad m where
-  return :: a #-> m a
-  (>>=) :: m a #-> (a #-> m b) #-> mb
-
------------------
-
-module M where
-
-import qualified Control.Monad.Linear as Linear
-
-f :: Linear.Monad m => a #-> m b
-f a = Linear.do
-  b <- someLinearFunction a Linear.>>= someOtherLinearFunction
-  c <- anotherLinearFunction b
-  Linear.return c
-
-g :: Monad m => a -> m b
-g a = do
-  b <- someNonLinearFunction a >>= someOtherNonLinearFunction
-  c <- anotherNonLinearFunction b
-  return c
-```
-
-`Linear.do` overloads `return` and `(>>=)` with functions from `Control.Monad.Linear`. Hey, isn't this is why Backpack was created? To replace the implementation? Also, it can be achieved with records. And the authors used that solution in [linear-base](https://github.com/tweag/linear-base/blob/0d6165fbd8ad84dd1574a36071f00a6137351637/src/System/IO/Resource.hs#L119-L120):
-
-```haskell
-(<*>) :: forall a b. RIO (a ->. b) ->. RIO a ->. RIO b
-f <*> x = do
-    f' <- f
-    x' <- x
-    Linear.pure $ f' x'
-  where
-    Linear.Builder { .. } = Linear.monadBuilder
-```
-
-The quote from the proposal:
-
->There is a way to emulate ``-XQualifiedDo`` in current GHC using ``-XRecordWildcards``: have no ``(>>=)`` and such in scope, and import a builder with ``Builder {..} = builder``. It is used in `linear-base`. This is not a very good solution: it is rather a impenetrable idiom, and, if a single function uses several builders, it yields syntactic contortion (which is why shadowing warnings are deactivated [here](https://github.com/tweag/linear-base/blob/0d6165fbd8ad84dd1574a36071f00a6137351637/src/System/IO/Resource.hs#L1))
-
-I don't mind about using records. It might be uncomfortable, but not worthing to patch the language. Maybe I'm missing something important.
-
-At first glance, this syntactic extension may even look okay, but a more fundamental solution would be local modules support where you can open a module locally and bring its content into the scope:
-
-```haskell
-(<*>) :: forall a b. RIO (a ->. b) ->. RIO a ->. RIO b
-f <*> x = let open Linear in do
-  f' <- f
-  x' <- x
-  Linear.pure $ f' x'
-```
-
-```haskell
-(<*>) :: forall a b. RIO (a ->. b) ->. RIO a ->. RIO b
-f <*> x = do
-    f' <- f
-    x' <- x
-    Linear.pure $ f' x'
-  where
-    { .. } = open Linear
-```
-
-It's just like opening the records! It might be tedious to write these imports instead of `Linear.do`, but we wouldn't need to bring new functionality to the language if we had local imports. Maybe it means that "do notation" is really important to the Haskell community but to me, it feels like a temporary hack at the moment, not a fundamental part of the language.
-
-#### Local modules
-
-[`LocalModules`](https://github.com/goldfirere/ghc-proposals/blob/local-modules/proposals/0000-local-modules.rst) sounds like a good step in the right direction. It will be possible to create modules in modules and to open them locally! Just like in the example above with `Linear` module. Another good thing is that each `data` declaration implicitly creates a new local module, [like in Agda](https://agda.readthedocs.io/en/v2.6.1/language/record-types.html#record-modules). I'm not sure if it's possible to open them, I haven't found it in the proposal, but that would unify the opening of records and modules. Unfortunately, the proposal doesn't explore the interaction with Backpack:
-
->This proposal does not appear to interact with Backpack. It does not address signatures, the key feature in Backpack. Perhaps the ideas here could be extended to work with signatures.
-
-Does it mean that there will be `LocalSignatures` in the future? Why not design the whole mechanism at once? Is there a risk of missing something important that would be hard to fix later?
-
-#### First class modules
-
-[This proposal](https://github.com/michaelpj/ghc-proposals/blob/imp/first-class-modules/proposals/0000-first-class-modules.rst) is about making a module a first-class entity in the language. Its status is *dormant* because it's too much to change while the benefits seem to be the same as in `LocalModules`. While `LocalModules` is a technical proposal that goes into details, `First class modules` is more about language design proposal. `LocalModules` does not replace `First class modules`, but *a part of it*. This is exactly what I was looking for, the proposal that tries to build a vision for the language, what it might look in the future. The proposal mentions Backpack only once:
-
-> Interface files must be able to handle the possibility that an exported name refers to a module. This may have some interaction with Backpack.
-
-Unfortunately, the work on this proposal was stopped because most interesting things were described in `LocalModules` — a proposal that is about *local namespaces*, not *modules*. There is nothing about abstraction there.
-
-#### Summing up
-
-It's important to remember that Haskell modules are just namespaces without any additional features. It's possible to import the contents of a module, everything or only specific things, and control what to export (except instances). While `LocalModules` will significantly improve developers' lives providing a flexible way to deal with scopes, it's unclear what the whole picture with modules will look like. And why Backpack is ignored by the proposals? What's wrong with it?
-
-The Backpack is ignored because it's not a proper part of the Haskell language. It's a mechanism that consists of *mixin linking* which is indifferent to Haskell source code, and *typechecking against interfaces*, which is purely the concern of the compiler. That's why it depends so much on Cabal — a frontend client for mixins description which can be replaced the compiler supports typechecking of interfaces. More details are available in Edward Z. Yang's [thesis](https://github.com/ezyang/thesis/releases/tag/rev20170925).
-
-### Modules and records, and type classes
-
-We understood that Backpack is a tool that uses the compiler and the package manager to express the features that are not supported in the language internally. Is it possible for Haskell to go further and improve the modularity in the language internally? To fit together anti-modular type classes and some subset of modules with abstract types? I want to explore what's in the ML languages at first.
-
-#### What's in the ML land
-
-Let's take a look at what happens in languages with the ML modules system. The users of these languages accept the cost of the explicitness. Although, they would be glad to reduce the boilerplate when it's necessary.
-
-The theoretical works demonstrate that type classes and modules are not that different. ["ML Modules and Haskell Type Classes: A Constructive Comparison"](http://www.stefanwehr.de/publications/Wehr_ML_modules_and_Haskell_type_classes.pdf) showed that a subset of Haskell with type classes can be expressed with ML modules and vice versa with some limitations. ["Modular Type Classes"](https://www.cs.cmu.edu/~rwh/papers/mtc/full.pdf) went further in expressing type classes with modules. It starts with modules as the fundamental concept and then recovers type classes as a particular mode of use of modularity.
-
-The example of bringing type classes to the language with modules can be found in ["Modular implicits"](https://arxiv.org/abs/1512.01895) — an extension to the OCaml language for ad-hoc polymorphism inspired by Scala implicits and modular type classes. It's not supported by mainstream OCaml yet because the proper implementation requires a big change in the language. But here is a small example of how it might look for the `Show` type class:
-
-```ocaml
-(*
-  We express `Show` as a module type. It's a module signature that
-  can be instantiated with different implementations. It has an
-  abstract type `t` and a function `show` that takes `t` and returns `string`.
-
-  class Show t where
-    show :: t -> String
-*)
-module type Show = sig
-  type t
-  val show : t -> string
-end
-
-(*
-  This is a global function `show` with an implicit argument `S : Show`.
-  It means that it takes a module that implements the module type `Show`,
-  an argument `x`, and calls `S.show x` using the `show` from `S`.
-
-  show' :: Show a => a -> String
-  show' = show
-*)
-let show {S : Show} x = S.show x
-
-(*
-  An implementation of `Show` for `int`.
-
-  instance Show Int where
-    show = string_of_int
-*)
-implicit module Show_int = struct
-  type t = int
-  let show x = string_of_int x
-end
-
-(*
-  An implementation of `Show` for `float`.
-
-  instance Show Float where
-    show = string_of_float
-*)
-implicit module Show_float = struct
-  type t = float
-  let show x = string_of_float x
-end
-
-(*
-  An implementation of `Show` for `list`.
-  Since `list` contains elements of some type `t` we require
-  a module `S` to show them.
-
-  instance Show a => Show [a] where
-    show = string_of_list show
-*)
-implicit module Show_list {S : Show} = struct
-  type t = S.t list
-  let show x = string_of_list S.show x
-end
-
-let () =
-  print_endline ("Show an int: " ^ show 5);
-  print_endline ("Show a float: " ^ show 1.5);
-  print_endline ("Show a list of ints: " ^ show [1; 2; 3]);
-```
-
-As we can see the languages with ML modules system can get ad-hoc programming support to some degree.
-
-#### Why modularity?
-
-Haskell's culture relies heavily on type classes. It's a foundation for monads, do-notation, and libraries. All instances of type classes should be unique and it's a cultural belief because the *global uniqueness of instances* is [just an expectation that isn't forced by GHC](http://blog.ezyang.com/2014/07/type-classes-confluence-coherence-global-uniqueness/). What's the point of living in an anti-modular myth that forbids the integration of possible modularity features?
-
->It is easy to dismiss this example as an implementation wart in GHC, and continue pretending that global uniqueness of instances holds. However, the problem with global uniqueness of instances is that they are inherently nonmodular: you might find yourself unable to compose two components because they accidentally defined the same type class instance, even though these instances are plumbed deep in the implementation details of the components. This is a big problem for Backpack, or really any module system, whose mantra of separate modular development seeks to guarantee that linking will succeed if the library writer and the application writer develop to a common signature.
-
-The example with `QualifiedDo` shows that even one of the key features of Haskell needs modularity — monads and do-notation. That required additional patching of the language because do-notation is based on type classes instead of modules.
-
-`LocalModules` may help to deal with scopes (it's really annoying sometimes), but they won't provide the abstraction mechanism — the key feature of a module system. Modules with abstract types allow replacing the implementations because of Reynolds’s abstraction theorem.
-
-Type classes allow to create interfaces and implement them for different types, but they are usually global and ad-hoc. They make the project, the libraries, and the whole Hackage into one global world. Not always in practice for now, but it can be very annoying to track the import statement that brings an instance into the scope especially in a big codebase. Type classes become too expensive at some point as an abstraction tool.
-
-#### Local signatures
-
-I wrote `LocalSignatures` as a joke when was writing about `LocalModules`, but then later I understood that it might work since GHC already supports type checking against interfaces it can be used to implement signatures on the language level. It might require lots of syntax changes though. Something like that:
-
-```haskell
-module type EQ where
-  data T
-  eq :: T -> T -> Bool
-
-module type MAP where
-  data Key
-  data Map a
-  empty :: Map a
-  lookup :: Key -> Map a -> Maybe a
-  add :: Key -> a -> Map a -> Map a
-
-module Map (Key :: EQ) as MAP with (type Key as Key.T) where
-  type Key = Key.T
-  type Map a = Key -> Maybe a
-  empty x = Nothing
-  lookup x m = m x
-  add x y m = \z -> if Key.eq z x then Just y else m z
-```
-
-We have created two signatures (module types) `EQ` and `MAP`. And a module `Map` that implements `MAP`. Writing `as MAP`, we seal the module `Map` and hide the implementation details behind the signature `MAP`, specifying that `Key.T` is the same as `Key`.
-
-This is just an example to demonstrate how it might look like. It introduces a module system to the language but on a different level. We can't pass a module to a function — modules and core terms are separated.
-
-#### Modules and records
-
-The Handle pattern demonstrates that Haskell's modules and records are alike in some way — they implement the Handle interface provided to the user, both containing functions. Records are dynamic and can be replaced in the runtime while signatures are static and can be specialized during the compilation. What if we could merge them into one entity?
-
-[1ML](https://people.mpi-sws.org/~rossberg/1ml/) does that — it merges two languages in one: *core* with types and expressions, and *modules*, with signatures, structures and functors. And requires only System Fω. The example for local signatures mentioned above is the code I adapted from 1ML. Here is the original version:
-
-```ocaml
-type EQ =
-{
-  type t;
-  eq : t -> t -> bool;
-};
-
-type MAP =
-{
-  type key;
-  type map a;
-  empty 'a : map a;
-  lookup 'a : key -> map a -> opt a;
-  add 'a : key -> a -> map a -> map a;
-};
-
-Map (Key : EQ) :> MAP with (type key = Key.t) =
-{
-  type key = Key.t;
-  type map a = key -> opt a;
-  empty = fun x => none;
-  lookup x m = m x;
-  add x y m = fun z => if Key.eq z x then some y else m z;
-};
-
-datasize = 117;
-OrderedMap = Map {include Int; eq = curry (==)} :> MAP;
-HashMap = Map {include Int; eq = curry (==)} :> MAP;
-
-Map = if datasize <= 100 then OrderedMap else HashMap : MAP;
-```
-
-Looks similar, but now we can choose what module to use by analyzing the runtime value similar to what can be done in Haskell with records, vinyl, or something else. But they lack the abstract types support.
-
-### Conclusions
-
-I haven't thought about how local signatures or first-class modules may interact with type classes to achieve the same experience as with implicits in Agda, Scala, or OCaml. According to [the recent paper on new implicits calculus](https://lirias.kuleuven.be/2343745), implicits don't have global uniqueness of instances, just GHC's type classes in practice, but have coherence and stability of type substitutions. It makes me wonder why not try to drop the global uniqueness property and improve the module system instead.
-
-The recently created [Haskell Foundation](https://haskell.foundation/en/) states that it's going to address the need for *driving adoption*. It means more developers will write Haskell, more libraries, more projects, more type classes, and more instances that are *global* for the entire Hackage. I think it's important to decide what to do with Backpack, consider the improvement of the module system, and design the language more carefully taking in mind the whole picture.
diff --git a/content/posts/why-i-am-not-a-scientist.html b/content/posts/why-i-am-not-a-scientist.html
new file mode 100644 (file)
index 0000000..a09627d
--- /dev/null
@@ -0,0 +1,57 @@
+---
+title: Why I am not a scientist
+date: 2024-02-03
+draft: false
+---
+I was an obsessive tv series binge-watcher in my teens. One of the numerous
+titles was "The Big Bang Theory" that I enjoyed while it was ongoing around
+2010. Only recently (around two years ago) I have realized the degree of
+influence towards my personality and decided to write it down.
+
+The show got me interested to become a scientist and try myself in the academia.
+It created an image of a cool scientist, nerdy and funny. That's why, up to
+a certain degree, I've tried to learn lambda calculus, followed a lot of people
+from academia, learned about type theory, read different papers, played with
+Agda, Twelf and other proof assistants, visited <a href="https://www.macs.hw.ac.uk/splv/splv19/">https://www.macs.hw.ac.uk/splv/splv19/</a>,
+and participated in the creating of functional programming course for Ural
+Federal University (this was mostly about giving back to the community and
+getting teaching experience). I seriously thought about applying for different
+PhD programs.
+
+Sounds great and cool! Except the fact that most of this, at the beginning, was
+about Ego. The biggest motivation was the desire to build an image of a smart
+person who has a PhD degree, knows cool words and facts, draws mysterious
+smart-looking diagrams on the board and notebook using greek letters and arrows.
+It was all about collecting and assigning different attributes myself that
+seemed cool to me, building a simulacrum and an absolute fetishization of it.
+
+It took me some time (years) to realize this and finally give up on this absurd
+quest. I have tried myself in teaching, learning things, creating educational
+materials, and tried to contribue to different scientific projects (not much).
+Yes, of course, I enjoyed some of these activities. I learned a lot of
+interesting things and it was a pleasant experience. But it was a wrong
+direction. A good test to check if the path is correct is to ask yourself
+(citing Naval Ravikant <a href="https://www.youtube.com/watch?v=3qHkcs3kG44">https://www.youtube.com/watch?v=3qHkcs3kG44</a>):
+
+> Would I still be interested in learning this thing if I couldn’t ever tell
+anybody about it? That’s how I know it’s real. That’s how I know something I
+actually want.
+
+That's a perfect way to figure out what's worth learning. What's the real
+interest. Unfortunately, I have learned it too late. I realized that I
+overvalued the theoretical and scientific stuff, that I prefer engineering and
+the practical side. It just feels more natural to me. And it took me some time
+to understand that software engineering is not less cool than doing science.
+All activities are different and require different skills. All we need to do is
+to find what suits ourselves better and makes happy.
+
+I talked to great researchers (who are amazing persons) about their experience
+and everyday work. I learned that scientists depend on their funding, on grants
+and writing grant proposals, and they can't just start researching what they
+find interesting. They deal with a lot of bureaucracy (which I can't stand,
+I'm extremely allergic to it) and exist in the rigid social structure
+(a university or a research institution), while I value freedom too much.
+
+That's how removing the Ego from the equation was a major factor that helped me
+to resolve my long-standing self-identification crises — to be an engineer or a
+scientist.
diff --git a/content/posts/why-i-am-not-a-scientist.md b/content/posts/why-i-am-not-a-scientist.md
deleted file mode 100644 (file)
index 8bf341d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Why I am not a scientist
-date: 2024-02-03
-draft: false
-tags: [reflection]
----
-
-I was an obsessive tv series binge-watcher in my teens. One of the numerous titles was "The Big Bang Theory" that I enjoyed while it was ongoing around 2010. Only recently (around two years ago) I have realized the degree of influence towards my personality and decided to write it down.
-
-The show got me interested to become a scientist and try myself in the academia. It created an image of a cool scientist, nerdy and funny. That's why, up to a certain degree, I've tried to learn lambda calculus, followed a lot of people from academia, learned about type theory, read different papers, played with Agda, Twelf and other proof assistants, visited [SPLV 2019](https://www.macs.hw.ac.uk/splv/splv19/), and participated in the creating of functional programming course for Ural Federal University (this was mostly about giving back to the community and getting teaching experience). I seriously thought about applying for different PhD programs.
-
-Sounds great and cool! Except the fact that most of this, at the beginning, was about Ego. The biggest motivation was the desire to build an image of a smart person who has a PhD degree, knows cool words and facts, draws mysterious smart-looking diagrams on the board and notebook using greek letters and arrows. It was all about collecting and assigning different attributes myself that seemed cool to me, building a simulacrum and an absolute fetishization of it.
-
-It took me some time (years) to realize this and finally give up on this absurd quest. I have tried myself in teaching, learning things, creating educational materials, and tried to contribue to different scientific projects (not much). Yes, of course, I enjoyed some of these activities. I learned a lot of interesting things and it was a pleasant experience. But it was a wrong direction. A good test to check if the path is correct is to ask yourself ([citing Naval Ravikant](https://www.youtube.com/watch?v=3qHkcs3kG44)):
-
-> Would I still be interested in learning this thing if I couldn’t ever tell anybody about it? That’s how I know it’s real. That’s how I know something I actually want.
-
-That's a perfect way to figure out what's worth learning. What's the real interest. Unfortunately, I have learned it too late. I realized that I overvalued the theoretical and scientific stuff, that I prefer engineering and the practical side. It just feels more natural to me. And it took me some time to understand that software engineering is not less cool than doing science. All activities are different and require different skills. All we need to do is to find what suits ourselves better and makes happy.
-
-I talked to great researchers (who are amazing persons) about their experience and everyday work. I learned that scientists depend on their funding, on grants and writing grant proposals, and they can't just start researching what they find interesting. They deal with a lot of bureaucracy (which I can't stand, I'm extremely allergic to it) and exist in the rigid social structure (a university or a research institution), while I value freedom too much.
-
-That's how removing the Ego from the equation was a major factor that helped me to resolve my long-standing self-identification crises — to be an engineer or a scientist.
diff --git a/content/posts/wisdom-and-software-engineering.html b/content/posts/wisdom-and-software-engineering.html
new file mode 100644 (file)
index 0000000..437020e
--- /dev/null
@@ -0,0 +1,197 @@
+---
+title: Wisdom and software engineering
+date: 2024-01-15
+draft: false
+---
+It's been a while since I read "The Intelligence Trap" — a nice book on
+intelligence and wisdom with many facts about knowledge, four stages of
+competence, how to teach children, how to learn, &c. More importantly it
+encourages humility and explains how big ego / expertise might be harmful.
+It certainly bootstraped some thought processes in my mind, getting me curious
+in different topics — especially wisdom.
+
+Afterwhile, I discovered John Vervaeke and his lecture course on wisdom
+<a href="https://www.youtube.com/playlist?list=PLND1JCRq8Vuh3f0P5qjrSdb5eC1ZfZwWJ">https://www.youtube.com/playlist?list=PLND1JCRq8Vuh3f0P5qjrSdb5eC1ZfZwWJ</a>, which
+raised an idea to reflect on software engineering, since it's something I know
+better than other domains. Quoting John Vervaeke:
+
+> Wisdom is an ecology of psychotechnologies. An ecology of styles that
+dynamically—and that means reciprocally, in a reciprocal fashion—constrain
+and optimize each other, such that there is an overall optimization,
+enhancement of relevance realization. Relevance realization within inference,
+within insight and intuition, the connection to implicit processing,
+internalization, understanding, gnosis, transformation and aspiration. Wisdom
+is an ecology of psychotechnologies and cognitive styles that dynamically
+enhance relevance realization in inference, insight and intuition,
+internalization, understanding, and gnosis, transformation, and aspiration.
+
+I want to note and write down what kind of meta skills (psychotechnologies)
+might be helpful in the following activities, representing the software
+engineer's work:
+
+- Coding;
+- Code review;
+- Release management;
+- Communication & team performance;
+- Problem solving;
+- Self-management.
+
+Most of them are well-covered in all sorts of educational materials, a couple
+of links:
+
+- <a href="https://www.kitchensoap.com/2012/10/25/on-being-a-senior-engineer/">https://www.kitchensoap.com/2012/10/25/on-being-a-senior-engineer/</a>
+- <a href="https://martinrue.com/my-engineering-axioms/">https://martinrue.com/my-engineering-axioms/</a>
+
+I won't write anything specific, just some general notes.
+
+Writing code
+------------
+
+Let's start with the basics — coding. I bet all programmers had a so called
+the flow state (<a href="https://en.wikipedia.org/wiki/Flow_(psychology)">https://en.wikipedia.org/wiki/Flow_(psychology)</a>) during the
+programming session, when a person gets focused that doesn't notice how the
+time passes. There is a list of qualities for a task to create the flow state.
+More details are available in "Flow", by Mihaly Csikszentmihalyi.
+
+I will mention the ones we are interested in:
+
+- The task should be competetive. Its complexity should be on par with the
+person's skill level. If the task is too easy, it won't be competetive and
+interesting. If it's too hard, it won't be possible to evolve;
+
+- There should be a feedback loop.
+
+The programming is great since it provides us a lot of interesting problems
+and, what's more amazing, it has an extremely short feedback loop, not many
+activies has are like that. And the loop could be shortened via more effective
+tools improving the compiler speed, using better editor, IDE, more suitable
+programming language, &c. Personally, I prefer Sublime Text & the compiler in
+Terminal.app without LSP plugins because I feel myself more effective this way,
+no matter how much time I invested in Vim/Emacs/&c. or other terminals.
+
+I think it's important to be aware of this state. Because of it, I think,
+we become programmers — we like to program. We like to work and build things,
+to iterate, to see the results, edit, compile, edit, &c. I mentioned it in
+<a href="https://ak3n.com/posts/on-short-lived-software.html">https://ak3n.com/posts/on-short-lived-software.html</a>, that this is what makes
+programming interesting, not the result, which is almost always temporary.
+What's even more important than to be aware of the flow state — the ability to
+control it.
+
+Meta skills
+-----------
+
+Of course, hard skills are important — that's why a person gets hired in first
+place. Soft skills are important as well, without them they will get fired soon.
+Meta skills, I suppose, come with experience over time — but unfortunately not
+for everyone. They are usually taught by experienced engineers either in person
+or via educational materials, and still might not be picked up by a person.
+
+- Ego
+
+  It's important to be humble not only for good communication and team work,
+  but also because it helps at avoiding the expertise traps. When being an
+  expert becomes a problem and a quick way to self-deception. That's why it's
+  important to always be careful with personal experience — it might be
+  irrelevant when a fresh look is required.
+
+- Empathy
+
+  Same thing as with Ego - being empathic is an important skill in human
+  relationships. But also, it might be a good hard skill. I learned about it in
+  the aforementioned Flow. It described an ability to identify with something
+  non-working (a toaster for example) — "if I'm a toaster, where would I break"
+  — this internalization approach might help to understand how something works
+  and figure out the problem.
+
+- Zooming out
+
+  It's valuable to be conscious enough of spending too much time on some
+  activity. There is no point in traversing the problem in depth if it's
+  unclear if the assumption/way is valid. Unfortunately, even experienced
+  engineers get into this trap quite regularly.
+
+  It's valuable to be able to zoom out, reflect on the process and time-spending
+  for overcoming the self-deception. I guess that's why the
+  <a href="https://en.wikipedia.org/wiki/Pomodoro_Technique">https://en.wikipedia.org/wiki/Pomodoro_Technique</a> is popular. Same thing as a
+  simple walking (also improving the mental health & thinking) and controled
+  interruptions (uncontroled ones just break the flow state).
+
+- Socratic method
+
+  <a href="https://en.wikipedia.org/wiki/Pair_programming">https://en.wikipedia.org/wiki/Pair_programming</a> is a popular and wide-known
+  technique to work together on a problem. Not only two expertises connect but,
+  more importantly, two different perspectives allow to exchange understandings.
+
+  <a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging">https://en.wikipedia.org/wiki/Rubber_duck_debugging</a> provides similar benefits,
+  where one person uses an object to talk to, getting a better understanding of
+  the problem by formulating thoughts aloud. And also it's much cheaper than
+  pairing, without distracting a coworker.
+
+  The next step would be the internalization of the sage. Quoting Vervaeke again:
+
+  > So we see across the traditions, the idea of internalizing the sage to
+  create an inner dialogue that helps to coordinate the various centers, gets
+  them to talk to each other. And I think this is something where cognitive
+  science can actually give us tremendous help. We’ve had a lot of increase in
+  our knowledge of the various/different areas of cognition, even different
+  kinds of centers processing in the brain and how they work and how they’re
+  operating and what we need is an internalized representation. A model. A role
+  model and a role as a way of taking on a new identity, right? We need a role
+  model for how we can engage in dialogue. and the proposal here – which is, of
+  course, the platonic proposal we already saw – that if I can internalize my
+  capacity and, developed by the Stoics, my capacity to interact with the sage,
+  eventually I get that ability that I have only with the sage. I can have it
+  with myself, within myself. And it means therefore that it becomes part of my
+  metacognitive machinery, the way I dialogue with myself and get the various
+  aspects of myself, the very centers to dialogue with each other.
+
+  > That’s why wisdom is going to matter to all of this, right? So I practice
+  indwelling the sage, right? And yet, people like, what would Socrates do?
+  What would Aristotle do? What would Jesus do, right? And you have to
+  regularly practice. So you practice indwelling and then you practice
+  internalizing and you practice indwelling and then you practice internalizing.
+  And that is how you basically start to afford the internalization of the sage
+  and the creation of your ability, as Antisthenes said, what he learned from
+  Socrates so long ago: to converse with yourself, to get, to enter into
+  something like platonic dialogue with yourself.
+
+  The idea is to develop a mental model, develop a psychotechnology, to be able
+  to have an internal dialogue with it. And it shouldn't be limited only to the
+  professional domain, it's also a very powerful thing for everyday life. A good
+  demonstration of this approach from therapy is
+  <a href="https://www.lesswrong.com/posts/mQmx4kQQtHeBip9ZC/internal-double-crux">https://www.lesswrong.com/posts/mQmx4kQQtHeBip9ZC/internal-double-crux</a>.
+
+- Relevance Realization
+
+  One more extremely important skill that intersects with the others — it's an
+  ability to know what's relevant at the moment (maybe it's more an attribute
+  or a mental tool that's not under direct control). This helps to understand
+  when to zoom out, to notice that something is wrong, this way or premise is
+  incorrect and it's time to get back. This skill helps to maintain a proper
+  discussion with coworkers, when people tend to speak about so many different
+  things, diving into technical details that might be simply _irrelevant_ to
+  the actual problem. It helps to write proper comments on reviews. Not to
+  mention a hundred typos, but to pay attention at the correctness, performance,
+  potential architecture problems. It helps to open proper PRs, without noisy
+  refactoring, &c.
+
+  Same happens with the ability to focus at will. Sometimes it's important to
+  be _passionate_ (recently extremely hackneyed word), it's important to care
+  about the code, to find it valuable and get into the flow state, but also
+  it's important to be able to turn it off and throw the code away. It's all
+  about context, trade-offs, and relevance. It's important to figure out the
+  relevance and realize it. It also helps to understand what's a good problem.
+  Good problem finding is an important skill and it's a matter of wisdom.
+
+- Conclusion
+
+The listening to this lecture course was a long but life changing experience.
+It's impossible to tell how many things I've learned and that's for sure that
+I will go over it again at some point in the future with a fresh look.
+
+Here, I've tried to briefly note the metaskills available for a software
+engineer, how valuable they might be, and that they are not specific to the
+software development. They are quite general and might be relevant in other
+domains as well, including everyday life situations. Improving and working on
+them helps to gather more insights and grow not only as a professional, but
+also as a person.
diff --git a/content/posts/wisdom-and-software-engineering.md b/content/posts/wisdom-and-software-engineering.md
deleted file mode 100644 (file)
index c9bb631..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
----
-title: Wisdom and software engineering
-date: 2024-01-15
-draft: false
-tags: [wisdom, software]
-toc: true
----
-
-It's been a while since I read ["The Intelligence Trap"](https://www.goodreads.com/book/show/41817546-the-intelligence-trap) — a nice book on intelligence and wisdom with many facts about knowledge, four stages of competence, how to teach children, how to learn, &c. More importantly it encourages humility and explains how big ego / expertise might be harmful. It certainly bootstraped some thought processes in my mind, getting me curious in different topics — especially wisdom.
-
-Afterwhile, I discovered John Vervaeke and his [lecture course on wisdom](https://www.youtube.com/playlist?list=PLND1JCRq8Vuh3f0P5qjrSdb5eC1ZfZwWJ), which raised an idea to reflect on software engineering, since it's something I know better than other domains. [Quoting](https://www.meaningcrisis.co/ep-45-awakening-from-the-meaning-crisis-the-nature-of-wisdom/) John Vervaeke:
-
-> Wisdom is an ecology of psychotechnologies. An ecology of styles that dynamically—and that means reciprocally, in a reciprocal fashion—constrain and optimize each other, such that there is an overall optimization, enhancement of relevance realization. Relevance realization within inference, within insight and intuition, the connection to implicit processing, internalization, understanding, gnosis, transformation and aspiration. Wisdom is an ecology of psychotechnologies and cognitive styles that dynamically enhance relevance realization in inference, insight and intuition, internalization, understanding, and gnosis, transformation, and aspiration.
-
-I want to note and write down what kind of meta skills (psychotechnologies) might be helpful in the following activities, representing the software engineer's work:
-
-- Coding;
-- Code review;
-- Release management;
-- Communication & team performance;
-- Problem solving;
-- Self-management.
-
-Most of them are well-covered in all sorts of educational materials (a few links: [link1](https://www.kitchensoap.com/2012/10/25/on-being-a-senior-engineer/), [link2](https://martinrue.com/my-engineering-axioms/)), so I won't write anything specific, just some general notes.
-
-### Writing code
-
-Let's start with the basics — coding. I bet all programmers had a so called [the flow state](https://en.wikipedia.org/wiki/Flow_(psychology)) during the programming session, when a person gets focused that doesn't notice how the time passes. There is a list of qualities for a task to create the flow state. More details are available in [Flow, by Mihaly Csikszentmihalyi](https://www.goodreads.com/en/book/show/66354).
-
-I will mention the ones we are interested in:
-
-- The task should be competetive. Its complexity should be on par with the person's skill level. If the task is too easy, it won't be competetive and interesting. If it's too hard, it won't be possible to evolve;
-
-- There should be a feedback loop.
-
-The programming is great since it provides us a lot of interesting problems and, what's more amazing, it has an extremely short feedback loop, not many activies has are like that. And the loop could be shortened via more effective tools improving the compiler speed, using better editor, IDE, more suitable programming language, &c. Personally, I prefer Sublime Text & the compiler in Terminal.app without [LSP](https://en.wikipedia.org/wiki/Language_Server_Protocol) plugins because I feel myself more effective this way, no matter how much time I invested in Vim/Emacs/&c. or other terminals.
-
-I think it's important to be aware of this state. Because of it (again, I think) we become programmers — we like to program. We like to work and build things, to iterate, to see the results, edit, compile, edit, &c. I mentioned it in ["On short-lived software"](http://localhost:1313/posts/on-short-lived-software/), that this is what makes programming interesting, not the result, which is almost always temporary. What's even more important than to be aware of the flow state — the ability to control it.
-
-### Meta skills
-
-Of course, hard skills are important — that's why a person gets hired in first place. Soft skills are important as well, without them they will get fired soon. Meta skills, I suppose, come with experience over time — but unfortunately not for everyone. They are usually taught by experienced engineers either in person or via educational materials, and still might not be picked up by a person.
-
-#### Ego
-
-  It's important to be humble not only for good communication and team work, but also because it helps at avoiding the expertise traps. When being an expert becomes a problem and a quick way to self-deception. That's why it's important to always be careful with personal experience — it might be irrelevant when a fresh look is required.
-
-#### Empathy
-
-  Same thing as with Ego - being empathic is an important skill in human relationships. But also, it might be a good hard skill. I learned about it in the aforementioned Flow. It described an ability to identify with something non-working (a toaster for example) — "if I'm a toaster, where would I break" — this internalization approach might help to understand how something works and figure out the problem.
-
-#### Zooming out
-
-  It's valuable to be conscious enough of spending too much time on some activity. There is no point in traversing the problem in depth if it's unclear if the assumption/way is valid. Unfortunately, even experienced engineers get into this trap quite regularly.
-
-  It's valuable to be able to zoom out, reflect on the process and time-spending for overcoming the self-deception. I guess that's why [the pomodoro technique](https://en.wikipedia.org/wiki/Pomodoro_Technique) is popular. Same thing as a simple walking (also improving the mental health & thinking) and controled interruptions (uncontroled ones just break the flow state).
-
-#### Socratic method
-
-  [Pair programming](https://en.wikipedia.org/wiki/Pair_programming) is a popular and wide-known technique to work together on a problem. Not only two expertises connect but, more importantly, two different perspectives allow to exchange understandings.
-
-  [Rubber duck debugging](https://en.wikipedia.org/wiki/Rubber_duck_debugging) provides similar benefits, where one person uses an object to talk to, getting a better understanding of the problem by formulating thoughts aloud. And also it's much cheaper than pairing, without distracting a coworker.
-
-  The next step would be the internalization of the sage. [Quoting](https://www.meaningcrisis.co/ep-37-awakening-from-the-meaning-crisis-reverse-engineering-enlightenment-part-2/) Vervaeke again:
-
-  > So we see across the traditions, the idea of internalizing the sage to create an inner dialogue that helps to coordinate the various centers, gets them to talk to each other. And I think this is something where cognitive science can actually give us tremendous help. We’ve had a lot of increase in our knowledge of the various/different areas of cognition, even different kinds of centers processing in the brain and how they work and how they’re operating and what we need is an internalized representation. A model. A role model and a role as a way of taking on a new identity, right? We need a role model for how we can engage in dialogue. and the proposal here – which is, of course, the platonic proposal we already saw – that if I can internalize my capacity and, developed by the Stoics, my capacity to interact with the sage, eventually I get that ability that I have only with the sage. I can have it with myself, within myself. And it means therefore that it becomes part of my metacognitive machinery, the way I dialogue with myself and get the various aspects of myself, the very centers to dialogue with each other.
-
-  > That’s why wisdom is going to matter to all of this, right? So I practice indwelling the sage, right? And yet, people like, what would Socrates do? What would Aristotle do? What would Jesus do, right? And you have to regularly practice. So you practice indwelling and then you practice internalizing and you practice indwelling and then you practice internalizing. And that is how you basically start to afford the internalization of the sage and the creation of your ability, as Antisthenes said, what he learned from Socrates so long ago: to converse with yourself, to get, to enter into something like platonic dialogue with yourself.
-
-  The idea is to develop a mental model, develop a psychotechnology, to be able to have an internal dialogue with it. And it shouldn't be limited only to the professional domain, it's also a very powerful thing for everyday life. A good demonstration of this approach is [Internal Double Crux](https://www.lesswrong.com/posts/mQmx4kQQtHeBip9ZC/internal-double-crux) from therapy.
-
-#### Relevance Realization
-
-  One more extremely important skill that intersects with the others — it's an ability to know what's relevant at the moment (maybe it's more an attribute or a mental tool that's not under direct control). This helps to understand when to zoom out, to notice that something is wrong, this way or premise is incorrect and it's time to get back. This skill helps to maintain a proper discussion with coworkers, when people tend to speak about so many different things, diving into technical details that might be simply _irrelevant_ to the actual problem. It helps to write proper comments on reviews. Not to mention a hundred typos, but to pay attention at the correctness, performance, potential architecture problems. It helps to open proper PRs, without noisy refactoring, &c.
-
-  Same happens with the ability to focus at will. Sometimes it's important to be _passionate_ (recently extremely hackneyed word), it's important to care about the code, to find it valuable and get into the flow state, but also it's important to be able to turn it off and throw the code away. It's all about context, trade-offs, and relevance. It's important to figure out the relevance and realize it. It also helps to understand what's a good problem. Good problem finding is an important skill and it's a matter of wisdom.
-
-### Conclusion
-
-The listening to this lecture course was a long but life changing experience. It's impossible to tell how many things I've learned and that's for sure that I will go over it again at some point in the future with a fresh look.
-
-Here, I've tried to briefly note the metaskills available for a software engineer, how valuable they might be, and that they are not specific to the software development. They are quite general and might be relevant in other domains as well, including everyday life situations. Improving and working on them helps to gather more insights and grow not only as a professional, but also as a person.
\ No newline at end of file
diff --git a/content/static/images/cubicaltt.png b/content/static/images/cubicaltt.png
deleted file mode 100644 (file)
index 74541b2..0000000
Binary files a/content/static/images/cubicaltt.png and /dev/null differ
diff --git a/content/static/images/rendertable.png b/content/static/images/rendertable.png
deleted file mode 100644 (file)
index 2ac23e1..0000000
Binary files a/content/static/images/rendertable.png and /dev/null differ
diff --git a/content/static/images/whereareyougame.png b/content/static/images/whereareyougame.png
deleted file mode 100644 (file)
index 38eee9a..0000000
Binary files a/content/static/images/whereareyougame.png and /dev/null differ
index 64ed7512c54af6e31c76f228fcf94c1e8e8562c7..e88e4122b7fed26cc75ee632923be5d430cb7981 100644 (file)
@@ -1,27 +1,12 @@
 {{ partial "header.html" . }}
 
-{{ partial "subheader.html" . }}
-
-<div class="pure-g">
-    <div class="pure-u-1 pure-u-lg-1-3"></div>
-
-    <div class="pure-u-1 pure-u-lg-1-3">
-        <h3>{{ .Title }}</h3>
-        <section>
-          <ul>
-            {{ range .Data.Pages.ByPublishDate.Reverse }}
-              <div class="posts">
-                <div id=date class="date-time-title">
-                    <time>{{ .Date.Format (.Site.Params.dateform | default "02 Jan 06") }}</time>
-                </div>
-                <div class="date-time-title post">
-                  <a href="{{ .Permalink }}">{{ .Title }}</a>
-                </div>
-              </div>
-            {{ end }}
-          </ul>
-        </section>
-    </div>
-</div>
+<pre>
+posts
+-----
+{{ range (where .Site.RegularPages.ByPublishDate.Reverse "Type" "in" .Site.Params.mainSections) }}
+- <time>{{ .Date.Format (.Site.Params.dateform | default "02 Jan 06") }}</time> <a href="{{ .Permalink }}">{{ .Title }}</a>{{ end }}
+
+rss is available at <a href="https:{{ .Site.BaseURL }}index.xml">https:{{ .Site.BaseURL }}index.xml</a> 
+</pre>
 
 {{ partial "footer.html" . }}
index 3954d7ab5e63ba5a5c5c40281affefc239713dd4..4a47019c066ad2c6a0bc23de3f28b50748362656 100644 (file)
@@ -1,35 +1,12 @@
 {{ partial "header.html" . }}
 
-{{ partial "subheader.html" . }}
+<pre>
+{{ .Title }}
+{{ range seq (len .Title) }}={{end}}
 
-<div class="pure-g">
-    <div class="pure-u-1 pure-u-lg-1-5">
-        {{ partial "toc.html" . }}
-    </div>
+{{ .Date.Format (.Site.Params.dateform | default "January 02, 2006") }}
 
-    <div class="pure-u-1 pure-u-lg-3-5">
-        <article id="main">
-
-            <section class="blog-post">
-                <h1>{{ .Title }}</h1>
-                <div class="blog-post-subheader">
-                    <div>
-                        {{ .Date.Format (.Site.Params.dateform | default "January 02, 2006") }}
-                    </div>
-                    <div>
-                        {{ partial "tags.html" (.GetTerms "tags") }}
-                    </div>
-                </div>
-                <div class="blog-post-content">
-                    {{ partial "headline.html" .Content }}
-                </div>
-
-                <div class="blog-post-feedback">
-                    <a href="mailto:hi@ak3n.com">say hi</a> to leave a comment or feedback
-                </div>
-            </section>
-     </article>
-    </div>
-</div>
+{{ .Content | safeHTML }}
+</pre>
 
 {{ partial "footer.html" . }}
index 77d558b82239f87f212ef4b86fe1d3f284ed103c..2f2586d74ce916232b956f7ada812baae9a96428 100644 (file)
@@ -1,26 +1,48 @@
 {{ partial "header.html" . }}
 
-{{ partial "subheader.html" . }}
-
-<div class="pure-g">
-    <div class="pure-u-1 pure-u-lg-1-3"></div>
-
-    <div class="pure-u-1 pure-u-lg-1-3">
-        <section>
-          <ul class="posts-links">
-            {{ range (where .Site.RegularPages.ByPublishDate.Reverse "Type" "in" .Site.Params.mainSections) }}
-              <div class="posts">
-                <div id=date class="date-time-title">
-                    <time>{{ .Date.Format (.Site.Params.dateform | default "02 Jan 06") }}</time>
-                </div>
-                <div class="date-time-title post">
-                  <a href="{{ .Permalink }}">{{ .Title }}</a>
-                </div>
-              </div>
-            {{ end }}
-          </ul>
-        </section>
-    </div>
-</div>
+<pre>
+evgenii akentev
+===============
+
+hi, i'm a software engineer interested in functional programming, compilers,
+programming languages, zero knowledge proofs, &c.
+
+posts
+-----
+{{ range (where .Site.RegularPages.ByPublishDate.Reverse "Type" "in" .Site.Params.mainSections) }}
+- <time>{{ .Date.Format (.Site.Params.dateform | default "02 Jan 06") }}</time> <a href="{{ .Permalink }}">{{ .Title }}</a>{{ end }}
+
+rss: <a href="https:{{ .Site.BaseURL }}index.xml">https:{{ .Site.BaseURL }}index.xml</a> 
+
+projects
+--------
+
+code: <a href="https://git.ak3n.com">https://git.ak3n.com</a> 
+
+Hackage packages
+
+- <a href="https://hackage.haskell.org/package/debug-trace-file">https://hackage.haskell.org/package/debug-trace-file</a>
+- <a href="https://hackage.haskell.org/package/line-indexed-cursor">https://hackage.haskell.org/package/line-indexed-cursor</a>
+
+lean4 packages
+
+- <a href="https://git.ak3n.com/?p=temple.lean.git">https://git.ak3n.com/?p=temple.lean.git</a> — A rudimentary template engine
+  written in Lean4 without fancy dependent types and useful operators yet.
+  It can parse, build a tree, and substitute using de Bruijn Indices.
+
+Educational
+
+- <a href="https://ulearn.me/Course/fpintroduction/">Introduction to Functional Programming</a> — An online course on functional
+  programming that I helped to create and teach between 2019 and 2021.
+  Designed for bachelor students at Ural Federal University (taught in Russian).
+
+- <a href="https://cubicaltt.ak3n.com">https://cubicaltt.ak3n.com</a> — A web version of <a href="https://github.com/mortberg/cubicaltt">https://github.com/mortberg/cubicaltt</a>,
+  built in Haskell using Reflex, GHCJS and Monaco, to reduce the entrance barrier.
+  Source code available at <a href="https://git.ak3n.com/?p=cubicaltt.git">https://git.ak3n.com/?p=cubicaltt.git</a>.
+
+contact
+-------
+hi @ ak3n.com
+</pre>
 
 {{ partial "footer.html" . }}
diff --git a/themes/theme/layouts/pages/single.html b/themes/theme/layouts/pages/single.html
deleted file mode 100644 (file)
index dc1a95c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-{{ partial "header.html" . }}
-
-{{ partial "subheader.html" . }}
-
-<div class="pure-g">
-    <div class="pure-u-1 pure-u-lg-1-5">
-        {{ partial "toc.html" . }}
-    </div>
-
-    <div class="pure-u-1 pure-u-lg-3-5">
-        <section class="blog-post">
-            <h1>{{ .Title }}</h1>
-            <div class="blog-post-subheader">
-            </div>
-            <div class="blog-post-content">
-                {{ partial "headline.html" .Content }}
-            </div>
-        </section>
-    </div>
-</div>
-
-{{ partial "footer.html" . }}
index cca28bffcccb42239b759ee3dd48c9a564653509..e57b620172258f5ff1fcabe25995f3237bc47a0c 100644 (file)
@@ -5,10 +5,6 @@
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <title>{{.Title}}</title>
         <link href="data:image/x-icon;base64,AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" rel="icon" type="image/x-icon">
-        <link rel="stylesheet" href="/css/pure-min.css">
-        <link rel="stylesheet" href="/css/stylesheet.css">
-        <link rel="stylesheet" href="/css/syntax.css">
-        <link rel="stylesheet" href="/css/grids-responsive-min.css" />
         <link rel="alternate"
           type="application/rss+xml"
           href="{{.Site.BaseURL }}/index.xml"
diff --git a/themes/theme/layouts/partials/headline.html b/themes/theme/layouts/partials/headline.html
deleted file mode 100644 (file)
index cd86bf7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{{ . | replaceRE "(<h[1-9] id=\"([^\"]+)\".+)(</h[1-9]+>)" "${1}&nbsp;<a class=\"headline-hash\" href=\"#${2}\">#</a> ${3}" | safeHTML }}
\ No newline at end of file
diff --git a/themes/theme/layouts/partials/subheader.html b/themes/theme/layouts/partials/subheader.html
deleted file mode 100644 (file)
index 41be4d0..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<section id="page-title" class="center">
-    <section id="info">
-      <ul class="center">
-        <li><a href="/">index</a></li>
-        {{ range (where .Site.RegularPages.ByPublishDate.Reverse "Section" "pages") }}
-          <li><a href="{{ .Permalink }}">{{ .Title | lower }}</a></li>
-        {{ end }}
-        <li><a href="https://git.ak3n.com">code</a></li>
-        <li><a href="/index.xml">rss</a></li>
-        <li><a href="mailto:hi@ak3n.com">say hi</a></li>
-      </ul>
-    </section>
-</section>
diff --git a/themes/theme/layouts/partials/tags.html b/themes/theme/layouts/partials/tags.html
deleted file mode 100644 (file)
index ce6b334..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<ul class="tags">
-    {{ range . }}
-        <li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
-    {{ end }}
-</ul>
\ No newline at end of file
diff --git a/themes/theme/layouts/partials/toc.html b/themes/theme/layouts/partials/toc.html
deleted file mode 100644 (file)
index a7251b3..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{{ if .Params.toc }}
-  <section class="toc">
-    <details open="">
-      <summary>
-        <b class="contents">Contents</b>
-      </summary>
-      {{ .TableOfContents }}
-    </details>
-  </section>
-{{ end }}
\ No newline at end of file
diff --git a/themes/theme/static/css/grids-responsive-min.css b/themes/theme/static/css/grids-responsive-min.css
deleted file mode 100644 (file)
index b0b190f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
-Pure v3.0.0
-Copyright 2013 Yahoo!
-Licensed under the BSD License.
-https://github.com/pure-css/pure/blob/master/LICENSE
-*/
-@media screen and (min-width:35.5em){.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-1-12,.pure-u-sm-1-2,.pure-u-sm-1-24,.pure-u-sm-1-3,.pure-u-sm-1-4,.pure-u-sm-1-5,.pure-u-sm-1-6,.pure-u-sm-1-8,.pure-u-sm-10-24,.pure-u-sm-11-12,.pure-u-sm-11-24,.pure-u-sm-12-24,.pure-u-sm-13-24,.pure-u-sm-14-24,.pure-u-sm-15-24,.pure-u-sm-16-24,.pure-u-sm-17-24,.pure-u-sm-18-24,.pure-u-sm-19-24,.pure-u-sm-2-24,.pure-u-sm-2-3,.pure-u-sm-2-5,.pure-u-sm-20-24,.pure-u-sm-21-24,.pure-u-sm-22-24,.pure-u-sm-23-24,.pure-u-sm-24-24,.pure-u-sm-3-24,.pure-u-sm-3-4,.pure-u-sm-3-5,.pure-u-sm-3-8,.pure-u-sm-4-24,.pure-u-sm-4-5,.pure-u-sm-5-12,.pure-u-sm-5-24,.pure-u-sm-5-5,.pure-u-sm-5-6,.pure-u-sm-5-8,.pure-u-sm-6-24,.pure-u-sm-7-12,.pure-u-sm-7-24,.pure-u-sm-7-8,.pure-u-sm-8-24,.pure-u-sm-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-sm-1-24{width:4.1667%}.pure-u-sm-1-12,.pure-u-sm-2-24{width:8.3333%}.pure-u-sm-1-8,.pure-u-sm-3-24{width:12.5%}.pure-u-sm-1-6,.pure-u-sm-4-24{width:16.6667%}.pure-u-sm-1-5{width:20%}.pure-u-sm-5-24{width:20.8333%}.pure-u-sm-1-4,.pure-u-sm-6-24{width:25%}.pure-u-sm-7-24{width:29.1667%}.pure-u-sm-1-3,.pure-u-sm-8-24{width:33.3333%}.pure-u-sm-3-8,.pure-u-sm-9-24{width:37.5%}.pure-u-sm-2-5{width:40%}.pure-u-sm-10-24,.pure-u-sm-5-12{width:41.6667%}.pure-u-sm-11-24{width:45.8333%}.pure-u-sm-1-2,.pure-u-sm-12-24{width:50%}.pure-u-sm-13-24{width:54.1667%}.pure-u-sm-14-24,.pure-u-sm-7-12{width:58.3333%}.pure-u-sm-3-5{width:60%}.pure-u-sm-15-24,.pure-u-sm-5-8{width:62.5%}.pure-u-sm-16-24,.pure-u-sm-2-3{width:66.6667%}.pure-u-sm-17-24{width:70.8333%}.pure-u-sm-18-24,.pure-u-sm-3-4{width:75%}.pure-u-sm-19-24{width:79.1667%}.pure-u-sm-4-5{width:80%}.pure-u-sm-20-24,.pure-u-sm-5-6{width:83.3333%}.pure-u-sm-21-24,.pure-u-sm-7-8{width:87.5%}.pure-u-sm-11-12,.pure-u-sm-22-24{width:91.6667%}.pure-u-sm-23-24{width:95.8333%}.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-24-24,.pure-u-sm-5-5{width:100%}}@media screen and (min-width:48em){.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-1-12,.pure-u-md-1-2,.pure-u-md-1-24,.pure-u-md-1-3,.pure-u-md-1-4,.pure-u-md-1-5,.pure-u-md-1-6,.pure-u-md-1-8,.pure-u-md-10-24,.pure-u-md-11-12,.pure-u-md-11-24,.pure-u-md-12-24,.pure-u-md-13-24,.pure-u-md-14-24,.pure-u-md-15-24,.pure-u-md-16-24,.pure-u-md-17-24,.pure-u-md-18-24,.pure-u-md-19-24,.pure-u-md-2-24,.pure-u-md-2-3,.pure-u-md-2-5,.pure-u-md-20-24,.pure-u-md-21-24,.pure-u-md-22-24,.pure-u-md-23-24,.pure-u-md-24-24,.pure-u-md-3-24,.pure-u-md-3-4,.pure-u-md-3-5,.pure-u-md-3-8,.pure-u-md-4-24,.pure-u-md-4-5,.pure-u-md-5-12,.pure-u-md-5-24,.pure-u-md-5-5,.pure-u-md-5-6,.pure-u-md-5-8,.pure-u-md-6-24,.pure-u-md-7-12,.pure-u-md-7-24,.pure-u-md-7-8,.pure-u-md-8-24,.pure-u-md-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-md-1-24{width:4.1667%}.pure-u-md-1-12,.pure-u-md-2-24{width:8.3333%}.pure-u-md-1-8,.pure-u-md-3-24{width:12.5%}.pure-u-md-1-6,.pure-u-md-4-24{width:16.6667%}.pure-u-md-1-5{width:20%}.pure-u-md-5-24{width:20.8333%}.pure-u-md-1-4,.pure-u-md-6-24{width:25%}.pure-u-md-7-24{width:29.1667%}.pure-u-md-1-3,.pure-u-md-8-24{width:33.3333%}.pure-u-md-3-8,.pure-u-md-9-24{width:37.5%}.pure-u-md-2-5{width:40%}.pure-u-md-10-24,.pure-u-md-5-12{width:41.6667%}.pure-u-md-11-24{width:45.8333%}.pure-u-md-1-2,.pure-u-md-12-24{width:50%}.pure-u-md-13-24{width:54.1667%}.pure-u-md-14-24,.pure-u-md-7-12{width:58.3333%}.pure-u-md-3-5{width:60%}.pure-u-md-15-24,.pure-u-md-5-8{width:62.5%}.pure-u-md-16-24,.pure-u-md-2-3{width:66.6667%}.pure-u-md-17-24{width:70.8333%}.pure-u-md-18-24,.pure-u-md-3-4{width:75%}.pure-u-md-19-24{width:79.1667%}.pure-u-md-4-5{width:80%}.pure-u-md-20-24,.pure-u-md-5-6{width:83.3333%}.pure-u-md-21-24,.pure-u-md-7-8{width:87.5%}.pure-u-md-11-12,.pure-u-md-22-24{width:91.6667%}.pure-u-md-23-24{width:95.8333%}.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-24-24,.pure-u-md-5-5{width:100%}}@media screen and (min-width:64em){.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-1-12,.pure-u-lg-1-2,.pure-u-lg-1-24,.pure-u-lg-1-3,.pure-u-lg-1-4,.pure-u-lg-1-5,.pure-u-lg-1-6,.pure-u-lg-1-8,.pure-u-lg-10-24,.pure-u-lg-11-12,.pure-u-lg-11-24,.pure-u-lg-12-24,.pure-u-lg-13-24,.pure-u-lg-14-24,.pure-u-lg-15-24,.pure-u-lg-16-24,.pure-u-lg-17-24,.pure-u-lg-18-24,.pure-u-lg-19-24,.pure-u-lg-2-24,.pure-u-lg-2-3,.pure-u-lg-2-5,.pure-u-lg-20-24,.pure-u-lg-21-24,.pure-u-lg-22-24,.pure-u-lg-23-24,.pure-u-lg-24-24,.pure-u-lg-3-24,.pure-u-lg-3-4,.pure-u-lg-3-5,.pure-u-lg-3-8,.pure-u-lg-4-24,.pure-u-lg-4-5,.pure-u-lg-5-12,.pure-u-lg-5-24,.pure-u-lg-5-5,.pure-u-lg-5-6,.pure-u-lg-5-8,.pure-u-lg-6-24,.pure-u-lg-7-12,.pure-u-lg-7-24,.pure-u-lg-7-8,.pure-u-lg-8-24,.pure-u-lg-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-lg-1-24{width:4.1667%}.pure-u-lg-1-12,.pure-u-lg-2-24{width:8.3333%}.pure-u-lg-1-8,.pure-u-lg-3-24{width:12.5%}.pure-u-lg-1-6,.pure-u-lg-4-24{width:16.6667%}.pure-u-lg-1-5{width:20%}.pure-u-lg-5-24{width:20.8333%}.pure-u-lg-1-4,.pure-u-lg-6-24{width:25%}.pure-u-lg-7-24{width:29.1667%}.pure-u-lg-1-3,.pure-u-lg-8-24{width:33.3333%}.pure-u-lg-3-8,.pure-u-lg-9-24{width:37.5%}.pure-u-lg-2-5{width:40%}.pure-u-lg-10-24,.pure-u-lg-5-12{width:41.6667%}.pure-u-lg-11-24{width:45.8333%}.pure-u-lg-1-2,.pure-u-lg-12-24{width:50%}.pure-u-lg-13-24{width:54.1667%}.pure-u-lg-14-24,.pure-u-lg-7-12{width:58.3333%}.pure-u-lg-3-5{width:60%}.pure-u-lg-15-24,.pure-u-lg-5-8{width:62.5%}.pure-u-lg-16-24,.pure-u-lg-2-3{width:66.6667%}.pure-u-lg-17-24{width:70.8333%}.pure-u-lg-18-24,.pure-u-lg-3-4{width:75%}.pure-u-lg-19-24{width:79.1667%}.pure-u-lg-4-5{width:80%}.pure-u-lg-20-24,.pure-u-lg-5-6{width:83.3333%}.pure-u-lg-21-24,.pure-u-lg-7-8{width:87.5%}.pure-u-lg-11-12,.pure-u-lg-22-24{width:91.6667%}.pure-u-lg-23-24{width:95.8333%}.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-24-24,.pure-u-lg-5-5{width:100%}}@media screen and (min-width:80em){.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-1-12,.pure-u-xl-1-2,.pure-u-xl-1-24,.pure-u-xl-1-3,.pure-u-xl-1-4,.pure-u-xl-1-5,.pure-u-xl-1-6,.pure-u-xl-1-8,.pure-u-xl-10-24,.pure-u-xl-11-12,.pure-u-xl-11-24,.pure-u-xl-12-24,.pure-u-xl-13-24,.pure-u-xl-14-24,.pure-u-xl-15-24,.pure-u-xl-16-24,.pure-u-xl-17-24,.pure-u-xl-18-24,.pure-u-xl-19-24,.pure-u-xl-2-24,.pure-u-xl-2-3,.pure-u-xl-2-5,.pure-u-xl-20-24,.pure-u-xl-21-24,.pure-u-xl-22-24,.pure-u-xl-23-24,.pure-u-xl-24-24,.pure-u-xl-3-24,.pure-u-xl-3-4,.pure-u-xl-3-5,.pure-u-xl-3-8,.pure-u-xl-4-24,.pure-u-xl-4-5,.pure-u-xl-5-12,.pure-u-xl-5-24,.pure-u-xl-5-5,.pure-u-xl-5-6,.pure-u-xl-5-8,.pure-u-xl-6-24,.pure-u-xl-7-12,.pure-u-xl-7-24,.pure-u-xl-7-8,.pure-u-xl-8-24,.pure-u-xl-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xl-1-24{width:4.1667%}.pure-u-xl-1-12,.pure-u-xl-2-24{width:8.3333%}.pure-u-xl-1-8,.pure-u-xl-3-24{width:12.5%}.pure-u-xl-1-6,.pure-u-xl-4-24{width:16.6667%}.pure-u-xl-1-5{width:20%}.pure-u-xl-5-24{width:20.8333%}.pure-u-xl-1-4,.pure-u-xl-6-24{width:25%}.pure-u-xl-7-24{width:29.1667%}.pure-u-xl-1-3,.pure-u-xl-8-24{width:33.3333%}.pure-u-xl-3-8,.pure-u-xl-9-24{width:37.5%}.pure-u-xl-2-5{width:40%}.pure-u-xl-10-24,.pure-u-xl-5-12{width:41.6667%}.pure-u-xl-11-24{width:45.8333%}.pure-u-xl-1-2,.pure-u-xl-12-24{width:50%}.pure-u-xl-13-24{width:54.1667%}.pure-u-xl-14-24,.pure-u-xl-7-12{width:58.3333%}.pure-u-xl-3-5{width:60%}.pure-u-xl-15-24,.pure-u-xl-5-8{width:62.5%}.pure-u-xl-16-24,.pure-u-xl-2-3{width:66.6667%}.pure-u-xl-17-24{width:70.8333%}.pure-u-xl-18-24,.pure-u-xl-3-4{width:75%}.pure-u-xl-19-24{width:79.1667%}.pure-u-xl-4-5{width:80%}.pure-u-xl-20-24,.pure-u-xl-5-6{width:83.3333%}.pure-u-xl-21-24,.pure-u-xl-7-8{width:87.5%}.pure-u-xl-11-12,.pure-u-xl-22-24{width:91.6667%}.pure-u-xl-23-24{width:95.8333%}.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-24-24,.pure-u-xl-5-5{width:100%}}@media screen and (min-width:120em){.pure-u-xxl-1,.pure-u-xxl-1-1,.pure-u-xxl-1-12,.pure-u-xxl-1-2,.pure-u-xxl-1-24,.pure-u-xxl-1-3,.pure-u-xxl-1-4,.pure-u-xxl-1-5,.pure-u-xxl-1-6,.pure-u-xxl-1-8,.pure-u-xxl-10-24,.pure-u-xxl-11-12,.pure-u-xxl-11-24,.pure-u-xxl-12-24,.pure-u-xxl-13-24,.pure-u-xxl-14-24,.pure-u-xxl-15-24,.pure-u-xxl-16-24,.pure-u-xxl-17-24,.pure-u-xxl-18-24,.pure-u-xxl-19-24,.pure-u-xxl-2-24,.pure-u-xxl-2-3,.pure-u-xxl-2-5,.pure-u-xxl-20-24,.pure-u-xxl-21-24,.pure-u-xxl-22-24,.pure-u-xxl-23-24,.pure-u-xxl-24-24,.pure-u-xxl-3-24,.pure-u-xxl-3-4,.pure-u-xxl-3-5,.pure-u-xxl-3-8,.pure-u-xxl-4-24,.pure-u-xxl-4-5,.pure-u-xxl-5-12,.pure-u-xxl-5-24,.pure-u-xxl-5-5,.pure-u-xxl-5-6,.pure-u-xxl-5-8,.pure-u-xxl-6-24,.pure-u-xxl-7-12,.pure-u-xxl-7-24,.pure-u-xxl-7-8,.pure-u-xxl-8-24,.pure-u-xxl-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xxl-1-24{width:4.1667%}.pure-u-xxl-1-12,.pure-u-xxl-2-24{width:8.3333%}.pure-u-xxl-1-8,.pure-u-xxl-3-24{width:12.5%}.pure-u-xxl-1-6,.pure-u-xxl-4-24{width:16.6667%}.pure-u-xxl-1-5{width:20%}.pure-u-xxl-5-24{width:20.8333%}.pure-u-xxl-1-4,.pure-u-xxl-6-24{width:25%}.pure-u-xxl-7-24{width:29.1667%}.pure-u-xxl-1-3,.pure-u-xxl-8-24{width:33.3333%}.pure-u-xxl-3-8,.pure-u-xxl-9-24{width:37.5%}.pure-u-xxl-2-5{width:40%}.pure-u-xxl-10-24,.pure-u-xxl-5-12{width:41.6667%}.pure-u-xxl-11-24{width:45.8333%}.pure-u-xxl-1-2,.pure-u-xxl-12-24{width:50%}.pure-u-xxl-13-24{width:54.1667%}.pure-u-xxl-14-24,.pure-u-xxl-7-12{width:58.3333%}.pure-u-xxl-3-5{width:60%}.pure-u-xxl-15-24,.pure-u-xxl-5-8{width:62.5%}.pure-u-xxl-16-24,.pure-u-xxl-2-3{width:66.6667%}.pure-u-xxl-17-24{width:70.8333%}.pure-u-xxl-18-24,.pure-u-xxl-3-4{width:75%}.pure-u-xxl-19-24{width:79.1667%}.pure-u-xxl-4-5{width:80%}.pure-u-xxl-20-24,.pure-u-xxl-5-6{width:83.3333%}.pure-u-xxl-21-24,.pure-u-xxl-7-8{width:87.5%}.pure-u-xxl-11-12,.pure-u-xxl-22-24{width:91.6667%}.pure-u-xxl-23-24{width:95.8333%}.pure-u-xxl-1,.pure-u-xxl-1-1,.pure-u-xxl-24-24,.pure-u-xxl-5-5{width:100%}}@media screen and (min-width:160em){.pure-u-xxxl-1,.pure-u-xxxl-1-1,.pure-u-xxxl-1-12,.pure-u-xxxl-1-2,.pure-u-xxxl-1-24,.pure-u-xxxl-1-3,.pure-u-xxxl-1-4,.pure-u-xxxl-1-5,.pure-u-xxxl-1-6,.pure-u-xxxl-1-8,.pure-u-xxxl-10-24,.pure-u-xxxl-11-12,.pure-u-xxxl-11-24,.pure-u-xxxl-12-24,.pure-u-xxxl-13-24,.pure-u-xxxl-14-24,.pure-u-xxxl-15-24,.pure-u-xxxl-16-24,.pure-u-xxxl-17-24,.pure-u-xxxl-18-24,.pure-u-xxxl-19-24,.pure-u-xxxl-2-24,.pure-u-xxxl-2-3,.pure-u-xxxl-2-5,.pure-u-xxxl-20-24,.pure-u-xxxl-21-24,.pure-u-xxxl-22-24,.pure-u-xxxl-23-24,.pure-u-xxxl-24-24,.pure-u-xxxl-3-24,.pure-u-xxxl-3-4,.pure-u-xxxl-3-5,.pure-u-xxxl-3-8,.pure-u-xxxl-4-24,.pure-u-xxxl-4-5,.pure-u-xxxl-5-12,.pure-u-xxxl-5-24,.pure-u-xxxl-5-5,.pure-u-xxxl-5-6,.pure-u-xxxl-5-8,.pure-u-xxxl-6-24,.pure-u-xxxl-7-12,.pure-u-xxxl-7-24,.pure-u-xxxl-7-8,.pure-u-xxxl-8-24,.pure-u-xxxl-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xxxl-1-24{width:4.1667%}.pure-u-xxxl-1-12,.pure-u-xxxl-2-24{width:8.3333%}.pure-u-xxxl-1-8,.pure-u-xxxl-3-24{width:12.5%}.pure-u-xxxl-1-6,.pure-u-xxxl-4-24{width:16.6667%}.pure-u-xxxl-1-5{width:20%}.pure-u-xxxl-5-24{width:20.8333%}.pure-u-xxxl-1-4,.pure-u-xxxl-6-24{width:25%}.pure-u-xxxl-7-24{width:29.1667%}.pure-u-xxxl-1-3,.pure-u-xxxl-8-24{width:33.3333%}.pure-u-xxxl-3-8,.pure-u-xxxl-9-24{width:37.5%}.pure-u-xxxl-2-5{width:40%}.pure-u-xxxl-10-24,.pure-u-xxxl-5-12{width:41.6667%}.pure-u-xxxl-11-24{width:45.8333%}.pure-u-xxxl-1-2,.pure-u-xxxl-12-24{width:50%}.pure-u-xxxl-13-24{width:54.1667%}.pure-u-xxxl-14-24,.pure-u-xxxl-7-12{width:58.3333%}.pure-u-xxxl-3-5{width:60%}.pure-u-xxxl-15-24,.pure-u-xxxl-5-8{width:62.5%}.pure-u-xxxl-16-24,.pure-u-xxxl-2-3{width:66.6667%}.pure-u-xxxl-17-24{width:70.8333%}.pure-u-xxxl-18-24,.pure-u-xxxl-3-4{width:75%}.pure-u-xxxl-19-24{width:79.1667%}.pure-u-xxxl-4-5{width:80%}.pure-u-xxxl-20-24,.pure-u-xxxl-5-6{width:83.3333%}.pure-u-xxxl-21-24,.pure-u-xxxl-7-8{width:87.5%}.pure-u-xxxl-11-12,.pure-u-xxxl-22-24{width:91.6667%}.pure-u-xxxl-23-24{width:95.8333%}.pure-u-xxxl-1,.pure-u-xxxl-1-1,.pure-u-xxxl-24-24,.pure-u-xxxl-5-5{width:100%}}@media screen and (min-width:240em){.pure-u-x4k-1,.pure-u-x4k-1-1,.pure-u-x4k-1-12,.pure-u-x4k-1-2,.pure-u-x4k-1-24,.pure-u-x4k-1-3,.pure-u-x4k-1-4,.pure-u-x4k-1-5,.pure-u-x4k-1-6,.pure-u-x4k-1-8,.pure-u-x4k-10-24,.pure-u-x4k-11-12,.pure-u-x4k-11-24,.pure-u-x4k-12-24,.pure-u-x4k-13-24,.pure-u-x4k-14-24,.pure-u-x4k-15-24,.pure-u-x4k-16-24,.pure-u-x4k-17-24,.pure-u-x4k-18-24,.pure-u-x4k-19-24,.pure-u-x4k-2-24,.pure-u-x4k-2-3,.pure-u-x4k-2-5,.pure-u-x4k-20-24,.pure-u-x4k-21-24,.pure-u-x4k-22-24,.pure-u-x4k-23-24,.pure-u-x4k-24-24,.pure-u-x4k-3-24,.pure-u-x4k-3-4,.pure-u-x4k-3-5,.pure-u-x4k-3-8,.pure-u-x4k-4-24,.pure-u-x4k-4-5,.pure-u-x4k-5-12,.pure-u-x4k-5-24,.pure-u-x4k-5-5,.pure-u-x4k-5-6,.pure-u-x4k-5-8,.pure-u-x4k-6-24,.pure-u-x4k-7-12,.pure-u-x4k-7-24,.pure-u-x4k-7-8,.pure-u-x4k-8-24,.pure-u-x4k-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-x4k-1-24{width:4.1667%}.pure-u-x4k-1-12,.pure-u-x4k-2-24{width:8.3333%}.pure-u-x4k-1-8,.pure-u-x4k-3-24{width:12.5%}.pure-u-x4k-1-6,.pure-u-x4k-4-24{width:16.6667%}.pure-u-x4k-1-5{width:20%}.pure-u-x4k-5-24{width:20.8333%}.pure-u-x4k-1-4,.pure-u-x4k-6-24{width:25%}.pure-u-x4k-7-24{width:29.1667%}.pure-u-x4k-1-3,.pure-u-x4k-8-24{width:33.3333%}.pure-u-x4k-3-8,.pure-u-x4k-9-24{width:37.5%}.pure-u-x4k-2-5{width:40%}.pure-u-x4k-10-24,.pure-u-x4k-5-12{width:41.6667%}.pure-u-x4k-11-24{width:45.8333%}.pure-u-x4k-1-2,.pure-u-x4k-12-24{width:50%}.pure-u-x4k-13-24{width:54.1667%}.pure-u-x4k-14-24,.pure-u-x4k-7-12{width:58.3333%}.pure-u-x4k-3-5{width:60%}.pure-u-x4k-15-24,.pure-u-x4k-5-8{width:62.5%}.pure-u-x4k-16-24,.pure-u-x4k-2-3{width:66.6667%}.pure-u-x4k-17-24{width:70.8333%}.pure-u-x4k-18-24,.pure-u-x4k-3-4{width:75%}.pure-u-x4k-19-24{width:79.1667%}.pure-u-x4k-4-5{width:80%}.pure-u-x4k-20-24,.pure-u-x4k-5-6{width:83.3333%}.pure-u-x4k-21-24,.pure-u-x4k-7-8{width:87.5%}.pure-u-x4k-11-12,.pure-u-x4k-22-24{width:91.6667%}.pure-u-x4k-23-24{width:95.8333%}.pure-u-x4k-1,.pure-u-x4k-1-1,.pure-u-x4k-24-24,.pure-u-x4k-5-5{width:100%}}
\ No newline at end of file
diff --git a/themes/theme/static/css/pure-min.css b/themes/theme/static/css/pure-min.css
deleted file mode 100644 (file)
index acdc431..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*!
-Pure v3.0.0
-Copyright 2013 Yahoo!
-Licensed under the BSD License.
-https://github.com/pure-css/pure/blob/master/LICENSE
-*/
-/*!
-normalize.css v | MIT License | https://necolas.github.io/normalize.css/
-Copyright (c) Nicolas Gallagher and Jonathan Neal
-*/
-/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}html{font-family:sans-serif}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{display:flex;flex-flow:row wrap;align-content:flex-start}.pure-u{display:inline-block;vertical-align:top}.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-1-4,.pure-u-6-24{width:25%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-1-2,.pure-u-12-24{width:50%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-18-24,.pure-u-3-4{width:75%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5{width:100%}.pure-button{display:inline-block;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;user-select:none;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-0.43em}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:rgba(0,0,0,.8);border:none transparent;background-color:#e6e6e6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:focus,.pure-button:hover{background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;opacity:.4;cursor:not-allowed;box-shadow:none;pointer-events:none}.pure-button-hidden{display:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button{margin:0;border-radius:0;border-right:1px solid rgba(0,0,0,.2)}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=color]:focus,.pure-form input[type=date]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=email]:focus,.pure-form input[type=month]:focus,.pure-form input[type=number]:focus,.pure-form input[type=password]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=text]:focus,.pure-form input[type=time]:focus,.pure-form input[type=url]:focus,.pure-form input[type=week]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129fea}.pure-form input:not([type]):focus{outline:0;border-color:#129fea}.pure-form input[type=checkbox]:focus,.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=color][disabled],.pure-form input[type=date][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=email][disabled],.pure-form input[type=month][disabled],.pure-form input[type=number][disabled],.pure-form input[type=password][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=text][disabled],.pure-form input[type=time][disabled],.pure-form input[type=url][disabled],.pure-form input[type=week][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form select:focus:invalid,.pure-form textarea:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=checkbox]:focus:invalid:focus,.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=color],.pure-form-stacked input[type=date],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=email],.pure-form-stacked input[type=file],.pure-form-stacked input[type=month],.pure-form-stacked input[type=number],.pure-form-stacked input[type=password],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=text],.pure-form-stacked input[type=time],.pure-form-stacked input[type=url],.pure-form-stacked input[type=week],.pure-form-stacked label,.pure-form-stacked select,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned select,.pure-form-aligned textarea,.pure-form-message-inline{display:inline-block;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form .pure-input-rounded,.pure-form input.pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-3-4{width:75%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=color],.pure-group input[type=date],.pure-group input[type=datetime-local],.pure-group input[type=datetime],.pure-group input[type=email],.pure-group input[type=month],.pure-group input[type=number],.pure-group input[type=password],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=text],.pure-group input[type=time],.pure-group input[type=url],.pure-group input[type=week]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0 0}.pure-form-message,.pure-form-message-inline{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-item,.pure-menu-list{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-heading,.pure-menu-link{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-separator{display:inline-block;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-active>.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;padding:.5em 0}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent;cursor:default}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected>.pure-menu-link,.pure-menu-selected>.pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0}
\ No newline at end of file
diff --git a/themes/theme/static/css/stylesheet.css b/themes/theme/static/css/stylesheet.css
deleted file mode 100644 (file)
index ee11e6b..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-body {
-    font-family: sans-serif;
-    color: black;
-}
-
-.center {
-    text-align: center;
-}
-
-#page-title h1 a, .post a, .toc a {
-    color: black;
-}
-
-a {
-    text-decoration: none;
-}
-
-#info ul {
-    margin-top: 1em;
-    padding: 0;
-    list-style-type: none;
-}
-
-#info ul li {
-    margin-left: 1em;
-    margin-right: 1em;
-    display: inline;
-}
-
-ul li h4 {
-  margin-bottom: 0.5em;
-}
-
-.post a:hover, .toc a:hover {
-    text-decoration: underline;
-}
-
-.date-time-title {
-    display: inline-block;
-}
-
-.posts {
-    margin: auto;
-}
-
-@media screen and (max-width: 64em) {
-    .posts-links {
-        padding-left: 1em;
-    }
-}
-
-.toc {
-    position: fixed;
-    width: inherit;
-    padding-left: 1em;
-    padding-right: 1em;
-}
-
-@media screen and (max-width: 64em) {
-    .toc {
-        display: none;
-    }
-}
-
-.toc summary::marker {
-    content: none;
-}
-
-.toc summary::after {
-  content: ' show';
-}
-.toc details[open] summary:after {
-  content: " hide";
-}
-
-.toc a {
-  color: #696969;
-}
-
-.toc li,
-.toc ul,
-.toc ul li {
-  list-style: outside none none;
-}
-
-.contents,
-.toc li,
-.toc ul,
-.toc ul li {
-    padding-left: 5px;
-}
-
-.post {
-    padding-left: 1em;
-}
-
-.blog-post {
-    padding-left: 2em;
-    padding-right: 2em;
-}
-
-.blog-post img {   
-    width: 65%;
-}
-
-.blog-post img.full {
-    width: 100%;
-}
-
-.blog-post img, iframe {
-    display: block;
-    margin-left: auto;
-    margin-right: auto;
-}
-
-.blog-post-content {
-    line-height: 1.5;
-}
-
-.blog-post-feedback {
-    padding: .5em .5em;
-    background-color: rgba(27,31,35,.05);
-    margin: 1.5em 0 3em 0;
-}
-
-.headline-hash {
-    font-size: 70%;
-    color: #000;
-    visibility: hidden;
-}
-
-.blog-post-subheader div {
-    display: inline-block;
-}
-
-ul.tags {
-    margin: 0;
-    padding: 0;
-    list-style-type: none;
-}
-
-ul.tags li {
-    display: inline;
-}
-
-ul.tags li:first-child:before {
-    content: "# ";
-}
-
-ul.tags li:last-child:after {
-    content: none;
-}
-
-ul.tags li:after {
-    content: ",";
-}
-
-h1 {
-    font-style: normal;
-    font-size: 2rem;
-}
-
-h2 {
-    font-style: normal;
-    font-size: 1.5rem;
-    margin: 0.8rem 0 .8rem;
-}
-
-h3 {
-    font-style: normal;
-    font-size: 1.3rem;
-    margin: 0.8rem 0 .8rem;
-}
-
-h4 {
-    font-style: normal;
-    font-size: 1.1rem;
-    margin: 0.8rem 0 .8rem;
-}
-
-h5 {
-    font-style: normal;
-    font-size: 0.9rem;
-    margin: 0.8rem 0 .8rem;
-}
-
-h1:hover a,
-h2:hover a,
-h3:hover a,
-h4:hover a,
-h5:hover a { visibility: visible }
-
-img.avatar {
-    margin-top: 2em;
-    width: 100%;
-}
-
-.about {
-    margin-top: 0.5em;
-    color: #9EA3AD;
-}
\ No newline at end of file
diff --git a/themes/theme/static/css/syntax.css b/themes/theme/static/css/syntax.css
deleted file mode 100644 (file)
index e13ae8b..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Background */ .chroma { background-color: #ffffff }
-/* Other */ .chroma .x {  }
-/* Error */ .chroma .err {  }
-/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
-/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
-/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
-/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
-/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
-/* Keyword */ .chroma .k { color: #0000ff }
-/* KeywordConstant */ .chroma .kc { color: #0000ff }
-/* KeywordDeclaration */ .chroma .kd { color: #0000ff }
-/* KeywordNamespace */ .chroma .kn { color: #0000ff }
-/* KeywordPseudo */ .chroma .kp { color: #0000ff }
-/* KeywordReserved */ .chroma .kr { color: #0000ff }
-/* KeywordType */ .chroma .kt { color: #2b91af }
-/* Name */ .chroma .n {  }
-/* NameAttribute */ .chroma .na {  }
-/* NameBuiltin */ .chroma .nb {  }
-/* NameBuiltinPseudo */ .chroma .bp {  }
-/* NameClass */ .chroma .nc { color: #2b91af }
-/* NameConstant */ .chroma .no {  }
-/* NameDecorator */ .chroma .nd {  }
-/* NameEntity */ .chroma .ni {  }
-/* NameException */ .chroma .ne {  }
-/* NameFunction */ .chroma .nf {  }
-/* NameFunctionMagic */ .chroma .fm {  }
-/* NameLabel */ .chroma .nl {  }
-/* NameNamespace */ .chroma .nn {  }
-/* NameOther */ .chroma .nx {  }
-/* NameProperty */ .chroma .py {  }
-/* NameTag */ .chroma .nt {  }
-/* NameVariable */ .chroma .nv {  }
-/* NameVariableClass */ .chroma .vc {  }
-/* NameVariableGlobal */ .chroma .vg {  }
-/* NameVariableInstance */ .chroma .vi {  }
-/* NameVariableMagic */ .chroma .vm {  }
-/* Literal */ .chroma .l {  }
-/* LiteralDate */ .chroma .ld {  }
-/* LiteralString */ .chroma .s { color: #a31515 }
-/* LiteralStringAffix */ .chroma .sa { color: #a31515 }
-/* LiteralStringBacktick */ .chroma .sb { color: #a31515 }
-/* LiteralStringChar */ .chroma .sc { color: #a31515 }
-/* LiteralStringDelimiter */ .chroma .dl { color: #a31515 }
-/* LiteralStringDoc */ .chroma .sd { color: #a31515 }
-/* LiteralStringDouble */ .chroma .s2 { color: #a31515 }
-/* LiteralStringEscape */ .chroma .se { color: #a31515 }
-/* LiteralStringHeredoc */ .chroma .sh { color: #a31515 }
-/* LiteralStringInterpol */ .chroma .si { color: #a31515 }
-/* LiteralStringOther */ .chroma .sx { color: #a31515 }
-/* LiteralStringRegex */ .chroma .sr { color: #a31515 }
-/* LiteralStringSingle */ .chroma .s1 { color: #a31515 }
-/* LiteralStringSymbol */ .chroma .ss { color: #a31515 }
-/* LiteralNumber */ .chroma .m {  }
-/* LiteralNumberBin */ .chroma .mb {  }
-/* LiteralNumberFloat */ .chroma .mf {  }
-/* LiteralNumberHex */ .chroma .mh {  }
-/* LiteralNumberInteger */ .chroma .mi {  }
-/* LiteralNumberIntegerLong */ .chroma .il {  }
-/* LiteralNumberOct */ .chroma .mo {  }
-/* Operator */ .chroma .o {  }
-/* OperatorWord */ .chroma .ow { color: #0000ff }
-/* Punctuation */ .chroma .p {  }
-/* Comment */ .chroma .c { color: #008000 }
-/* CommentHashbang */ .chroma .ch { color: #008000 }
-/* CommentMultiline */ .chroma .cm { color: #008000 }
-/* CommentSingle */ .chroma .c1 { color: #008000 }
-/* CommentSpecial */ .chroma .cs { color: #008000 }
-/* CommentPreproc */ .chroma .cp { color: #0000ff }
-/* CommentPreprocFile */ .chroma .cpf { color: #0000ff }
-/* Generic */ .chroma .g {  }
-/* GenericDeleted */ .chroma .gd {  }
-/* GenericEmph */ .chroma .ge { font-style: italic }
-/* GenericError */ .chroma .gr {  }
-/* GenericHeading */ .chroma .gh { font-weight: bold }
-/* GenericInserted */ .chroma .gi {  }
-/* GenericOutput */ .chroma .go {  }
-/* GenericPrompt */ .chroma .gp { font-weight: bold }
-/* GenericStrong */ .chroma .gs { font-weight: bold }
-/* GenericSubheading */ .chroma .gu { font-weight: bold }
-/* GenericTraceback */ .chroma .gt {  }
-/* GenericUnderline */ .chroma .gl {  }
-/* TextWhitespace */ .chroma .w {  }
diff --git a/themes/theme/static/img/me_myself_and_i_tbilisi_2023.webp b/themes/theme/static/img/me_myself_and_i_tbilisi_2023.webp
deleted file mode 100644 (file)
index 70fff60..0000000
Binary files a/themes/theme/static/img/me_myself_and_i_tbilisi_2023.webp and /dev/null differ