rawfeed 0.3.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +25 -0
  3. data/.gitignore +19 -0
  4. data/.gitlab/ci/gitlab-pages.yml +51 -0
  5. data/.hidden +6 -0
  6. data/404.html +6 -0
  7. data/Gemfile +51 -0
  8. data/README.md +102 -26
  9. data/_config.yml +77 -0
  10. data/_data/generic.yml +29 -0
  11. data/_data/screen/blog.yml +46 -0
  12. data/_data/screen/contact.yml +31 -0
  13. data/_data/screen/donate.yml +45 -0
  14. data/_data/screen/footer.yml +17 -0
  15. data/_data/screen/head.yml +49 -0
  16. data/_data/screen/home.yml +24 -0
  17. data/_data/screen/maintenance.yml +8 -0
  18. data/_data/screen/navbar.yml +41 -0
  19. data/_data/screen/page.yml +12 -0
  20. data/_data/screen/pixels.yml +7 -0
  21. data/_data/screen/pub.yml +4 -0
  22. data/_data/{resume.yml → screen/resume.yml} +8 -8
  23. data/_data/screen/socials.yml +20 -0
  24. data/_includes/assigned +36 -0
  25. data/_includes/layout/blog_search.html +22 -15
  26. data/_includes/layout/disqus.html +7 -8
  27. data/_includes/layout/footer.html +43 -28
  28. data/_includes/layout/giscus.html +15 -19
  29. data/_includes/layout/head.html +97 -75
  30. data/_includes/layout/maintenance.html +14 -11
  31. data/_includes/layout/navbar.html +253 -0
  32. data/_includes/layout/paginator.html +12 -13
  33. data/_includes/{alert → markdown/alert} +2 -2
  34. data/_includes/{chart → markdown/chart} +3 -3
  35. data/_includes/{image → markdown/image} +4 -4
  36. data/_includes/{socials → markdown/socials} +5 -5
  37. data/_includes/{video → markdown/video} +2 -2
  38. data/_layouts/blog/index.html +53 -0
  39. data/_layouts/{post.html → blog/post.html} +50 -36
  40. data/_layouts/blog/posts_by_tag.html +27 -0
  41. data/_layouts/blog/tags.html +32 -0
  42. data/_layouts/contact.html +156 -114
  43. data/_layouts/default.html +53 -48
  44. data/_layouts/donate.html +112 -0
  45. data/_layouts/error.html +9 -7
  46. data/_layouts/home.html +22 -19
  47. data/_layouts/licenses.html +2 -2
  48. data/_layouts/page.html +18 -17
  49. data/_layouts/pixels/index.html +75 -0
  50. data/_layouts/{pixel.html → pixels/post.html} +5 -5
  51. data/_layouts/pub.html +50 -44
  52. data/_layouts/resume.html +308 -265
  53. data/_pages/any-page.md +336 -0
  54. data/_pages/contact.md +16 -0
  55. data/_pages/donate.md +16 -0
  56. data/_pages/licenses.md +17 -0
  57. data/_pages/resume.md +14 -0
  58. data/_pixels/2025-10-15-first-my-pixel.md +34 -0
  59. data/_posts/2025-09-20-welcome-to-jekyll.md +36 -0
  60. data/_posts/2025-09-25-this-post-demonstrates-post-codeblocks.md +141 -0
  61. data/_posts/2025-09-25-this-post-demonstrates-post-content-styles.md +133 -0
  62. data/_posts/2025-10-04-content-styles-and-codeblocks.md +330 -0
  63. data/_sass/components/_markdown.scss +2 -2
  64. data/_sass/includes/_index.scss +2 -2
  65. data/_sass/includes/{_header.scss → _navbar.scss} +2 -6
  66. data/_sass/includes/_toc.scss +146 -0
  67. data/_sass/layouts/_blog.scss +1 -1
  68. data/_sass/layouts/_index.scss +2 -2
  69. data/_sass/layouts/_page.scss +0 -5
  70. data/_sass/layouts/_post.scss +8 -138
  71. data/_sass/layouts/{_tag-posts.scss → _posts_by_tag.scss} +3 -3
  72. data/_sass/layouts/_resume.scss +1 -1
  73. data/_sass/layouts/{_tag.scss → _tags.scss} +10 -6
  74. data/_sass/main.scss +2 -2
  75. data/_sass/theme/_dark.scss +2 -2
  76. data/_sass/theme/_light.scss +1 -1
  77. data/assets/js/blog.js +52 -18
  78. data/assets/js/contact.js +21 -20
  79. data/assets/js/default.js +67 -50
  80. data/assets/js/discus.js +2 -2
  81. data/assets/js/{donation.js → donate.js} +10 -9
  82. data/assets/js/home.js +18 -16
  83. data/assets/js/page.js +50 -172
  84. data/assets/js/toc.js +133 -0
  85. data/assets/json/blog_search.json +6 -6
  86. data/assets/vendors/fuse.min.js +9 -0
  87. data/blog/index.md +14 -0
  88. data/blog/tags/index.md +12 -0
  89. data/exe/rawfeed +29 -0
  90. data/index.md +15 -0
  91. data/lib/rawfeed/build/cleaner.rb +60 -0
  92. data/lib/rawfeed/build/image_minifier.rb +163 -0
  93. data/lib/rawfeed/build/minifier.rb +89 -0
  94. data/lib/rawfeed/build.rb +9 -0
  95. data/lib/rawfeed/command/backup.rb +124 -0
  96. data/lib/rawfeed/command/cli.rb +118 -0
  97. data/lib/rawfeed/command/installer.rb +156 -0
  98. data/lib/rawfeed/command/tools.rb +138 -0
  99. data/lib/rawfeed/{author.rb → content/author.rb} +7 -7
  100. data/lib/rawfeed/content/contact.rb +51 -0
  101. data/lib/rawfeed/content/donate.rb +48 -0
  102. data/lib/rawfeed/{draft.rb → content/draft.rb} +5 -3
  103. data/lib/rawfeed/content/licenses.rb +46 -0
  104. data/lib/rawfeed/{page.rb → content/page.rb} +4 -3
  105. data/lib/rawfeed/{pixel.rb → content/pixel.rb} +7 -4
  106. data/lib/rawfeed/content/post.rb +107 -0
  107. data/lib/rawfeed/{resume.rb → content/resume.rb} +23 -19
  108. data/lib/rawfeed/{layout.rb → core/layout.rb} +1 -1
  109. data/lib/rawfeed/core/utils.rb +103 -0
  110. data/lib/rawfeed/{version.rb → core/version.rb} +1 -1
  111. data/lib/rawfeed/{datelang.rb → plugin/datelang.rb} +5 -6
  112. data/lib/rawfeed/{pub.rb → plugin/pub.rb} +33 -31
  113. data/lib/rawfeed/{reading_time.rb → plugin/reading_time.rb} +5 -4
  114. data/lib/rawfeed/root.rb +3 -0
  115. data/lib/rawfeed.rb +36 -14
  116. data/pixels/index.md +11 -0
  117. data/robots.txt +26 -0
  118. metadata +167 -119
  119. data/_data/options.yml +0 -329
  120. data/_includes/layout/data.liquid +0 -31
  121. data/_includes/layout/header.html +0 -173
  122. data/_layouts/blog.html +0 -52
  123. data/_layouts/donation.html +0 -113
  124. data/_layouts/pixels.html +0 -71
  125. data/_layouts/tag.html +0 -33
  126. data/_layouts/tag_posts.html +0 -28
  127. data/assets/vendor/simple-jekyll-search.js +0 -433
  128. data/assets/vendor/simple-jekyll-search.min.js +0 -6
  129. data/lib/rawfeed/installer.rb +0 -37
  130. data/lib/rawfeed/post.rb +0 -60
  131. data/lib/rawfeed/utils.rb +0 -75
  132. /data/_includes/{details → markdown/details} +0 -0
  133. /data/_includes/{enddetails → markdown/enddetails} +0 -0
  134. /data/_includes/{endtabs → markdown/endtabs} +0 -0
  135. /data/_includes/{tabs → markdown/tabs} +0 -0
  136. /data/assets/images/{avatar_back.png → avatars/back.png} +0 -0
  137. /data/assets/images/{avatar_dark.png → avatars/dark.png} +0 -0
  138. /data/assets/images/{avatar_light.png → avatars/light.png} +0 -0
  139. /data/assets/images/{icons → donate}/bitcoin.svg +0 -0
  140. /data/assets/images/{icons → donate}/card.svg +0 -0
  141. /data/assets/images/{icons → donate}/donation.svg +0 -0
  142. /data/assets/images/{icons → donate}/lightning_network.svg +0 -0
  143. /data/assets/images/{icons → donate}/paypal.svg +0 -0
  144. /data/assets/images/{icons → donate}/pix.svg +0 -0
  145. /data/assets/images/{qrcode_btc_binance.jpg → donate/qrcode_btc_binance.jpg} +0 -0
  146. /data/assets/images/{qrcode_inter.jpg → donate/qrcode_inter.jpg} +0 -0
  147. /data/assets/images/{qrcode_wos.jpg → donate/qrcode_wos.jpg} +0 -0
  148. /data/assets/images/{icons → donate}/wos.png +0 -0
  149. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-grid.css +0 -0
  150. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-grid.css.map +0 -0
  151. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-grid.min.css +0 -0
  152. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-grid.min.css.map +0 -0
  153. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-grid.rtl.css +0 -0
  154. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-grid.rtl.css.map +0 -0
  155. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-grid.rtl.min.css +0 -0
  156. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-grid.rtl.min.css.map +0 -0
  157. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-reboot.css +0 -0
  158. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-reboot.css.map +0 -0
  159. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-reboot.min.css +0 -0
  160. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-reboot.min.css.map +0 -0
  161. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-reboot.rtl.css +0 -0
  162. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-reboot.rtl.css.map +0 -0
  163. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-reboot.rtl.min.css +0 -0
  164. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-reboot.rtl.min.css.map +0 -0
  165. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-utilities.css +0 -0
  166. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-utilities.css.map +0 -0
  167. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-utilities.min.css +0 -0
  168. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-utilities.min.css.map +0 -0
  169. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-utilities.rtl.css +0 -0
  170. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-utilities.rtl.css.map +0 -0
  171. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-utilities.rtl.min.css +0 -0
  172. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap-utilities.rtl.min.css.map +0 -0
  173. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap.css +0 -0
  174. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap.css.map +0 -0
  175. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap.min.css +0 -0
  176. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap.min.css.map +0 -0
  177. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap.rtl.css +0 -0
  178. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap.rtl.css.map +0 -0
  179. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap.rtl.min.css +0 -0
  180. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/css/bootstrap.rtl.min.css.map +0 -0
  181. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.bundle.js +0 -0
  182. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.bundle.js.map +0 -0
  183. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.bundle.min.js +0 -0
  184. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.bundle.min.js.map +0 -0
  185. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.esm.js +0 -0
  186. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.esm.js.map +0 -0
  187. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.esm.min.js +0 -0
  188. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.esm.min.js.map +0 -0
  189. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.js +0 -0
  190. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.js.map +0 -0
  191. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.min.js +0 -0
  192. /data/assets/{vendor/bootstrap → vendors/bootstrap-5.2.3}/js/bootstrap.min.js.map +0 -0
  193. /data/lib/rawfeed/{csp_filters.rb → plugin/csp_filters.rb} +0 -0
  194. /data/lib/rawfeed/{typescript_liquid.rb → plugin/typescript_liquid.rb} +0 -0
  195. /data/lib/rawfeed/{with_class.rb → plugin/with_class.rb} +0 -0
