Basics off
Descripción del contenido de la página
Metaproyecto sobre los proyectos «Basics of…».
Basics off es un metaproyecto sobre los 58 proyectos «Basics of…» (49 comenzados). Consta de tres programas que usan el contenido de los repositorios para contar las conversiones (en fish), extraer los datos de actividad (en Julia), y construir las páginas web (en D); así como de varios ficheros de gnuplot que crean los gráficos, y un Makefile para construir todo. Los resultados se muestran a continuación: los informes sobre las conversiones, los gráficos de actividad y un informe sobre el tamaño de un ejecutable, elaborado a mano.
Número de conversiones por lenguaje de programación
| Lenguaje de programación | Conversiones acabadas | Conversiones inacabadas |
|---|---|---|
D |
20 |
0 |
C# |
19 |
0 |
Chapel |
19 |
0 |
Crystal |
19 |
0 |
Hare |
19 |
0 |
Kotlin |
19 |
0 |
Nim |
19 |
0 |
Odin |
19 |
0 |
Pike |
19 |
0 |
V |
19 |
0 |
Raku |
17 |
0 |
Go |
15 |
0 |
Julia |
15 |
0 |
Janet |
14 |
0 |
Arturo |
13 |
0 |
Python |
12 |
0 |
Ring |
11 |
1 |
Swift |
10 |
0 |
Scala |
9 |
0 |
Scheme |
8 |
1 |
FreeBASIC |
7 |
0 |
C3 |
6 |
0 |
Icon |
5 |
1 |
8th |
5 |
0 |
Ada |
5 |
0 |
Vala |
4 |
1 |
Haxe |
3 |
0 |
Racket |
3 |
0 |
Rust |
3 |
0 |
F# |
2 |
1 |
Factor |
2 |
1 |
Io |
2 |
0 |
Lobster |
2 |
0 |
Oberon-07 |
2 |
0 |
Nit |
1 |
2 |
Elixir |
1 |
1 |
Gleam |
1 |
1 |
Nature |
1 |
1 |
Neat |
1 |
1 |
Neko |
1 |
1 |
OCaml |
1 |
1 |
Pony |
1 |
1 |
Rexx |
1 |
1 |
Zig |
1 |
1 |
Clojure |
1 |
0 |
Lua |
1 |
0 |
Nelua |
1 |
0 |
Retro |
1 |
0 |
Styx |
1 |
0 |
Haskell |
0 |
1 |
Lisp |
0 |
1 |
Prolog |
0 |
1 |
Red |
0 |
1 |
SBCL |
0 |
1 |
Dylan |
0 |
0 |
Euphoria |
0 |
0 |
Miranda |
0 |
0 |
Vale |
0 |
0 |
TOTALES |
381 |
22 |
Programas convertidos a cada lenguaje de programación
| Lenguaje de programación | 3D Plot | Bagels | Bug | Bunny | Chase | Diamond | Hammurabi | High Noon | Math | Mugwump | Name | Poetry | Russian Roulette | Seance | Sine Wave | Slots | Stars | Strings | Xchange | Z-End |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
8th |
✓ |
✓ |
✓ |
✓ |
✓ |
|||||||||||||||
Ada |
✓ |
✓ |
✓ |
✓ |
✓ |
|||||||||||||||
Arturo |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|||||||
C# |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
C3 |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
||||||||||||||
Chapel |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
Clojure |
✓ |
|||||||||||||||||||
Crystal |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
D |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
Dylan |
||||||||||||||||||||
Elixir |
… |
✓ |
||||||||||||||||||
Euphoria |
||||||||||||||||||||
F# |
✓ |
✓ |
… |
|||||||||||||||||
Factor |
… |
✓ |
✓ |
|||||||||||||||||
FreeBASIC |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|||||||||||||
Gleam |
✓ |
|||||||||||||||||||
Go |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|||||
Hare |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
Haskell |
… |
|||||||||||||||||||
Haxe |
✓ |
✓ |
✓ |
|||||||||||||||||
Icon |
✓ |
✓ |
… |
✓ |
✓ |
✓ |
||||||||||||||
Io |
✓ |
✓ |
||||||||||||||||||
Janet |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
||||||
Julia |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|||||
Kotlin |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
Lisp |
… |
|||||||||||||||||||
Lobster |
✓ |
✓ |
||||||||||||||||||
Lua |
✓ |
|||||||||||||||||||
Miranda |
||||||||||||||||||||
Nature |
… |
✓ |
||||||||||||||||||
Neat |
… |
✓ |
||||||||||||||||||
Neko |
✓ |
… |
||||||||||||||||||
Nelua |
✓ |
|||||||||||||||||||
Nim |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
Nit |
… |
✓ |
… |
|||||||||||||||||
Oberon-07 |
✓ |
✓ |
||||||||||||||||||
OCaml |
… |
✓ |
||||||||||||||||||
Odin |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
Pike |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
Pony |
… |
✓ |
||||||||||||||||||
Prolog |
… |
|||||||||||||||||||
Python |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
||||||||
Racket |
✓ |
✓ |
✓ |
|||||||||||||||||
Raku |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|||
Red |
… |
|||||||||||||||||||
Retro |
✓ |
|||||||||||||||||||
Rexx |
… |
✓ |
||||||||||||||||||
Ring |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
… |
✓ |
✓ |
||||||||
Rust |
✓ |
✓ |
✓ |
|||||||||||||||||
SBCL |
… |
|||||||||||||||||||
Scala |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|||||||||||
Scheme |
✓ |
✓ |
✓ |
✓ |
✓ |
… |
✓ |
✓ |
✓ |
|||||||||||
Styx |
✓ |
|||||||||||||||||||
Swift |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
||||||||||
V |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
|
Vala |
✓ |
… |
✓ |
✓ |
✓ |
|||||||||||||||
Vale |
||||||||||||||||||||
Zig |
✓ |
… |
- ✓
-
Programa completado
- …
-
Programa inacabado
Conversiones empezadas mensualmente
Entradas mensuales
Tamaño del ejecutable de Sine Wave
Sine Wave se usa para comparar los tamaños de los ejecutables, nativos o gestionados, creados por los lenguajes de programación del proyecto. La siguiente tabla contiene los resultados en orden creciente.
| Lenguaje | Versión | KiB | Tipo | Compilador | Optimización | Compresor | Nota |
|---|---|---|---|---|---|---|---|
Arturo |
0.9.83 |
0,4 |
gestionado |
el intérprete va aparte: 6,4 MiB |
|||
Kotlin |
2.3.10 |
2,2 |
gestionado |
kotlinc-jvm |
.jar mínimo, ejecutable solo con |
||
Kotlin |
2.1.0 |
2,2 |
gestionado |
kotlinc-jvm |
.jar mínimo, ejecutable solo con |
||
Kotlin |
1.9.10 |
2,2 |
gestionado |
kotlinc-jvm |
.jar mínimo, ejecutable solo con |
||
Kotlin |
1.3.31 |
2,4 |
gestionado |
kotlinc-jvm |
.jar mínimo, ejecutable solo con |
||
C# |
5 |
4,0 |
gestionado |
mcs 6.8.0.105 |
.exe para Mono/.NET |
||
C# |
6 |
4,0 |
gestionado |
mcs 6.12.0.200 |
.exe para Mono/.NET |
||
Icon |
9.5.23a |
4,4 |
gestionado |
el intérprete va aparte: 415 KiB |
|||
C# |
13 |
9,0 |
gestionado |
csc 3.9.0-6.21124.20 |
.exe para Mono/.NET |
||
Scala |
3.3.0 |
6,8 |
gestionado |
.jar mínimo, ejecutable solo con |
|||
Scala |
3.3.0 |
7,0 |
gestionado |
scalac |
.jar mínimo, ejecutable solo con |
||
Swift |
6.1 |
9,2 |
nativo |
|
|||
Swift |
6.1 |
11,1 |
nativo |
|
|||
Scheme |
11,3 |
nativo |
bigloo 4.6a |
|
|||
Ada |
Ada 2012 |
12,5 |
nativo |
gnat 12.2.0 |
|
||
Vala |
0.56.3 |
17,0 |
nativo |
||||
Ada |
Ada 2012 |
17,1 |
nativo |
gnat 12.2.0 |
|
||
Ring |
1.20 |
19,7 |
nativo |
||||
Swift |
6.1 |
19,9 |
nativo |
|
|||
Swift |
5.9.1 |
22,0 |
nativo |
|
|||
Scheme |
23,8 |
nativo |
bigloo 4.6a |
||||
C3 |
0.6.8 |
25,1 |
nativo |
|
|
||
Haxe |
4.3.6 |
25,4 |
gestionado |
.n para Neko, creado con la opción |
|||
Swift |
6.1 |
25,5 |
nativo |
las opciones |
|||
Swift |
5.9.1 |
26,0 |
nativo |
||||
Ada |
Ada 2012 |
26,8 |
nativo |
gnat 12.2.0 |
|
||
Nim |
2.2.0 |
27,4 |
nativo |
|
|
||
Nim |
2.2.2 |
27,4 |
nativo |
|
|
||
Nim |
2.2.2 |
34,2 |
nativo |
|
|
||
Nim |
2.2.2 |
34,4 |
nativo |
|
|||
Oberon-07 |
39,0 |
nativo |
OBNC 0.16.1 |
||||
Nim |
2.2.2 |
42,0 |
nativo |
|
|||
Haxe |
4.3.6 |
43,3 |
gestionado |
.hl para HashLink, creado con la opción |
|||
Ada |
Ada 2012 |
43,8 |
nativo |
gnat 12.2.0 |
|||
Haxe |
4.3.6 |
44,9 |
gestionado |
.jar creado con la opción |
|||
Hare |
0.24.2 |
46,2 |
nativo |
|
|
||
FreeBASIC |
1.09.0 |
53,0 |
nativo |
||||
C3 |
0.6.8 |
56,4 |
nativo |
|
|
||
Haxe |
4.3.6 |
57,5 |
gestionado |
.exe para Mono/.NET, creado con la opción |
|||
D |
59,5 |
nativo |
LDC2 1.42.0-beta2 |
|
|
||
D |
59,6 |
nativo |
LDC2 1.42.0-beta2 |
|
|
||
Nim |
2.2.0 |
66,7 |
nativo |
|
|
||
Nim |
2.2.2 |
66,7 |
nativo |
|
|
||
Odin |
dev-2024-12 |
67,7 |
nativo |
|
|
||
Odin |
dev-2024-12 |
67,8 |
nativo |
|
|
||
Odin |
dev-2023-11 |
69,0 |
nativo |
|
|
||
C3 |
0.6.8 |
69,1 |
nativo |
|
|||
D |
69,2 |
nativo |
gdc 12.2.0 |
|
|||
Haxe |
4.3.6 |
69,7 |
gestionado |
.jar creado con la opción |
|||
Odin |
dev-2024-04 |
71,0 |
nativo |
|
|
||
Odin |
dev-2024-11 |
71,2 |
nativo |
|
|
||
Odin |
dev-2024-07 |
71,3 |
nativo |
|
|
||
Nim |
2.2.0 |
87,5 |
nativo |
|
|||
Nim |
2.2.2 |
87,7 |
nativo |
|
|||
Nim |
2.0.0 |
95,0 |
nativo |
|
|||
Nim |
2.2.2 |
106,7 |
nativo |
|
|||
Nelua |
0.2.0-dev |
110,0 |
nativo |
||||
Hare |
0.24.2 |
111,5 |
nativo |
|
|
||
Nim |
1.x |
122,0 |
nativo |
||||
Nim |
2.2.0 |
130,3 |
nativo |
||||
Nim |
2.2.2 |
130,7 |
nativo |
||||
Hare |
0.24.2 |
136,7 |
nativo |
|
|
||
Hare |
0.24.2 |
152,7 |
nativo |
|
|||
V |
0.4.10 |
152,9 |
nativo |
|
|||
V |
0.4.9 |
155,0 |
nativo |
|
|||
Nim |
2.0.0 |
158,0 |
nativo |
||||
Kotlin |
2.3.10 |
168,2 |
nativo |
kotlinc-native |
|
|
|
Kotlin |
1.9.10 |
176,0 |
nativo |
kotlinc-native |
|
|
|
Crystal |
1.14.0 |
177,0 |
nativo |
|
|
||
Crystal |
1.14.0 |
177,5 |
nativo |
|
|
||
Odin |
dev-2023-11 |
186,0 |
nativo |
|
|||
Odin |
dev-2024-12 |
189,7 |
nativo |
|
|||
Odin |
dev-2024-11 |
191,3 |
nativo |
|
|||
Odin |
dev-2024-03 |
195,0 |
nativo |
|
|||
D |
195,3 |
nativo |
LDC2 1.42.0-beta2 |
|
|
||
Crystal |
1.14.0 |
195,6 |
nativo |
|
|
||
Crystal |
1.14.0 |
196,6 |
nativo |
|
|
||
D |
203,3 |
nativo |
LDC2 1.42.0-beta2 |
|
|
||
Kotlin |
2.3.10 |
210,1 |
nativo |
kotlinc-native |
|
||
Odin |
dev-2024-07 |
210,9 |
nativo |
|
|||
Odin |
dev-2024-04 |
216,0 |
nativo |
|
|||
C3 |
0.6.8 |
230,4 |
nativo |
|
|||
D |
253,4 |
nativo |
LDC2 1.42.0-beta2 |
|
|||
Ring |
1.19 |
255,7 |
nativo |
||||
C3 |
0.6.8 |
261,7 |
nativo |
|
|||
D |
262,2 |
nativo |
LDC2 1.42.0-beta2 |
|
|||
C3 |
0.6.8 |
262,4 |
nativo |
|
|||
Odin |
dev-2023-11 |
280,0 |
nativo |
||||
D |
284,9 |
nativo |
DMD64 OpenD 2.107.0-beta.1 |
|
|||
D |
285,0 |
nativo |
LDC2 1.30.0 |
|
|||
D |
287,1 |
nativo |
DMD 2.110.0 |
|
|||
D |
287,1 |
nativo |
gdc 12.2.0 |
|
|||
D |
306,1 |
nativo |
LDC2 1.42.0-beta2 |
|
|||
Haxe |
4.3.6 |
320,2 |
nativo |
|
creado con la opción |
||
Janet |
1.40.1 |
326,1 |
nativo |
|
|||
Hare |
0.24.2 |
334,9 |
nativo |
|
|||
Odin |
dev-2024-04 |
345,0 |
nativo |
||||
D |
364,6 |
nativo |
DMD 2.109.0 |
|
|
||
D |
369,1 |
nativo |
DMD 2.110.0 |
|
|||
D |
370,9 |
nativo |
DMD 2.109.0 |
|
|
||
C3 |
0.6.8 |
388,9 |
nativo |
|
|||
D |
387,7 |
nativo |
gdc 12.2.0 |
||||
C3 |
0.6.8 |
390,3 |
nativo |
|
|||
Haxe |
4.3.6 |
397,9 |
nativo |
|
creado con la opción |
||
V |
0.4.10 |
406,9 |
nativo |
|
|||
V |
0.4.9 |
414,4 |
nativo |
|
|||
Ring |
1.20 |
415,0 |
nativo |
creado con la opción |
|||
Chapel |
2.7.0 |
438,1 |
nativo |
|
|||
Crystal |
1.14.0 |
456,3 |
nativo |
|
|
||
Chapel |
1.29.0 |
456,4 |
nativo |
|
|||
Hare |
0.24.2 |
477,9 |
nativo |
||||
Kotlin |
2.3.10 |
488,1 |
nativo |
kotlinc-native |
|
||
V |
0.4.10 |
491,0 |
nativo |
||||
V |
0.4.9 |
500,1 |
nativo |
||||
D |
521,2 |
nativo |
DMD 2.110.0 |
|
|||
D |
521,9 |
nativo |
DMD64 OpenD 2.107.0-beta.1 |
|
|||
Crystal |
1.14.0 |
524,9 |
nativo |
|
|||
Kotlin |
1.9.10 |
530,0 |
nativo |
kotlinc-native |
|
||
Chapel |
2.4.0 |
534,7 |
nativo |
|
|||
C3 |
0.6.8 |
572,1 |
nativo |
||||
C3 |
0.6.8 |
471,6 |
nativo |
|
|||
Go |
1.19.8 |
575,6 |
nativo |
|
|||
Go |
1.19.8 |
640,5 |
nativo |
|
.exe para MS Windows |
||
Ring |
1.19 |
642,0 |
nativo |
creado con la opción |
|||
Go |
1.23.4 |
654,2 |
nativo |
|
|||
Kotlin |
2.3.10 |
675,2 |
nativo |
kotlinc-native |
|||
Go |
1.23.4 |
704,5 |
nativo |
|
.exe para MS Windows |
||
Chapel |
2.7.0 |
812,1 |
nativo |
|
|||
Chapel |
1.29.0 |
817,8 |
nativo |
|
|||
Janet |
1.40.1 |
822,9 |
nativo |
|
|||
Kotlin |
1.9.10 |
828,0 |
nativo |
kotlinc-native |
|||
Janet |
1.40.1 |
844,1 |
nativo |
|
|||
Crystal |
1.10.1 |
864,0 |
nativo |
|
|||
Chapel |
2.4.0 |
905,5 |
nativo |
|
|||
Rust |
1.82.0 |
950,7 |
nativo |
|
|||
Crystal |
1.14.0 |
1003,8 |
nativo |
|
|||
Go |
1.19.8 |
1207,4 |
nativo |
|
|||
Scheme |
1020,1 |
nativo |
bigloo 4.6a |
|
|
||
Haxe |
4.3.6 |
1223,1 |
nativo |
|
creado con la opción |
||
D |
1250,3 |
nativo |
LDC2 1.42.0-beta2 |
|
|||
D |
1261,0 |
nativo |
DMD 2.109.0 |
|
|||
D |
1272,0 |
nativo |
DMD 2.110.0 |
||||
D |
1279,0 |
nativo |
DMD 2.105.0 |
|
|||
D |
1292,8 |
nativo |
DMD64 OpenD 2.107.0-beta.1 |
||||
Go |
1.19.8 |
1305,8 |
nativo |
|
|||
Chapel |
1.29.0 |
1368,9 |
nativo |
|
|||
V |
0.3.4 |
1393,0 |
nativo |
||||
Go |
1.19.8 |
1249,5 |
nativo |
|
.exe para MS Windows |
||
Go |
1.23.4 |
1475,3 |
nativo |
|
|||
Chapel |
2.7.0 |
1512,8 |
nativo |
|
|||
Go |
1.19.8 |
1519,5 |
nativo |
|
.exe para MS Windows |
||
Haxe |
4.3.6 |
1544,4 |
nativo |
creado con la opción |
|||
Chapel |
2.4.0 |
1668,8 |
nativo |
|
|||
Kotlin |
2.1.0 |
1657,2 |
gestionado |
kotlinc-jvm |
.jar completo, ejecutable con |
||
Go |
1.23.4 |
1677,5 |
nativo |
|
.exe para MS Windows |
||
Kotlin |
2.3.10 |
1761,7 |
gestionado |
kotlinc-jvm |
.jar completo, ejecutable con |
||
Crystal |
1.10.1 |
1812,0 |
nativo |
||||
Go |
1.19.8 |
1954,1 |
nativo |
||||
Janet |
1.40.1 |
2010,2 |
nativo |
||||
Go |
1.19.8 |
2085,0 |
nativo |
.exe para MS Windows |
|||
Crystal |
1.14.0 |
2096,5 |
nativo |
||||
Scheme |
2367,7 |
nativo |
gambit 0.4.9 |
|
|||
Chapel |
2.7.0 |
2449,8 |
nativo |
||||
Chapel |
2.4.0 |
2583,2 |
nativo |
||||
Chapel |
1.29.0 |
2604,0 |
nativo |
||||
Kotlin |
1.3.31 |
3058,0 |
gestionado |
kotlinc-jvm |
.jar completo, ejecutable con |
||
Scheme |
3450,3 |
nativo |
bigloo 4.6a |
|
|||
Rust |
1.82.0 |
3788,9 |
nativo |
||||
Kotlin |
2.1.0 |
4416,0 |
nativo |
|
creado con GraalVM a partir del .jar completo |
||
Kotlin |
1.9.10 |
4428,6 |
nativo |
|
creado con GraalVM a partir del .jar completo |
||
Kotlin |
1.9.10 |
4833,8 |
gestionado |
.jar completo, ejecutable con |
|||
Scala |
3.3.0 |
7037,0 |
gestionado |
.jar completo, ejecutable con |
|||
8th |
23.06 |
8646,0 |
nativo |
más un fichero de datos de 2,9 KiB |
|||
Scheme |
11131,6 |
nativo |
gambit 0.4.9 |
||||
Kotlin |
2.1.0 |
13231,3 |
nativo |
creado con GraalVM a partir del .jar completo |
|||
Kotlin |
1.3.31 |
13640,0 |
nativo |
creado con GraalVM a partir del .jar completo |
|||
Kotlin |
1.9.10 |
13664,3 |
nativo |
creado con GraalVM a partir del .jar completo |
|||
Scala |
3.3.0 |
15008,0 |
nativo |
creado con GraalVM a partir del .jar completo |
|||
Racket |
8.15 |
58192,0 |
nativo |
Herramientas
Calculador de conversiones
Este programa, escrito en fish, crea dos documentos en AsciiDoc con tablas que muestran el número de programas convertidos a cada lenguaje de programación y qué programa ha sido convertido a cuál.
#!/usr/bin/env fish
# count_conversions.fish
# Copyright (c) 2023, 2024, 2025, 2026, Marcos Cruz (programandala.net)
# Fair License (Fair)
# SPDX-License-Identifier: Fair
# This program is part of "Basics off".
# Last modified 20260207T1133+0100.
# See change log at the end of the file.
# Config {{{1
# ==============================================================
set column_separator "|"
set first_column_title "{language}"
set table_mark "|==="
# Get data {{{1
# ==============================================================
# get list of project directories
set project_dirs \
(find -L ./repos -maxdepth 1 -type d \
| grep "/basics_of_.*" )
# get list of project identifiers
set project_ids \
(string split " " $project_dirs \
| sed -e 's/.\+basics_of_\([a-z0-9-]\+\)/\1/')
# get list of unique programs
set programs \
(find -L $project_dirs -maxdepth 2 -type f -name "*.bas" \
| grep --invert-match "\.free\.bas" \
| grep --invert-match --ignore-case d3_plot \
| grep --invert-match Diamond \
| grep --invert-match Sine_wave \
| grep --invert-match sinewave \
| xargs -I _ basename --suffix .bas _ \
| sort \
| uniq)
# calculate the number of projects
set projects (count $project_ids)
# width of the first
set column_width 0
for i in $project_ids "$first_column_title"
set column_width (math "max($column_width[1], $(string length $i) + 1)")
end
# return the given string with an uppercase initial
function capitalized # string
echo (string upper (string sub --length 1 $argv[1]))(string sub --start 2 $argv[1])
end
# convert the given project identifier (which is a language name in
# lowercase) to the proper language name
function language # project_id
switch $argv[1]
case c-sharp ; echo "C#"
case f-sharp ; echo "F#"
case freebasic ; echo FreeBASIC
case ocaml ; echo OCaml
case sbcl ; echo SBCL
case "*" ; echo (capitalized "$argv[1]")
end
end
# return the filename extension correspondent to the given project identifier
function extension # project_id
switch $argv[1]
case ada ; echo "adb"
case arturo ; echo "art"
case c-sharp ; echo "cs"
case chapel ; echo "chpl"
case clojure ; echo "clj"
case crystal ; echo "cr"
case elixir ; echo "ex"
case euphoria ; echo "eu"
case f-sharp ; echo "fs"
case freebasic ; echo "free.bas"
case hare ; echo "ha"
case haskell ; echo "hs"
case haxe ; echo "hx"
case icon ; echo "icn"
case julia ; echo "jl"
case kotlin ; echo "kt"
case miranda ; echo "m"
case nature ; echo "n"
case neat ; echo "nt"
case oberon-07 ; echo "obn"
case ocaml ; echo "ml"
case prolog ; echo "pl"
case python ; echo "py"
case racket ; echo "rkt"
case rust ; echo "rs"
case sbcl ; echo "lisp"
case scheme ; echo "scm"
case styx ; echo "sx"
case '*' ; echo $argv[1]
end
end
# return the program name correspondent to its given base filename
function program_name # base_filename
set result ''
set name $argv[1]
set name (string replace '_' ' ' $name)
set name (string replace '3d' '3D' $name)
set characters (string split '' $name)
set previous_character ' '
for character in $characters
if test $previous_character = ' ' -o $previous_character = '-'
set character (string upper $character)
end
set result "$result$character"
set previous_character $character
end
echo $result
end
# Make table with the number of conversions per language {{{1
# ==============================================================
function print_column_titles
# calculate the width of data columns
set column_title $first_column_title "{finished}" "{unfinished}"
for i in 2 3
set column_width[$i] (string length $column_title[$i])
end
for i in 1 2 3
echo -n \
$column_separator \
(string pad --right --width (math "$column_width[$i]+1") "$column_title[$i]")
end
echo -e "\n"
end
set total_number_of_finished_conversions 0
set total_number_of_unfinished_conversions 0
function print_conversions_rows
for i in (seq $projects)
# get the proper files from the project's <src> directory
set source_files (\
find -L $project_dirs[$i]/src -maxdepth 1 -name "*.$(extension $project_ids[$i])")
# get the finished and unfinished conversions
if test (count $source_files) -eq 0
set list_of_finished_conversions
set list_of_unfinished_conversions
else
set list_of_finished_conversions (\
grep \
--files-without-match \
"XXX\sUNDER\sDEVELOPMENT" $source_files)
set list_of_unfinished_conversions (\
grep \
"XXX\sUNDER\sDEVELOPMENT" $source_files)
end
set number_of_finished_conversions (count $list_of_finished_conversions)
set number_of_unfinished_conversions (count $list_of_unfinished_conversions)
set total_number_of_finished_conversions (math "$total_number_of_finished_conversions + $number_of_finished_conversions")
set total_number_of_unfinished_conversions (math "$total_number_of_unfinished_conversions + $number_of_unfinished_conversions")
# print the row
echo \
$column_separator \
(string pad --right --width $column_width[1] "$(language $project_ids[$i])") \
$column_separator \
(string pad --width $column_width[2] $number_of_finished_conversions) \
$column_separator \
(string pad --width $column_width[3] $number_of_unfinished_conversions)
end
end
# print the ranking, i.e. a table containing the number of finished and unfinished
# conversions per language, sorted in descending order of conversions.
function print_ranking
echo "ifdef::en[]"
echo "== Number of conversions by programming language"
echo "endif::en[]"
echo "ifdef::eo[]"
echo "== Nombro de konvertoj po program-lingvo"
echo "endif::eo[]"
echo "ifdef::es[]"
echo "== Número de conversiones por lenguaje de programación"
echo "endif::es[]"
echo "ifdef::ie[]"
echo "== Númere de conversiones por lingue de programation"
echo "endif::ie[]"
echo
echo "ifdef::en[]"
echo ":language: Programming language"
echo ":finished: Finished conversions"
echo ":unfinished: Unfinished conversions"
echo ":totals: TOTALS"
echo "endif::en[]"
echo "ifdef::eo[]"
echo ":language: Program-lingvo"
echo ":finished: Finitaj konvertoj"
echo ":unfinished: Nefinitaj konvertoj"
echo ":totals: TOTALOJ"
echo "endif::eo[]"
echo "ifdef::es[]"
echo ":language: Lenguaje de programación"
echo ":finished: Conversiones acabadas"
echo ":unfinished: Conversiones inacabadas"
echo ":totals: TOTALES"
echo "endif::es[]"
echo "ifdef::ie[]"
echo ":language: Lingue de programation"
echo ":finished: Conversiones terminat"
echo ":unfinished: Conversiones ínterminat"
echo ":totals: TOTALES"
echo "endif::ie[]"
echo
echo '[width=50%, cols="<10h,>6,>6"]'
echo $table_mark
print_column_titles
print_conversions_rows \
| sort \
--ignore-case \
--field-separator=$column_separator \
--key=3nr --key=4nr --key=2d
# print the totals row
echo
echo \
$column_separator \
(string pad --right --width $column_width[1] "{totals}") \
$column_separator \
(string pad --width $column_width[2] $total_number_of_finished_conversions) \
$column_separator \
(string pad --width $column_width[3] $total_number_of_unfinished_conversions)
echo $table_mark
end
# Make table with the names of the programs converted per language {{{1
# ==============================================================
set symbol_of_finished_program "✓"
set symbol_of_unfinished_program "…"
function print_programs_rows
for project_number in (seq $projects)
echo -n \
$column_separator \
(string pad --right --width $column_width[1] (language $project_ids[$project_number]))
for program_number in (seq (count $programs))
set column_number (math "$program_number + 1")
set program_filename $programs[$program_number].(extension $project_ids[$project_number])
switch $program_filename
case "3d_plot.hx"
set conversion (find -L $project_dirs[$project_number] -maxdepth 2 -type f -path "*/src/D3_plot.hx")
case "3d_plot.nim"
set conversion (find -L $project_dirs[$project_number] -maxdepth 2 -type f -path "*/src/d3_plot.nim")
case "diamond.hx"
set conversion (find -L $project_dirs[$project_number] -maxdepth 2 -type f -path "*/src/Diamond.hx")
case "sine_wave.hx"
set conversion (find -L $project_dirs[$project_number] -maxdepth 2 -type f -path "*/src/Sine_wave.hx")
case "sine_wave.obn"
set conversion (find -L $project_dirs[$project_number] -maxdepth 2 -type f -path "*/src/sinewave.obn")
case '*'
set conversion (find -L $project_dirs[$project_number] -maxdepth 2 -type f -path "*/src/$program_filename")
end
if test -z "$conversion"
# the program has not been converted to the current language
echo -n $column_separator (string repeat --count $column_width[$column_number] " ")
else if grep --quiet "XXX\sUNDER\sDEVELOPMENT" $conversion
# the program conversion is under development
echo -n $column_separator (string pad --right --width $column_width[$column_number] $symbol_of_unfinished_program)
else
# the program conversion is finished
echo -n $column_separator (string pad --right --width $column_width[$column_number] $symbol_of_finished_program)
end
end
echo
end
end
# print a table showing the programs (columns) converted to each
# language (rows), including unfinished conversions (marked with a
# different symbol).
function print_programs
echo "ifdef::en[]"
echo "== Programs converted to each programming language"
echo "endif::en[]"
echo "ifdef::eo[]"
echo "== Programoj konvertitaj al ĉiu program-lingvo"
echo "endif::eo[]"
echo "ifdef::es[]"
echo "== Programas convertidos a cada lenguaje de programación"
echo "endif::es[]"
echo "ifdef::ie[]"
echo "== Programas convertet a chascun lingue de programation"
echo "endif::ie[]"
echo
echo "ifdef::en[]"
echo ":language: Programming language"
echo ":symbols: Symbols"
echo ":finished_program: Finished program"
echo ":unfinished_program: Unfinished program"
echo "endif::en[]"
echo "ifdef::eo[]"
echo ":language: Program-lingvo"
echo ":symbols: Simboloj"
echo ":finished_program: Finita programo"
echo ":unfinished_program: Nefinita programo"
echo "endif::eo[]"
echo "ifdef::es[]"
echo ":language: Lenguaje de programación"
echo ":symbols: Símbolos"
echo ":finished_program: Programa completado"
echo ":unfinished_program: Programa inacabado"
echo "endif::es[]"
echo "ifdef::ie[]"
echo ":language: Lingue de programation"
echo ":symbols: Simboles"
echo ":finished_program: Programa terminat"
echo ":unfinished_program: Programa ínterminat"
echo "endif::ie[]"
echo
echo "[cols=\"<3h,"(count $programs)"*^1\"]"
echo $table_mark
# calculate the width of the data columns
for column_number in (seq 2 (math "$(count $programs) + 1"))
set column_width[$column_number] (math "$(string length $programs[(math "$column_number - 1")]) + 1")
end
set column_title $first_column_title $programs
for column_number in (seq (count $column_title))
# echo $column_width[$column_number] $column_title[$column_number]
echo -n \
$column_separator \
(string pad --right --width $column_width[$column_number] (program_name $column_title[$column_number]))
end
echo -e "\n"
print_programs_rows \
| sort \
--ignore-case \
--field-separator=$column_separator \
--key=2d
echo $table_mark
echo -e "\n.{symbols}\n"
echo "$symbol_of_finished_program:: {finished_program}"
echo "$symbol_of_unfinished_program:: {unfinished_program}"
end
# Main {{{1
# ==============================================================
# print the document corresponding to the given report type,
# "ranking" or "programs".
function print_document # report
set report $argv[1]
echo "= Basics off"
echo ":author: Marcos Cruz (programandala.net)"
echo ":revdate:" (date +%Y-%m-%d)
switch $report
case ranking
echo ":pdf-page-layout: portrait"
echo
print_ranking
case programs
echo ":pdf-page-layout: landscape"
echo
print_programs
end
end
print_document $argv[1]
# Change log {{{1
# ==============================================================
# 2023-09-16: Start.
#
# 2023-09-17: Reject the conversions containing a note "XXX UNDER
# DEVELOPMENT". Fix and improve the filename extensions regex. Select
# the conversions by filename extension. Print the language names with
# proper case. Add a column with the unfinished conversions. Add
# column titles. Sort the table.
#
# 2023-10-17: Add the Arturo language.
#
# 2023-10-19: Add the OCaml language.
#
# 2023-10-29: Update to the new project tree. Build an AsciiDoc table.
#
# 2023-11-02: Add the Swift language.
#
# 2023-11-08: Prepare to build a second table.
#
# 2023-11-10: Build a second table with the programs converted to each
# language.
#
# 2023-11-14: Add the Haxe language.
#
# 2023-11-26: Support the Oberon-07's exceptional base filename "sinewave".
#
# 2023-12-15: Set variables with the symbols of finished and
# unfinished programs; add a legend. Convert program base filenames to
# names.
#
# 2024-07-19: Improve the layout of the report.
#
# 2024-07-20: Update after the renaming the project and its subprojecs.
#
# 2024-10-29: Add the Python language.
#
# 2024-11-20: Update extension of FreeBASIC source files.
#
# 2024-11-26: Add the Nit language.
#
# 2024-11-30: Add the Factor language.
#
# 2024-12-02: Add languages Io and Raku.
#
# 2024-12-10: Add the Clojure language.
#
# 2024-12-14: Add the Hare language.
#
# 2024-12-16: Simplify the filename extensions function.
#
# 2024-12-19: Support Haxe's <D3_plot.hx>. Improve layout of tables.
#
# 2024-12-20: Add the C# language.
#
# 2024-12-24: Update the C# language project identifier.
#
# 2024-12-26: Add the Rust language.
#
# 2024-12-27: Simplify expression and conversion of unusual filenames.
# Support Haxe's <Sine_wave.hx>.
#
# 2024-12-28: Fix bug: the source files of the conversions were
# searched for also in project directories other than <src>.
#
# 2024-12-30: Add the F# language.
#
# 2025-01-02: Add totals.
#
# 2025-01-20: Update path to repos. Split the document in two,
# depending on an argument: the language ranking and the programs table.
#
# 2025-03-19: Add the Ada language.
#
# 2025-03-31: Rename main lists.
#
# 2025-04-07: Fix typo.
#
# 2025-06-10: Build multilingual Asciidoctor documents.
#
# 2025-06-11: Reword translation. Translate also the legend.
#
# 2025-06-27: Simplify layout of legend. Reword some texts.
#
# 2025-08-14: Reword some texts. Translate "totals".
#
# 2025-12-17: Add the Styx and Neat languages.
#
# 2025-12-19: Update name conversion to support "Z-End".
#
# 2026-01-23: Add the Haskell and Elixir languages.
#
# 2026-02-07: Fix typo; improve table headings and titles.
Calculador de actividad
Este programa, escrito en Julia, crea varios ficheros de datos en formato CSV que contienen la actividad de los repositorios de los proyectos.
# calculate_activity.jl
# Copyright (c) 2024, 2025, Marcos Cruz (programandala.net)
# Fair License (Fair)
# SPDX-License-Identifier: Fair
# This program is part of "Basics off".
# Last modified 20250604T0056+0200.
# See change log at the end of the file.
# Requirements {{{1
# ==============================================================
import CSV
import DataFrames
# Globals {{{1
# ==============================================================
const SRC_DIR = "repos"
const TARGET_DIR = "target"
const TMP_DIR = "tmp"
@enum Command no_command log_command summary_command tabular_command
command::Command = no_command
@enum Plot no_plot commits_plot started_conversions_plot
plot_type::Plot = no_plot
# Input file path set by the `--input` command-line option.
input_file = ""
# Output file path set by the `--output` command-line option.
output_file = ""
# Errors and warnings {{{1
# ============================================================================
# Print an error message and quit.
function fail(message::String, result::Int = 1)
println("Error: $message.")
exit(result)
end
function fail_because_of_missing_value(option::String)
fail("falta el valor de la opción `$option`")
end
function fail_because_of_repeated_option(option::String)
fail("se permite solamente una opción `$option`")
end
function warn(message::String)
println("Aviso: $message.")
end
function warn_about_useless_option(command::String, option::String)
warn("el comando `$command` no necesita la opción `$option`")
end
# Languages {{{1
# ==============================================================
# Convert the given language label into its proper name.
function language_name(label::SubString)::String
if label == "c-sharp"
return "C#"
elseif label == "f-sharp"
return "F#"
elseif label == "freebasic"
return "FreeBASIC"
elseif label == "ocaml"
return "OCaml"
elseif label == "sbcl"
return "SBCL"
else
return uppercasefirst(label)
end
end
# Make log data file {{{1
# ==============================================================
# Make a log data file out of the Mercurial logs of the projects.
#
# The log data file is a headerless CSV file containing 2 fields: commit month
# (in YYYY-MM format) and programming language; i.e. one record for every
# commit done in the given month.
function make_log_data_file()
global log_data_file
global output_file
global plot_type
output_file = abspath(output_file == "" ? log_data_file : output_file)
# (the output file must be absolute in order to pass it to mercurial, which
# is called in a subdirectory)
rm(output_file, force = true)
# get list of project directories
project_dir::Array{String} = []
for entry in readdir(SRC_DIR)
if isdir(joinpath(SRC_DIR, entry))
push!(project_dir, entry)
end
end
# add the data, extracted from the Mercurial repositories
working_dir = pwd()
for dir in project_dir
project_id = match(r"basics_of_([a-z0-9-]+)", dir).captures[1]
cd(joinpath(SRC_DIR, dir))
if plot_type == commits_plot
mercurial_command = `hg log --template "{date|shortdate},$(language_name(project_id))\n"`
else # conversions_plot
mercurial_command = `hg log --template "{date|shortdate},{file_adds},$(language_name(project_id))\n"`
end
run(pipeline(mercurial_command, stdout = output_file, append = true))
cd(working_dir)
end
# select and format the data lines
lines = readlines(output_file)
selected_and_formatted_lines::Array{String} = []
for line in lines
if plot_type == commits_plot
field = match(r"(\d\d\d\d-\d\d)-\d\d,(.+)", line).captures
month = field[1]
language = field[2]
push!(selected_and_formatted_lines, "$month,$language")
else # conversions_plot
field = match(r"(\d\d\d\d-\d\d)-\d\d,(.*),(.+)", line).captures
month = field[1]
files = field[2]
language = field[3]
if contains(files, ".bas") && !contains(files, ".free.bas")
push!(selected_and_formatted_lines, "$month,$language")
end
end
end
# sort the lines into the data file
output_io = open(output_file, "w")
for line in sort(selected_and_formatted_lines, by=uppercase)
println(output_io, line)
end
close(output_io)
end
# Make summary data file {{{1
# ==============================================================
# Make a summary data file out of the log data file.
#
# The summary data file is a headerless CSV file containing 3 fields: commit
# month (in YYYY-MM format), programming language and number of commits; i.e.
# one record for every language used in any month.
function make_summary_data_file()
global log_data_file
global summary_data_file
global input_file
global output_file
global plot_type
input_file = input_file == "" ? log_data_file : input_file
output_file = output_file == "" ? summary_data_file : output_file
output_io = open(output_file, "w")
previous_month = ""
previous_language = ""
language_activity_per_month = 0
if plot_type == commits_plot
println(output_io, "month,language,commits")
else
println(output_io, "month,language,started_conversions")
end
for record in push!(readlines(input_file), "end_of_data,end_of_data")
field = split(record, ",")
month = field[1]
language = field[2]
if (month == previous_month && language == previous_language) ||
(previous_month == "" && previous_language == "")
language_activity_per_month += 1
else
println(output_io, "$previous_month,$previous_language,$language_activity_per_month")
language_activity_per_month = 1
end
previous_month = month
previous_language = language
end
close(output_io)
end
# Make tabular data file {{{1
# ==============================================================
# Make a tabular data file out of the summary data file.
#
# The tabular data file is a CSV file containing one field for the month (in
# YYYY-MM format) and one field for the commit count of every language; i.e.
# one record to hold the number of commits done in a month in every language.
function make_tabular_data_file()
global summary_data_file
global table_data_file
global input_file
global output_file
input_file = input_file == "" ? summary_data_file : input_file
output_file = output_file == "" ? table_data_file : output_file
lines = readlines(input_file)
first_record = lines[2] # skip headers
last_record = last(lines)
first_date = split(first_record, ",")[1]
last_date = split(last_record, ",")[1]
first_year = parse(Int, split(first_date, "-")[1])
last_year = parse(Int, split(last_date, "-")[1])
first_month = parse(Int, split(first_date, "-")[2])
last_month = parse(Int, split(last_date, "-")[2])
# extract the language names from the log
langs::Array{String} = []
for line in lines[2 : end] # skip headers
lang = match(r"\d\d\d\d-\d\d,(.+),\d+", line).captures[1]
push!(langs, lang)
end
sort!(langs, by=uppercase)
unique!(langs)
output_io = open(output_file, "w")
# create the column headers
print(output_io, "date")
for lang in langs
print(output_io, ",$lang")
end
println(output_io, "")
# add the data
for year in first_year : last_year
for month in 1 : 12
if (year == first_year && month < first_month) ||
(year == last_year && month > last_month)
continue
end
padded_month = lpad(month, 2, '0')
print(output_io, "$year-$padded_month")
for lang in langs
count = 0
for record in readlines(input_file)
if contains(record, "$year-$padded_month,$lang,")
count = split(record, ",")[3]
break
end
end
print(output_io, ",$count")
end
println(output_io, "")
end
end
end
# Command-line arguments {{{1
# ============================================================================
# Read and check the given command-line arguments.
function read_arguments(args::Array{String})
global command
global input_file
global output_file
global plot_type
local user_command
i = 1
while i <= length(args)
if i == 1
# Check the user command, which must be the first argument
user_command = args[1]
if user_command in ["log", "l"]
command = log_command
elseif user_command in ["summary", "s"]
command = summary_command
elseif user_command in ["tabular", "t"]
command = tabular_command
else
fail("comando `$user_command` no reconocido")
end
else
# Check the options
if args[i] in ["--input", "-input", "-i"]
if ! (command in [summary_command, tabular_command])
warn_about_useless_option(user_command, args[i])
end
if input_file != ""
fail_because_of_repeated_option(args[i])
else
if i < length(args)
input_file = args[i+1]
i += 1
else
fail_because_of_missing_value(args[i])
end
end
elseif args[i] in ["--output", "-output", "-o"]
if ! (command in [log_command, summary_command, tabular_command])
warn_about_useless_option(user_command, args[i])
end
if output_file != ""
fail_because_of_repeated_option(args[i])
else
if i < length(args)
output_file = args[i+1]
i += 1
else
fail_because_of_missing_value(args[i])
end
end
elseif args[i] in ["--plot-type", "-plot-type", "-p"]
if ! (command in [log_command, summary_command])
warn_about_useless_option(user_command, args[i])
end
if plot_type != no_plot
fail_because_of_repeated_option(args[i])
else
if i < length(args)
plot_type_argument = args[i+1]
i += 1
if plot_type_argument in ["commits", "c"]
plot_type = commits_plot
elseif plot_type_argument in ["started_conversions", "sc", "s", "conversions", "c"]
plot_type = started_conversions_plot
else
fail("opción `$plot_type_argument` no reconocida")
end
else
fail_because_of_missing_value(args[i])
end
end
else
fail("opción no reconocida: $(args[i])")
end
end
i += 1
end
end
function check_plot_type()
if plot_type == no_plot
fail("falta la opción `--plot-type`")
end
end
# Main {{{1
# ==============================================================
read_arguments(ARGS)
if plot_type == commits_plot
log_data_file = joinpath(TMP_DIR, "activity__commits.log")
summary_data_file = joinpath(TARGET_DIR, "activity__commits_summary.csv")
table_data_file = joinpath(TARGET_DIR, "activity__commits_table.csv")
elseif plot_type == started_conversions_plot
log_data_file = joinpath(TMP_DIR, "activity__conversions.log")
summary_data_file = joinpath(TARGET_DIR, "activity__conversions_summary.csv")
table_data_file = joinpath(TARGET_DIR, "activity__conversions_table.csv")
end
if command == log_command
check_plot_type()
make_log_data_file()
elseif command == summary_command
check_plot_type()
make_summary_data_file()
elseif command == tabular_command
make_tabular_data_file()
else
fail("es necesario un comando")
end
# Change log {{{1
# ==============================================================
# 2024-07-07: Start in fish shell. Make log CSV data file out of the logs of
# the repos.
#
# 2024-07-09: Make summary CSV data file: activity per month and language. Make
# tabular CSV data file. Make gnuplot data file. Make a graphic chart. Start
# conversion of the fish code to the Julia language.
#
# 2024-07-10: Convert to Julia the making of the log and summary files.
#
# 2024-07-11: Convert to Julia the making of the tabular file.
#
# 2024-07-18: Organize the code into functions. Simplify the sorting of the log
# data file lines.
#
# 2024-07-19: Remove 2 unnecessary `rm()`.
#
# 2024-07-20: Update after the renaming the project and its subprojects.
#
# 2024-07-21: Rename this file. Support `--input` and `--output` options.
#
# 2024-07-23: Add a `plot` no-op command.
#
# 2024-12-20: Update regular expression to catch "c#".
#
# 2024-12-24: Update after the renaming of the C# repository link.
#
# 2024-12-30: Add the F# language.
#
# 2025-01-07: Remove the plot code, which was unfinished: the plotting is done
# by gnuplot. Copy to <calculate_commits_activity.jl> and
# <calculate_conversions_activity.jl>; keep only the code common to both.
#
# 2025-01-08: Undo the file factoring: integrate the different code of
# <calculate_commits_activity.jl> and <calculate_conversions_activity.jl>; add
# a `--plot-type` option accordingly.
#
# 2025-01-20: Update path to repos.
#
# 2025-02-14: Update naming convention of output files.
Constructor de páginas
Este programa, escrito en D, crea las fuentes, en formato de Fendo, de las páginas de programandala.net sobre el metaproyecto «Basics off», los 49 proyectos «Basic of…» iniciados y sus 20 programas. Todo ello en 4 lenguas; por tanto, un total de 280 páginas.
// build_pages.d
// Copyright (c) 2025, 2026, Marcos Cruz (programandala.net)
// Fair License (Fair)
// SPDX-License-Identifier: Fair
// This program is part of "Basics off"
// Last modified 20260215T2003+0100.
// See change log at the end of the file.
// Requirements {{{1
// =============================================================================
import std.algorithm.searching :
can_find = canFind,
find;
import std.algorithm.sorting :
sort;
import std.array :
array,
replicate,
split;
import std.ascii :
is_digit = isDigit;
import std.conv :
octal,
to;
import std.datetime.systime :
Clock,
System_Time = SysTime;
import std.file :
dir_entries = dirEntries,
exists,
is_dir = isDir,
mkdir,
read_text = readText,
remove,
set_attributes = setAttributes,
Span_Mode = SpanMode,
fwrite = write;
import std.format :
format;
import std.path :
base_name = baseName,
build_normalized_path = buildNormalizedPath,
build_path = buildPath,
dir_name = dirName;
import std.range :
retro;
import std.stdio :
File,
writef,
writefln,
writeln;
import std.string :
capitalize,
starts_with = startsWith,
to_lower = toLower;
// Syntactic sugar {{{1
// =============================================================================
/// Fake keyword used as a user-defined attribute for marking the declarations
/// of functions in order to facilitate searching the sources, especially with
/// external tools like `grep`, and their legibility.
enum fn;
/// Fake keyword used as a user-defined attribute for marking the declarations
/// of variables in order to facilitate searching the sources, especially with
/// external tools like `grep`, and their legibility.
enum var;
// Constants {{{1
// =============================================================================
/// Absolute path to the directory of this project.
@var immutable string WORKING_DIR = build_path(dir_name(__FILE_FULL_PATH__), "..");
/// Absolute path to the directory containing the links to the projects' repos.
@var immutable string REPOS_DIR = build_normalized_path(WORKING_DIR, "repos");
/// Absolute path to a project directory containing all outputs of the original
/// programs.
@var immutable string OUTPUTS_DIR =
build_path(REPOS_DIR, "basics_of_d", "_meta", "outputs");
/// Absolute path to the target directory where the pages will be built.
@var immutable string TARGET_DIR =
build_normalized_path(WORKING_DIR, "target", "pages");
/// ISO codes of the languages used in the target website, plus languages used
/// in some names, plus two fake ones used as default and for abstraction.
enum Human_Lang
{
en, // English
eo, // Esperanto
es, // Spanish
ie, // Interlingue/Occidental
it, // Italian
pt, // Portuguese
none,
any
};
/// ISO codes of the languages used in the target website.
@var immutable Human_Lang[] human_langs =
[Human_Lang.en, Human_Lang.eo, Human_Lang.es, Human_Lang.ie];
/// Comment used in the unfinished source files. Files containing this comment
/// will not be included in the pages.
@var immutable string UNFINISHED = "XXX UNDER DEVELOPMENT";
// Data conversions {{{1
// =============================================================================
/// Convert the given programming language identifier to the human language of
/// its proper name.
@fn Human_Lang programming_lang_name_lang(string programming_lang_id)
{
switch(programming_lang_id)
{
case "ada":
case "c3":
case "d":
case "io":
case "miranda":
case "neko":
case "nim":
case "nit":
case "raku":
case "retro":
case "sbcl":
case "v":
case "vala":
case "vale":
return Human_Lang.any;
case "arturo":
return Human_Lang.es;
case "scala":
return Human_Lang.it;
case "lua":
return Human_Lang.pt;
default:
return Human_Lang.en;
}
}
/// Convert the given programming language identifier to its proper name.
@fn string programming_lang_name(string programming_lang_id)
{
switch (programming_lang_id)
{
case "c-sharp":
return "C#";
case "f-sharp":
return "F#";
case "freebasic":
return "FreeBASIC";
case "ocaml":
return "OCaml";
case "sbcl":
return "SBCL";
default:
return capitalize(programming_lang_id);
}
}
/// Convert the given programming language identifier to the corresponding
/// filename extension, with initial dot.
@fn string filename_extension(string programming_lang_id)
{
switch (programming_lang_id)
{
case "ada":
return ".adb";
case "arturo":
return ".art";
case "c-sharp":
return ".cs";
case "chapel":
return ".chpl";
case "clojure":
return ".clj";
case "crystal":
return ".cr";
case "elixir":
return ".ex";
case "euphoria":
return ".eu";
case "f-sharp":
return ".fs";
case "freebasic":
return ".free.bas";
case "hare":
return ".ha";
case "haskell":
return ".hs";
case "haxe":
return ".hx";
case "icon":
return ".icn";
case "julia":
return ".jl";
case "kotlin":
return ".kt";
case "miranda":
return ".m";
case "nature":
return ".n";
case "neat":
return ".nt";
case "oberon-07":
return ".obn";
case "ocaml":
return ".ml";
case "prolog":
return ".pl";
case "python":
return ".py";
case "racket":
return ".rkt";
case "rust":
return ".rs";
case "sbcl":
return ".lisp";
case "scheme":
return ".scm";
case "styx":
return ".sx";
default:
return "." ~ programming_lang_id;
}
}
/// Convert the given programming language identifier to a flag indicating the
/// corresponding language is actually used in its "basics_of_" project, ie. at
/// least one program has been converted to it.
// Ideally, all the relevant information about the projects should be collected
// at the start of the program into a one single array of structures, in order
// to make it accessible to every function. This function is a simpler,
// hard-coded workaround.
@fn bool is_programming_lang_used(string programming_lang_id)
{
switch (programming_lang_id)
{
case "dylan":
case "euphoria":
case "haskell":
case "lisp":
case "miranda":
case "prolog":
case "red":
case "sbcl":
case "vale":
return false;
default:
return true;
}
}
/// Convert a program identifier (which may have a special form, imposed by its
/// programming language) to its usual form, i.e. "lower_camel_case".
@fn string usual_program_id(string program_id)
{
switch (program_id)
{
case "Diamond":
return "diamond";
case "D3_plot", "d3_plot":
return "3d_plot";
case "Sine_wave", "sinewave":
return "sine_wave";
default:
return program_id;
}
}
/// Convert a usual program identifier to the actual one used by the given
/// programming language.
@fn string actual_program_id(string program_id, string programming_lang_id)
{
final switch (program_id)
{
case "3d_plot":
final switch (programming_lang_id)
{
case "haxe":
return "D3_plot";
case "nim":
return "d3_plot";
}
case "diamond":
final switch (programming_lang_id)
{
case "haxe":
return "Diamond";
}
case "sine_wave":
final switch (programming_lang_id)
{
case "haxe":
return "Sine_wave";
case "oberon-07":
return "sinewave";
}
}
return program_id;
}
/// Return the [Fendo](http://programandala.net/en.program.fendo.html) language
/// markup to open an inlined text in the given language.
@fn string open_lang_markup(Human_Lang human_lang)
{
return iso_code(human_lang) ~ "(( ";
}
/// Return a true flag if the given text starts with the
/// [Fendo](http://programandala.net/en.program.fendo.html) language markup
/// that opens an inlined text in the given language.
@fn bool already_in_lang_markup(string text, Human_Lang human_lang)
{
return starts_with(text, open_lang_markup(human_lang));
}
/// Return the given string with the
/// [Fendo](http://programandala.net/en.program.fendo.html) markup
/// corresponding to the given language, unless it already has it.
@fn string in_lang_markup(string text, Human_Lang human_lang)
{
if (already_in_lang_markup(text, human_lang))
{
return text;
}
else
{
return open_lang_markup(human_lang) ~ text ~ " ))";
}
}
/// Return the given string with the
/// [Fendo](http://programandala.net/en.program.fendo.html) markup
/// corresponding to its given language, unless the language of the string is
/// the same as the given context language.
@fn string in_lang_markup_if_needed
(
string text,
Human_Lang text_human_lang,
Human_Lang context_human_lang,
)
{
if (text_human_lang == context_human_lang)
{
return text;
}
else
{
return in_lang_markup(text, text_human_lang);
}
}
/// Return the given string with the
/// [Fendo](http://programandala.net/en.program.fendo.html) markup
/// corresponding to the English language, unless the given language is
/// English.
@fn string in_english_markup
(
string text,
Human_Lang context_human_lang = Human_Lang.none,
)
{
return in_lang_markup_if_needed(text, Human_Lang.en, context_human_lang);
}
/// Return the title of the program whose identifier is given, in the given
/// language.
@fn string program_title(string program_id, Human_Lang human_lang = Human_Lang.none)
{
@var string result;
switch (program_id.to_lower)
{
case "3d_plot", "d3_plot":
result = "3D Plot";
break;
case "high_noon":
result = "High Noon";
break;
case "sine_wave":
result = "Sine Wave";
break;
case "russian_roulette":
result = "Russian Roulette";
break;
case "z-end":
result = "Z-End";
break;
default:
result = capitalize(program_id);
}
return in_english_markup(result, human_lang);
}
/// Return the programming language identifier corresponding to the given
/// programming language project identifier.
@fn string programming_lang_id_of_project(string project)
{
return split(project, "_")[$ - 1];
}
unittest
{
assert(programming_lang_id_of_project("foo_bar") == "bar");
assert(programming_lang_id_of_project("foo_bar_zx") == "zx");
}
/// Return the page title corresponding to the given project, in the given
/// language.
@fn string page_title(string project, Human_Lang human_lang)
{
@var string result;
if (starts_with(project, "basics_of_"))
{
@var string programming_lang_id = programming_lang_id_of_project(project);
result = "Basics of " ~ programming_lang_name(programming_lang_id);
}
else if (project == "basics_off")
{
result = "Basics off";
}
else
{
result = program_title(project, human_lang);
}
return in_english_markup(result, human_lang);
}
/// Identifiers of translatable texts.
enum Text
{
activity,
activity_tool,
all_versions_of,
commits_plot,
conversions, // XXX OLD not used
conversions_plot,
conversions_tool,
en,
first,
gnuplot_files,
new_page,
original, // (substantive)
output, // (substantive)
pages_tool,
program,
reports,
second,
see_also,
size_report,
third,
tools,
}
/// Return a text, whose [identifier][Text] is given, translated to the given
/// language.
@fn string translated(Text text, Human_Lang human_lang)
{
final switch (text)
{
case Text.activity:
switch (human_lang)
{
case Human_Lang.en:
return "Activity";
case Human_Lang.eo:
return "Aktivecon";
case Human_Lang.es:
return "Actividad";
case Human_Lang.ie:
return "Activitá";
default:
assert(false);
}
case Text.activity_tool:
switch (human_lang)
{
case Human_Lang.en:
return "Activity calculator";
case Human_Lang.eo:
return "Aktiveco-kalkulilo";
case Human_Lang.es:
return "Calculador de actividad";
case Human_Lang.ie:
return "Calculator de activitá";
default:
assert(false);
}
case Text.all_versions_of:
switch (human_lang)
{
case Human_Lang.en:
return "All versions of";
case Human_Lang.eo:
return "Ĉiuj versioj de";
case Human_Lang.es:
return "Todas las versiones de";
case Human_Lang.ie:
return "Omni versiones de";
default:
assert(false);
}
case Text.commits_plot:
switch (human_lang)
{
case Human_Lang.en:
return "Monthly commits";
case Human_Lang.eo:
return "Monataj enmetoj";
case Human_Lang.es:
return "Entradas mensuales";
case Human_Lang.ie:
return "Depositiones mensual";
default:
assert(false);
}
case Text.conversions: // XXX OLD not used
switch (human_lang)
{
case Human_Lang.en:
return "Conversions";
case Human_Lang.eo:
return "Konvertoj";
case Human_Lang.es:
return "Conversiones";
case Human_Lang.ie:
return "Conversiones";
default:
assert(false);
}
case Text.conversions_plot:
switch (human_lang)
{
case Human_Lang.en:
return "Monthly started conversions";
case Human_Lang.eo:
return "Monate komencitaj konvertoj";
case Human_Lang.es:
return "Conversiones empezadas mensualmente";
case Human_Lang.ie:
return "Conversiones comensat mensualmen";
default:
assert(false);
}
case Text.conversions_tool:
switch (human_lang)
{
case Human_Lang.en:
return "Conversion counter";
case Human_Lang.eo:
return "Konverto-kalkulilo";
case Human_Lang.es:
return "Calculador de conversiones";
case Human_Lang.ie:
return "Calculator de conversiones";
default:
assert(false);
}
case Text.en:
switch (human_lang)
{
case Human_Lang.en:
return "in";
case Human_Lang.eo:
return "en";
case Human_Lang.es:
return "en";
case Human_Lang.ie:
return "in";
default:
assert(false);
}
case Text.first:
switch (human_lang)
{
case Human_Lang.en:
return "first";
case Human_Lang.eo:
return "unua";
case Human_Lang.es:
return "primer";
case Human_Lang.ie:
return "unesim";
default:
assert(false);
}
case Text.gnuplot_files:
switch (human_lang)
{
case Human_Lang.en:
return "en(( gnuplot )) files for making the graphics";
case Human_Lang.eo:
return "Dosieroj de en(( gnuplot )) por krei la grafikaĵojn";
case Human_Lang.es:
return "Ficheros de en(( gnuplot )) para crear los gráficos";
case Human_Lang.ie:
return "Files de en(( gnuplot )) por crear li grafics";
default:
assert(false);
}
case Text.new_page:
switch (human_lang)
{
case Human_Lang.en:
return "New page";
case Human_Lang.eo:
return "Nova paĝo";
case Human_Lang.es:
return "Nueva página";
case Human_Lang.ie:
return "Nov págine";
default:
assert(false);
}
case Text.original: // (substantive)
switch (human_lang)
{
case Human_Lang.en:
return "Original";
case Human_Lang.eo:
return "Originalo";
case Human_Lang.es:
return "Original";
case Human_Lang.ie:
return "Originale";
default:
assert(false);
}
case Text.output: // (substantive)
switch (human_lang)
{
case Human_Lang.en:
return "Output";
case Human_Lang.eo:
return "Eliraĵo";
case Human_Lang.es:
return "Salida";
case Human_Lang.ie:
return "Printate";
default:
assert(false);
}
case Text.pages_tool:
switch (human_lang)
{
case Human_Lang.en:
return "Page builder";
case Human_Lang.eo:
return "Paĝo-konstruilo";
case Human_Lang.es:
return "Constructor de páginas";
case Human_Lang.ie:
return "Constructor de págines";
default:
assert(false);
}
case Text.program:
switch (human_lang)
{
case Human_Lang.en:
return "program";
case Human_Lang.eo:
return "programo";
case Human_Lang.es:
return "programa";
case Human_Lang.ie:
return "programa";
default:
assert(false);
}
case Text.reports:
switch (human_lang)
{
case Human_Lang.en:
return "Reports";
case Human_Lang.eo:
return "Raportoj";
case Human_Lang.es:
return "Informes";
case Human_Lang.ie:
return "Raportes";
default:
assert(false);
}
case Text.second:
switch (human_lang)
{
case Human_Lang.en:
return "second";
case Human_Lang.eo:
return "dua";
case Human_Lang.es:
return "segundo";
case Human_Lang.ie:
return "duesim";
default:
assert(false);
}
case Text.see_also:
switch (human_lang)
{
case Human_Lang.en:
return "See also";
case Human_Lang.eo:
return "Vidu ankaŭ";
case Human_Lang.es:
return "Véase también";
case Human_Lang.ie:
return "Vide anc";
default:
assert(false);
}
case Text.size_report:
switch (human_lang)
{
case Human_Lang.en:
return "Size of the en(( Sine Wave )) executable";
case Human_Lang.eo:
return "Grando de la ekzekutebla dosiero de en(( Sine Wave ))";
case Human_Lang.es:
return "Tamaño del ejecutable de en(( Sine Wave ))";
case Human_Lang.ie:
return "Grandore del executibile de en(( Sine Wave ))";
default:
assert(false);
}
case Text.third:
switch (human_lang)
{
case Human_Lang.en:
return "third";
case Human_Lang.eo:
return "tria";
case Human_Lang.es:
return "tercer";
case Human_Lang.ie:
return "triesim";
default:
assert(false);
}
case Text.tools:
switch (human_lang)
{
case Human_Lang.en:
return "Tools";
case Human_Lang.eo:
return "Iloj";
case Human_Lang.es:
return "Herramientas";
case Human_Lang.ie:
return "Instrumentes";
default:
assert(false);
}
}
}
/// Return the textual form of the given [ISO code language
/// identifier][Human_Lang].
@fn string iso_code(Human_Lang human_lang)
{
switch (human_lang)
{
case
Human_Lang.en,
Human_Lang.eo,
Human_Lang.es,
Human_Lang.ie,
Human_Lang.it,
Human_Lang.pt:
return to!string(human_lang);
default:
assert(false);
}
}
/// Return the filename prefix for the given human lang.
@fn string filename_lang_prefix(Human_Lang human_lang)
{
return iso_code(human_lang) ~ ".";
}
/// Return the filename suffix for the given human lang.
@fn string filename_lang_suffix(Human_Lang human_lang)
{
return "__" ~ iso_code(human_lang);
}
/// Return the page identifier corresponding to the given project and language.
/// The page identifier used by
/// [Fendo](http://programandala.net/en.program.fendo.html) is the page
/// filename without the [Gforth](http://gnu.org/software/gforth)'s ".fs"
/// filename extension, with an optional anchor at the end (including its "#"
/// prefix).
@fn string page_id(string project, Human_Lang human_lang)
{
return
iso_code(human_lang)
~ "."
~ translated(Text.program, human_lang)
~ "."
~ usual_program_id(project);
}
/// Return the page filename corresponding to the given project and language.
@fn string page_filename(string project, Human_Lang human_lang)
{
return page_id(project, human_lang) ~ ".fs";
}
/// Return the item which is before the given one in the given list; if the
/// given item is the first one, return an empty string instead.
@fn string previous(string item, ref string[] list)
{
@var auto previous_items = find!("a < b")(retro(list), item);
return previous_items.length ? previous_items[0] : "";
}
unittest
{
@var string[] list = ["a", "b", "c"];
assert(previous("a", list) == "");
assert(previous("b", list) == "a");
assert(previous("c", list) == "b");
}
/// Return the item which is after the given one in the given list; if the
/// given item is the last one, return an empty string instead.
@fn string next(string item, ref string[] list)
{
@var auto next_items = find!("a > b")(list, item);
return next_items.length ? next_items[0] : "";
}
unittest
{
@var string[] list = ["a", "b", "c"];
assert(next("a", list) == "b");
assert(next("b", list) == "c");
assert(next("c", list) == "");
}
// Markup {{{2
// -----------------------------------------------------------------------------
/// [Fendo](http://programandala.net/en.program.fendo.html) markup to start an
/// unordered list item.
@var immutable string LIST_ITEM = "- ";
/// Return the given text as a heading
/// [Fendo](http://programandala.net/en.program.fendo.html) markup of the given
/// level.
@fn string heading(int level, string text)
{
@var string ruler = replicate("=", level);
return ruler ~ " " ~ text ~ " " ~ ruler ~ "\n";
}
/// Return the given text as
/// [Fendo](http://programandala.net/en.program.fendo.html) code.
@fn string in_code_markup(string text)
{
return "<[ " ~ text ~ " ]>\n";
}
/// Return the given string with
/// [Fendo](http://programandala.net/en.program.fendo.html) image markup.
@fn string image(string s)
{
return "{{ " ~ s ~ " }}\n";
}
/// Return [Fendo](http://programandala.net/en.program.fendo.html) code to
/// import the corresponding file path into the page.
@fn string as_source_code_import_markup(string file_path)
{
return in_code_markup("s\" prog/" ~ file_path ~ "\" source_code");
}
/// Return [Fendo](http://programandala.net/en.program.fendo.html) code to
/// import the corresponding file path into the page.
@fn string as_source_code_block_markup(string code)
{
enum string code_block_markup = "\n####\n";
return code_block_markup ~ code ~ code_block_markup;
}
/// Return the given text with the Fendo
/// [Fendo](http://programandala.net/en.program.fendo.html) paragraph markup.
@fn string paragraph(string text)
{
enum string PARAGRAPH_START = "_ "; // Fendo markup
return PARAGRAPH_START ~ text ~ "\n";
}
/// Return [Fendo](http://programandala.net/en.program.fendo.html) markup
/// required to include the contents of the given filename into the page.
@fn string include_file_markup
(
string filename,
string filename_extension, // with initial dot
string project_dir // dir containing the <src> subdir
)
{
@var string result;
// make fendo use a neovim's specific syntax instead the default one
// associated to some filename extensions
switch(filename_extension)
{
case ".fs":
// fsharp instead of gforth
result ~= in_code_markup("s\" fsharp\" programming_language!");
break;
case ".free.bas":
// freebasic instead of generic basic
result ~= in_code_markup("s\" freebasic\" programming_language!");
break;
default:
break;
}
return
result
~ as_source_code_import_markup
(
build_path
(
project_dir,
"src",
base_name(filename)
)
);
}
/// Return the [Fendo](http://programandala.net/en.program.fendo.html) markup
/// to create a link to the given target page using the given link text.
@fn string link(string target, string text = "")
{
enum FENDO_NEW_LINK_FORMAT = false;
if (text.length)
{
return
FENDO_NEW_LINK_FORMAT
? format("[[ \"%s\" \"%s\" ]]", target, text)
: format("[[ %s | %s ]]", target, text);
}
else
{
return
FENDO_NEW_LINK_FORMAT
? format("[[ \"%s\" ]]", target)
: format("[[ %s ]]", target);
}
}
/// Return the [Fendo](http://programandala.net/en.program.fendo.html) markup
/// to create a link to the "Sine Wave" executables report with the link text
/// in the given language.
@fn string size_report_link(Human_Lang human_lang)
{
return
link
(
page_id("basics_off#sine_wave", human_lang),
translated(Text.size_report, human_lang)
);
}
/// Return the [Fendo](http://programandala.net/en.program.fendo.html) markup
/// to create a link to the "Sine Wave" program page with the link text in the
/// given language.
@fn string sine_wave_link(Human_Lang human_lang)
{
@var string program_id = "sine_wave";
return
link
(
page_id(program_id, human_lang),
program_title(program_id, human_lang)
);
}
/// Return the given string as a proper anchor ID.
@fn string proper_id(string id)
in
{
assert(id.length);
}
do
{
if (is_digit(id[0]))
{
id = '_' ~ id;
}
if (id[$ - 1] == '#')
{
id = id[0 .. $ - 1] ~ "sharp";
}
return to_lower(id);
}
/// Return [Fendo](http://programandala.net/en.program.fendo.html) markup
/// required to create an anchor with the given ID.
@fn string anchor(string id)
{
return in_code_markup("s\" " ~ proper_id(id) ~ "\" id=!");
}
// Pages {{{1
// =============================================================================
// Data {{{2
// -----------------------------------------------------------------------------
/// Identifiers of page types.
enum Page_Type { metaproject, lang_project, program_project }
/// Program version data.
struct Program_Version
{
@var string programming_lang_id;
@var string source_file;
@var string filename_extension;
@var string project_dir;
}
/// Return an array of [versions][Program_Version] of the given program
/// project.
Program_Version[] program_project_versions(string project)
{
@var Program_Version[] list;
foreach (string programming_lang_id; programming_lang_ids)
{
@var string project_dir = "basics_of_" ~ programming_lang_id;
@var string source_dir = build_path(REPOS_DIR, project_dir, "src");
@var string filename_extension = filename_extension(programming_lang_id);
@var string source_file_wildcard = project ~ filename_extension;
foreach
(
string source_file;
dir_entries(source_dir, source_file_wildcard, Span_Mode.shallow)
)
{
if (is_finished(source_file))
{
list ~= Program_Version
(
programming_lang_id,
source_file,
filename_extension,
project_dir
);
}
}
}
return list;
}
// Pages metadata {{{2
// -----------------------------------------------------------------------------
/// Struct to hold the dates of a page.
struct Page_Date
{
// Fendo metadata fields:
@var string start; /// When the page was started.
@var string creation; /// When the page was created, i.e. finished.
@var string modification; /// When the page was modified.
/// When the page file was modified. Added as a comment. This is useful
/// in order to force the rebuilding of a page in case its textual contents
/// have not changed but its embedded contents, e.g. a source code file,
/// have been updated.
@var string last_modified;
}
/// Return the dates of page.
@fn Page_Date page_date(string filename)
{
enum string FIRST_START = "2025-06-01";
enum string FIRST_CREATION = "2025-08-19";
enum string LAST_MODIFIED = "20260208T1302+0100";
enum string LAST_PROJECT_ADDITION = "2026-02-07";
switch (filename)
{
// "basics off" metaproject
case "en.program.basics_off.fs":
case "eo.programo.basics_off.fs":
case "es.programa.basics_off.fs":
case "ie.programa.basics_off.fs":
return Page_Date(FIRST_START, FIRST_CREATION, "2026-02-15", "20260215T2003+0100");
// "basics of…" projects
case "en.program.basics_of_8th.fs":
case "eo.programo.basics_of_8th.fs":
case "es.programa.basics_of_8th.fs":
case "ie.programa.basics_of_8th.fs":
case "en.program.basics_of_ada.fs":
case "eo.programo.basics_of_ada.fs":
case "es.programa.basics_of_ada.fs":
case "ie.programa.basics_of_ada.fs":
case "en.program.basics_of_arturo.fs":
case "eo.programo.basics_of_arturo.fs":
case "es.programa.basics_of_arturo.fs":
case "ie.programa.basics_of_arturo.fs":
case "en.program.basics_of_c-sharp.fs":
case "eo.programo.basics_of_c-sharp.fs":
case "es.programa.basics_of_c-sharp.fs":
case "ie.programa.basics_of_c-sharp.fs":
case "en.program.basics_of_c3.fs":
case "eo.programo.basics_of_c3.fs":
case "es.programa.basics_of_c3.fs":
case "ie.programa.basics_of_c3.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_chapel.fs":
case "eo.programo.basics_of_chapel.fs":
case "es.programa.basics_of_chapel.fs":
case "ie.programa.basics_of_chapel.fs":
return Page_Date(FIRST_START, FIRST_CREATION, "2026-02-09", "20260209T1324+0100");
case "en.program.basics_of_clojure.fs":
case "eo.programo.basics_of_clojure.fs":
case "es.programa.basics_of_clojure.fs":
case "ie.programa.basics_of_clojure.fs":
case "en.program.basics_of_crystal.fs":
case "eo.programo.basics_of_crystal.fs":
case "es.programa.basics_of_crystal.fs":
case "ie.programa.basics_of_crystal.fs":
case "en.program.basics_of_d.fs":
case "eo.programo.basics_of_d.fs":
case "es.programa.basics_of_d.fs":
case "ie.programa.basics_of_d.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_elixir.fs":
case "eo.programo.basics_of_elixir.fs":
case "es.programa.basics_of_elixir.fs":
case "ie.programa.basics_of_elixir.fs":
return Page_Date("2026-01-23", "2026-01-23", LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_f-sharp.fs":
case "eo.programo.basics_of_f-sharp.fs":
case "es.programa.basics_of_f-sharp.fs":
case "ie.programa.basics_of_f-sharp.fs":
case "en.program.basics_of_factor.fs":
case "eo.programo.basics_of_factor.fs":
case "es.programa.basics_of_factor.fs":
case "ie.programa.basics_of_factor.fs":
case "en.program.basics_of_freebasic.fs":
case "eo.programo.basics_of_freebasic.fs":
case "es.programa.basics_of_freebasic.fs":
case "ie.programa.basics_of_freebasic.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_gleam.fs":
case "eo.programo.basics_of_gleam.fs":
case "es.programa.basics_of_gleam.fs":
case "ie.programa.basics_of_gleam.fs":
return Page_Date("2026-01-23", "2026-01-23", LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_go.fs":
case "eo.programo.basics_of_go.fs":
case "es.programa.basics_of_go.fs":
case "ie.programa.basics_of_go.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_hare.fs":
case "eo.programo.basics_of_hare.fs":
case "es.programa.basics_of_hare.fs":
case "ie.programa.basics_of_hare.fs":
return Page_Date(FIRST_START, FIRST_CREATION, "2026-02-13", "20260213T1646+0100");
case "en.program.basics_of_haxe.fs":
case "eo.programo.basics_of_haxe.fs":
case "es.programa.basics_of_haxe.fs":
case "ie.programa.basics_of_haxe.fs":
case "en.program.basics_of_icon.fs":
case "eo.programo.basics_of_icon.fs":
case "es.programa.basics_of_icon.fs":
case "ie.programa.basics_of_icon.fs":
case "en.program.basics_of_io.fs":
case "eo.programo.basics_of_io.fs":
case "es.programa.basics_of_io.fs":
case "ie.programa.basics_of_io.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_janet.fs":
case "eo.programo.basics_of_janet.fs":
case "es.programa.basics_of_janet.fs":
case "ie.programa.basics_of_janet.fs":
return Page_Date("2025-12-25", "2025-12-25", "2026-02-15", "20260215T2003+0100");
case "en.program.basics_of_julia.fs":
case "eo.programo.basics_of_julia.fs":
case "es.programa.basics_of_julia.fs":
case "ie.programa.basics_of_julia.fs":
case "en.program.basics_of_kotlin.fs":
case "eo.programo.basics_of_kotlin.fs":
case "es.programa.basics_of_kotlin.fs":
case "ie.programa.basics_of_kotlin.fs":
case "en.program.basics_of_lobster.fs":
case "eo.programo.basics_of_lobster.fs":
case "es.programa.basics_of_lobster.fs":
case "ie.programa.basics_of_lobster.fs":
case "en.program.basics_of_lua.fs":
case "eo.programo.basics_of_lua.fs":
case "es.programa.basics_of_lua.fs":
case "ie.programa.basics_of_lua.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_nature.fs":
case "eo.programo.basics_of_nature.fs":
case "es.programa.basics_of_nature.fs":
case "ie.programa.basics_of_nature.fs":
return Page_Date("2025-12-25", "2025-12-25", LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_neat.fs":
case "eo.programo.basics_of_neat.fs":
case "es.programa.basics_of_neat.fs":
case "ie.programa.basics_of_neat.fs":
return Page_Date("2025-12-17", "2025-12-17", LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_neko.fs":
case "eo.programo.basics_of_neko.fs":
case "es.programa.basics_of_neko.fs":
case "ie.programa.basics_of_neko.fs":
case "en.program.basics_of_nelua.fs":
case "eo.programo.basics_of_nelua.fs":
case "es.programa.basics_of_nelua.fs":
case "ie.programa.basics_of_nelua.fs":
case "en.program.basics_of_nim.fs":
case "eo.programo.basics_of_nim.fs":
case "es.programa.basics_of_nim.fs":
case "ie.programa.basics_of_nim.fs":
case "en.program.basics_of_nit.fs":
case "eo.programo.basics_of_nit.fs":
case "es.programa.basics_of_nit.fs":
case "ie.programa.basics_of_nit.fs":
case "en.program.basics_of_oberon-07.fs":
case "eo.programo.basics_of_oberon-07.fs":
case "es.programa.basics_of_oberon-07.fs":
case "ie.programa.basics_of_oberon-07.fs":
case "en.program.basics_of_ocaml.fs":
case "eo.programo.basics_of_ocaml.fs":
case "es.programa.basics_of_ocaml.fs":
case "ie.programa.basics_of_ocaml.fs":
case "en.program.basics_of_odin.fs":
case "eo.programo.basics_of_odin.fs":
case "es.programa.basics_of_odin.fs":
case "ie.programa.basics_of_odin.fs":
case "en.program.basics_of_pike.fs":
case "eo.programo.basics_of_pike.fs":
case "es.programa.basics_of_pike.fs":
case "ie.programa.basics_of_pike.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_pony.fs":
case "eo.programo.basics_of_pony.fs":
case "es.programa.basics_of_pony.fs":
case "ie.programa.basics_of_pony.fs":
return Page_Date("2026-02-07", "2026-02-07", LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_python.fs":
case "eo.programo.basics_of_python.fs":
case "es.programa.basics_of_python.fs":
case "ie.programa.basics_of_python.fs":
case "en.program.basics_of_racket.fs":
case "eo.programo.basics_of_racket.fs":
case "es.programa.basics_of_racket.fs":
case "ie.programa.basics_of_racket.fs":
case "en.program.basics_of_raku.fs":
case "eo.programo.basics_of_raku.fs":
case "es.programa.basics_of_raku.fs":
case "ie.programa.basics_of_raku.fs":
case "en.program.basics_of_retro.fs":
case "eo.programo.basics_of_retro.fs":
case "es.programa.basics_of_retro.fs":
case "ie.programa.basics_of_retro.fs":
case "en.program.basics_of_rexx.fs":
case "eo.programo.basics_of_rexx.fs":
case "es.programa.basics_of_rexx.fs":
case "ie.programa.basics_of_rexx.fs":
case "en.program.basics_of_ring.fs":
case "eo.programo.basics_of_ring.fs":
case "es.programa.basics_of_ring.fs":
case "ie.programa.basics_of_ring.fs":
case "en.program.basics_of_rust.fs":
case "eo.programo.basics_of_rust.fs":
case "es.programa.basics_of_rust.fs":
case "ie.programa.basics_of_rust.fs":
case "en.program.basics_of_scala.fs":
case "eo.programo.basics_of_scala.fs":
case "es.programa.basics_of_scala.fs":
case "ie.programa.basics_of_scala.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_scheme.fs":
case "eo.programo.basics_of_scheme.fs":
case "es.programa.basics_of_scheme.fs":
case "ie.programa.basics_of_scheme.fs":
return Page_Date("2025-12-01", "2025-12-01", LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_styx.fs":
case "eo.programo.basics_of_styx.fs":
case "es.programa.basics_of_styx.fs":
case "ie.programa.basics_of_styx.fs":
return Page_Date("2025-12-17", "2025-12-17", LAST_PROJECT_ADDITION, LAST_MODIFIED);
case "en.program.basics_of_swift.fs":
case "eo.programo.basics_of_swift.fs":
case "es.programa.basics_of_swift.fs":
case "ie.programa.basics_of_swift.fs":
case "en.program.basics_of_v.fs":
case "eo.programo.basics_of_v.fs":
case "es.programa.basics_of_v.fs":
case "ie.programa.basics_of_v.fs":
case "en.program.basics_of_vala.fs":
case "eo.programo.basics_of_vala.fs":
case "es.programa.basics_of_vala.fs":
case "ie.programa.basics_of_vala.fs":
case "en.program.basics_of_zig.fs":
case "eo.programo.basics_of_zig.fs":
case "es.programa.basics_of_zig.fs":
case "ie.programa.basics_of_zig.fs":
return Page_Date(FIRST_START, FIRST_CREATION, LAST_PROJECT_ADDITION, LAST_MODIFIED);
// programs
case "en.program.3d_plot.fs":
case "eo.programo.3d_plot.fs":
case "es.programa.3d_plot.fs":
case "ie.programa.3d_plot.fs":
case "en.program.bagels.fs":
case "eo.programo.bagels.fs":
case "es.programa.bagels.fs":
case "ie.programa.bagels.fs":
case "en.program.bug.fs":
case "eo.programo.bug.fs":
case "es.programa.bug.fs":
case "ie.programa.bug.fs":
case "en.program.bunny.fs":
case "eo.programo.bunny.fs":
case "es.programa.bunny.fs":
case "ie.programa.bunny.fs":
case "en.program.chase.fs":
case "eo.programo.chase.fs":
case "es.programa.chase.fs":
case "ie.programa.chase.fs":
case "en.program.diamond.fs":
case "eo.programo.diamond.fs":
case "es.programa.diamond.fs":
case "ie.programa.diamond.fs":
case "en.program.hammurabi.fs":
case "eo.programo.hammurabi.fs":
case "es.programa.hammurabi.fs":
case "ie.programa.hammurabi.fs":
case "en.program.high_noon.fs":
case "eo.programo.high_noon.fs":
case "es.programa.high_noon.fs":
case "ie.programa.high_noon.fs":
case "en.program.math.fs":
case "eo.programo.math.fs":
case "es.programa.math.fs":
case "ie.programa.math.fs":
case "en.program.mugwump.fs":
case "eo.programo.mugwump.fs":
case "es.programa.mugwump.fs":
case "ie.programa.mugwump.fs":
case "en.program.name.fs":
case "eo.programo.name.fs":
case "es.programa.name.fs":
case "ie.programa.name.fs":
case "en.program.poetry.fs":
case "eo.programo.poetry.fs":
case "es.programa.poetry.fs":
case "ie.programa.poetry.fs":
case "en.program.russian_roulette.fs":
case "eo.programo.russian_roulette.fs":
case "es.programa.russian_roulette.fs":
case "ie.programa.russian_roulette.fs":
case "en.program.seance.fs":
case "eo.programo.seance.fs":
case "es.programa.seance.fs":
case "ie.programa.seance.fs":
return Page_Date(FIRST_START, FIRST_CREATION, "2026-02-13", "20260213T1646+0100");
case "en.program.sine_wave.fs":
case "eo.programo.sine_wave.fs":
case "es.programa.sine_wave.fs":
case "ie.programa.sine_wave.fs":
return Page_Date(FIRST_START, FIRST_CREATION, "2026-02-15", "20260215T2004+0100");
case "en.program.slots.fs":
case "eo.programo.slots.fs":
case "es.programa.slots.fs":
case "ie.programa.slots.fs":
case "en.program.stars.fs":
case "eo.programo.stars.fs":
case "es.programa.stars.fs":
case "ie.programa.stars.fs":
case "en.program.strings.fs":
case "eo.programo.strings.fs":
case "es.programa.strings.fs":
case "ie.programa.strings.fs":
case "en.program.xchange.fs":
case "eo.programo.xchange.fs":
case "es.programa.xchange.fs":
case "ie.programa.xchange.fs":
return Page_Date(FIRST_START, FIRST_CREATION, "2026-02-13", "20260213T1646+0100");
case "en.program.z-end.fs":
case "eo.programo.z-end.fs":
case "es.programa.z-end.fs":
case "ie.programa.z-end.fs":
return Page_Date("2025-12-19", "2025-12-19", "2026-02-09", "20260209T1324+0100");
default:
assert(false);
}
}
/// Write the [Fendo](http://programandala.net/en.program.fendo.html) metadata
/// fields of the given project, of the give type, in the given language and to
/// the given file.
@fn void write_metadata
(
File file,
string project,
Human_Lang human_lang,
Page_Type type,
Page_Date page_date,
)
{
@var string programming_lang_id = programming_lang_id_of_project(project);
@var string programming_lang_name = programming_lang_name(programming_lang_id);
@var string page_title = page_title(project, human_lang);
@var string root =
filename_lang_prefix(human_lang)
~ translated(Text.program, human_lang);
file.writeln("\ndata{\n");
file.writeln("edit_summary ", translated(Text.new_page, human_lang), ".");
file.writeln("title ", page_title);
// `description` field
file.write("description ");
final switch(type)
{
case Page_Type.metaproject:
switch(human_lang)
{
case Human_Lang.en:
file.writeln("Metaproject about the \"Basics of…\" projects.");
break;
case Human_Lang.eo:
file.writeln("Metaprojekto pri la projektoj en(( «Basics of…» )) .");
break;
case Human_Lang.es:
file.writeln("Metaproyecto sobre los proyectos en(( «Basics of…» )) .");
break;
case Human_Lang.ie:
file.writeln("Metaprojecte pri li projectes en(( «Basics of…» )) .");
break;
default:
assert(false);
}
break;
case Page_Type.lang_project:
switch(human_lang)
{
case Human_Lang.en:
file.write("Conversion of old BASIC programs to ");
break;
case Human_Lang.eo:
file.write("Konverto de malnovaj BASIC-programoj al ");
break;
case Human_Lang.es:
file.write("Conversión de antiguos programas de BASIC a ");
break;
case Human_Lang.ie:
file.write("Conversion de old BASIC-programas a ");
break;
default:
assert(false);
}
file.write(programming_lang_name, " ");
switch(human_lang)
{
case Human_Lang.en:
file.writeln("in order to learn the basics of this language.");
break;
case Human_Lang.eo:
file.writeln("por lerni la fundamentojn de ĉi-tiu lingvo.");
break;
case Human_Lang.es:
file.writeln("para aprender los rudimentos de este lenguaje.");
break;
case Human_Lang.ie:
file.writeln("por aprender lu elementari de ti-ci lingue.");
break;
default:
assert(false);
}
break;
case Page_Type.program_project:
switch(human_lang)
{
case Human_Lang.en:
file.write("Conversion of ");
break;
case Human_Lang.eo:
file.write("Konvertado de ");
break;
case Human_Lang.es:
file.write("Conversión de ");
break;
case Human_Lang.ie:
file.write("Conversion de ");
break;
default:
assert(false);
}
file.write(page_title);
switch(human_lang)
{
case Human_Lang.en:
file.writeln(" to several programming languages.");
break;
case Human_Lang.eo:
file.writeln(" al pluri program-lingvoj.");
break;
case Human_Lang.es:
file.writeln(" a varios lenguajes de programación.");
break;
case Human_Lang.ie:
file.writeln(" a pluri lingues de programation.");
break;
default:
assert(false);
}
break;
}
file.writeln("started ", page_date.start);
file.writeln("created ", page_date.creation);
file.writeln("modified ", page_date.modification);
file.writeln("upper_page ", root);
final switch(type)
{
case Page_Type.metaproject:
file.writeln("previous_page [calculated]");
file.writeln("next_page [calculated]");
break;
case Page_Type.lang_project:
// NB the contents of these fields must be manually adapted.
@var string previous = previous(programming_lang_id, programming_lang_ids);
file.writeln
(
"previous_page",
previous.length ? format(" %s.basics_of_%s", root, previous) : ""
);
@var string next = next(programming_lang_id, programming_lang_ids);
file.writeln
(
"next_page",
next.length ? format(" %s.basics_of_%s", root, next) : ""
);
break;
case Page_Type.program_project:
// NB the contents of these fields must be manually adapted.
@var string previous = previous(project, program_ids);
file.writeln
(
"previous_page",
previous.length ? format(" %s.%s", root, previous) : ""
);
@var string next = next(project, program_ids);
file.writeln("next_page", (next.length ? format(" %s.%s", root, next) : ""));
break;
}
file.writeln("first_page ", root, ".**first**");
file.writeln("last_page ", root, ".**last**");
file.writeln("language ", human_lang);
// `alternate` fields
foreach (Human_Lang lang; human_langs)
{
if (lang != human_lang)
{
file.writefln
(
"alternate.%1$s %1$s.%s.%s",
iso_code(lang),
translated(Text.program, lang),
project
);
}
}
// `related` field
file.write("related");
final switch(type)
{
case Page_Type.metaproject:
foreach (programming_lang_id_; programming_lang_ids)
{
file.write(" ", page_id("basics_of_" ~ programming_lang_id_, human_lang));
}
file.writeln();
break;
case Page_Type.lang_project:
file.write(" ");
file.write(page_id("basics_off", human_lang));
foreach (programming_lang_id_; programming_lang_ids)
{
if (programming_lang_id_ != programming_lang_id)
{
file.write(" ", page_id("basics_of_" ~ programming_lang_id_, human_lang));
}
}
file.writeln();
break;
case Page_Type.program_project:
file.write(" ");
file.write(page_id("basics_off", human_lang));
if (project == "sine_wave")
{
file.write(" ", page_id("basics_off#sine_wave", human_lang));
}
file.writeln();
break;
}
// `external_related` field
final switch(type)
{
case Page_Type.metaproject:
file.write("external_related");
foreach (programming_lang_id_; programming_lang_ids)
{
file.write(" " ~ programming_lang_id_ ~ "_ext" );
}
file.writeln();
break;
case Page_Type.lang_project:
file.writeln("external_related " ~ programming_lang_id ~ "_ext" );
break;
case Page_Type.program_project:
file.write("external_related");
foreach (program_version; program_project_versions(project))
{
file.write(" " ~ program_version.programming_lang_id ~ "_ext");
}
file.writeln();
break;
}
// `tags` field
final switch(type)
{
case Page_Type.metaproject:
file.write("tags");
foreach (programming_lang_id_; programming_lang_ids)
{
file.write(" ", programming_lang_id_);
}
file.writeln();
break;
case Page_Type.lang_project:
file.writeln("tags ", programming_lang_id_of_project(project));
break;
case Page_Type.program_project:
file.write("tags");
foreach (program_version; program_project_versions(project))
{
file.write(" ", program_version.programming_lang_id);
}
break;
}
file.writeln("\n}data");
}
// "Basics off" metaproject pages {{{2
// -----------------------------------------------------------------------------
/// Return the description of the conversions tool in the given language.
@fn string description_of_conversions_tool(Human_Lang human_lang)
{
switch (human_lang)
{
case Human_Lang.en:
return
"This program, written in [[ fish ]] ,\n"
~ "creates two [[ asciidoc ]] documents\n"
~ "containing tables which show the number of\n"
~ "conversions per programming language and which program\n"
~ "has been converted to which.";
case Human_Lang.eo:
return
"Ĉi-tiu programo, verkita en [[ fish ]] ,\n"
~ "kreas du [[ asciidoc | AsciiDoc-dokumentojn ]]\n"
~ "enhavantajn tabelojn kiuj montras\n"
~ "la nombron de programoj konvertitaj al ĉiu\n"
~ "program-lingvo kaj kiu programo estas konvertitaj en kiu.";
case Human_Lang.es:
return
"Este programa, escrito en [[ fish ]] ,\n"
~ "crea dos documentos en [[ asciidoc ]]\n"
~ "con tablas que muestran el número de\n"
~ "programas convertidos a cada lenguaje de programación y\n"
~ "qué programa ha sido convertido a cuál.";
case Human_Lang.ie:
return
"Ti-ci programa, scrit in [[ fish ]] ,\n"
~ "crea du documentes en [[ asciidoc ]]\n"
~ "con tabelles queles monstra li númere de\n"
~ "programas convertet a chascun lingue de programation e\n"
~ "quel programa ha esset convertet a quel.";
default:
assert(false);
}
}
/// Return the description of the activity tool in the given language.
@fn string description_of_activity_tool(Human_Lang human_lang)
{
switch (human_lang)
{
case Human_Lang.en:
return
"This program, written in [[ julia ]] , creates several\n"
~ "CSV-format data files containing the activity\n"
~ "of the project repositories.";
case Human_Lang.eo:
return
"Ĉi-tiu programo, verkita en [[ julia ]] , kreas plurajn\n"
~ "CSV-formatajn daten-dosierojn enhavantajn la aktivecon\n"
~ "de la projektaj deponejoj.";
case Human_Lang.es:
return
"Este programa, escrito en [[ julia ]] , crea varios\n"
~ "ficheros de datos en formato CSV que contienen la\n"
~ "actividad de los repositorios de los proyectos.";
case Human_Lang.ie:
return
"Ti-ci programa, scrit in [[ julia ]] , crea pluri\n"
~ "data-files in CSV-formate queles contene li activitá\n"
~ "del depositorias del projectes.";
default:
assert(false);
}
}
/// Return the description of the pages tool in the given language.
@fn string description_of_pages_tool(Human_Lang human_lang)
{
@var immutable ulong programming_languages = programming_lang_ids.length;
@var immutable ulong human_languages = human_langs.length;
@var immutable ulong programs = program_ids.length;
@var immutable ulong pages =
(1 + programming_languages + programs) * human_languages;
@var immutable string programming_languages_ = to!string(programming_languages);
@var immutable string human_languages_ = to!string(human_languages);
@var immutable string programs_ = to!string(programs);
@var immutable string pages_ = to!string(pages);
switch (human_lang)
{
case Human_Lang.en:
return
"This program, written in [[ d ]] ,\n"
~ "creates the [[ fendo | Fendo-format ]] sources\n"
~ "of the pages of [[ en | programandala.net ]] about the\n"
~ " // Basics off // metaproject, the\n"
~ programming_languages_
~ " started \"Basics of…\" projects and their\n"
~ programs_ ~ " programs.\n"
~ "Everything in " ~ human_languages_ ~ " languages;\n"
~ "therefore, a total of " ~ pages_ ~ " pages.";
case Human_Lang.eo:
return
"Ĉi-tiu programo, verkita en [[ d ]] ,\n"
~ "kreas la [[ fendo | Fendo-formatajn ]] fontojn\n"
~ "de la paĝoj de [[ eo | programandala.net ]] pri la\n"
~ "metaprojekto // en(( Basics off )) // , la\n"
~ programming_languages_
~ " komencitaj projektoj « en(( Basic of… )) » kaj\n"
~ "iliaj " ~ programs_ ~ " programoj.\n"
~ "Ĉio en " ~ human_languages_ ~ " lingvoj;\n"
~ "do, totale " ~ pages_ ~ " paĝojn.";
case Human_Lang.es:
return
"Este programa, escrito en [[ d ]] ,\n"
~ "crea las fuentes, en formato de [[ fendo ]] ,\n"
~ "de las páginas de [[ es | programandala.net ]] sobre el\n"
~ "metaproyecto « en(( Basics off )) » , los\n"
~ programming_languages_
~ " proyectos « en(( Basic of… )) » iniciados y\n"
~ "sus " ~ programs_ ~ " programas.\n"
~ "Todo ello en " ~ human_languages_ ~ " lenguas;\n"
~ "por tanto, un total de " ~ pages_ ~ " páginas.";
case Human_Lang.ie:
return
"Ti-ci programa, scrit in [[ d ]] ,\n"
~ "crea li fontes, in formate de [[ fendo ]] ,\n"
~ "del págines de [[ ie | programandala.net ]] pri li\n"
~ "metaprojecte // en(( Basics off )) // , li\n"
~ programming_languages_
~ " projectes « en(( Basic of… )) » iniciat e\n"
~ "lor " ~ programs_ ~ " programas.\n"
~ "Omno in " ~ human_languages_ ~ " lingues;\n"
~ "dunc, un totale de " ~ pages_ ~ " págines.";
default:
assert(false);
}
}
/// Return the description of the gnuplot files in the given language.
@fn string description_of_gnuplot_files(Human_Lang human_lang)
{
switch (human_lang)
{
case Human_Lang.en:
return
"These [[ gnuplot ]] configuration files make it possible\n"
~ "to convert the CSV data files to graphics.";
case Human_Lang.eo:
return
"Ĉi-tiuj dosieroj de konfiguro de [[ gnuplot ]] ebligas\n"
~ "konverti la CSV-formatajn daten-dosierojn en grafikaĵojn.";
case Human_Lang.es:
return
"Estos ficheros de configuración de [[ gnuplot ]]\n"
~ "posibilitan convertir los ficheros de datos\n"
~ "de formato CSV en gráficos.";
case Human_Lang.ie:
return
"Ti-ci files de configuration de [[ gnuplot ]] possibilisa\n"
~ "converter li data-files de CSV-formate in grafics.";
default:
assert(false);
}
}
/// Return the description of the "basics off" metaproject.
@fn string metaproject_description(Human_Lang human_lang)
{
@var immutable ulong projects = project_dirs.length;
@var immutable ulong programming_languages = programming_lang_ids.length;
@var immutable string projects_ = to!string(projects);
@var immutable string programming_languages_ = to!string(programming_languages);
switch (human_lang)
{
case Human_Lang.en:
return
"// Basics off // is a metaproject about the "
~ projects_
~ " \"Basics of…\" projects"
~ " (" ~ programming_languages_ ~ " started)."
~ " It consists of three programs that"
~ " use the contents of the repositories in order to "
~ link("#conversions_tool", "count the conversions (in fish)")
~ " , "
~ link("#activity_tool", "extract the activity data (in Julia)")
~ " , and "
~ link("#pages_tool", "build the webpages (in D)")
~ " ; also several "
~ link("#gnuplot_files", "gnuplot files")
~ " that create the graphics, and a "
~ link("#makefile", "Makefile")
~ " to build everything. The results are shown below: the "
~ link("#conversions", "conversion reports")
~ " , the "
~ link("#graphics", "activity graphics")
~ " and a hand-made "
~ link("#sine_wave", "report on the size of one of the executables")
~ " ."
;
case Human_Lang.eo:
return
"en(( // Basics off // )) estas metaprojekto pri la "
~ projects_
~ " projektoj « en(( // Basics of… // )) »"
~ " (" ~ programming_languages_ ~ " komencitaj)."
~ " Ĝi konsistas el tri programoj kiuj"
~ " uzas la enhavon de la deponejoj por "
~ link("#conversions_tool", "kalkuli la konvertojn (en fish)")
~ " , "
~ link("#activity_tool", "elpreni la datenojn pri aktiveco (en Julia)")
~ " , kaj "
~ link("#pages_tool", "konstrui la ret-paĝojn (en D)")
~ " ; ankaŭ el pluraj "
~ link("#gnuplot_files", "dosieroj de gnuplot")
~ " kiuj kreas la grafikaĵojn, kaj "
~ link("#makefile", "Makefile")
~ " por konstrui ĉion. La rezultoj estas sube montritaj: la "
~ link("#conversions", "raportoj pri la konvertoj")
~ " , la "
~ link("#graphics", "grafikaĵoj pri aktiveco")
~ " kaj man-farita "
~ link("#sine_wave", "raporto pri la grando de ekzekutebla dosiero")
~ " ."
;
case Human_Lang.es:
return
"en(( // Basics off // )) es un metaproyecto sobre los "
~ projects_
~ " proyectos « en(( // Basics of… // )) »"
~ " (" ~ programming_languages_ ~ " comenzados)."
~ " Consta de tres programas que"
~ " usan el contenido de los repositorios para "
~ link("#conversions_tool", "contar las conversiones (en fish)")
~ " , "
~ link("#activity_tool", "extraer los datos de actividad (en Julia)")
~ " , y "
~ link("#pages_tool", "construir las páginas web (en D)")
~ " ; así como de varios "
~ link("#gnuplot_files", "ficheros de gnuplot")
~ " que crean los gráficos, y un "
~ link("#makefile", "Makefile")
~ " para construir todo. Los resultados se muestran a continuación: los "
~ link("#conversions", "informes sobre las conversiones")
~ " , los "
~ link("#graphics", "gráficos de actividad")
~ " y un "
~ link("#sine_wave", "informe sobre el tamaño de un ejecutable")
~ " , elaborado a mano"
~ " ."
;
case Human_Lang.ie:
return
"en(( // Basics off // )) es un metaprojecte pri li "
~ projects_
~ " projectes « en(( // Basics of… // )) »"
~ " (" ~ programming_languages_ ~ " comensat)."
~ " It consiste in tri programas queles"
~ " usa li contenete del depositorias por "
~ link("#conversions_tool", "contar li conversiones (in fish)")
~ " , "
~ link("#activity_tool", "extracter li data de activitá (in Julia)")
~ " , e "
~ link("#pages_tool", "constructer li págines retal (in D)")
~ " ; anc pluri "
~ link("#gnuplot_files", "gnuplot-files")
~ " queles crea li grafics e un "
~ link("#makefile", "Makefile")
~ " por constructer omno. Li resultates es monstrat in infra: li "
~ link("#conversions", "raportes pri li conversiones")
~ " , li "
~ link("#graphics", "grafics de activitá")
~ " e un "
~ link("#sine_wave", "raporte pri li grandore de un executibile")
~ " , manualmen fat"
~ " ."
;
default:
assert(false);
}
}
/// Write to the given file the contents of the metaproject [page
/// type][Page_Type] in the given language.
@fn void write_contents_of_metaproject(File file, Human_Lang human_lang)
{
enum string PROG_TARGET = "prog/basics_off/target/";
enum string SOURCE = "basics_off/src/";
enum string PROG_SOURCE = "prog/" ~ SOURCE;
file.writeln(paragraph(metaproject_description(human_lang)));
file.writeln(anchor("conversions"));
// NB The following fake `<a>` HTML tag is added in order to force Fendo to
// execute it and apply the "conversions" anchor to it; otherwise the
// anchor will have no effect in the final code because the first HTML tag
// after it is not created directly by a Fendo markup but by the HTML code
// Fendo inserts out of a converted AsciiDoc document:
file.writeln("<a>");
file.writeln("</a>");
file.writeln
(
in_code_markup
(
"s\" --attribute "
~ to!string(human_lang)
~ "\" asciidoctor_options!"
~ " s\" "
~ PROG_TARGET
~ "conversions__language_ranking.adoc\" include_asciidoctor"
~ " s\" \" asciidoctor_options!"
)
);
file.writeln
(
in_code_markup
(
"s\" --attribute "
~ to!string(human_lang)
~ "\" asciidoctor_options!"
~ " s\" "
~ PROG_TARGET
~ "conversions__programs_and_languages.adoc\" include_asciidoctor"
~ " s\" \" asciidoctor_options!"
)
);
file.writeln(anchor("graphics"));
file.writeln(heading(2, translated(Text.conversions_plot, human_lang)));
file.writeln
(
image
(
PROG_TARGET
~ "activity__conversions_plot_rowstacked"
~ filename_lang_suffix(human_lang)
~ ".png"
)
);
file.writeln(heading(2, translated(Text.commits_plot, human_lang)));
file.writeln
(
image
(
PROG_TARGET
~ "activity__commits_plot_rowstacked"
~ filename_lang_suffix(human_lang)
~ ".png"
)
);
file.writeln(anchor("sine_wave"));
file.writeln(heading(2, translated(Text.size_report, human_lang)));
switch(human_lang)
{
case Human_Lang.en:
file.writeln
(
paragraph
(
sine_wave_link(human_lang)
~ " is used to compare the sizes of the executables,"
~ " native or handled,"
~ " created by the programming languages of the project."
~ " The following table contains the results"
~ " in increasing order."
)
);
break;
case Human_Lang.eo:
file.writeln
(
paragraph
(
sine_wave_link(human_lang)
~ " estas uzita por kompari la grandojn de la ekzekuteblaj dosieroj,"
~ " dosieroj, nativaj aŭ traktataj,"
~ " kreitaj de la program-lingvoj de la projekto."
~ " La suba tabelo enhavas la rezultojn"
~ " en kreskanta ordo."
)
);
break;
case Human_Lang.es:
file.writeln
(
paragraph
(
sine_wave_link(human_lang)
~ " se usa para comparar los tamaños de los ejecutables,"
~ " nativos o gestionados,"
~ " creados por los lenguajes de programación del proyecto."
~ " La siguiente tabla contiene los resultados"
~ " en orden creciente."
)
);
break;
case Human_Lang.ie:
file.writeln
(
paragraph
(
sine_wave_link(human_lang)
~ " es usat por comparar li grandores del executibiles,"
~ " natal o tractat,"
~ " creat per li lingues de programation del projecte."
~ " Li sequent tabelle contene li resultates"
~ " in órdine crescent."
)
);
break;
default:
assert(false);
}
file.writeln
(
in_code_markup
(
"s\" --attribute "
~ to!string(human_lang)
~ "\" asciidoctor_options!"
~ " s\" "
~ PROG_SOURCE
~ "sine_wave_executable_sizes.adoc\" include_asciidoctor"
~ " s\" \" asciidoctor_options!"
)
);
file.writeln(heading(2, translated(Text.tools, human_lang)));
file.writeln(anchor("conversions_tool"));
file.writeln(heading(3, translated(Text.conversions_tool, human_lang)));
file.writeln(paragraph(description_of_conversions_tool(human_lang)));
file.writeln(as_source_code_import_markup(SOURCE ~ "count_conversions.fish"));
file.writeln(anchor("activity_tool"));
file.writeln(heading(3, translated(Text.activity_tool, human_lang)));
file.writeln(paragraph(description_of_activity_tool(human_lang)));
file.writeln(as_source_code_import_markup(SOURCE ~ "calculate_activity.jl"));
file.writeln(anchor("pages_tool"));
file.writeln(heading(3, translated(Text.pages_tool, human_lang)));
file.writeln(paragraph(description_of_pages_tool(human_lang)));
file.writeln(as_source_code_import_markup(SOURCE ~ "build_pages.d"));
file.writeln(anchor("gnuplot_files"));
file.writeln(heading(3, translated(Text.gnuplot_files, human_lang)));
file.writeln(paragraph(description_of_gnuplot_files(human_lang)));
file.writeln
(
as_source_code_import_markup(SOURCE ~ "make_conversions_plot_rowstacked.gnuplot")
);
file.writeln
(
as_source_code_import_markup(SOURCE ~ "make_commits_plot_rowstacked.gnuplot")
);
file.writeln
(
as_source_code_import_markup(SOURCE ~ "make_conversions_plot_with_linespoints.gnuplot")
);
file.writeln
(
as_source_code_import_markup(SOURCE ~ "make_commits_plot_with_linespoints.gnuplot")
);
file.writeln(as_source_code_import_markup(SOURCE ~ "common.gnuplot"));
file.writeln(as_source_code_import_markup(SOURCE ~ "colors.gnuplot"));
file.writeln(anchor("makefile"));
file.writeln(heading(3, "Makefile"));
file.writeln(as_source_code_import_markup("basics_off/Makefile"));
}
// "Basics of…" project pages {{{2
// -----------------------------------------------------------------------------
/// Does the given source file contains a finished program? Unfinished programs
/// contain a comment with a conventional [note][UNFINISHED].
@fn bool is_finished(string source_file)
{
return (!can_find(read_text(source_file), UNFINISHED));
}
/// Write to the given file the contents of a language project [page
/// type][Page_Type] in the given human and programming languages.
@fn void write_contents_of_lang_project
(
File file,
string project,
Human_Lang human_lang,
string programming_lang_id,
)
{
@var string programming_lang_name = programming_lang_name(programming_lang_id);
@var string filename_extension = filename_extension(programming_lang_id);
@var string source_dir = build_path(REPOS_DIR, project, "src");
foreach
(
string source_file;
dir_entries(source_dir, "*" ~ filename_extension, Span_Mode.shallow)
.array()
.sort()
)
{
if (is_finished(source_file))
{
@var string source_file_base_name =
base_name(source_file, filename_extension);
file.writeln(anchor(source_file_base_name));
file.writeln
(
heading(2, program_title(source_file_base_name, human_lang))
);
file.writeln
(
include_file_markup
(
source_file,
filename_extension,
project
)
);
file.write(LIST_ITEM);
file.writeln
(
link
(
page_id(source_file_base_name, human_lang),
translated(Text.all_versions_of, human_lang)
~ " "
~ program_title(source_file_base_name, human_lang)
)
);
if (source_file_base_name == "sine_wave")
{
file.write(LIST_ITEM);
file.writeln(size_report_link(human_lang));
}
file.writeln();
}
}
}
// Program pages {{{2
// -----------------------------------------------------------------------------
/// Write to the given file the contents of a program project [page
/// type][Page_Type] in the given language.
@fn void write_contents_of_program_project
(
File file,
string project,
Human_Lang human_lang,
)
{
// Return the [Fendo](http://programandala.net/en.program.fendo.html)
// markup to create a link to the "Basics off" metaproject page.
@fn string basics_off_link()
{
return
link
(
page_id("basics_off", human_lang),
"// Basics off //"
);
};
@fn bool has_output(string)
{
switch (project)
{
case "diamond":
case "3d_plot":
case "bunny":
return true;
default:
return false;
}
}
// Return a note about the given conversion order of a project.
@fn string conversion_order(string order)
{
switch (human_lang)
{
case Human_Lang.en:
return
"Usually "
~ program_title(project, human_lang)
~ " is the "
~ order
~ " program converted in the "
~ basics_off_link()
~ " projects.";
case Human_Lang.eo:
return
program_title(project, human_lang)
~ " ofte estas la "
~ order
~ " programo konvertita en la projektoj "
~ basics_off_link()
~ " .";
case Human_Lang.es:
return
"Normalmente "
~ program_title(project, human_lang)
~ " es el "
~ order
~ " programa convertido en los proyectos "
~ basics_off_link()
~ " .";
case Human_Lang.ie:
return
program_title(project, human_lang)
~ " normalmen es li "
~ order
~ " programa convertet in li projectes "
~ basics_off_link()
~ " .";
default:
assert(false);
}
}
// Write a note about the given conversion order of a project.
@fn void write_conversion_order(Text order)
{
file.writeln
(
paragraph(conversion_order(translated(order, human_lang)))
);
}
// If the project is one of the first three, write a note about its
// conversion order.
switch (project)
{
case "diamond":
write_conversion_order(Text.first);
break;
case "3d_plot":
write_conversion_order(Text.second);
break;
case "sine_wave":
write_conversion_order(Text.third);
break;
default:
break;
}
@fn string plural(ulong n, string ending = "s")
{
return n > 1 ? ending : "";
}
// Write a note about the number of conversions.
@var Program_Version[] program_versions = program_project_versions(project);
@var string number_of_versions = to!string(program_versions.length);
switch (human_lang)
{
case Human_Lang.en:
file.writeln
(
paragraph
(
"This program has been converted to "
~ number_of_versions
~ " programming language" ~ plural(program_versions.length) ~ "."
)
);
break;
case Human_Lang.eo:
file.writeln
(
paragraph
(
"Ĉi-tiu programo estas konvertita en "
~ number_of_versions
~ " program-lingvo" ~ plural(program_versions.length, "j") ~ "n."
)
);
break;
case Human_Lang.es:
file.writeln
(
paragraph
(
"Este programa ha sido convertido a "
~ number_of_versions
~ " lenguaje" ~ plural(program_versions.length) ~ " de programación."
)
);
break;
case Human_Lang.ie:
file.writeln
(
paragraph
(
"Ti-ci programa esset convertet a "
~ number_of_versions
~ " lingue" ~ plural(program_versions.length) ~ " de programation."
)
);
break;
default:
assert(false);
}
// If the project is "Sine Wave", create a link to its executables report
// in the "Basics off" metaproject page.
if (project == "sine_wave")
{
file.writeln
(
paragraph
(
translated(Text.see_also, human_lang)
~ ": "
~ size_report_link(human_lang)
~ " ."
)
);
}
file.writeln
(
heading(2, capitalize(translated(Text.original, human_lang)))
);
file.writeln(human_lang == Human_Lang.en ? "en((((" : "");
file.writeln
(
include_file_markup
(
base_name
(
program_versions[0].source_file,
program_versions[0].filename_extension,
) ~ ".txt",
"",
program_versions[0].project_dir
)
);
file.writeln(human_lang == Human_Lang.en ? "))))" : "");
@var string source_base_filename = base_name
(
program_versions[0].source_file,
program_versions[0].filename_extension,
);
file.writeln
(
include_file_markup
(
source_base_filename ~ ".bas",
"",
program_versions[0].project_dir
)
);
if (has_output(source_base_filename))
{
file.writeln
(
heading(3, capitalize(translated(Text.output, human_lang)))
);
import std.file : read;
file.writeln
(
as_source_code_block_markup
(
to!string
(
read
(
build_path(OUTPUTS_DIR, source_base_filename ~ "_basic.txt")
)
)
)
);
}
// Return the human lang of the name of the given programming lang.
@fn Human_Lang programming_lang_lang(string programming_lang_id)
{
Human_Lang lang = programming_lang_name_lang(programming_lang_id);
return lang == Human_Lang.any ? human_lang : lang;
}
// Add a section for each version of the program.
foreach (program_version; program_versions)
{
file.writeln
(
anchor(programming_lang_name(program_version.programming_lang_id))
);
file.writeln
(
heading
(
2,
capitalize(translated(Text.en, human_lang))
~ " "
~ in_lang_markup_if_needed
(
programming_lang_name
(
program_version.programming_lang_id
),
programming_lang_lang(program_version.programming_lang_id),
human_lang
)
)
);
file.writeln
(
include_file_markup
(
program_version.source_file,
program_version.filename_extension,
program_version.project_dir
)
);
file.write(LIST_ITEM);
file.writeln
(
link
(
page_id
(
"basics_of_" ~ program_version.programming_lang_id,
human_lang
)
),
"\n"
);
}
}
// Page building {{{2
// -----------------------------------------------------------------------------
/// Write to the given file the header of the currently built page, including
/// the shebang required to execute the
/// [Fendo](http://programandala.net/en.program.fendo.html) page with
/// [Gforth](http://gnu.org/software/gforth).
@fn void write_header(File file, string filename)
{
file.writeln("#! /usr/bin/env gforth");
file.writeln("\n\\ ", filename);
file.writeln("\n\\ N.B. this file was created by <build_pages.d>,");
file.writeln("\\ which is part of the \"basics off\" metaproject");
file.writeln("\\ (http://programandala.net/en.program.basics_off.html);");
file.writeln("\\ please do not edit.");
file.writeln("\n\\ last modified ", page_date(filename).last_modified);
file.writeln("\nrequire ../fendo-programandala.fs");
}
/// Write to the given file the footer of the currently built page, contating
/// just a Vim modeline to set the filetype to
/// [Fendo](http://programandala.net/en.program.fendo.html).
@fn void write_footer(File file)
{
file.writeln("\n\\ vim: filetype=fendo");
}
@fn void write_redirection(File file, string project, Human_Lang human_lang)
{
switch (project)
{
case "basics_off":
file.writefln
(
"\nredirect %s.%s.%s",
human_lang,
translated(Text.program, human_lang),
"basics_of_haskell"
);
break;
default:
break;
}
}
/// Build the page corresponding to the given project, [type][Page_Type], human
/// and programming languages.
@fn void build_page
(
string project,
Human_Lang human_lang,
Page_Type type,
string programming_lang_id = "",
)
{
@var string filename = page_filename(project, human_lang);
@var string filepath = build_path(TARGET_DIR, filename);
debug (build)
{
writefln("building <%s>...", filename);
}
// XXX FIXME DMD 2.111.0 crashes when a user attribute is applied to a
// `File` declaration, unless the initialization is separated
@var File file;
file = File(filepath, "w");
write_header(file, filename);
write_metadata(file, project, human_lang, type, page_date(filename));
write_redirection(file, project, human_lang);
file.writeln("\ncontent{\n");
final switch (type)
{
case Page_Type.metaproject:
write_contents_of_metaproject(file, human_lang);
break;
case Page_Type.lang_project:
write_contents_of_lang_project
(
file,
project,
human_lang,
programming_lang_id
);
break;
case Page_Type.program_project:
write_contents_of_program_project(file, project, human_lang);
break;
}
file.writeln("\n}content");
write_footer(file);
file.close();
set_attributes(filepath, octal!755);
}
// Init {{{1
// =============================================================================
/// Array containing the directories of the "Basics of…" projects.
@var string[] project_dirs;
/// Array containing the identifiers of the programming languages.
@var string[] programming_lang_ids;
/// Array containing the identifiers of the programs.
@var string[] program_ids;
/// Init the data used by the program, i.e. arrays `programming_lang_ids`
/// and `program_ids`.
@fn void init_data()
{
foreach
(
string entry;
dir_entries(REPOS_DIR, "basics_of_*", Span_Mode.shallow)
)
{
if (is_dir(entry))
{
project_dirs ~= entry;
}
}
debug (data)
{
writefln("project_dirs = %s", project_dirs);
}
foreach (string dir; project_dirs)
{
if (is_dir(build_path(REPOS_DIR, dir)))
{
@var string programming_lang_id = programming_lang_id_of_project(dir);
if (is_programming_lang_used(programming_lang_id))
{
programming_lang_ids ~= programming_lang_id;
}
}
}
sort(programming_lang_ids);
debug (data)
{
writefln("programming_lang_ids = %s", programming_lang_ids);
}
foreach (string project_dir; project_dirs)
{
if (is_dir(build_path(REPOS_DIR, project_dir)))
{
@var string project_source_path =
build_path(REPOS_DIR, project_dir, "src");
debug (init)
{
writefln("project_source_path = %s", project_source_path);
}
foreach
(
string file;
dir_entries(project_source_path, "*", Span_Mode.shallow)
)
{
@var string[] filename = split(split(file, "/")[$ - 1], ".");
@var string base_filename = filename[0];
@var string extension = "";
if (filename.length > 1)
{
extension = filename[1];
}
debug (init)
{
writefln("extension = %s", extension);
}
if (extension == "txt")
{
debug (init)
{
writefln
(
"%s -> %s + %s",
file,
base_filename,
extension
);
}
@var string program_id = usual_program_id(base_filename);
debug (init)
{
writeln("program_id = ", program_id);
}
if (!can_find(program_ids, program_id))
{
debug (init)
{
writefln("adding &s", program_id);
}
program_ids ~= program_id;
}
}
}
}
}
sort(program_ids);
}
/// Init the program.
@fn void init()
{
// Make sure the target directory exists.
if (exists(TARGET_DIR))
{
assert
(
is_dir(TARGET_DIR),
"Fatal error: <" ~ TARGET_DIR ~ "> exists but it's not a directory"
);
}
else
{
mkdir(TARGET_DIR);
}
init_data();
}
// Main {{{1
// =============================================================================
/// Init the data and build all pages in the four languages of the website.
@fn void main()
{
init();
foreach (Human_Lang human_lang; human_langs)
{
build_page
(
"basics_off",
human_lang,
Page_Type.metaproject,
);
foreach (string programming_lang_id; programming_lang_ids)
{
// note the `programming_lang_ids` array contains only the
// identifiers of the programming languages actually used to make
// at least one conversion. the filter is hardcoded in
// `is_programming_lang_used` and was applied in `init_data`.
build_page
(
"basics_of_" ~ programming_lang_id,
human_lang,
Page_Type.lang_project,
programming_lang_id,
);
}
foreach (string program_id; program_ids)
{
build_page
(
program_id,
human_lang,
Page_Type.program_project,
);
}
}
}
// Change log {{{1
// =============================================================================
// 2025-02-16: First draft in Nim. Convert or get programming language names,
// filename extensions, program names, texts, page names; create lists of
// project dirs and programs.
//
// 2025-02-23: Fix `program_page_name`. Improve the names of many identifiers.
//
// 2025-03-12: Remove unnecessary `of` in `filename_extension`.
//
// 2025-03-16: Start conversion from Nim to Pike.
//
// 2025-03-22: Finish conversion from Nim to Pike. Convert from Pike to D.
//
// 2025-05-31: Update conversion from Pike.
//
// 2025-06-02: fix, improve. build basic contents of "basics_off" and
// "basics_of_*" pages.
//
// 2025-06-03: improve building flow. build basic contents of program pages.
// improve page metadata. start text translations.
//
// 2025-06-04: improve pages metadata, handling of target dir. factor.
//
// 2025-06-06: improve identifiers. add `tags` metadata field. add content of
// `related` metadata fields to metaproject pages. factor the calculation of
// program versions.
//
// 2025-06-08: add `description` metadata field. add `require`. make page
// files executable. fix `alternate` fields. fix path to source code files.
// fix markup of `description` metadata field. fix default value of hierarchy
// metadata fields. fix path of executable sizes report. improve `related`
// metadata field.
//
// 2025-06-09: add `external_related` metadata field. add translated version
// of the executable sizes report.
//
// 2025-06-10: remove files of empty "basics_of_" projects. omit unused
// languages. add graphics and <Makefile> to "basics off" projects.
//
// 2025-06-11: add conversion reports to "basics off" project pages.
//
// 2025-06-27: move graphics and add them descriptions. convert code to allman
// style. reword some texts. rearrange headings of "basics off" project pages.
//
// 2025-08-08: add link to all version of a program after its source code; add
// links to "sine wave" size report after its source code and to the `related`
// field of its page. fix `page_id`. add descriptions to the "basics off"
// programs.
//
// 2025-08-13: add description texts to the program pages. fix f# vim syntax
// identifier. complete page metadata.
//
// 2025-08-14: fix/improve markup creation. add text and link to "sine wave"
// sizes report.
//
// 2025-08-15: add description to the "basics off" pages. factor calculation
// and printing of conversion order text. add note to pages' header about
// their origin.
//
// 2025-08-16: improve note about "sine wave" report.
//
// 2025-08-29: fix typo.
//
// 2025-11-18: add `@fn` and `@var`.
//
// 2025-12-17: make page dates configurable. add "basics of styx" and "basics
// of neat".
//
// 2025-12-18: fix typo.
//
// 2025-12-19: add "z-end".
//
// 2025-12-20: update page dates.
//
// 2025-12-25: add "basics of nature" and "basics of janet".
//
// 2025-12-27: update page dates.
//
// 2025-12-30: update page dates; add anchors to the program headers of "basics
// of" pages.
//
// 2026-01-06: update page dates.
//
// 2026-01-23: add "basics of elixir", "basics of gleam", "basics of haskell".
//
// 2026-02-06: update.
//
// 2026-02-07: update "basics of gleam"; fix typos; improve description of the
// "basics off" page; add "basics of pony".
//
// 2026-02-08: fix: remove "basics of haskell", add it to the projects having
// no conversion and create a redirection for it. update "basics of chapel".
// fix the final rendering of the "conversions" anchor.
//
// 2026-02-13: update "basics of hare".
//
// 2026-02-15: update "sine wave" in janet.
Ficheros de gnuplot para crear los gráficos
Estos ficheros de configuración de gnuplot posibilitan convertir los ficheros de datos de formato CSV en gráficos.
# make_conversions_plot_rowstacked.gnuplot
#
# By Marcos Cruz (programandala.net), 2024, 2025, 2026.
#
# This file is part of "Basics off"
# Last modified 20260207T1550+0100.
set grid y
set style data histograms
set style histogram rowstacked
set boxwidth 0.5
set style fill solid 1.0 border -1
plot for [col=2:56] input_file using col:xticlabels(1) linetype col
# make_commits_plot_rowstacked.gnuplot
#
# By Marcos Cruz (programandala.net), 2024, 2025, 2026.
#
# This file is part of "Basics off"
# Last modified 20260207T1550+0100.
set grid y
set style data histograms
set style histogram rowstacked
set boxwidth 0.5
set style fill solid 1.0 border -1
plot for [col=2:59] input_file using col:xticlabels(1) linetype col
# make_conversions_plot_with_linespoints.gnuplot
#
# By Marcos Cruz (programandala.net), 2024, 2025, 2026.
#
# This file is part of "Basics off"
# Last modified 20260206T1309+0100.
set grid
plot for [col=2:48] input_file using col:xticlabels(1) linetype col with linespoints
# make_commits_plot_with_linespoints.gnuplot
#
# By Marcos Cruz (programandala.net), 2024, 2025, 2026.
#
# This file is part of "Basics off"
# Last modified 20260206T1309+0100.
set grid
plot for [col=2:48] input_file using col:xticlabels(1) linetype col with linespoints
# comman.gnuplot
#
# By Marcos Cruz (programandala.net), 2024, 2025, 2026.
#
# This file is part of "Basics off"
# Last modified 20260206T1257+0100.
set datafile separator comma
set terminal png size 2560, 2048
set title title_
set key autotitle columnhead
set xlabel xlabel_
set ylabel ylabel_
set key rmargin
set xtics rotate by 45 right
# colors.gnuplot
#
# By Marcos Cruz (programandala.net), 2025, 2026.
#
# This file is part of "Basics off".
# Last modified 20260123T2151+0100.
# See change log at the end of the file.
# Acknowledgment:
# The palette of distinct colors was made by https://mokole.com/palette.html
set linetype 2 lc rgb '#a9a9a9' lw 1 # darkgray
set linetype 3 lc rgb '#2f4f4f' lw 1 # darkslategray
set linetype 4 lc rgb '#556b2f' lw 1 # darkolivegreen
set linetype 5 lc rgb '#8b4513' lw 1 # saddlebrown
set linetype 6 lc rgb '#2e8b57' lw 1 # seagreen
set linetype 7 lc rgb '#800000' lw 1 # maroon
set linetype 8 lc rgb '#191970' lw 1 # midnightblue
set linetype 9 lc rgb '#708090' lw 1 # slategray
set linetype 10 lc rgb '#808000' lw 1 # olive
set linetype 11 lc rgb '#008000' lw 1 # green
set linetype 12 lc rgb '#bc8f8f' lw 1 # rosybrown
set linetype 13 lc rgb '#663399' lw 1 # rebeccapurple
set linetype 14 lc rgb '#008080' lw 1 # teal
set linetype 15 lc rgb '#b8860b' lw 1 # darkgoldenrod
set linetype 16 lc rgb '#cd853f' lw 1 # peru
set linetype 17 lc rgb '#4682b4' lw 1 # steelblue
set linetype 18 lc rgb '#000080' lw 1 # navy
set linetype 19 lc rgb '#d2691e' lw 1 # chocolate
set linetype 20 lc rgb '#9acd32' lw 1 # yellowgreen
set linetype 21 lc rgb '#20b2aa' lw 1 # lightseagreen
set linetype 22 lc rgb '#32cd32' lw 1 # limegreen
set linetype 23 lc rgb '#7f007f' lw 1 # purple2
set linetype 24 lc rgb '#8fbc8f' lw 1 # darkseagreen
set linetype 25 lc rgb '#b03060' lw 1 # maroon3
set linetype 26 lc rgb '#9932cc' lw 1 # darkorchid
set linetype 27 lc rgb '#ff0000' lw 1 # red
set linetype 28 lc rgb '#ffa500' lw 1 # orange
set linetype 29 lc rgb '#ffd700' lw 1 # gold
set linetype 30 lc rgb '#ffff00' lw 1 # yellow
set linetype 31 lc rgb '#c71585' lw 1 # mediumvioletred
set linetype 32 lc rgb '#0000cd' lw 1 # mediumblue
set linetype 33 lc rgb '#deb887' lw 1 # burlywood
set linetype 34 lc rgb '#00ff00' lw 1 # lime
set linetype 35 lc rgb '#00ff7f' lw 1 # springgreen
set linetype 36 lc rgb '#4169e1' lw 1 # royalblue
set linetype 37 lc rgb '#dc143c' lw 1 # crimson
set linetype 38 lc rgb '#00ffff' lw 1 # aqua
set linetype 39 lc rgb '#00bfff' lw 1 # deepskyblue
set linetype 40 lc rgb '#9370db' lw 1 # mediumpurple
set linetype 41 lc rgb '#0000ff' lw 1 # blue
set linetype 42 lc rgb '#a020f0' lw 1 # purple3
set linetype 43 lc rgb '#f08080' lw 1 # lightcoral
set linetype 44 lc rgb '#adff2f' lw 1 # greenyellow
set linetype 45 lc rgb '#ff6347' lw 1 # tomato
set linetype 46 lc rgb '#da70d6' lw 1 # orchid
set linetype 47 lc rgb '#d8bfd8' lw 1 # thistle
set linetype 48 lc rgb '#ff00ff' lw 1 # fuchsia
set linetype 49 lc rgb '#1e90ff' lw 1 # dodgerblue
set linetype 50 lc rgb '#db7093' lw 1 # palevioletred
set linetype 51 lc rgb '#f0e68c' lw 1 # khaki
set linetype 52 lc rgb '#dda0dd' lw 1 # plum
set linetype 53 lc rgb '#90ee90' lw 1 # lightgreen
set linetype 54 lc rgb '#87ceeb' lw 1 # skyblue
set linetype 55 lc rgb '#ff1493' lw 1 # deeppink
set linetype 56 lc rgb '#ffa07a' lw 1 # lightsalmon
set linetype 57 lc rgb '#afeeee' lw 1 # paleturquoise
set linetype 58 lc rgb '#7fffd4' lw 1 # aquamarine
set linetype 59 lc rgb '#ff69b4' lw 1 # hotpink
set linetype 60 lc rgb '#ffe4c4' lw 1 # bisque
set linetype 61 lc rgb '#ffb6c1' lw 1 # lightpink
# Change log
# 2025-01-07: Start with 45 colors.
# 2025-03-19: Update to 49 colors.
# 2025-08-14: Update to 50 colors.
# 2026-02-07: Update to 60 colors.
Makefile
# Makefile of "Basics off"
#
# By Marcos Cruz (programandala.net), 2023, 2024, 2025, 2026
#
# Last modified 20260209T1325+0100.
# Requirements:
# Asciidoctor
# https://asciidoctor.org
# Asciidoctor PDF
# https://github.com/asciidoctor/asciidoctor-pdf
# D
# https://dlang.org
# fish
# https://fishshell.com/
# gnuplot
# http://www.gnuplot.info
# Julia
# https://julialang.org
commits_plot_targets = \
target/activity__commits_plot_with_linespoints__en.png \
target/activity__commits_plot_rowstacked__en.png \
target/activity__commits_plot_with_linespoints__eo.png \
target/activity__commits_plot_rowstacked__eo.png \
target/activity__commits_plot_with_linespoints__es.png \
target/activity__commits_plot_rowstacked__es.png \
target/activity__commits_plot_with_linespoints__ie.png \
target/activity__commits_plot_rowstacked__ie.png
conversions_plot_targets = \
target/activity__conversions_plot_with_linespoints__en.png \
target/activity__conversions_plot_rowstacked__en.png \
target/activity__conversions_plot_with_linespoints__eo.png \
target/activity__conversions_plot_rowstacked__eo.png \
target/activity__conversions_plot_with_linespoints__es.png \
target/activity__conversions_plot_rowstacked__es.png \
target/activity__conversions_plot_with_linespoints__ie.png \
target/activity__conversions_plot_rowstacked__ie.png
plot_targets = $(commits_plot_targets) $(conversions_plot_targets)
activity__commits_targets = \
target/activity__commits_summary.csv \
target/activity__commits_table.csv \
$(commits_plot_targets)
activity__conversions_targets = \
target/activity__conversions_summary.csv \
target/activity__conversions_table.csv \
$(conversions_plot_targets)
activity_targets = $(activity__commits_targets) $(activity__conversions_targets)
conversion_targets = \
target/conversions__language_ranking.adoc \
target/conversions__language_ranking__en.html \
target/conversions__language_ranking__en.pdf \
target/conversions__language_ranking__eo.html \
target/conversions__language_ranking__eo.pdf \
target/conversions__language_ranking__es.html \
target/conversions__language_ranking__es.pdf \
target/conversions__language_ranking__ie.html \
target/conversions__language_ranking__ie.pdf \
target/conversions__programs_and_languages.adoc \
target/conversions__programs_and_languages__en.html \
target/conversions__programs_and_languages__en.pdf \
target/conversions__programs_and_languages__eo.html \
target/conversions__programs_and_languages__eo.pdf \
target/conversions__programs_and_languages__es.html \
target/conversions__programs_and_languages__es.pdf \
target/conversions__programs_and_languages__ie.html \
target/conversions__programs_and_languages__ie.pdf
size_targets = \
target/sine_wave_executable_sizes__en.html \
target/sine_wave_executable_sizes__en.pdf \
target/sine_wave_executable_sizes__eo.html \
target/sine_wave_executable_sizes__eo.pdf \
target/sine_wave_executable_sizes__es.html \
target/sine_wave_executable_sizes__es.pdf \
target/sine_wave_executable_sizes__ie.html \
target/sine_wave_executable_sizes__ie.pdf
all_targets := $(activity_targets) $(conversion_targets) $(size_targets)
.PHONY: all # build all targets
all: $(all_targets) pages
.PHONY: log # build log file of commits activity
log: tmp/activity__commits.log
.PHONY: activity__commits # build CSV files of commits activity
commits_activity: $(activity__commits_targets)
.PHONY: activity__conversions # build CSV files of conversions activity
conversions_activity: $(activity__conversions_targets)
.PHONY: activity # build all of the CSV files of activity
activity: activity__commits activity__conversions
.PHONY: conversion # build CSV files of conversions
conversion: $(conversion_targets)
.PHONY: plot # build PNG plot graphics
plot: $(plot_targets)
.PHONY: size # build "sine wave" size reports
size: $(size_targets)
.PHONY: clean # remove target and temporary files
clean:
@rm --force $(all_targets) tmp/*
.PHONY: cleanactivity # remove CSV files of activity
cleanactivity:
@rm --force $(activity_targets) tmp/*_activity.log
.PHONY: cleanconversion # remove CSV files of conversions
cleanconversion:
@rm --force $(conversion_targets)
.PHONY: cleanplot # remove PNG plot graphics
cleanplot:
@rm --force $(plot_targets)
.PHONY: pages # build programandala.net pages
pages:
rdmd src/build_pages.d
.PHONY: help # list available recipes
help:
@echo Available recipes:
@grep "^\.PHONY:" Makefile | sed -e 's/\.PHONY:\s\+\([a-z_0-9]\+\) \+#/ \1 =/' | sort
target/%__en.html: src/%.adoc
asciidoctor --attribute en --out-file $@ $<
target/%__eo.html: src/%.adoc
asciidoctor --attribute eo --out-file $@ $<
target/%__es.html: src/%.adoc
asciidoctor --attribute es --out-file $@ $<
target/%__ie.html: src/%.adoc
asciidoctor --attribute ie --out-file $@ $<
target/%__ie.html: src/%.adoc
asciidoctor --attribute ie --out-file $@ $<
target/%__en.pdf: src/%.adoc
asciidoctor-pdf --attribute en --out-file $@ $<
target/%__eo.pdf: src/%.adoc
asciidoctor-pdf --attribute eo --out-file $@ $<
target/%__es.pdf: src/%.adoc
asciidoctor-pdf --attribute es --out-file $@ $<
target/%__ie.pdf: src/%.adoc
asciidoctor-pdf --attribute ie --out-file $@ $<
target/%__en.html: target/%.adoc
asciidoctor --attribute en --out-file $@ $<
target/%__eo.html: target/%.adoc
asciidoctor --attribute eo --out-file $@ $<
target/%__es.html: target/%.adoc
asciidoctor --attribute es --out-file $@ $<
target/%__ie.html: target/%.adoc
asciidoctor --attribute ie --out-file $@ $<
target/%__ie.html: target/%.adoc
asciidoctor --attribute ie --out-file $@ $<
target/%__en.pdf: target/%.adoc
asciidoctor-pdf --attribute en --out-file $@ $<
target/%__eo.pdf: target/%.adoc
asciidoctor-pdf --attribute eo --out-file $@ $<
target/%__es.pdf: target/%.adoc
asciidoctor-pdf --attribute es --out-file $@ $<
target/%__ie.pdf: target/%.adoc
asciidoctor-pdf --attribute ie --out-file $@ $<
target/%.html: target/%.adoc
asciidoctor --out-file $@ $<
target/%.pdf: target/%.adoc
asciidoctor-pdf --out-file $@ $<
tmp/activity__commits.log:
julia ./src/calculate_activity.jl log --plot-type commits --output $@
target/activity__commits_summary.csv: tmp/activity__commits.log
julia ./src/calculate_activity.jl summary --plot-type commits --input $< --output $@
target/activity__commits_table.csv: target/activity__commits_summary.csv
julia ./src/calculate_activity.jl tabular --input $< --output $@
tmp/activity__conversions.log:
julia ./src/calculate_activity.jl log --plot-type conversions --output $@
target/activity__conversions_summary.csv: tmp/activity__conversions.log
julia ./src/calculate_activity.jl summary --plot-type conversions --input $< --output $@
target/activity__conversions_table.csv: target/activity__conversions_summary.csv
julia ./src/calculate_activity.jl tabular --input $< --output $@
target/activity__commits_plot_with_linespoints__en.png: target/activity__commits_table.csv src/colors.gnuplot src/common.gnuplot src/make_commits_plot_with_linespoints.gnuplot
gnuplot \
-e "input_file='$<'; title_='Monthly activity of Basics off'; xlabel_='Month'; ylabel_='Commits'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_commits_plot_with_linespoints.gnuplot
target/activity__commits_plot_rowstacked__en.png: target/activity__commits_table.csv src/colors.gnuplot src/common.gnuplot src/make_commits_plot_rowstacked.gnuplot
gnuplot \
-e "input_file='$<'; title_='Monthly activity of Basics off'; xlabel_='Month'; ylabel_='Commits'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_commits_plot_rowstacked.gnuplot
target/activity__conversions_plot_with_linespoints__en.png: target/activity__conversions_table.csv src/colors.gnuplot src/common.gnuplot src/make_conversions_plot_with_linespoints.gnuplot
gnuplot \
-e "input_file='$<'; title_='Monthly activity of Basics off'; xlabel_='Month'; ylabel_='Conversions started'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_conversions_plot_with_linespoints.gnuplot
target/activity__conversions_plot_rowstacked__en.png: target/activity__conversions_table.csv src/colors.gnuplot src/common.gnuplot src/make_conversions_plot_rowstacked.gnuplot
gnuplot \
-e "input_file='$<'; title_='Monthly activity of Basics off'; xlabel_='Month'; ylabel_='Conversions started'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_conversions_plot_rowstacked.gnuplot
target/activity__commits_plot_with_linespoints__eo.png: target/activity__commits_table.csv src/colors.gnuplot src/common.gnuplot src/make_commits_plot_with_linespoints.gnuplot
gnuplot \
-e "input_file='$<'; title_='Monata aktiveco de Basics off'; xlabel_='Monato'; ylabel_='Enmetoj'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_commits_plot_with_linespoints.gnuplot
target/activity__commits_plot_rowstacked__eo.png: target/activity__commits_table.csv src/colors.gnuplot src/common.gnuplot src/make_commits_plot_rowstacked.gnuplot
gnuplot \
-e "input_file='$<'; title_='Monata aktiveco de Basics off'; xlabel_='Monato'; ylabel_='Enmetoj'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_commits_plot_rowstacked.gnuplot
target/activity__conversions_plot_with_linespoints__eo.png: target/activity__conversions_table.csv src/colors.gnuplot src/common.gnuplot src/make_conversions_plot_with_linespoints.gnuplot
gnuplot \
-e "input_file='$<'; title_='Monata aktiveco de Basics off'; xlabel_='Monato'; ylabel_='Konvertoj komencitaj'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_conversions_plot_with_linespoints.gnuplot
target/activity__conversions_plot_rowstacked__eo.png: target/activity__conversions_table.csv src/colors.gnuplot src/common.gnuplot src/make_conversions_plot_rowstacked.gnuplot
gnuplot \
-e "input_file='$<'; title_='Monata aktiveco de Basics off'; xlabel_='Monato'; ylabel_='Konvertoj komencitaj'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_conversions_plot_rowstacked.gnuplot
target/activity__commits_plot_with_linespoints__es.png: target/activity__commits_table.csv src/colors.gnuplot src/common.gnuplot src/make_commits_plot_with_linespoints.gnuplot
gnuplot \
-e "input_file='$<'; title_='Actividad mensual de Basics off'; xlabel_='Mes'; ylabel_='Enmetoj'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_commits_plot_with_linespoints.gnuplot
target/activity__commits_plot_rowstacked__es.png: target/activity__commits_table.csv src/colors.gnuplot src/common.gnuplot src/make_commits_plot_rowstacked.gnuplot
gnuplot \
-e "input_file='$<'; title_='Actividad mensual de Basics off'; xlabel_='Mes'; ylabel_='Entradas'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_commits_plot_rowstacked.gnuplot
target/activity__conversions_plot_with_linespoints__es.png: target/activity__conversions_table.csv src/colors.gnuplot src/common.gnuplot src/make_conversions_plot_with_linespoints.gnuplot
gnuplot \
-e "input_file='$<'; title_='Actividad mensual de Basics off'; xlabel_='Mes'; ylabel_='Conversiones comenzadas'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_conversions_plot_with_linespoints.gnuplot
target/activity__conversions_plot_rowstacked__es.png: target/activity__conversions_table.csv src/colors.gnuplot src/common.gnuplot src/make_conversions_plot_rowstacked.gnuplot
gnuplot \
-e "input_file='$<'; title_='Actividad mensual de Basics off'; xlabel_='Mes'; ylabel_='Conversiones comenzadas'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_conversions_plot_rowstacked.gnuplot
target/activity__commits_plot_with_linespoints__ie.png: target/activity__commits_table.csv src/colors.gnuplot src/common.gnuplot src/make_commits_plot_with_linespoints.gnuplot
gnuplot \
-e "input_file='$<'; title_='Activitá mensual de Basics off'; xlabel_='Mensu'; ylabel_='Depositiones'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_commits_plot_with_linespoints.gnuplot
target/activity__commits_plot_rowstacked__ie.png: target/activity__commits_table.csv src/colors.gnuplot src/common.gnuplot src/make_commits_plot_rowstacked.gnuplot
gnuplot \
-e "input_file='$<'; title_='Activitá mensual de Basics off'; xlabel_='Mensu'; ylabel_='Depositiones'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_commits_plot_rowstacked.gnuplot
target/activity__conversions_plot_with_linespoints__ie.png: target/activity__conversions_table.csv src/colors.gnuplot src/common.gnuplot src/make_conversions_plot_with_linespoints.gnuplot
gnuplot \
-e "input_file='$<'; title_='Activitá mensual de Basics off'; xlabel_='Mensu'; ylabel_='Conversiones comensat'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_conversions_plot_with_linespoints.gnuplot
target/activity__conversions_plot_rowstacked__ie.png: target/activity__conversions_table.csv src/colors.gnuplot src/common.gnuplot src/make_conversions_plot_rowstacked.gnuplot
gnuplot \
-e "input_file='$<'; title_='Activitá mensual de Basics off'; xlabel_='Mensu'; ylabel_='Conversiones comensat'; set output '$@'" \
src/colors.gnuplot \
src/common.gnuplot \
src/make_conversions_plot_rowstacked.gnuplot
target/conversions__language_ranking.adoc: FORCE
./src/count_conversions.fish ranking > $@
target/conversions__programs_and_languages.adoc: FORCE
./src/count_conversions.fish programs > $@
FORCE:
