jekyll-ai-visible-content 0.4.6 → 0.4.8
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Gemfile.lock +1 -1
- data/README.md +7 -0
- data/lib/jekyll_ai_visible_content/configuration.rb +1 -0
- data/lib/jekyll_ai_visible_content/hooks/post_render_hook.rb +72 -9
- data/lib/jekyll_ai_visible_content/version.rb +1 -1
- metadata +2 -17
- data/.playwright-mcp/console-2026-04-07T14-47-00-050Z.log +0 -2
- data/.playwright-mcp/console-2026-04-07T14-47-21-660Z.log +0 -2
- data/.playwright-mcp/console-2026-04-07T14-50-13-784Z.log +0 -2
- data/.playwright-mcp/console-2026-04-07T14-50-27-912Z.log +0 -3
- data/.playwright-mcp/console-2026-04-07T15-07-51-108Z.log +0 -2
- data/.playwright-mcp/console-2026-04-07T15-07-59-236Z.log +0 -2
- data/.playwright-mcp/console-2026-04-07T15-08-12-452Z.log +0 -2
- data/.playwright-mcp/page-2026-04-07T14-47-02-356Z.yml +0 -297
- data/.playwright-mcp/page-2026-04-07T14-47-22-295Z.yml +0 -989
- data/.playwright-mcp/page-2026-04-07T14-50-14-081Z.yml +0 -989
- data/.playwright-mcp/page-2026-04-07T14-50-28-154Z.yml +0 -159
- data/.playwright-mcp/page-2026-04-07T15-07-52-686Z.yml +0 -323
- data/.playwright-mcp/page-2026-04-07T15-07-59-677Z.yml +0 -346
- data/.playwright-mcp/page-2026-04-07T15-08-06-166Z.yml +0 -1
- data/.playwright-mcp/page-2026-04-07T15-08-12-836Z.yml +0 -381
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9afcf72aab91e0280ce7b14771e3b7ddd940e00093bec970feb0a5d4e0242e4d
|
|
4
|
+
data.tar.gz: 1b5229d2111d8e4b70518ea864863e79e7274c1c31d93f3e0658352ff7f78683
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0ccc34ccf335efbbd8b9e7151ab3d116ef2163bb02897f267b884aaa69b2a04ebf09ea7ec1d099b18904bd0a379de93a5de616b58b268c58446bf7b73d4b516a
|
|
7
|
+
data.tar.gz: 286af1a67ed7b1e39be4a8abe206f2bad467ef241ac1bc7a0f794578772337741d560c51172efd370f86e78fc31e7dc836e9a519813b7d27fbfc8d8a7832a277
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -132,6 +132,7 @@ ai_visible_content:
|
|
|
132
132
|
# --- Internal Linking ---
|
|
133
133
|
linking:
|
|
134
134
|
enable_entity_links: true # Auto-link known entities in post body
|
|
135
|
+
apply_to_metadata: false # Safe default: never inject <a> into head/SEO/JSON-LD/feed fields
|
|
135
136
|
entity_definitions: {} # Custom: slug -> {name, url, description}
|
|
136
137
|
max_links_per_entity_per_post: 1
|
|
137
138
|
enable_related_posts: true
|
|
@@ -151,6 +152,12 @@ ai_visible_content:
|
|
|
151
152
|
max_examples: 3 # Max examples per warning group in summary mode
|
|
152
153
|
```
|
|
153
154
|
|
|
155
|
+
### Entity Linking Safety
|
|
156
|
+
|
|
157
|
+
`linking.apply_to_metadata` defaults to `false` to keep metadata as plain text. With this default, entity auto-linking is applied to article body content only and is not applied to `<head>` meta tags, JSON-LD descriptions, or feed summaries.
|
|
158
|
+
|
|
159
|
+
Set `linking.apply_to_metadata: true` only if you explicitly want legacy full-document linking behavior.
|
|
160
|
+
|
|
154
161
|
## Layout Integration
|
|
155
162
|
|
|
156
163
|
### Automatic Mode (Recommended)
|
|
@@ -75,6 +75,48 @@ module JekyllAiVisibleContent
|
|
|
75
75
|
registry = Entity::Registry.new(config)
|
|
76
76
|
definitions = registry.entity_definitions
|
|
77
77
|
max_per = config.linking['max_links_per_entity_per_post'] || 1
|
|
78
|
+
apply_to_metadata = config.linking['apply_to_metadata'] == true
|
|
79
|
+
|
|
80
|
+
if apply_to_metadata
|
|
81
|
+
Jekyll.logger.warn(
|
|
82
|
+
'ai_visible_content',
|
|
83
|
+
'linking.apply_to_metadata=true may inject HTML into metadata fields'
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
doc.output = link_entities(
|
|
88
|
+
doc.output,
|
|
89
|
+
definitions: definitions,
|
|
90
|
+
max_per: max_per,
|
|
91
|
+
context: (apply_to_metadata ? :legacy_full_document : :body)
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def link_entities(text, definitions:, max_per:, context:)
|
|
96
|
+
return text unless text
|
|
97
|
+
|
|
98
|
+
case context
|
|
99
|
+
when :body
|
|
100
|
+
link_entities_in_body(text, definitions, max_per)
|
|
101
|
+
when :metadata
|
|
102
|
+
sanitize_metadata_text(text)
|
|
103
|
+
when :legacy_full_document
|
|
104
|
+
replace_entities_in_fragment(text, definitions, max_per)
|
|
105
|
+
else
|
|
106
|
+
text
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def link_entities_in_body(html, definitions, max_per)
|
|
111
|
+
return html unless html.include?('<body')
|
|
112
|
+
|
|
113
|
+
html.sub(%r{<body\b[^>]*>.*</body>}im) do |body_fragment|
|
|
114
|
+
replace_entities_in_fragment(body_fragment, definitions, max_per)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def replace_entities_in_fragment(fragment, definitions, max_per)
|
|
119
|
+
result = fragment.dup
|
|
78
120
|
|
|
79
121
|
definitions.each_value do |defn|
|
|
80
122
|
name = defn['name']
|
|
@@ -83,25 +125,42 @@ module JekyllAiVisibleContent
|
|
|
83
125
|
|
|
84
126
|
link_html = %(<a href="#{url}" itemprop="about" itemscope ) +
|
|
85
127
|
%(itemtype="https://schema.org/Thing"><span itemprop="name">#{name}</span></a>)
|
|
86
|
-
|
|
87
|
-
doc.output = replace_entity_outside_anchor(doc.output, name, max_per, link_html)
|
|
128
|
+
result = replace_entity_outside_anchor(result, name, max_per, link_html)
|
|
88
129
|
end
|
|
130
|
+
|
|
131
|
+
result
|
|
89
132
|
end
|
|
90
133
|
|
|
91
134
|
def replace_entity_outside_anchor(html, name, max_per, link_html)
|
|
92
|
-
pattern = /(
|
|
93
|
-
chunks = html.split(
|
|
135
|
+
pattern = /(^|[\s>])(#{Regexp.escape(name)})(?=[\s,.<])/i
|
|
136
|
+
chunks = html.split(/(<[^>]+>)/m)
|
|
94
137
|
replaced = 0
|
|
138
|
+
skip_text_replacement = false
|
|
139
|
+
|
|
140
|
+
chunks.map! do |chunk|
|
|
141
|
+
if chunk.start_with?('<')
|
|
142
|
+
opening_name = chunk[/\A<\s*([a-z0-9:-]+)/i, 1]&.downcase
|
|
143
|
+
closing_name = chunk[%r{\A<\s*/\s*([a-z0-9:-]+)}i, 1]&.downcase
|
|
144
|
+
|
|
145
|
+
if %w[a script style template].include?(opening_name) && chunk !~ %r{/\s*>\z}
|
|
146
|
+
skip_text_replacement = true
|
|
147
|
+
elsif %w[a script style template].include?(closing_name)
|
|
148
|
+
skip_text_replacement = false
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
next chunk
|
|
152
|
+
end
|
|
95
153
|
|
|
96
|
-
|
|
97
|
-
next chunk if idx.odd?
|
|
154
|
+
next chunk if skip_text_replacement
|
|
98
155
|
|
|
99
|
-
chunk.gsub(pattern) do
|
|
156
|
+
chunk.gsub(pattern) do
|
|
157
|
+
prefix = ::Regexp.last_match(1)
|
|
158
|
+
match = ::Regexp.last_match(2)
|
|
100
159
|
if replaced < max_per
|
|
101
160
|
replaced += 1
|
|
102
|
-
link_html
|
|
161
|
+
"#{prefix}#{link_html}"
|
|
103
162
|
else
|
|
104
|
-
match
|
|
163
|
+
"#{prefix}#{match}"
|
|
105
164
|
end
|
|
106
165
|
end
|
|
107
166
|
end
|
|
@@ -109,6 +168,10 @@ module JekyllAiVisibleContent
|
|
|
109
168
|
chunks.join
|
|
110
169
|
end
|
|
111
170
|
|
|
171
|
+
def sanitize_metadata_text(text)
|
|
172
|
+
text.to_s.gsub(/<[^>]*>/, ' ').gsub(/\s+/, ' ').strip
|
|
173
|
+
end
|
|
174
|
+
|
|
112
175
|
def inject_ai_resource_links(doc, config)
|
|
113
176
|
resources = doc.site.data['ai_page_resources']
|
|
114
177
|
return unless resources
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jekyll-ai-visible-content
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- madmatvey
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: jekyll
|
|
@@ -39,21 +39,6 @@ extensions: []
|
|
|
39
39
|
extra_rdoc_files: []
|
|
40
40
|
files:
|
|
41
41
|
- ".gitignore"
|
|
42
|
-
- ".playwright-mcp/console-2026-04-07T14-47-00-050Z.log"
|
|
43
|
-
- ".playwright-mcp/console-2026-04-07T14-47-21-660Z.log"
|
|
44
|
-
- ".playwright-mcp/console-2026-04-07T14-50-13-784Z.log"
|
|
45
|
-
- ".playwright-mcp/console-2026-04-07T14-50-27-912Z.log"
|
|
46
|
-
- ".playwright-mcp/console-2026-04-07T15-07-51-108Z.log"
|
|
47
|
-
- ".playwright-mcp/console-2026-04-07T15-07-59-236Z.log"
|
|
48
|
-
- ".playwright-mcp/console-2026-04-07T15-08-12-452Z.log"
|
|
49
|
-
- ".playwright-mcp/page-2026-04-07T14-47-02-356Z.yml"
|
|
50
|
-
- ".playwright-mcp/page-2026-04-07T14-47-22-295Z.yml"
|
|
51
|
-
- ".playwright-mcp/page-2026-04-07T14-50-14-081Z.yml"
|
|
52
|
-
- ".playwright-mcp/page-2026-04-07T14-50-28-154Z.yml"
|
|
53
|
-
- ".playwright-mcp/page-2026-04-07T15-07-52-686Z.yml"
|
|
54
|
-
- ".playwright-mcp/page-2026-04-07T15-07-59-677Z.yml"
|
|
55
|
-
- ".playwright-mcp/page-2026-04-07T15-08-06-166Z.yml"
|
|
56
|
-
- ".playwright-mcp/page-2026-04-07T15-08-12-836Z.yml"
|
|
57
42
|
- ".rubocop.yml"
|
|
58
43
|
- CHANGELOG.md
|
|
59
44
|
- Gemfile
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
[ 2214ms] [WARNING] For security reasons, Hotjar only works over HTTPS. Learn more: https://help.hotjar.com/hc/en-us/articles/115011624047 @ https://static.hotjar.com/c/hotjar-5066415.js?sv=7:2
|
|
2
|
-
[ 2225ms] [WARNING] <meta name="apple-mobile-web-app-capable" content="yes"> is deprecated. Please include <meta name="mobile-web-app-capable" content="yes"> @ http://127.0.0.1:4000/:0
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
[ 144ms] [WARNING] For security reasons, Hotjar only works over HTTPS. Learn more: https://help.hotjar.com/hc/en-us/articles/115011624047 @ https://static.hotjar.com/c/hotjar-5066415.js?sv=7:2
|
|
2
|
-
[ 594ms] [WARNING] <meta name="apple-mobile-web-app-capable" content="yes"> is deprecated. Please include <meta name="mobile-web-app-capable" content="yes"> @ http://127.0.0.1:4000/posts/redis-is-single-threaded/:0
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
[ 241ms] [WARNING] For security reasons, Hotjar only works over HTTPS. Learn more: https://help.hotjar.com/hc/en-us/articles/115011624047 @ https://static.hotjar.com/c/hotjar-5066415.js?sv=7:2
|
|
2
|
-
[ 242ms] [WARNING] <meta name="apple-mobile-web-app-capable" content="yes"> is deprecated. Please include <meta name="mobile-web-app-capable" content="yes"> @ http://127.0.0.1:4000/posts/redis-is-single-threaded/:0
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
[ 93ms] [ERROR] Failed to load resource: the server responded with a status of 404 (Not Found) @ http://127.0.0.1:4000/ai/topic/redis-is-single-threaded.json:0
|
|
2
|
-
[ 149ms] [WARNING] For security reasons, Hotjar only works over HTTPS. Learn more: https://help.hotjar.com/hc/en-us/articles/115011624047 @ https://static.hotjar.com/c/hotjar-5066415.js?sv=7:2
|
|
3
|
-
[ 223ms] [WARNING] <meta name="apple-mobile-web-app-capable" content="yes"> is deprecated. Please include <meta name="mobile-web-app-capable" content="yes"> @ http://127.0.0.1:4000/ai/topic/redis-is-single-threaded.json:0
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
[ 1428ms] [WARNING] For security reasons, Hotjar only works over HTTPS. Learn more: https://help.hotjar.com/hc/en-us/articles/115011624047 @ https://static.hotjar.com/c/hotjar-5066415.js?sv=7:2
|
|
2
|
-
[ 1557ms] [WARNING] <meta name="apple-mobile-web-app-capable" content="yes"> is deprecated. Please include <meta name="mobile-web-app-capable" content="yes"> @ http://127.0.0.1:4000/:0
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
[ 106ms] [WARNING] For security reasons, Hotjar only works over HTTPS. Learn more: https://help.hotjar.com/hc/en-us/articles/115011624047 @ https://static.hotjar.com/c/hotjar-5066415.js?sv=7:2
|
|
2
|
-
[ 422ms] [WARNING] <meta name="apple-mobile-web-app-capable" content="yes"> is deprecated. Please include <meta name="mobile-web-app-capable" content="yes"> @ http://127.0.0.1:4000/about/:0
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
[ 96ms] [WARNING] For security reasons, Hotjar only works over HTTPS. Learn more: https://help.hotjar.com/hc/en-us/articles/115011624047 @ https://static.hotjar.com/c/hotjar-5066415.js?sv=7:2
|
|
2
|
-
[ 359ms] [WARNING] <meta name="apple-mobile-web-app-capable" content="yes"> is deprecated. Please include <meta name="mobile-web-app-capable" content="yes"> @ http://127.0.0.1:4000/posts/ai-junior/:0
|
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
- generic [active] [ref=e1]:
|
|
2
|
-
- complementary "Sidebar" [ref=e2]:
|
|
3
|
-
- generic [ref=e3]:
|
|
4
|
-
- link "Go to homepage" [ref=e4] [cursor=pointer]:
|
|
5
|
-
- /url: /
|
|
6
|
-
- generic [ref=e5]: Go to homepage
|
|
7
|
-
- generic [ref=e6]: Go to homepage
|
|
8
|
-
- img [ref=e7]
|
|
9
|
-
- heading "Go to homepage" [level=1] [ref=e8]:
|
|
10
|
-
- link "Go to homepage" [ref=e9] [cursor=pointer]:
|
|
11
|
-
- /url: /
|
|
12
|
-
- text: Eugene Leontev The Engineer
|
|
13
|
-
- paragraph [ref=e10]: Innovate. Code. Inspire. Since 1984.
|
|
14
|
-
- navigation [ref=e11]:
|
|
15
|
-
- list [ref=e12]:
|
|
16
|
-
- listitem [ref=e13]:
|
|
17
|
-
- link "Go to homepage" [ref=e14] [cursor=pointer]:
|
|
18
|
-
- /url: /
|
|
19
|
-
- generic [ref=e15]:
|
|
20
|
-
- generic [ref=e16]: HOME
|
|
21
|
-
- listitem [ref=e17]:
|
|
22
|
-
- link "Go to CATEGORIES" [ref=e18] [cursor=pointer]:
|
|
23
|
-
- /url: /categories/
|
|
24
|
-
- generic [ref=e19]:
|
|
25
|
-
- generic [ref=e20]: CATEGORIES
|
|
26
|
-
- listitem [ref=e21]:
|
|
27
|
-
- link "Go to TAGS" [ref=e22] [cursor=pointer]:
|
|
28
|
-
- /url: /tags/
|
|
29
|
-
- generic [ref=e23]:
|
|
30
|
-
- generic [ref=e24]: TAGS
|
|
31
|
-
- listitem [ref=e25]:
|
|
32
|
-
- link "Go to ARCHIVES" [ref=e26] [cursor=pointer]:
|
|
33
|
-
- /url: /archives/
|
|
34
|
-
- generic [ref=e27]:
|
|
35
|
-
- generic [ref=e28]: ARCHIVES
|
|
36
|
-
- listitem [ref=e29]:
|
|
37
|
-
- link "Go to ABOUT" [ref=e30] [cursor=pointer]:
|
|
38
|
-
- /url: /about/
|
|
39
|
-
- generic [ref=e31]:
|
|
40
|
-
- generic [ref=e32]: ABOUT
|
|
41
|
-
- listitem [ref=e33]:
|
|
42
|
-
- link "Go to MOTIVATION TEST" [ref=e34] [cursor=pointer]:
|
|
43
|
-
- /url: /motivation-test/
|
|
44
|
-
- generic [ref=e35]:
|
|
45
|
-
- generic [ref=e36]: MOTIVATION TEST
|
|
46
|
-
- listitem [ref=e37]:
|
|
47
|
-
- link "Go to TERMS PRIVACY POLICY" [ref=e38] [cursor=pointer]:
|
|
48
|
-
- /url: /terms-privacy-policy/
|
|
49
|
-
- generic [ref=e39]:
|
|
50
|
-
- generic [ref=e40]: TERMS PRIVACY POLICY
|
|
51
|
-
- generic [ref=e41]:
|
|
52
|
-
- link "Visit GitHub profile" [ref=e42] [cursor=pointer]:
|
|
53
|
-
- /url: https://github.com/madmatvey
|
|
54
|
-
- generic [ref=e43]: Visit GitHub profile
|
|
55
|
-
- generic [ref=e44]: Visit GitHub profile
|
|
56
|
-
- generic [ref=e45]:
|
|
57
|
-
- link "Visit X (Twitter) profile" [ref=e46] [cursor=pointer]:
|
|
58
|
-
- /url: https://x.com/EugeneLeontev
|
|
59
|
-
- generic [ref=e47]: Visit X (Twitter) profile
|
|
60
|
-
- generic [ref=e48]: Visit X (Twitter) profile
|
|
61
|
-
- generic [ref=e49]:
|
|
62
|
-
- link "Send email" [ref=e50] [cursor=pointer]:
|
|
63
|
-
- /url: javascript:location.href = 'mailto:' + ['potehin','gmail.com'].join('@')
|
|
64
|
-
- generic [ref=e51]: Send email
|
|
65
|
-
- generic [ref=e52]: Send email
|
|
66
|
-
- generic [ref=e53]:
|
|
67
|
-
- link "RSS feed" [ref=e54] [cursor=pointer]:
|
|
68
|
-
- /url: /feed.xml
|
|
69
|
-
- generic [ref=e55]: RSS feed
|
|
70
|
-
- generic [ref=e56]: RSS feed
|
|
71
|
-
- generic [ref=e57]:
|
|
72
|
-
- link "Visit LinkedIn profile" [ref=e58] [cursor=pointer]:
|
|
73
|
-
- /url: https://www.linkedin.com/in/eugeneleontev/
|
|
74
|
-
- generic [ref=e59]: Visit LinkedIn profile
|
|
75
|
-
- generic [ref=e60]: Visit LinkedIn profile
|
|
76
|
-
- generic [ref=e61]:
|
|
77
|
-
- generic [ref=e62]:
|
|
78
|
-
- generic [ref=e63]:
|
|
79
|
-
- banner "Top Bar" [ref=e64]:
|
|
80
|
-
- generic [ref=e65]:
|
|
81
|
-
- navigation "Breadcrumb" [ref=e66]: Home
|
|
82
|
-
- text:
|
|
83
|
-
- search [ref=e67]:
|
|
84
|
-
- generic [ref=e68]:
|
|
85
|
-
- searchbox "search" [ref=e69]
|
|
86
|
-
- generic [ref=e70]:
|
|
87
|
-
- main "Main Content" [ref=e71]:
|
|
88
|
-
- generic [ref=e72]:
|
|
89
|
-
- article [ref=e73]:
|
|
90
|
-
- link "Diagram showing Redis is single-threaded on the outside, but multithreaded on the inside Single-Threaded on the Outside, Multithreaded on the Inside Learn how Redis is single-threaded on the outside, but multithreaded on the inside. Read the full case study! Mar 4, 2026 Tutorial, Coding" [ref=e74] [cursor=pointer]:
|
|
91
|
-
- /url: /posts/redis-is-single-threaded/
|
|
92
|
-
- img "Diagram showing Redis is single-threaded on the outside, but multithreaded on the inside" [ref=e77]
|
|
93
|
-
- generic [ref=e79]:
|
|
94
|
-
- heading "Single-Threaded on the Outside, Multithreaded on the Inside" [level=2] [ref=e80]
|
|
95
|
-
- paragraph [ref=e82]: Learn how Redis is single-threaded on the outside, but multithreaded on the inside. Read the full case study!
|
|
96
|
-
- generic [ref=e84]:
|
|
97
|
-
- generic [ref=e85]:
|
|
98
|
-
- time [ref=e86]: Mar 4, 2026
|
|
99
|
-
- generic [ref=e87]:
|
|
100
|
-
- text: Tutorial, Coding
|
|
101
|
-
- article [ref=e88]:
|
|
102
|
-
- 'link "Diagram showing data loading optimization in Telegram Mini App When Loading Data Isn''t Simple: Decisions Under Uncertainty Learn how we eliminated UI flicker and reduced load time in a Telegram Mini App by loading all user data in a single PostgreSQL query. Read the full case study! Feb 4, 2026 Product, UX" [ref=e89] [cursor=pointer]':
|
|
103
|
-
- /url: /posts/ux-when-initial-app-loading/
|
|
104
|
-
- img "Diagram showing data loading optimization in Telegram Mini App" [ref=e92]
|
|
105
|
-
- generic [ref=e94]:
|
|
106
|
-
- 'heading "When Loading Data Isn''t Simple: Decisions Under Uncertainty" [level=2] [ref=e95]'
|
|
107
|
-
- paragraph [ref=e97]: Learn how we eliminated UI flicker and reduced load time in a Telegram Mini App by loading all user data in a single PostgreSQL query. Read the full case study!
|
|
108
|
-
- generic [ref=e99]:
|
|
109
|
-
- generic [ref=e100]:
|
|
110
|
-
- time [ref=e101]: Feb 4, 2026
|
|
111
|
-
- generic [ref=e102]:
|
|
112
|
-
- text: Product, UX
|
|
113
|
-
- article [ref=e103]:
|
|
114
|
-
- link "AI assistant coding illustration showing architectural thinking importance Why an AI Assistant Won’t Replace Your Architectural Thinking Learn why effective AI-powered development starts with your own architectural thinking and task decomposition — not just prompts. Discover how to think architecturally! Nov 3, 2025 AI, Problem Solving" [ref=e104] [cursor=pointer]:
|
|
115
|
-
- /url: /posts/ai-assited-coding-statement/
|
|
116
|
-
- img "AI assistant coding illustration showing architectural thinking importance" [ref=e107]
|
|
117
|
-
- generic [ref=e109]:
|
|
118
|
-
- heading "Why an AI Assistant Won’t Replace Your Architectural Thinking" [level=2] [ref=e110]
|
|
119
|
-
- paragraph [ref=e112]: Learn why effective AI-powered development starts with your own architectural thinking and task decomposition — not just prompts. Discover how to think architecturally!
|
|
120
|
-
- generic [ref=e114]:
|
|
121
|
-
- generic [ref=e115]:
|
|
122
|
-
- time [ref=e116]: Nov 3, 2025
|
|
123
|
-
- generic [ref=e117]:
|
|
124
|
-
- text: AI, Problem Solving
|
|
125
|
-
- article [ref=e118]:
|
|
126
|
-
- link "Illustration showing startup failure statistics and customer pain validation 90% of Startups Die Because the Customer Doesn’t Feel Pain 90% of startups fail because customers don’t feel real pain. Learn how to validate ideas, avoid AI chaos, and turn vision into a working product. Oct 13, 2025 Read this, Problem Solving" [ref=e119] [cursor=pointer]:
|
|
127
|
-
- /url: /posts/startups-will-die/
|
|
128
|
-
- img "Illustration showing startup failure statistics and customer pain validation" [ref=e122]
|
|
129
|
-
- generic [ref=e124]:
|
|
130
|
-
- heading "90% of Startups Die Because the Customer Doesn’t Feel Pain" [level=2] [ref=e125]
|
|
131
|
-
- paragraph [ref=e127]: 90% of startups fail because customers don’t feel real pain. Learn how to validate ideas, avoid AI chaos, and turn vision into a working product.
|
|
132
|
-
- generic [ref=e129]:
|
|
133
|
-
- generic [ref=e130]:
|
|
134
|
-
- time [ref=e131]: Oct 13, 2025
|
|
135
|
-
- generic [ref=e132]:
|
|
136
|
-
- text: Read this, Problem Solving
|
|
137
|
-
- article [ref=e133]:
|
|
138
|
-
- link "Cybersecurity warning about fake recruiters and LinkedIn phishing attacks When a Job Interview Turned Into a Cybersecurity Investigation Beware fake recruiters on LinkedIn. A real case of malware disguised as a job test, targeting crypto wallets and system data. Learn how to protect yourself. Aug 18, 2025 Cybersecurity, Crypto" [ref=e134] [cursor=pointer]:
|
|
139
|
-
- /url: /posts/recruiter-hacker/
|
|
140
|
-
- img "Cybersecurity warning about fake recruiters and LinkedIn phishing attacks" [ref=e137]
|
|
141
|
-
- generic [ref=e139]:
|
|
142
|
-
- heading "When a Job Interview Turned Into a Cybersecurity Investigation" [level=2] [ref=e140]
|
|
143
|
-
- paragraph [ref=e142]: Beware fake recruiters on LinkedIn. A real case of malware disguised as a job test, targeting crypto wallets and system data. Learn how to protect yourself.
|
|
144
|
-
- generic [ref=e144]:
|
|
145
|
-
- generic [ref=e145]:
|
|
146
|
-
- time [ref=e146]: Aug 18, 2025
|
|
147
|
-
- generic [ref=e147]:
|
|
148
|
-
- text: Cybersecurity, Crypto
|
|
149
|
-
- article [ref=e148]:
|
|
150
|
-
- 'link "TARS technique diagram for formulating AI prompts in Cursor How to Formulate Prompts in Cursor: The TARS Technique Learn how to formulate prompts in Cursor using the TARS technique (Task, Assumptions, Requirements, Specification) to get more accurate and helpful results. Jul 9, 2025 Tutorial, AI" [ref=e149] [cursor=pointer]':
|
|
151
|
-
- /url: /posts/tars-prompting/
|
|
152
|
-
- img "TARS technique diagram for formulating AI prompts in Cursor" [ref=e152]
|
|
153
|
-
- generic [ref=e154]:
|
|
154
|
-
- 'heading "How to Formulate Prompts in Cursor: The TARS Technique" [level=2] [ref=e155]'
|
|
155
|
-
- paragraph [ref=e157]: Learn how to formulate prompts in Cursor using the TARS technique (Task, Assumptions, Requirements, Specification) to get more accurate and helpful results.
|
|
156
|
-
- generic [ref=e159]:
|
|
157
|
-
- generic [ref=e160]:
|
|
158
|
-
- time [ref=e161]: Jul 9, 2025
|
|
159
|
-
- generic [ref=e162]:
|
|
160
|
-
- text: Tutorial, AI
|
|
161
|
-
- article [ref=e163]:
|
|
162
|
-
- 'link "Gasless USDT transactions on TRON blockchain using Ruby SDK Ruby gem ''gasfree_sdk'': Send USDT Without TRX on TRON Learn how to send USDT TRC-20 on TRON without needing TRX or energy using Ruby gem gasfree_sdk. Build gasless transactions and simplify Web3 UX. Jun 8, 2025 Tutorial, Crypto" [ref=e164] [cursor=pointer]':
|
|
163
|
-
- /url: /posts/introducing-ruby-gasless-sdk/
|
|
164
|
-
- img "Gasless USDT transactions on TRON blockchain using Ruby SDK" [ref=e167]
|
|
165
|
-
- generic [ref=e169]:
|
|
166
|
-
- 'heading "Ruby gem ''gasfree_sdk'': Send USDT Without TRX on TRON" [level=2] [ref=e170]'
|
|
167
|
-
- paragraph [ref=e172]: Learn how to send USDT TRC-20 on TRON without needing TRX or energy using Ruby gem gasfree_sdk. Build gasless transactions and simplify Web3 UX.
|
|
168
|
-
- generic [ref=e174]:
|
|
169
|
-
- generic [ref=e175]:
|
|
170
|
-
- time [ref=e176]: Jun 8, 2025
|
|
171
|
-
- generic [ref=e177]:
|
|
172
|
-
- text: Tutorial, Crypto
|
|
173
|
-
- article [ref=e178]:
|
|
174
|
-
- link "AI junior developer illustration showing Cursor.ai productivity boost How I Hired a Fast AI Junior Developer for $192 a Year How I use Cursor.ai as a fast AI junior developer for $192/year to speed up coding, automate tasks, and boost productivity by 2-3x. Learn more! Feb 3, 2025 Personal, Blog" [ref=e179] [cursor=pointer]:
|
|
175
|
-
- /url: /posts/ai-junior/
|
|
176
|
-
- img "AI junior developer illustration showing Cursor.ai productivity boost" [ref=e182]
|
|
177
|
-
- generic [ref=e184]:
|
|
178
|
-
- heading "How I Hired a Fast AI Junior Developer for $192 a Year" [level=2] [ref=e185]
|
|
179
|
-
- paragraph [ref=e187]: How I use Cursor.ai as a fast AI junior developer for $192/year to speed up coding, automate tasks, and boost productivity by 2-3x. Learn more!
|
|
180
|
-
- generic [ref=e189]:
|
|
181
|
-
- generic [ref=e190]:
|
|
182
|
-
- time [ref=e191]: Feb 3, 2025
|
|
183
|
-
- generic [ref=e192]:
|
|
184
|
-
- text: Personal, Blog
|
|
185
|
-
- article [ref=e193]:
|
|
186
|
-
- link "Top 5 must-read books for engineering leaders Top 5 Must-Read Books for Engineering Leaders Top 5 must-read books for engineering leaders to boost team dynamics, drive innovation, and master flexible leadership. Read more! Sep 26, 2024 Read this, Leadership" [ref=e194] [cursor=pointer]:
|
|
187
|
-
- /url: /posts/top-five-books-for-engineering-leaders/
|
|
188
|
-
- img "Top 5 must-read books for engineering leaders" [ref=e197]
|
|
189
|
-
- generic [ref=e199]:
|
|
190
|
-
- heading "Top 5 Must-Read Books for Engineering Leaders" [level=2] [ref=e200]
|
|
191
|
-
- paragraph [ref=e202]: Top 5 must-read books for engineering leaders to boost team dynamics, drive innovation, and master flexible leadership. Read more!
|
|
192
|
-
- generic [ref=e204]:
|
|
193
|
-
- generic [ref=e205]:
|
|
194
|
-
- time [ref=e206]: Sep 26, 2024
|
|
195
|
-
- generic [ref=e207]:
|
|
196
|
-
- text: Read this, Leadership
|
|
197
|
-
- article [ref=e208]:
|
|
198
|
-
- 'link "Product-minded software engineer illustration showing product-focused development approach Product-Minded Software Engineer: Key Asset for Teams In today''s tech industry, successful engineers are product-minded, deeply involved in product decisions, user behavior, and business success. Aug 30, 2024 Leadership, Product Development" [ref=e209] [cursor=pointer]':
|
|
199
|
-
- /url: /posts/product-minded-engineer/
|
|
200
|
-
- img "Product-minded software engineer illustration showing product-focused development approach" [ref=e212]
|
|
201
|
-
- generic [ref=e214]:
|
|
202
|
-
- 'heading "Product-Minded Software Engineer: Key Asset for Teams" [level=2] [ref=e215]'
|
|
203
|
-
- paragraph [ref=e217]: In today's tech industry, successful engineers are product-minded, deeply involved in product decisions, user behavior, and business success.
|
|
204
|
-
- generic [ref=e219]:
|
|
205
|
-
- generic [ref=e220]:
|
|
206
|
-
- time [ref=e221]: Aug 30, 2024
|
|
207
|
-
- generic [ref=e222]:
|
|
208
|
-
- text: Leadership, Product Development
|
|
209
|
-
- navigation "Page Navigation" [ref=e223]:
|
|
210
|
-
- list [ref=e224]:
|
|
211
|
-
- listitem [ref=e225]:
|
|
212
|
-
- link "Go to previous page":
|
|
213
|
-
- /url: "#"
|
|
214
|
-
- generic: Go to previous page
|
|
215
|
-
- generic: Go to previous page
|
|
216
|
-
- generic:
|
|
217
|
-
- listitem [ref=e226]:
|
|
218
|
-
- link "Go to page 1" [ref=e227] [cursor=pointer]:
|
|
219
|
-
- /url: /
|
|
220
|
-
- text: "1"
|
|
221
|
-
- listitem [ref=e228]:
|
|
222
|
-
- link "Go to page 2" [ref=e229] [cursor=pointer]:
|
|
223
|
-
- /url: /page2
|
|
224
|
-
- text: "2"
|
|
225
|
-
- listitem [ref=e230]:
|
|
226
|
-
- link "Go to page 3" [ref=e231] [cursor=pointer]:
|
|
227
|
-
- /url: /page3
|
|
228
|
-
- text: "3"
|
|
229
|
-
- listitem [ref=e232]:
|
|
230
|
-
- link "Go to next page" [ref=e233] [cursor=pointer]:
|
|
231
|
-
- /url: /page2
|
|
232
|
-
- generic [ref=e234]: Go to next page
|
|
233
|
-
- generic [ref=e235]: Go to next page
|
|
234
|
-
- generic [ref=e236]:
|
|
235
|
-
- complementary "Panel" [ref=e237]:
|
|
236
|
-
- generic [ref=e238]:
|
|
237
|
-
- generic [ref=e239]:
|
|
238
|
-
- heading "Recently Updated" [level=2] [ref=e240]
|
|
239
|
-
- list [ref=e241]:
|
|
240
|
-
- listitem [ref=e242]:
|
|
241
|
-
- link "Single-Threaded on the Outside, Multithreaded on the Inside" [ref=e243] [cursor=pointer]:
|
|
242
|
-
- /url: /posts/redis-is-single-threaded/
|
|
243
|
-
- listitem [ref=e244]:
|
|
244
|
-
- 'link "How to Formulate Prompts in Cursor: The TARS Technique" [ref=e245] [cursor=pointer]':
|
|
245
|
-
- /url: /posts/tars-prompting/
|
|
246
|
-
- listitem [ref=e246]:
|
|
247
|
-
- 'link "Product-Minded Software Engineer: Key Asset for Teams" [ref=e247] [cursor=pointer]':
|
|
248
|
-
- /url: /posts/product-minded-engineer/
|
|
249
|
-
- listitem [ref=e248]:
|
|
250
|
-
- 'link "Ruby gem ''gasfree_sdk'': Send USDT Without TRX on TRON" [ref=e249] [cursor=pointer]':
|
|
251
|
-
- /url: /posts/introducing-ruby-gasless-sdk/
|
|
252
|
-
- listitem [ref=e250]:
|
|
253
|
-
- 'link "Discovering Your IKIGAI: Foundation of Strategic Job Search" [ref=e251] [cursor=pointer]':
|
|
254
|
-
- /url: /posts/ikigai/
|
|
255
|
-
- generic [ref=e252]:
|
|
256
|
-
- heading "Trending Tags" [level=2] [ref=e253]
|
|
257
|
-
- generic [ref=e254]:
|
|
258
|
-
- link "software development" [ref=e255] [cursor=pointer]:
|
|
259
|
-
- /url: /tags/software-development/
|
|
260
|
-
- link "innovation" [ref=e256] [cursor=pointer]:
|
|
261
|
-
- /url: /tags/innovation/
|
|
262
|
-
- link "programming" [ref=e257] [cursor=pointer]:
|
|
263
|
-
- /url: /tags/programming/
|
|
264
|
-
- link "tech blog" [ref=e258] [cursor=pointer]:
|
|
265
|
-
- /url: /tags/tech-blog/
|
|
266
|
-
- link "problem-solving" [ref=e259] [cursor=pointer]:
|
|
267
|
-
- /url: /tags/problem-solving/
|
|
268
|
-
- link "engineering leadership" [ref=e260] [cursor=pointer]:
|
|
269
|
-
- /url: /tags/engineering-leadership/
|
|
270
|
-
- link "personal development" [ref=e261] [cursor=pointer]:
|
|
271
|
-
- /url: /tags/personal-development/
|
|
272
|
-
- link "tech" [ref=e262] [cursor=pointer]:
|
|
273
|
-
- /url: /tags/tech/
|
|
274
|
-
- link "leadership" [ref=e263] [cursor=pointer]:
|
|
275
|
-
- /url: /tags/leadership/
|
|
276
|
-
- link "career development" [ref=e264] [cursor=pointer]:
|
|
277
|
-
- /url: /tags/career-development/
|
|
278
|
-
- contentinfo "Site Info" [ref=e267]:
|
|
279
|
-
- paragraph [ref=e268]:
|
|
280
|
-
- text: ©
|
|
281
|
-
- time [ref=e269]: "2026"
|
|
282
|
-
- link "Visit Eugene Leontev's profile" [ref=e270] [cursor=pointer]:
|
|
283
|
-
- /url: https://x.com/EugeneLeontev
|
|
284
|
-
- text: Eugene Leontev
|
|
285
|
-
- text: . Some rights reserved.
|
|
286
|
-
- paragraph [ref=e271]:
|
|
287
|
-
- text: Using the
|
|
288
|
-
- link "Visit Chirpy theme on GitHub" [ref=e272] [cursor=pointer]:
|
|
289
|
-
- /url: https://github.com/cotes2020/jekyll-theme-chirpy
|
|
290
|
-
- text: Chirpy
|
|
291
|
-
- text: theme for
|
|
292
|
-
- link "Visit Jekyll website" [ref=e273] [cursor=pointer]:
|
|
293
|
-
- /url: https://jekyllrb.com
|
|
294
|
-
- text: Jekyll
|
|
295
|
-
- text: .
|
|
296
|
-
- text: "# # # # # # # # # #"
|
|
297
|
-
- complementary "Scroll to Top"
|