@@ -1,154 +1,176 @@
1
- {%- include layout/data.liquid -%}
1
+ {%- include assigned -%}
2
2
 
3
- <head>
3
+ <head>
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1">
5
5
  <meta charset="utf-8">
6
- {%- if page.url == "/" -%}
7
- <title>{{ site_title | replace: "/", "" | default: theme_name }} | {{ site.baseurl | prepend: site.url }}</title>
6
+ {%- if page.url == '/' -%}
7
+ <title>
8
+ {{ site_title | replace: '/', '' | default: theme_name }}
9
+ |
10
+ {{ site.baseurl | prepend: site.url }}
11
+ </title>
8
12
  {%- else -%}
9
- <title>{{ page.title | replace: "/", "" | capitalize }} | {{ site_title | default: theme_name }}</title>
13
+ <title>
14
+ {{ page.title | replace: '/', '' | capitalize }}
15
+ |
16
+ {{ site_title | default: theme_name }}
17
+ </title>
10
18
  {%- endif -%}
11
19
 
12
20
  <!-- SEO -->
13
- <meta name="description" content="{{ page.description | capitalize | default: header_.description | strip_html | truncate: 50 }}">
14
- <meta name="author" content="{{ page.author | default: author_ }}">
21
+ <meta name="description" content="{{ page.description | capitalize | default: navbar.description | strip_html | truncate: 50 }}">
22
+ <meta name="author" content="{{ page.author | default: author }}">
15
23
  <meta property="og:title" content="{{ page.title | capitalize | default: site_title }}">
16
- <meta property="og:locale" content="{{ default_.lang | replace: "-", "_" | default: "en_US" }}">
24
+ <meta property="og:locale" content="{{ default.lang | replace: "-", "_" | default: "en_US" }}">
17
25
  <meta property="og:locale:alternate" content="en_US">
18
- <meta property="og:description" content="{{ page.description | capitalize | default: header_.description | strip_html | truncate: 50 }}">
26
+ <meta property="og:description" content="{{ page.description | capitalize | default: navbar.description | strip_html | truncate: 50 }}">
19
27
  <link rel="canonical" href="{{ page.url | prepend: site.url }}">
20
28
  <meta property="og:url" content="{{ page.url | prepend: site.url }}">
21
29
  <meta property="og:site_name" content="{{ site_title }}">
22
30
  <meta property="og:type" content="website">
23
31
  <meta name="twitter:card" content="summary">
24
32
  <meta name="twitter:title" content="{{ site_title }}">
25
- {% for item in socials_.links %}
26
- {% if item.url contains "x.com" %}
27
- {% assign username = item.url | remove: "https://x.com/" %}
28
- {% if username != blank %}
29
- <meta name="twitter:site" content="@{{ username }}"/>
33
+ {%- for item in socials.links -%}
34
+ {%- if item.url contains 'x.com' -%}
35
+ {%- assign username = item.url | remove: 'https://x.com/' -%}
36
+ {%- if username != blank -%}
37
+ <meta name="twitter:site" content="@{{ username }}">
30
38
  <meta name="twitter:creator" content="@{{ username }}">
31
- {% endif %}
32
- {% endif %}
33
- {% endfor %}
39
+ {%- endif -%}
40
+ {%- endif -%}
41
+ {%- endfor -%}
34
42
  <meta name="robots" content="index, follow">
35
43
  <script type="application/ld+json">
36
44
  {
37
- "@context": "https://schema.org",
38
- {% if page.url == "/blog/" %}
39
- "@type": "BlogPosting",
40
- "datePublished": "{{ page.date | date_to_xmlschema }}",
41
- "author": {
42
- "@type": "Person",
43
- "name": "{{ author_.name }}"
44
- },
45
- {% else %}
46
- "@type": "WebSite",
47
- {% endif %}
48
- "description": "{{ page.description | default: header_.description | strip_html | truncate: 160 | escape }}",
49
- "headline": "{{ page.title | default: site_title | escape }}",
50
- "name": "{{ site_title }}",
51
- "url": "{{ page.url | prepend: site.url }}"
52
- }
45
+ "@context": "https://schema.org",
46
+ {%- if page.url == "/blog/" -%}
47
+ "@type" : "BlogPosting",
48
+ "datePublished" : "{{ page.date | date_to_xmlschema }}",
49
+ "author" : {
50
+ "@type": "Person",
51
+ "name": "{{ author.name }}"
52
+ },
53
+ {%- else -%}
54
+ "@type" : "WebSite",
55
+ {%- endif -%}
56
+ "description": "{{ page.description | default: navbar.description | strip_html | truncate: 160 | escape }}",
57
+ "headline": "{{ page.title | default: site_title | escape }}",
58
+ "name": "{{ site_title }}",
59
+ "url": "{{ page.url | prepend: site.url }}"
60
+ }
53
61
  </script>
54
62
  <!-- SEO -->
55
63
 
56
- {% comment %} Security {% endcomment %}
64
+ {%- comment -%} Security {%- endcomment -%}
57
65
  {%- if jekyll.environment == 'production' %}
58
-
59
66
  <script src="{{ '/assets/js/no_inframe.js' | relative_url }}"></script>
60
67
 
61
- <meta http-equiv="Content-Security-Policy"
62
- content="
68
+ <meta http-equiv="Content-Security-Policy" content="
63
69
  default-src 'self';
64
- img-src 'self' data: {{ head_.csp.img-src | join: ' ' }};
65
- script-src 'self' 'unsafe-inline' {{ head_.csp.script-src | join: ' ' }};
66
- style-src 'self' 'unsafe-inline' {{ head_.csp.style-src | join: ' ' }};
67
- font-src 'self' {{ head_.csp.font-src | join: ' ' }} data:;
68
- connect-src 'self' {{ head_.csp.connect-src | join: ' ' }};
69
- frame-src {{ head_.csp.frame-src | join: ' ' }};
70
+ img-src 'self' data: {{ head.csp["img-src"] | join: ' ' }};
71
+ script-src 'self' 'unsafe-inline' {{ head.csp["script-src"] | join: ' ' }};
72
+ style-src 'self' 'unsafe-inline' {{ head.csp["style-src"] | join: ' ' }};
73
+ font-src 'self' {{ head.csp["font-src"] | join: ' ' }} data:;
74
+ connect-src 'self' {{ head.csp["connect-src"] | join: ' ' }};
75
+ frame-src {{ head.csp["frame-src"] | join: ' ' }};
70
76
  object-src 'none';
71
77
  base-uri 'self';
72
78
  form-action 'self';
73
- ">
74
- <!-- ⚠️ CSP,HSTS,COOP and enabled in the theme, remember to also configure it in Cloudflare or your server -->
79
+ ">
80
+ <!-- ⚠️ CSP,HSTS,COOP and enabled in the theme, remember to also configure it in Cloudflare or your server -->
75
81
  <meta http-equiv="Strict-Transport-Security" content="max-age=31536000; includeSubDomains; preload">
76
82
  <meta http-equiv="Cross-Origin-Opener-Policy" content="same-origin">
77
83
  <meta http-equiv="Cross-Origin-Embedder-Policy" content="require-corp">
78
84
  <!-- ⚠️ CSP,HSTS,COOP enabled in the theme, remember to also configure it in Cloudflare or your server -->
79
85
  {%- endif -%}
80
86
 
81
- {% comment %} favicon {% endcomment %}
82
- <link rel="icon" type="image/png" href="{{ '/assets/images/favicon.png' | relative_url }}">
87
+ {%- comment -%} favicon {%- endcomment -%}
88
+ <link
89
+ rel="icon"
90
+ type="image/png"
91
+ href="{{ '/assets/images/favicon.png' | relative_url }}">
83
92
  <link rel="apple-touch-icon" href="{{ '/assets/images/favicon.png' | relative_url }}">
84
93
 
85
- {%- if head_.google.site_verification != "" -%}
94
+ {%- if head.google.site_verification != '' -%}
86
95
  <!-- Google Site Verification -->
87
- <meta name="google-site-verification" content="{{ head_.google.site_verification }}">
96
+ <meta name="google-site-verification" content="{{ head.google.site_verification }}">
88
97
  <!-- Google Site Verification -->
89
98
  {%- endif -%}
90
99
 
91
- {% comment %} Fonts {% endcomment %}
100
+ {%- comment -%} Fonts {%- endcomment -%}
92
101
  {%- comment -%}
93
- TODO: version: 0.3.0: place fonts used in the project instead of using Google Fonts.
102
+ TODO: version: 0.3.0: place fonts used in the project instead of using Google Fonts.
94
103
  {%- endcomment -%}
95
104
  <link rel="preconnect" href="https://fonts.googleapis.com">
96
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
105
+ <link
106
+ rel="preconnect"
107
+ href="https://fonts.gstatic.com"
108
+ crossorigin>
97
109
  <link href="https://fonts.googleapis.com/css2?family=SUSE+Mono:ital,wght@0,100..800;1,100..800&display=swap" rel="stylesheet">
98
110
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inconsolata:400,700&amp;display=swap">
99
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"/>
111
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
100
112
 
101
- <!-- Google Fonts -->
113
+ <!-- Google Fonts -->
102
114
  <link rel="preconnect" href="https://fonts.googleapis.com">
103
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
115
+ <link
116
+ rel="preconnect"
117
+ href="https://fonts.gstatic.com"
118
+ crossorigin>
104
119
  <link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@200..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap" rel="stylesheet">
105
120
  <!-- Google Fonts -->
106
121
 
107
- {% comment %} bootstrap {% endcomment %}
108
- <link rel="stylesheet" href="{{ '/assets/vendor/bootstrap/css/bootstrap.min.css' | relative_url }}">
122
+ {%- comment -%} bootstrap {%- endcomment -%}
123
+ <link rel="stylesheet" href="{{ '/assets/vendors/bootstrap-5.2.3/css/bootstrap.min.css' | relative_url }}">
109
124
 
110
- {% comment %} fixes FOUC/flicker in firefox {% endcomment %}
125
+ {%- comment -%} fixes FOUC/flicker in firefox {%- endcomment -%}
111
126
  <script src="{{ '/assets/js/theme_load.js' | relative_url }}"></script>
112
127
 
113
- {% comment %} load theme {% endcomment %}
114
- <link rel="stylesheet" href="{{ '/assets/css/style.css' | relative_url }}">
128
+ {%- comment -%} load theme {%- endcomment -%}
129
+ <link rel="stylesheet" href="{{ '/assets/css/style.css' | relative_url }}">
115
130
 
116
- {% comment %} custom theme {% endcomment %}
131
+ {%- comment -%} custom theme {%- endcomment -%}
117
132
  {%- assign file_path = '/assets/css/custom.css' -%}
118
- {%- assign file_exists = site.static_files | where: "path", file_path | size -%}
133
+ {%- assign file_exists = site.static_files | where: 'path', file_path | size -%}
119
134
  {%- if file_exists > 0 -%}
120
135
  <link rel="stylesheet" href="{{ '/assets/css/custom.css' | relative_url }}">
121
136
  {%- endif -%}
122
137
 
123
- {% comment %} feed {% endcomment %}
124
- <link rel="alternate" type="application/atom+xml" title="{{ site_title }}" href="{{ '/feed.xml' | relative_url }}">
138
+ {%- comment -%} feed {%- endcomment -%}
139
+ <link
140
+ rel="alternate"
141
+ type="application/atom+xml"
142
+ title="{{ site_title }}"
143
+ href="{{ '/feed.xml' | relative_url }}">
125
144
 
126
145
  <!-- Google Analytics -->
127
- {%- if jekyll.environment == 'production' and head_.google.analytics.enable == true and head_.google.analytics.id != "" -%}
146
+ {%- if jekyll.environment == 'production' and head.google.analytics.enable == true and head.google.analytics.id != ''
147
+ -%}
128
148
  <script>
129
- (function() {
149
+ (function () {
130
150
  function activeTrackers() {
131
- var ga_id = "{{ head_.google.analytics.id }}";
151
+ var ga_id = '{{ head.google.analytics.id }}';
132
152
 
133
153
  var script = document.createElement('script');
134
154
  script.async = true;
135
- script.src = "https://www.googletagmanager.com/gtag/js?id=" + ga_id;
155
+ script.src = 'https://www.googletagmanager.com/gtag/js?id=' + ga_id;
136
156
  document.head.appendChild(script);
137
157
 
138
158
  window.dataLayer = window.dataLayer || [];
139
- function gtag(){dataLayer.push(arguments);}
159
+ function gtag() {
160
+ dataLayer.push(arguments);
161
+ }
140
162
  gtag('js', new Date());
141
163
  gtag('config', ga_id, {
142
- 'cookie_domain': '{{ site.url | replace: "https://", "" | replace: "http://", "" | split: "/" | first }}',
143
- 'anonymize_ip': true,
144
- 'cookie_flags': 'SameSite=None;Secure',
145
- 'update': true
164
+ cookie_domain: '{{ site.url | replace: "https://", "" | replace: "http://", "" | split: "/" | first }}',
165
+ anonymize_ip: true,
166
+ cookie_flags: 'SameSite=None;Secure',
167
+ update: true,
146
168
  });
147
169
 
148
- console.log("Google Analytics loaded!");
170
+ console.log('Google Analytics loaded!');
149
171
  }
150
172
 
151
- // Chama direto, sem esperar o DOMContentLoaded, para capturar a visita o quanto antes
173
+ // Call directly, without waiting for DOMContentLoaded, to capture the visit as soon as possible.
152
174
  activeTrackers();
153
175
  })();
154
176
  </script>
@@ -1,23 +1,26 @@
1
- {% include layout/data.liquid %}
1
+ {% include assigned %}
2
2
 
3
- <!DOCTYPE html>
4
- <html lang="{{ default_.lang | default: 'en-US' }}" data-theme="light">
3
+ <!doctype html>
4
+ <html lang="{{ default.lang | default: 'en-US' }}" data-theme="light">
5
5
  {%- include layout/head.html -%}
6
6
  <body>
7
- <div class="mt-4 maintenance" style="font-family: {{ default_.font.style }} !important; font-size: {{ default_.font.size }} !important; letter-spacing:{{ default_.font.spacing }} !important;">
7
+ <div class="mt-4 maintenance" style="font-family: {{ default.font.style }} !important; font-size: {{ default.font.size }} !important; letter-spacing:{{ default.font.spacing }} !important;">
8
8
  <div class="container">
9
- {%- if maintenance_.gif != "" -%}
10
- <div class="row">
11
- <div class="col-sm text-center">
12
- <img class="maintenance-gif" src="{{ maintenance_.gif | relative_url }}" alt="under maintenance">
9
+ {%- if maintenance.gif != '' -%}
10
+ <div class="row">
11
+ <div class="col-sm text-center">
12
+ <img
13
+ class="maintenance-gif"
14
+ src="{{ maintenance.gif | relative_url }}"
15
+ alt="under maintenance">
16
+ </div>
13
17
  </div>
14
- </div>
15
18
  {%- endif -%}
16
19
  <div class="row mt-5 text-center">
17
- <h1 class="maintenance-title">[&nbsp;{{ maintenance_.title }}&nbsp;]</h1>
20
+ <h1 class="maintenance-title">[&nbsp;{{ maintenance.title }}&nbsp;]</h1>
18
21
  </div>
19
22
  <div class="row text-center">
20
- <h3 class="maintenance-subtitle">{{ maintenance_.subtitle | markdownify }}</h3>
23
+ <h3 class="maintenance-subtitle">{{ maintenance.subtitle | markdownify }}</h3>
21
24
  </div>
22
25
  </div>
23
26
  </div>
@@ -0,0 +1,253 @@
1
+ {%- include assigned -%}
2
+
3
+ {%- assign index = site.pages | where: 'path', 'index.md' | first -%}
4
+
5
+ {%- for item in site.defaults -%}
6
+ {%- if item.scope.path == '_posts' -%}
7
+ {%- assign blog_page = item.values.published -%}
8
+ {%- endif -%}
9
+ {%- if item.scope.path == '_pixels' -%}
10
+ {%- assign pixels_page = item.values.published -%}
11
+ {%- endif -%}
12
+ {%- endfor -%}
13
+
14
+ {%- assign menu_separator = default.separator -%}
15
+
16
+ <!-- modal avatar -->
17
+ <div
18
+ class="modal fade"
19
+ id="avatarModal"
20
+ tabindex="-1"
21
+ aria-hidden="true">
22
+ <div class="modal-dialog modal-dialog-centered">
23
+ <div class="modal-content bg-transparent border-0 shadow-none">
24
+ <div class="modal-body d-flex justify-content-center">
25
+ <img
26
+ id="modalAvatar"
27
+ class="avatar-img{% if default.rounding %} rounding{% endif %}"
28
+ src=""
29
+ alt="">
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ <!-- modal avatar -->
35
+
36
+ <header class="navigation" style="max-width: {{ navbar.width | default: "860" }}px !important; font-family: {{ default.font.style }} !important; font-size: {{ default.font.size }} !important; letter-spacing:{{ default.font.spacing }} !important;">
37
+ <div class="row ">
38
+ <!-- column home -->
39
+ <div class="col-sm-3 d-flex flex-column justify-content-end navigation__column-home">
40
+ {%- if index.layout == 'blog' -%}
41
+ <span>[{{ navbar.menu.home.emoji | with_class: 'spacer' -}}
42
+ <a class="{% if page.url == "/" or page.url == "/index.html" %}menu-active{% endif %}" href="{{home_url}}">
43
+ {{- navbar.menu.blog.title | default: 'blog' | downcase -}}</a>&nbsp;]</span>
44
+ {%- else -%}
45
+ <span>[{{ navbar.menu.home.emoji | with_class: 'spacer' -}}
46
+ <a class="{% if page.url == "/" or page.url == "/index.html" %}menu-active{% endif %}" href="{{home_url}}">
47
+ {{- navbar.menu.home.title | default: 'home' | downcase -}}</a>&nbsp;]</span>
48
+ {%- endif -%}
49
+ </div>
50
+ <!-- column home -->
51
+
52
+ <!-- column description -->
53
+ <div class="col-sm-6 d-flex flex-column justify-content-end">
54
+ <span class="title">{{ navbar.title | default: theme_name }}</span>
55
+ <small class="description">
56
+ {{ navbar.description | default: 'A batteries-included Jekyll framework and CLI' }}
57
+ </small>
58
+ </div>
59
+ <!-- column description -->
60
+
61
+ <!-- column avatar -->
62
+ <div class="col-sm-3 d-flex justify-content-end avatar">
63
+ {%- assign images_ = site.static_files | map: 'path' -%}
64
+ {%- assign avatar_path_light = navbar.avatar.image.front.light -%}
65
+ {%- assign avatar_path_dark = navbar.avatar.image.front.dark -%}
66
+ {%- assign avatar_path_back = navbar.avatar.image.back -%}
67
+
68
+ {%- if images_ contains avatar_path_light and images_ contains avatar_path_dark and images_ contains avatar_path_back
69
+ -%}
70
+ <div class="avatar-wrapper">
71
+ <div class="avatar-flipper light-theme {% if navbar.avatar.open %}avatar-flipper__open-true{% endif %}{% if navbar.avatar.flip %} can-flip{% endif %}">
72
+ <div class="avatar-card">
73
+ <div class="avatar-front">
74
+ <img
75
+ id="avatarImgLight"
76
+ class="avatar-img{% if default.rounding %} rounding{% endif %}"
77
+ src="{{ avatar_path_light | relative_url }}"
78
+ alt="{{ site_title }}">
79
+ </div>
80
+ <div class="avatar-back">
81
+ <img
82
+ class="avatar-img{% if default.rounding %} rounding{% endif %}"
83
+ src="{{ avatar_path_back | relative_url }}"
84
+ alt="{{ site_title }}">
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <div class="avatar-flipper dark-theme {% if navbar.avatar.open %} avatar-flipper__open-true{% endif %}{% if navbar.avatar.flip %} can-flip{% endif %}">
90
+ <div class="avatar-card">
91
+ <div class="avatar-front">
92
+ <img
93
+ id="avatarImgDark"
94
+ class="avatar-img{% if default.rounding %} rounding{% endif %}"
95
+ src="{{ avatar_path_dark | relative_url }}"
96
+ alt="{{ site_title }}">
97
+ </div>
98
+ <div class="avatar-back">
99
+ <img
100
+ class="avatar-img{% if default.rounding %} rounding{% endif %}"
101
+ src="{{ avatar_path_back | relative_url }}"
102
+ alt="{{ site_title }}">
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ {%- endif -%}
108
+ </div>
109
+ <!-- column avatar -->
110
+ </div>
111
+
112
+ <!-- row separator -->
113
+ <div class="row ">
114
+ <div class="col-sm d-flex justify-content-center">
115
+ <div class="line-separator"></div>
116
+ </div>
117
+ </div>
118
+ <!-- row separator -->
119
+
120
+ <!-- row menu -->
121
+ <div class="row">
122
+ <div class="col-sm d-flex justify-content-center menu">
123
+ {%- if index.layout == 'blog' -%}
124
+ <div>
125
+ {{ navbar.menu.title }}&nbsp;»&nbsp;
126
+ <div class="menu-wrap-link">
127
+ {{ navbar.menu.blog.search.emoji | with_class: 'spacer' }}
128
+ {%- if blog.search.enable -%}
129
+ <a id="blog-search__btn" href="{{search_url}}">{{- navbar.menu.blog.search.title | default: 'search' -}}</a><strong class="separator">{{- menu_separator -}}</strong>
130
+ {%- endif -%}
131
+ </div>
132
+ <div class="menu-wrap-link">
133
+ {{ navbar.menu.blog.tags.emoji | with_class: 'spacer' -}}
134
+ <a class="{% if page.url == "/blog/tags/" or page.url == "/blog/tags/index.html" %} menu-active{% endif %}" href="{{tags_url}}">{{- navbar.menu.blog.tags.title | default: 'tags' -}}</a><strong class="separator">{{- menu_separator -}}</strong>
135
+ </div>
136
+ {%- assign sorted_pages = site.pages | sort: 'order' -%}
137
+ {%- for item in sorted_pages -%}
138
+ {%- if item.path contains '_pages/' and item.published != false and item.in_menu -%}
139
+ {%- unless item.url contains '/tags/' or item.url contains '404.html' -%}
140
+ <div class="menu-wrap-link">
141
+ {{ item.emoji | with_class: 'spacer' -}}
142
+ <a class="{% if page.url == item.url %}menu-active{% endif %}" href="{{ item.url | relative_url }}">{{- item.title | downcase -}}</a><strong class="separator">{{- menu_separator -}}</strong>
143
+ </div>
144
+ {%- endunless -%}
145
+ {%- endif -%}
146
+ {%- endfor -%}
147
+ <div class="menu-wrap-link">
148
+ {{ navbar.menu.blog.feed.emoji | with_class: 'spacer' -}}
149
+ <a href="{{feed_url}}">{{- navbar.menu.blog.feed.title | default: 'feed' -}}</a><strong class="separator">{{- menu_separator -}}</strong>
150
+ </div>
151
+ </div>
152
+ {%- else -%}
153
+ {%- if page.url contains '/blog/' -%}
154
+ <div>
155
+ {{ navbar.menu.blog.title | replace: '/', '' | replace: 'ls ', '' }}&nbsp;»
156
+ <div class="menu-wrap-link">
157
+ {{ navbar.menu.blog.emoji | with_class: 'spacer' -}}
158
+ <a class="{% if page.url == "/blog/" or page.url == "/blog/index.html" or page.url contains "/blog/page/" %} menu-active{% endif %}" href="{{blog_url}}">{{- navbar.menu.blog.subtitle -}}</a><strong class="separator">{{- menu_separator -}}</strong>
159
+ </div>
160
+ {%- if blog.search.enable -%}
161
+ <span style="display: inline-block;">
162
+ {{- navbar.menu.blog.search.emoji | with_class: 'spacer' -}}
163
+ <a id="blog-search__btn" href="{{search_url}}">{{- navbar.menu.blog.search.title | default: 'search' -}}</a><strong class="separator">{{- menu_separator -}}</strong>
164
+ </span>
165
+ {%- endif -%}
166
+ <div class="menu-wrap-link">
167
+ {{ navbar.menu.blog.tags.emoji | with_class: 'spacer' -}}
168
+ <a class="{% if page.url == "/blog/tags/" or page.url == "/blog/tags/index.html" %} menu-active{% endif %}" href="{{tags_url}}">{{- navbar.menu.blog.tags.title | default: 'tags' -}}</a><strong class="separator">{{- menu_separator -}}</strong>
169
+ </div>
170
+ <div class="menu-wrap-link">
171
+ {{ navbar.menu.blog.feed.emoji | with_class: 'spacer' -}}
172
+ <a href="{{feed_url}}">{{- navbar.menu.blog.feed.title | default: 'feed' -}}</a><strong class="separator">{{- menu_separator -}}</strong>
173
+ </div>
174
+ </div>
175
+ {%- else -%}
176
+ <div>
177
+ {%- assign published_pages = site.pages | where_exp: 'p', "p.path contains '_pages/' and p.published" -%}
178
+ {%- if published_pages.size > 0 -%}
179
+ <span>{{ navbar.menu.title }}&nbsp;»&nbsp;</span>
180
+ {%- endif -%}
181
+ {%- if site.pagination.enabled == true -%}
182
+ {%- if blog_page -%}
183
+ <div class="menu-wrap-link">
184
+ {{ navbar.menu.blog.emoji | with_class: 'spacer' -}}
185
+ <a href="{{blog_url}}">{{- navbar.menu.blog.title | replace: 'ls ', '' -}}</a><strong class="separator">{{- menu_separator -}}</strong>
186
+ </div>
187
+ {%- endif -%}
188
+ {%- if pixels_page -%}
189
+ <div class="menu-wrap-link">
190
+ {{ navbar.menu.pixels.emoji | with_class: 'spacer' -}}
191
+ <a href="{{pixels_url}}">{{- navbar.menu.pixels.title -}}</a><strong class="separator">{{- menu_separator -}}</strong>
192
+ </div>
193
+ {%- endif -%}
194
+ {%- assign sorted_pages = site.pages | sort: 'order' -%}
195
+ {%- for item in sorted_pages -%}
196
+ {%- if item.path contains '_pages/' and item.in_menu -%}
197
+ {%- unless item.url contains 'blog' or item.url contains '404.html' -%}
198
+ <div class="menu-wrap-link">
199
+ {{ item.emoji | with_class: 'spacer' -}}
200
+ <a class="{% if page.url == item.url %}menu-active{% endif %}" href="{{ item.url | relative_url }}">{{- item.title | downcase -}}</a><strong class="separator">{{- menu_separator -}}</strong>
201
+ </div>
202
+ {%- endunless -%}
203
+ {%- endif -%}
204
+ {%- endfor -%}
205
+ {%- else -%}
206
+ {%- if blog_page -%}
207
+ <div class="menu-wrap-link">
208
+ {{ navbar.menu.blog.emoji | with_class: 'spacer' -}}
209
+ <a href="{{blog_url}}">{{- navbar.menu.blog.title | replace: '/', '' -}}</a><strong class="separator">{{- menu_separator -}}</strong>
210
+ </div>
211
+ {%- endif -%}
212
+ {%- if pixels_page -%}
213
+ <div class="menu-wrap-link">
214
+ {{ navbar.menu.pixels.emoji | with_class: 'spacer' -}}
215
+ <a href="{{pixels_url}}">pixels</a><strong class="separator">{{- menu_separator -}}</strong>
216
+ </div>
217
+ {%- endif -%}
218
+ {%- assign sorted_pages = site.pages | sort: 'order' -%}
219
+ {%- for item in sorted_pages -%}
220
+ {%- if item.path contains '_pages/' and item.published != false and item.in_menu -%}
221
+ {%- unless item.url contains '/tags/' or item.url contains '404.html' -%}
222
+ <div class="menu-wrap-link">
223
+ {{ item.emoji | with_class: 'spacer' -}}
224
+ <a class="{% if page.url == item.url %}menu-active{% endif %}" href="{{ item.url | relative_url }}">{{- item.title | downcase -}}</a><strong class="separator">{{- menu_separator -}}</strong>
225
+ </div>
226
+ {%- endunless -%}
227
+ {%- endif -%}
228
+ {%- endfor -%}
229
+ {%- endif -%}
230
+ {%- assign files_in_pub = site.static_files | where_exp: 'item', 'item.path contains pub_url' -%}
231
+ {%- if files_in_pub.size > 0 -%}
232
+ <div class="menu-wrap-link">
233
+ {{ navbar.menu.pub.emoji | with_class: 'spacer' -}}
234
+ <a href="{{ pub_url | relative_url }}">{{ navbar.menu.pub.title }}</a>
235
+ </div>
236
+ {%- endif -%}
237
+ </div>
238
+ {%- endif -%}
239
+ {%- endif -%}
240
+ </div>
241
+ </div>
242
+ <!-- row menu -->
243
+
244
+ <!-- row button light/dark -->
245
+ <div class="row justify-content-end">
246
+ <div class="col-sm-2 d-flex justify-content-end">
247
+ <span id="toggle-theme">
248
+ <i class="fa-solid fa-moon"></i>
249
+ </span>
250
+ </div>
251
+ </div>
252
+ <!-- row button light/dark -->
253
+ </header>
@@ -1,4 +1,4 @@
1
- {% include layout/data.liquid %}
1
+ {% include assigned %}
2
2
 
3
3
  {%- if page.pagination.enabled == true and site.pagination.enabled == true -%}
4
4
  {%- assign total_page = paginator.total_pages -%}
@@ -6,30 +6,29 @@
6
6
  <nav>
7
7
  <ul class="pagination justify-content-center blog-pagination">
8
8
  {%- if paginator.previous_page -%}
9
- <li class="page-item">
10
- <a class="page-link blog-pagination__newer" href="{{ paginator.previous_page_path | prepend: site.baseurl | prepend: site.url }}">
11
- &larr;&nbsp;{{ blog_.pagination.newer_text }}
12
- </a>
13
- </li>
9
+ <li class="page-item">
10
+ <a class="page-link blog-pagination__newer" href="{{ paginator.previous_page_path | prepend: site.baseurl | prepend: site.url }}">
11
+ &larr;&nbsp;{{ blog.pagination.newer_text }}</a>
12
+ </li>
14
13
  {%- endif -%}
15
14
 
16
15
  {%- if total_page > 1 -%}
17
16
  <li class="page-item">
18
17
  <span class="page-link blog-pagination__counter">
19
- &nbsp;[&nbsp;{{ blog_.pagination.counter[0] }}
18
+ &nbsp;[&nbsp;{{ blog.pagination.counter[0] }}
20
19
  {{ paginator.page }}
21
- {{ blog_.pagination.counter[1] }}
20
+ {{ blog.pagination.counter[1] }}
22
21
  {{ total_page }}&nbsp;]&nbsp;
23
22
  </span>
24
23
  </li>
25
24
  {%- endif -%}
26
25
 
27
26
  {%- if paginator.next_page -%}
28
- <li class="page-item">
29
- <a class="page-link blog-pagination__older" href="{{ paginator.next_page_path | prepend: site.baseurl | prepend: site.url }}">
30
- {{ blog_.pagination.older_text }}&nbsp;&rarr;
31
- </a>
32
- </li>
27
+ <li class="page-item">
28
+ <a class="page-link blog-pagination__older" href="{{ paginator.next_page_path | prepend: site.baseurl | prepend: site.url }}">
29
+ {{ blog.pagination.older_text }}&nbsp;&rarr;
30
+ </a>
31
+ </li>
33
32
  {%- endif -%}
34
33
  </ul>
35
34
  </nav>
@@ -1,5 +1,5 @@
1
- {%- include layout/data.liquid -%}
1
+ {%- include assigned -%}
2
2
 
3
- <div class="alert alert-{{ include.type | default: 'info' }}{% if default_.rounding %} rounding-plugins{% endif %}">
3
+ <div class="alert alert-{{ include.type | default: 'info' }}{% if default.rounding %} rounding-plugins{% endif %}">
4
4
  {{ include.content | markdownify }}
5
5
  </div>
@@ -1,7 +1,7 @@
1
- {%- include layout/data.liquid -%}
1
+ {%- include assigned -%}
2
2
 
3
3
  <canvas
4
- class="chart{% if default_.rounding %} rounding-plugins{% endif %}"
4
+ class="chart{% if default.rounding %} rounding-plugins{% endif %}"
5
5
  id="chart-{{ include.label | slugify }}"
6
6
  data-label="{{ include.label | default: 'Dataset' }}"
7
7
  data-type="{{ include.type | default: 'line' }}"
@@ -11,5 +11,5 @@
11
11
  >
12
12
  </canvas>
13
13
 
14
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
14
+ <script>if(!window.Chart){var s=document.createElement('script');s.src='https://cdn.jsdelivr.net/npm/chart.js';document.head.appendChild(s);}</script>
15
15